зеркало из https://github.com/mozilla/pjs.git
Bug 709566 - B2G SMS: PDU parser for GSM. r=qDot
This commit is contained in:
Родитель
3c7a99f993
Коммит
eb48fa8489
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Kyle Machulis <kyle@nonpolynomial.com>
|
||||
* Philipp von Weitershausen <philipp@weitershausen.de>
|
||||
* Fernando Jimenez <ferjmoreno@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -205,6 +206,8 @@ const CALL_PRESENTATION_RESTRICTED = 1;
|
|||
const CALL_PRESENTATION_UNKNOWN = 2;
|
||||
const CALL_PRESENTATION_PAYPHONE = 3;
|
||||
|
||||
const SMS_HANDLED = 0;
|
||||
|
||||
|
||||
/**
|
||||
* DOM constants
|
||||
|
@ -241,3 +244,172 @@ const RIL_TO_DOM_CALL_STATE = [
|
|||
DOM_CALL_READYSTATE_INCOMING, // CALL_READYSTATE_INCOMING
|
||||
DOM_CALL_READYSTATE_HELD // CALL_READYSTATE_WAITING (XXX is this right?)
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* GSM PDU constants
|
||||
*/
|
||||
|
||||
// PDU TYPE-OF-ADDRESS
|
||||
const PDU_TOA_UNKNOWN = 0x80; // Unknown. This is used when the user or
|
||||
// network has no a priori information
|
||||
// about the numbering plan.
|
||||
const PDU_TOA_ISDN = 0x81; // ISDN/Telephone numbering
|
||||
const PDU_TOA_DATA_NUM = 0x83; // Data numbering plan
|
||||
const PDU_TOA_TELEX_NUM = 0x84; // Telex numbering plan
|
||||
const PDU_TOA_NATIONAL_NUM = 0x88; // National numbering plan
|
||||
const PDU_TOA_PRIVATE_NUM = 0x89; // Private numbering plan
|
||||
const PDU_TOA_ERMES_NUM = 0x8A; // Ermes numbering plan
|
||||
const PDU_TOA_INTERNATIONAL = 0x90; // International number
|
||||
const PDU_TOA_NATIONAL = 0xA0; // National number. Prefix or escape digits
|
||||
// shall not be included
|
||||
const PDU_TOA_NETWORK_SPEC = 0xB0; // Network specific number This is used to
|
||||
// indicate administration/service number
|
||||
// specific to the serving network
|
||||
const PDU_TOA_SUSCRIBER = 0xC0; // Suscriber number. This is used when a
|
||||
// specific short number representation is
|
||||
// stored in one or more SCs as part of a
|
||||
// higher layer application
|
||||
const PDU_TOA_ALPHANUMERIC = 0xD0; // Alphanumeric, (coded according to GSM TS
|
||||
// 03.38 7-bit default alphabet)
|
||||
const PDU_TOA_ABBREVIATED = 0xE0; // Abbreviated number
|
||||
|
||||
/**
|
||||
* First octet of the SMS-DELIVER PDU
|
||||
*
|
||||
* RP: 0 Reply Path parameter is not set in this PDU
|
||||
* 1 Reply Path parameter is set in this PDU
|
||||
*
|
||||
* UDHI: 0 The UD field contains only the short message
|
||||
* 1 The beginning of the UD field contains a header in addition of
|
||||
* the short message
|
||||
*
|
||||
* SRI: (is only set by the SMSC)
|
||||
* 0 A status report will not be returned to the SME
|
||||
* 1 A status report will be returned to the SME
|
||||
*
|
||||
* MMS: (is only set by the SMSC)
|
||||
* 0 More messages are waiting for the MS in the SMSC
|
||||
* 1 No more messages are waiting for the MS in the SMSC
|
||||
*
|
||||
* MTI: bit1 bit0 Message type
|
||||
* 0 0 SMS-DELIVER (SMSC ==> MS)
|
||||
* 0 0 SMS-DELIVER REPORT (MS ==> SMSC, is generated
|
||||
* automatically by the M20, after receiving a
|
||||
* SMS-DELIVER)
|
||||
* 0 1 SMS-SUBMIT (MS ==> SMSC)
|
||||
* 0 1 SMS-SUBMIT REPORT (SMSC ==> MS)
|
||||
* 1 0 SMS-STATUS REPORT (SMSC ==> MS)
|
||||
* 1 0 SMS-COMMAND (MS ==> SMSC)
|
||||
* 1 1 Reserved
|
||||
*/
|
||||
const PDU_RP = 0x80; // Reply path. Parameter indicating that
|
||||
// reply path exists.
|
||||
const PDU_UDHI = 0x40; // User data header indicator. This bit is
|
||||
// set to 1 if the User Data field starts
|
||||
// with a header
|
||||
const PDU_SRI_SRR = 0x20; // Status report indication (SMS-DELIVER)
|
||||
// or request (SMS-SUBMIT)
|
||||
const PDU_VPF_ABSOLUTE = 0x18;// Validity period aboslute format
|
||||
// (SMS-SUBMIT only)
|
||||
const PDU_VPF_RELATIVE = 0x10;// Validity period relative format
|
||||
// (SMS-SUBMIT only)
|
||||
const PDU_VPF_ENHANCED = 0x8; // Validity period enhance format
|
||||
// (SMS-SUBMIT only)
|
||||
const PDU_MMS_RD = 0x04;// More messages to send. (SMS-DELIVER only) or
|
||||
// Reject duplicates (SMS-SUBMIT only)
|
||||
|
||||
// MTI - Message Type Indicator
|
||||
const PDU_MTI_SMS_STATUS_COMMAND = 0x02;
|
||||
const PDU_MTI_SMS_SUBMIT = 0x01;
|
||||
const PDU_MTI_SMS_DELIVER = 0x00;
|
||||
|
||||
// User Data max length in octets
|
||||
const PDU_MAX_USER_DATA_7BIT = 160;
|
||||
|
||||
// DCS - Data Coding Scheme
|
||||
const PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0xF0;
|
||||
const PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0xF4;
|
||||
const PDU_DCS_MSG_CODING_16BITS_ALPHABET= 0x08;
|
||||
const PDU_DCS_MSG_CLASS_ME_SPECIFIC = 0xF1;
|
||||
const PDU_DCS_MSG_CLASS_SIM_SPECIFIC = 0xF2;
|
||||
const PDU_DCS_MSG_CLASS_TE_SPECIFIC = 0xF3;
|
||||
|
||||
// Because service center timestamp omit the century. Yay.
|
||||
const PDU_TIMESTAMP_YEAR_OFFSET = 2000;
|
||||
|
||||
// 7bit Default Alphabet
|
||||
//TODO: maybe convert this to a string? might be faster/cheaper
|
||||
const alphabet_7bit = [
|
||||
"@", // COMMERCIAL AT
|
||||
"\xa3", // POUND SIGN
|
||||
"$", // DOLLAR SIGN
|
||||
"\xa5", // YEN SIGN
|
||||
"\xe8", // LATIN SMALL LETTER E WITH GRAVE
|
||||
"\xe9", // LATIN SMALL LETTER E WITH ACUTE
|
||||
"\xf9", // LATIN SMALL LETTER U WITH GRAVE
|
||||
"\xec", // LATIN SMALL LETTER I WITH GRAVE
|
||||
"\xf2", // LATIN SMALL LETTER O WITH GRAVE
|
||||
"\xc7", // LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
"\n", // LINE FEED
|
||||
"\xd8", // LATIN CAPITAL LETTER O WITH STROKE
|
||||
"\xf8", // LATIN SMALL LETTER O WITH STROKE
|
||||
"\r", // CARRIAGE RETURN
|
||||
"\xc5", // LATIN CAPITAL LETTER A WITH RING ABOVE
|
||||
"\xe5", // LATIN SMALL LETTER A WITH RING ABOVE
|
||||
"\u0394", // GREEK CAPITAL LETTER DELTA
|
||||
"_", // LOW LINE
|
||||
"\u03a6", // GREEK CAPITAL LETTER PHI
|
||||
"\u0393", // GREEK CAPITAL LETTER GAMMA
|
||||
"\u039b", // GREEK CAPITAL LETTER LAMBDA
|
||||
"\u03a9", // GREEK CAPITAL LETTER OMEGA
|
||||
"\u03a0", // GREEK CAPITAL LETTER PI
|
||||
"\u03a8", // GREEK CAPITAL LETTER PSI
|
||||
"\u03a3", // GREEK CAPITAL LETTER SIGMA
|
||||
"\u0398", // GREEK CAPITAL LETTER THETA
|
||||
"\u039e", // GREEK CAPITAL LETTER XI
|
||||
"\u20ac", // (escape to extension table)
|
||||
"\xc6", // LATIN CAPITAL LETTER AE
|
||||
"\xe6", // LATIN SMALL LETTER AE
|
||||
"\xdf", // LATIN SMALL LETTER SHARP S (German)
|
||||
"\xc9", // LATIN CAPITAL LETTER E WITH ACUTE
|
||||
" ", // SPACE
|
||||
"!", // EXCLAMATION MARK
|
||||
"\"", // QUOTATION MARK
|
||||
"#", // NUMBER SIGN
|
||||
"\xa4", // CURRENCY SIGN
|
||||
"%", // PERCENT SIGN
|
||||
"&", // AMPERSAND
|
||||
"'", // APOSTROPHE
|
||||
"(", // LEFT PARENTHESIS
|
||||
")", // RIGHT PARENTHESIS
|
||||
"*", // ASTERISK
|
||||
"+", // PLUS SIGN
|
||||
",", // COMMA
|
||||
"-", // HYPHEN-MINUS
|
||||
".", // FULL STOP
|
||||
"/", // SOLIDUS (SLASH)
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
":", // COLON
|
||||
";", // SEMICOLON
|
||||
"<", // LESS-THAN SIGN
|
||||
"=", // EQUALS SIGN
|
||||
">", // GREATER-THAN SIGN
|
||||
"?", // QUESTION MARK
|
||||
"\xa1", // INVERTED EXCLAMATION MARK
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
|
||||
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"\xc4", // LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
"\xd6", // LATIN CAPITAL LETTER O WITH DIAERESIS
|
||||
"\xd1", // LATIN CAPITAL LETTER N WITH TILDE
|
||||
"\xdc", // LATIN CAPITAL LETTER U WITH DIAERESIS
|
||||
"\xa7", // SECTION SIGN
|
||||
"\xbf", // INVERTED QUESTION MARK
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
|
||||
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"\xe4", // LATIN SMALL LETTER A WITH DIAERESIS
|
||||
"\xf6", // LATIN SMALL LETTER O WITH DIAERESIS
|
||||
"\xf1", // LATIN SMALL LETTER N WITH TILDE
|
||||
"\xfc", // LATIN SMALL LETTER U WITH DIAERESIS
|
||||
"\xe0" // LATIN SMALL LETTER A WITH GRAVE
|
||||
];
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* Contributor(s):
|
||||
* Kyle Machulis <kyle@nonpolynomial.com>
|
||||
* Philipp von Weitershausen <philipp@weitershausen.de>
|
||||
* Fernando Jimenez <ferjmoreno@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
|
@ -1452,6 +1453,312 @@ let Phone = {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* This object exposes the functionality to parse and serialize PDU strings
|
||||
*
|
||||
* A PDU is a string containing a series of hexadecimally encoded octets
|
||||
* or nibble-swapped binary-coded decimals (BCDs). It contains not only the
|
||||
* message text but information abou the sender, the SMS service center,
|
||||
* timestamp, etc.
|
||||
*/
|
||||
let GsmPDUHelper = {
|
||||
|
||||
/**
|
||||
* Read one character (2 bytes) from a RIL string and decode as hex.
|
||||
*
|
||||
* @return the nibble as a number.
|
||||
*/
|
||||
readHexNibble: function readHexNibble() {
|
||||
let nibble = Buf.readUint16();
|
||||
if (nibble >= 48 && nibble <= 57) {
|
||||
nibble -= 48;
|
||||
} else if (nibble >= 65 && nibble <= 70) {
|
||||
nibble -= 55;
|
||||
} else if (nibble >= 97 && nibble <= 102) {
|
||||
nibble -= 87;
|
||||
} else {
|
||||
throw "Found invalid nibble during PDU parsing: " +
|
||||
String.fromCharCode(nibble);
|
||||
}
|
||||
return nibble;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read a hex-encoded octet (two nibbles).
|
||||
*
|
||||
* @return the octet as a number.
|
||||
*/
|
||||
readHexOctet: function readHexOctet() {
|
||||
return (this.readHexNibble() << 4) | this.readHexNibble();
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert an octet (number) to a BCD number.
|
||||
*
|
||||
* Any nibbles that are not in the BCD range count as 0.
|
||||
*
|
||||
* @param octet
|
||||
* The octet (a number, as returned by getOctet())
|
||||
*
|
||||
* @return the corresponding BCD number.
|
||||
*/
|
||||
octetToBCD: function octetToBCD(octet) {
|
||||
return ((octet & 0xf0) <= 0x90) * ((octet >> 4) & 0x0f) +
|
||||
((octet & 0x0f) <= 0x09) * (octet & 0x0f) * 10;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read a *swapped nibble* binary coded decimal (BCD)
|
||||
*
|
||||
* @param length
|
||||
* Number of nibble *pairs* to read.
|
||||
*
|
||||
* @return the decimal as a number.
|
||||
*/
|
||||
readSwappedNibbleBCD: function readSwappedNibbleBCD(length) {
|
||||
let number = 0;
|
||||
for (let i = 0; i < length; i++) {
|
||||
let octet = this.readHexOctet();
|
||||
// If the first nibble is an "F" , only the second nibble is to be taken
|
||||
// into account.
|
||||
if ((octet & 0xf0) == 0xf0) {
|
||||
number *= 10;
|
||||
number += octet & 0x0f;
|
||||
continue;
|
||||
}
|
||||
number *= 100;
|
||||
number += this.octetToBCD(octet);
|
||||
}
|
||||
return number;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read user data, convert to septets, look up relevant characters in a
|
||||
* 7-bit alphabet, and construct string.
|
||||
*
|
||||
* @param length
|
||||
* Number of septets to read (*not* octets)
|
||||
*
|
||||
* @return a string.
|
||||
*
|
||||
* TODO: support other alphabets
|
||||
* TODO: support escape chars
|
||||
*/
|
||||
readSeptetsToString: function readSeptetsToString(length) {
|
||||
let ret = "";
|
||||
let byteLength = Math.ceil(length * 7 / 8);
|
||||
|
||||
let leftOver = 0;
|
||||
for (let i = 0; i < byteLength; i++) {
|
||||
let octet = this.readHexOctet();
|
||||
let shift = (i % 7);
|
||||
let leftOver_mask = (0xff << (7 - shift)) & 0xff;
|
||||
let septet_mask = (0xff >> (shift + 1));
|
||||
|
||||
let septet = ((octet & septet_mask) << shift) | leftOver;
|
||||
ret += alphabet_7bit[septet];
|
||||
leftOver = (octet & leftOver_mask) >> (7 - shift);
|
||||
|
||||
// Every 7th byte we have a whole septet left over that we can apply.
|
||||
if (shift == 6) {
|
||||
ret += alphabet_7bit[leftOver];
|
||||
leftOver = 0;
|
||||
}
|
||||
}
|
||||
if (ret.length != length) {
|
||||
ret = ret.slice(0, length);
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read user data and decode as a UCS2 string.
|
||||
*
|
||||
* @param length
|
||||
* XXX TODO
|
||||
*
|
||||
* @return a string.
|
||||
*/
|
||||
readUCS2String: function readUCS2String(length) {
|
||||
//TODO
|
||||
},
|
||||
|
||||
/**
|
||||
* User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit
|
||||
* (UCS2) data.
|
||||
*
|
||||
* TODO: This function currently supports only the default alphabet.
|
||||
*/
|
||||
readUserData: function readUserData(length, codingScheme) {
|
||||
if (DEBUG) {
|
||||
debug("Reading " + length + " bytes of user data.");
|
||||
debug("Coding scheme: " + codingScheme);
|
||||
}
|
||||
// 7 bit is the default fallback encoding.
|
||||
let encoding = 7;
|
||||
switch (codingScheme & 0xC0) {
|
||||
case 0x0:
|
||||
// bits 7..4 = 00xx
|
||||
switch (codingScheme & 0x0C) {
|
||||
case 0x4:
|
||||
encoding = 8;
|
||||
break;
|
||||
case 0x8:
|
||||
encoding = 16;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xC0:
|
||||
// bits 7..4 = 11xx
|
||||
switch (codingScheme & 0x30) {
|
||||
case 0x20:
|
||||
encoding = 16;
|
||||
break;
|
||||
case 0x30:
|
||||
if (!codingScheme & 0x04) {
|
||||
encoding = 8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Falling back to default encoding.
|
||||
break;
|
||||
}
|
||||
|
||||
if (DEBUG) debug("PDU: message encoding is " + encoding + " bit.");
|
||||
switch (encoding) {
|
||||
case 7:
|
||||
// 7 bit encoding allows 140 octets, which means 160 characters
|
||||
// ((140x8) / 7 = 160 chars)
|
||||
if (length > PDU_MAX_USER_DATA_7BIT) {
|
||||
if (DEBUG) debug("PDU error: user data is too long: " + length);
|
||||
return null;
|
||||
}
|
||||
return this.readSeptetsToString(length);
|
||||
case 8:
|
||||
// Unsupported.
|
||||
return null;
|
||||
case 16:
|
||||
return this.readUCS2String(length);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Read and decode a PDU-encoded message from the stream.
|
||||
*
|
||||
* TODO: add some basic sanity checks like:
|
||||
* - do we have the minimum number of chars available
|
||||
*/
|
||||
readMessage: function readMessage() {
|
||||
// An empty message object. This gets filled below and then returned.
|
||||
let msg = {
|
||||
SMSC: null,
|
||||
reference: null,
|
||||
sender: null,
|
||||
body: null,
|
||||
validity: null,
|
||||
timestamp: null
|
||||
};
|
||||
|
||||
// SMSC info
|
||||
let smscLength = this.readHexOctet();
|
||||
if (smscLength > 0) {
|
||||
let smscTypeOfAddress = this.readHexOctet();
|
||||
// Subtract the type-of-address octet we just read from the length.
|
||||
msg.SMSC = this.readSwappedNibbleBCD(smscLength - 1).toString();
|
||||
if ((smscTypeOfAddress >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) {
|
||||
msg.SMSC = '+' + msg.SMSC;
|
||||
}
|
||||
}
|
||||
|
||||
// First octet of this SMS-DELIVER or SMS-SUBMIT message
|
||||
let firstOctet = this.readHexOctet();
|
||||
// if the sms is of SMS-SUBMIT type it would contain a TP-MR
|
||||
let isSmsSubmit = firstOctet & PDU_MTI_SMS_SUBMIT;
|
||||
if (isSmsSubmit) {
|
||||
msg.reference = this.readHexOctet(); // TP-Message-Reference
|
||||
}
|
||||
|
||||
// - Sender Address info -
|
||||
// Address length
|
||||
let senderAddressLength = this.readHexOctet();
|
||||
if (senderAddressLength <= 0) {
|
||||
if (DEBUG) debug("PDU error: invalid sender address length: " + senderAddressLength);
|
||||
return null;
|
||||
}
|
||||
// Type-of-Address
|
||||
let senderTypeOfAddress = this.readHexOctet();
|
||||
if (senderAddressLength % 2 == 1) {
|
||||
senderAddressLength += 1;
|
||||
}
|
||||
if (DEBUG) debug("PDU: Going to read sender address: " + senderAddressLength);
|
||||
msg.sender = this.readSwappedNibbleBCD(senderAddressLength / 2).toString();
|
||||
if (msg.sender.length <= 0) {
|
||||
if (DEBUG) debug("PDU error: no sender number provided");
|
||||
return null;
|
||||
}
|
||||
if ((senderTypeOfAddress >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) {
|
||||
msg.sender = '+' + msg.sender;
|
||||
}
|
||||
|
||||
// - TP-Protocolo-Identifier -
|
||||
let protocolIdentifier = this.readHexOctet();
|
||||
|
||||
// - TP-Data-Coding-Scheme -
|
||||
let dataCodingScheme = this.readHexOctet();
|
||||
|
||||
// SMS of SMS-SUBMIT type contains a TP-Service-Center-Time-Stamp field
|
||||
// SMS of SMS-DELIVER type contains a TP-Validity-Period octet
|
||||
if (isSmsSubmit) {
|
||||
// - TP-Validity-Period -
|
||||
// The Validity Period octet is optional. Depends on the SMS-SUBMIT
|
||||
// first octet
|
||||
// Validity Period Format. Bit4 and Bit3 specify the TP-VP field
|
||||
// according to this table:
|
||||
// bit4 bit3
|
||||
// 0 0 : TP-VP field not present
|
||||
// 1 0 : TP-VP field present. Relative format (one octet)
|
||||
// 0 1 : TP-VP field present. Enhanced format (7 octets)
|
||||
// 1 1 : TP-VP field present. Absolute format (7 octets)
|
||||
if (firstOctet & (PDU_VPF_ABSOLUTE | PDU_VPF_RELATIVE | PDU_VPF_ENHANCED)) {
|
||||
msg.validity = this.readHexOctet();
|
||||
}
|
||||
//TODO: check validity period
|
||||
} else {
|
||||
// - TP-Service-Center-Time-Stamp -
|
||||
let year = this.readSwappedNibbleBCD(1) + PDU_TIMESTAMP_YEAR_OFFSET;
|
||||
let month = this.readSwappedNibbleBCD(1) - 1;
|
||||
let day = this.readSwappedNibbleBCD(1) - 1;
|
||||
let hour = this.readSwappedNibbleBCD(1) - 1;
|
||||
let minute = this.readSwappedNibbleBCD(1) - 1;
|
||||
let second = this.readSwappedNibbleBCD(1) - 1;
|
||||
msg.timestamp = Date.UTC(year, month, day, hour, minute, second);
|
||||
|
||||
// If the most significant bit of the least significant nibble is 1,
|
||||
// the timezone offset is negative (fourth bit from the right => 0x08).
|
||||
let tzOctet = this.readHexOctet();
|
||||
let tzOffset = this.octetToBCD(tzOctet & ~0x08) * 15 * 60 * 1000;
|
||||
if (tzOctet & 0x08) {
|
||||
msg.timestamp -= tzOffset;
|
||||
} else {
|
||||
msg.timestamp += tzOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// - TP-User-Data-Length -
|
||||
let userDataLength = this.readHexOctet();
|
||||
|
||||
// - TP-User-Data -
|
||||
if (userDataLength > 0) {
|
||||
msg.body = this.readUserData(userDataLength, dataCodingScheme);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Global stuff.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче