Give the esm_class bits one owner beside the constants
This commit is contained in:
@@ -206,6 +206,8 @@ exactly 140.
|
|||||||
keeps the scrape: SMSCs that send text-only receipts leave `esm_class` at 0, and reading that as
|
keeps the scrape: SMSCs that send text-only receipts leave `esm_class` at 0, and reading that as
|
||||||
the spec's "default message type" would lose every one of them. A `receipted_message_id` TLV marks
|
the spec's "default message type" would lose every one of them. A `receipted_message_id` TLV marks
|
||||||
a receipt on the same footing where the message type is 0, since nothing but a receipt carries one.
|
a receipt on the same footing where the message type is 0, since nothing but a receipt carries one.
|
||||||
|
What gets scraped is the decoded `short_message` with any UDH stripped, so a concatenated receipt
|
||||||
|
is read like any other.
|
||||||
The `message_state` TLV is authoritative only where it names a state in the table — SMPP reserves
|
The `message_state` TLV is authoritative only where it names a state in the table — SMPP reserves
|
||||||
0x80-0xFF for MC-vendor-specific values, so an unnameable one keeps its raw `statusId` and leaves
|
0x80-0xFF for MC-vendor-specific values, so an unnameable one keeps its raw `statusId` and leaves
|
||||||
`statusMsg` to the body.
|
`statusMsg` to the body.
|
||||||
|
|||||||
@@ -103,6 +103,15 @@ export const consts = {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
/** esm_class bits 5-2 name the message type; bit 6 is the UDH indicator. */
|
||||||
|
export function hasUdh(esmClass: number): boolean {
|
||||||
|
return (esmClass & consts.ESM_CLASS.UDH_INDICATOR) === consts.ESM_CLASS.UDH_INDICATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function messageTypeOf(esmClass: number): number {
|
||||||
|
return esmClass & 0x3c;
|
||||||
|
}
|
||||||
|
|
||||||
export type ConstGroup = keyof typeof consts;
|
export type ConstGroup = keyof typeof consts;
|
||||||
export type MessageState = keyof typeof consts.MESSAGE_STATE;
|
export type MessageState = keyof typeof consts.MESSAGE_STATE;
|
||||||
|
|
||||||
|
|||||||
+2
-5
@@ -1,7 +1,7 @@
|
|||||||
import type { MessageState } from './defs/constants.ts';
|
import type { MessageState } from './defs/constants.ts';
|
||||||
import type { ParamValue } from './defs/types.ts';
|
import type { ParamValue } from './defs/types.ts';
|
||||||
import type { PduObject } from './pdu.ts';
|
import type { PduObject } from './pdu.ts';
|
||||||
import { consts, constsById } from './defs/constants.ts';
|
import { consts, constsById, messageTypeOf } from './defs/constants.ts';
|
||||||
import { decodeMessage } from './message.ts';
|
import { decodeMessage } from './message.ts';
|
||||||
import { paramNumber, paramText } from './defs/types.ts';
|
import { paramNumber, paramText } from './defs/types.ts';
|
||||||
|
|
||||||
@@ -123,13 +123,10 @@ export function parseReceipt(message: string): Receipt {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** esm_class bits 5-2 name the message type; the rest are the messaging mode and the GSM features. */
|
|
||||||
const messageTypeBits = 0x3c;
|
|
||||||
|
|
||||||
type MessageType = 'other' | 'receipt' | 'unmarked';
|
type MessageType = 'other' | 'receipt' | 'unmarked';
|
||||||
|
|
||||||
function messageType(pduObj: PduObject): MessageType {
|
function messageType(pduObj: PduObject): MessageType {
|
||||||
const type = paramNumber(pduObj.params.esm_class, 0) & messageTypeBits;
|
const type = messageTypeOf(paramNumber(pduObj.params.esm_class, 0));
|
||||||
|
|
||||||
if (type === consts.ESM_CLASS.MC_DELIVERY_RECEIPT) return 'receipt';
|
if (type === consts.ESM_CLASS.MC_DELIVERY_RECEIPT) return 'receipt';
|
||||||
if (type !== 0) return 'other';
|
if (type !== 0) return 'other';
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import type { SmppLog } from './log.ts';
|
|||||||
import { Reassembler, decodeSegments } from './reassembly.ts';
|
import { Reassembler, decodeSegments } from './reassembly.ts';
|
||||||
import { bindCommands, defaults } from './session-options.ts';
|
import { bindCommands, defaults } from './session-options.ts';
|
||||||
import { concatInfo } from './udh.ts';
|
import { concatInfo } from './udh.ts';
|
||||||
import { consts } from './defs/constants.ts';
|
import { hasUdh } from './defs/constants.ts';
|
||||||
import { createSms } from './sms.ts';
|
import { createSms } from './sms.ts';
|
||||||
import { dlrFromPdu } from './dlr.ts';
|
import { dlrFromPdu } from './dlr.ts';
|
||||||
import { paramText } from './defs/types.ts';
|
import { paramNumber, paramText } from './defs/types.ts';
|
||||||
|
|
||||||
export type IncomingRequestsOptions = {
|
export type IncomingRequestsOptions = {
|
||||||
dlrMerger: DlrMerger;
|
dlrMerger: DlrMerger;
|
||||||
@@ -115,10 +115,8 @@ export class IncomingRequests {
|
|||||||
|
|
||||||
private onMessage(pduObj: PduObject): void {
|
private onMessage(pduObj: PduObject): void {
|
||||||
const message = pduObj.params.short_message;
|
const message = pduObj.params.short_message;
|
||||||
const esmClass = pduObj.params.esm_class;
|
const carriesUdh = hasUdh(paramNumber(pduObj.params.esm_class, 0));
|
||||||
const hasUdh = typeof esmClass === 'number'
|
const concat = carriesUdh && Buffer.isBuffer(message) ? concatInfo(message) : undefined;
|
||||||
&& (esmClass & consts.ESM_CLASS.UDH_INDICATOR) === consts.ESM_CLASS.UDH_INDICATOR;
|
|
||||||
const concat = hasUdh && Buffer.isBuffer(message) ? concatInfo(message) : undefined;
|
|
||||||
|
|
||||||
if (!concat) {
|
if (!concat) {
|
||||||
this.emitSms([pduObj]);
|
this.emitSms([pduObj]);
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
import type { Result } from './result.ts';
|
import type { Result } from './result.ts';
|
||||||
import type { EncodingName } from './defs/encodings.ts';
|
import type { EncodingName } from './defs/encodings.ts';
|
||||||
import { consts } from './defs/constants.ts';
|
import { hasUdh } from './defs/constants.ts';
|
||||||
import { detect, encodingByDataCoding, encodings } from './defs/encodings.ts';
|
import { detect, encodingByDataCoding, encodings } from './defs/encodings.ts';
|
||||||
|
|
||||||
/** A single SMS carries 1120 bits, whatever the alphabet. */
|
/** A single SMS carries 1120 bits, whatever the alphabet. */
|
||||||
@@ -33,7 +33,7 @@ export function decodeMessage(
|
|||||||
): { message: string; udh: Buffer | undefined } {
|
): { message: string; udh: Buffer | undefined } {
|
||||||
const encoding = encodingByDataCoding(dataCoding);
|
const encoding = encodingByDataCoding(dataCoding);
|
||||||
|
|
||||||
if ((esmClass & consts.ESM_CLASS.UDH_INDICATOR) !== consts.ESM_CLASS.UDH_INDICATOR) {
|
if (!hasUdh(esmClass)) {
|
||||||
return { message: encodings[encoding].decode(buffer), udh: undefined };
|
return { message: encodings[encoding].decode(buffer), udh: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@ import type { ParamValue } from './defs/types.ts';
|
|||||||
import type { Result, VoidResult } from './result.ts';
|
import type { Result, VoidResult } from './result.ts';
|
||||||
import type { Tlv } from './defs/tlvs.ts';
|
import type { Tlv } from './defs/tlvs.ts';
|
||||||
import { cmds, commandNameById, isCommandName } from './defs/commands.ts';
|
import { cmds, commandNameById, isCommandName } from './defs/commands.ts';
|
||||||
import { consts } from './defs/constants.ts';
|
import { consts, hasUdh } from './defs/constants.ts';
|
||||||
import { decodeMessage, encodeMessage } from './message.ts';
|
import { decodeMessage, encodeMessage } from './message.ts';
|
||||||
import { detect, encodingByDataCoding } from './defs/encodings.ts';
|
import { detect, encodingByDataCoding } from './defs/encodings.ts';
|
||||||
import { errorNameById, errors, isErrorName } from './defs/errors.ts';
|
import { errorNameById, errors, isErrorName } from './defs/errors.ts';
|
||||||
@@ -327,7 +327,7 @@ function parseOnce(pdu: Buffer, trailingNull: boolean): Result<{ aligned: boolea
|
|||||||
const esmClass = paramNumber(params.esm_class, 0);
|
const esmClass = paramNumber(params.esm_class, 0);
|
||||||
|
|
||||||
// A message carrying a UDH stays a buffer; the session needs the header intact to reassemble.
|
// A message carrying a UDH stays a buffer; the session needs the header intact to reassemble.
|
||||||
if (Buffer.isBuffer(message) && (esmClass & consts.ESM_CLASS.UDH_INDICATOR) !== consts.ESM_CLASS.UDH_INDICATOR) {
|
if (Buffer.isBuffer(message) && !hasUdh(esmClass)) {
|
||||||
params.short_message = decodeMessage(message, paramNumber(params.data_coding, 0)).message;
|
params.short_message = decodeMessage(message, paramNumber(params.data_coding, 0)).message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,12 +147,6 @@ session message is a change to every call site.
|
|||||||
`reassembly`, `dlr-merger`, `send-window`, `link-timers`, `reconnect-loop`, `pending-requests`
|
`reassembly`, `dlr-merger`, `send-window`, `link-timers`, `reconnect-loop`, `pending-requests`
|
||||||
and `send-sms`, so the directory would make that boundary visible. Do it on the next
|
and `send-sms`, so the directory would make that boundary visible. Do it on the next
|
||||||
extraction out of `session.ts`, not as a move of its own.
|
extraction out of `session.ts`, not as a move of its own.
|
||||||
- [ ] **Nothing owns the `esm_class` bits.** Three modules read them with their own literals:
|
|
||||||
`pdu.ts` decides decode-or-not, `incoming-requests.ts` reassemble-or-not and `dlr.ts`
|
|
||||||
receipt-or-not. That divergence is what let a UDH-carrying receipt reach `dlrFromPdu()` as an
|
|
||||||
undecoded buffer. Two predicates next to the constants would collapse it without touching
|
|
||||||
`index.ts`.
|
|
||||||
|
|
||||||
- [ ] **`submit_multi` and the broadcast commands** encode and decode, but nothing exercises them
|
- [ ] **`submit_multi` and the broadcast commands** encode and decode, but nothing exercises them
|
||||||
end to end. The interop suite is the natural place.
|
end to end. The interop suite is the natural place.
|
||||||
- [ ] **Move to TypeScript 7** once `typescript-eslint` supports it; `renovate.json` pins TypeScript
|
- [ ] **Move to TypeScript 7** once `typescript-eslint` supports it; `renovate.json` pins TypeScript
|
||||||
|
|||||||
Reference in New Issue
Block a user