ca1a7473ed
* Regression tests for the alphabet a GSM message declares * Declare the alphabet a GSM message is actually written in * Reflow the composing-by-hand paragraph * Drop the ASCII alias SMPP's flat table shares with the option's own * Bound the receipt test's wait and tighten the notes around it
152 lines
3.6 KiB
TypeScript
152 lines
3.6 KiB
TypeScript
/** The version declared on the wire. The tables below cover 5.0, which is a superset of it. */
|
|
export const defaultInterfaceVersion = 0x34;
|
|
|
|
/** Spec rule, not a preference: a peer declaring less than 3.4 is sent no optional parameters. */
|
|
export const optionalParamsMinVersion = 0x34;
|
|
|
|
export const consts = {
|
|
BROADCAST_AREA_FORMAT: {
|
|
ALIAS: 0x00,
|
|
ELLIPSOID_ARC: 0x01,
|
|
NAME: 0x00,
|
|
POLYGON: 0x02,
|
|
},
|
|
BROADCAST_FREQUENCY_INTERVAL: {
|
|
DAYS: 0x0B,
|
|
HOURS: 0x0A,
|
|
MAX_POSSIBLE: 0x00,
|
|
MINUTES: 0x09,
|
|
MONTHS: 0x0D,
|
|
SECONDS: 0x08,
|
|
WEEKS: 0x0C,
|
|
YEARS: 0x0E,
|
|
},
|
|
ENCODING: {
|
|
BINARY: 0x04,
|
|
CYRILLIC: 0x06,
|
|
EXTENDED_KANJI_JIS: 0x0D,
|
|
FLASH: 0x10,
|
|
HEBREW: 0x07,
|
|
IA5: 0x01,
|
|
ISO_2022_JP: 0x0A,
|
|
ISO_8859_1: 0x03,
|
|
ISO_8859_5: 0x06,
|
|
ISO_8859_8: 0x07,
|
|
JIS: 0x05,
|
|
KS_C_5601: 0x0E,
|
|
LATIN1: 0x03,
|
|
PICTOGRAM: 0x09,
|
|
UCS2: 0x08,
|
|
X_0208_1990: 0x05,
|
|
X_0212_1990: 0x0D,
|
|
},
|
|
ESM_CLASS: {
|
|
CONVERSATION_ABORT: 0x18,
|
|
DELIVERY_ACKNOWLEDGEMENT: 0x08,
|
|
INTERMEDIATE_DELIVERY: 0x20,
|
|
MC_DELIVERY_RECEIPT: 0x04,
|
|
SET_REPLY_PATH: 0x80,
|
|
UDH_INDICATOR: 0x40,
|
|
USER_ACKNOWLEDGEMENT: 0x10,
|
|
},
|
|
MESSAGE_STATE: {
|
|
ACCEPTED: 6,
|
|
DELETED: 4,
|
|
DELIVERED: 2,
|
|
ENROUTE: 1,
|
|
EXPIRED: 3,
|
|
REJECTED: 8,
|
|
SCHEDULED: 0,
|
|
SKIPPED: 9,
|
|
UNDELIVERABLE: 5,
|
|
UNKNOWN: 7,
|
|
},
|
|
/** SMPP 3.4 5.2.12 bits 1-0 of esm_class, the field the rest of that octet is OR-ed into. */
|
|
MESSAGING_MODE: {
|
|
DATAGRAM: 0x01,
|
|
FORWARD: 0x02,
|
|
SMSC_DEFAULT: 0x00,
|
|
STORE_FORWARD: 0x03,
|
|
},
|
|
NETWORK: {
|
|
CDMA: 0x03,
|
|
GENERIC: 0x00,
|
|
GSM: 0x01,
|
|
TDMA: 0x02,
|
|
},
|
|
NPI: {
|
|
DATA: 0x03,
|
|
ERMES: 0x0A,
|
|
INTERNET: 0x0E,
|
|
IP: 0x0E,
|
|
ISDN: 0x01,
|
|
LAND_MOBILE: 0x06,
|
|
NATIONAL: 0x08,
|
|
PRIVATE: 0x09,
|
|
TELEX: 0x04,
|
|
UNKNOWN: 0x00,
|
|
WAP: 0x12,
|
|
},
|
|
REGISTERED_DELIVERY: {
|
|
DELIVERY_ACKNOWLEDGEMENT: 0x04,
|
|
FAILURE: 0x02,
|
|
FINAL: 0x01,
|
|
INTERMEDIATE: 0x10,
|
|
SUCCESS: 0x03,
|
|
USER_ACKNOWLEDGEMENT: 0x08,
|
|
},
|
|
TON: {
|
|
ABBREVIATED: 0x06,
|
|
ALPHANUMERIC: 0x05,
|
|
INTERNATIONAL: 0x01,
|
|
NATIONAL: 0x02,
|
|
NETWORK_SPECIFIC: 0x03,
|
|
SUBSCRIBER_NUMBER: 0x04,
|
|
UNKNOWN: 0x00,
|
|
},
|
|
} as const;
|
|
|
|
export function hasUdh(esmClass: number): boolean {
|
|
return (esmClass & consts.ESM_CLASS.UDH_INDICATOR) === consts.ESM_CLASS.UDH_INDICATOR;
|
|
}
|
|
|
|
/** Bits 5-2 of esm_class; the rest carry the messaging mode and the GSM features. */
|
|
export function messageTypeOf(esmClass: number): number {
|
|
return esmClass & 0x3c;
|
|
}
|
|
|
|
export type ConstGroup = keyof typeof consts;
|
|
export type MessageState = keyof typeof consts.MESSAGE_STATE;
|
|
export type MessagingMode = keyof typeof consts.MESSAGING_MODE;
|
|
|
|
/** SMPP 3.4 2.10.3 carries transaction mode on `data_sm` alone, so a `submit_sm` never asks for it. */
|
|
const transactionMode = 'FORWARD' satisfies MessagingMode;
|
|
|
|
export const defaultMessagingMode = 'SMSC_DEFAULT' satisfies MessagingMode;
|
|
|
|
export type SubmitMessagingMode = Exclude<MessagingMode, typeof transactionMode>;
|
|
|
|
export const submitMessagingModes: readonly string[] = Object.keys(consts.MESSAGING_MODE)
|
|
.filter(mode => mode !== transactionMode);
|
|
|
|
export function isMessagingMode(value: unknown): value is MessagingMode {
|
|
return typeof value === 'string' && Object.hasOwn(consts.MESSAGING_MODE, value);
|
|
}
|
|
|
|
export function isSubmitMessagingMode(value: unknown): value is SubmitMessagingMode {
|
|
return isMessagingMode(value) && value !== transactionMode;
|
|
}
|
|
|
|
// Aliased values (NPI.IP === NPI.INTERNET === 0x0E) resolve to whichever name sorts last.
|
|
export const constsById: Record<string, Record<number, string>> = {};
|
|
|
|
for (const [groupName, group] of Object.entries(consts)) {
|
|
const byId: Record<number, string> = {};
|
|
|
|
for (const [name, value] of Object.entries(group)) {
|
|
byId[value] = name;
|
|
}
|
|
|
|
constsById[groupName] = byId;
|
|
}
|