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
|
||||
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.
|
||||
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
|
||||
0x80-0xFF for MC-vendor-specific values, so an unnameable one keeps its raw `statusId` and leaves
|
||||
`statusMsg` to the body.
|
||||
|
||||
@@ -103,6 +103,15 @@ export const consts = {
|
||||
},
|
||||
} 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 MessageState = keyof typeof consts.MESSAGE_STATE;
|
||||
|
||||
|
||||
+2
-5
@@ -1,7 +1,7 @@
|
||||
import type { MessageState } from './defs/constants.ts';
|
||||
import type { ParamValue } from './defs/types.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 { 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';
|
||||
|
||||
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 !== 0) return 'other';
|
||||
|
||||
@@ -6,10 +6,10 @@ import type { SmppLog } from './log.ts';
|
||||
import { Reassembler, decodeSegments } from './reassembly.ts';
|
||||
import { bindCommands, defaults } from './session-options.ts';
|
||||
import { concatInfo } from './udh.ts';
|
||||
import { consts } from './defs/constants.ts';
|
||||
import { hasUdh } from './defs/constants.ts';
|
||||
import { createSms } from './sms.ts';
|
||||
import { dlrFromPdu } from './dlr.ts';
|
||||
import { paramText } from './defs/types.ts';
|
||||
import { paramNumber, paramText } from './defs/types.ts';
|
||||
|
||||
export type IncomingRequestsOptions = {
|
||||
dlrMerger: DlrMerger;
|
||||
@@ -115,10 +115,8 @@ export class IncomingRequests {
|
||||
|
||||
private onMessage(pduObj: PduObject): void {
|
||||
const message = pduObj.params.short_message;
|
||||
const esmClass = pduObj.params.esm_class;
|
||||
const hasUdh = typeof esmClass === 'number'
|
||||
&& (esmClass & consts.ESM_CLASS.UDH_INDICATOR) === consts.ESM_CLASS.UDH_INDICATOR;
|
||||
const concat = hasUdh && Buffer.isBuffer(message) ? concatInfo(message) : undefined;
|
||||
const carriesUdh = hasUdh(paramNumber(pduObj.params.esm_class, 0));
|
||||
const concat = carriesUdh && Buffer.isBuffer(message) ? concatInfo(message) : undefined;
|
||||
|
||||
if (!concat) {
|
||||
this.emitSms([pduObj]);
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import type { Result } from './result.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';
|
||||
|
||||
/** A single SMS carries 1120 bits, whatever the alphabet. */
|
||||
@@ -33,7 +33,7 @@ export function decodeMessage(
|
||||
): { message: string; udh: Buffer | undefined } {
|
||||
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 };
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import type { ParamValue } from './defs/types.ts';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { Tlv } from './defs/tlvs.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 { detect, encodingByDataCoding } from './defs/encodings.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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -147,12 +147,6 @@ session message is a change to every call site.
|
||||
`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
|
||||
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
|
||||
end to end. The interop suite is the natural place.
|
||||
- [ ] **Move to TypeScript 7** once `typescript-eslint` supports it; `renovate.json` pins TypeScript
|
||||
|
||||
Reference in New Issue
Block a user