Full Code of linxGnu/gosmpp for AI

master 577c73e414d2 cached
115 files
344.5 KB
110.8k tokens
1106 symbols
1 requests
Download .txt
Showing preview only (372K chars total). Download the full file or copy to clipboard to get everything.
Repository: linxGnu/gosmpp
Branch: master
Commit: 577c73e414d2
Files: 115
Total size: 344.5 KB

Directory structure:
gitextract_d637zljl/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       └── go.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── README.md
├── connect.go
├── connect_test.go
├── connection.go
├── connection_test.go
├── data/
│   ├── 7bit.go
│   ├── 7bit_test.go
│   ├── codings.go
│   ├── codings_test.go
│   ├── header_data.go
│   ├── header_data_string.go
│   ├── other_codings.go
│   ├── pkg.go
│   ├── pkg_test.go
│   ├── utils.go
│   └── utils_test.go
├── errors/
│   ├── pkg.go
│   └── pkg_test.go
├── example/
│   ├── smsc_simulator/
│   │   └── smsc.cpp
│   ├── transceiver_with_auto_response/
│   │   └── main.go
│   ├── transceiver_with_manual_response/
│   │   └── main.go
│   ├── transeiver_with_custom_store/
│   │   ├── CustomStore.go
│   │   └── main.go
│   └── transeiver_with_request_window_and_custom_submitSm/
│       ├── CustomSubmitSM.go
│       └── main.go
├── go.mod
├── go.sum
├── pdu/
│   ├── Address.go
│   ├── AddressRange.go
│   ├── AddressRange_test.go
│   ├── Address_test.go
│   ├── AlertNotification.go
│   ├── AlertNotification_test.go
│   ├── BindRequest.go
│   ├── BindRequest_test.go
│   ├── BindResponse.go
│   ├── BindResponse_test.go
│   ├── Buffer.go
│   ├── Buffer_test.go
│   ├── CancelSM.go
│   ├── CancelSMResp.go
│   ├── CancelSMResp_test.go
│   ├── CancelSM_test.go
│   ├── DataSM.go
│   ├── DataSMResp.go
│   ├── DataSMResp_test.go
│   ├── DataSM_test.go
│   ├── DeliverSM.go
│   ├── DeliverSMResp.go
│   ├── DeliverSMResp_test.go
│   ├── DeliverSM_test.go
│   ├── DestinationAddress.go
│   ├── DestinationAddress_test.go
│   ├── DistributionList.go
│   ├── DistributionList_test.go
│   ├── EnquireLink.go
│   ├── EnquireLinkResp.go
│   ├── EnquireLinkResp_test.go
│   ├── EnquireLink_test.go
│   ├── GenericNack.go
│   ├── GenericNack_test.go
│   ├── Outbind.go
│   ├── Outbind_test.go
│   ├── PDU.go
│   ├── PDUFactory.go
│   ├── PDUFactory_test.go
│   ├── PDUHeader.go
│   ├── PDUHeader_test.go
│   ├── PDU_test.go
│   ├── QuerySM.go
│   ├── QuerySMResp.go
│   ├── QuerySMResp_test.go
│   ├── QuerySM_test.go
│   ├── ReplaceSM.go
│   ├── ReplaceSMResp.go
│   ├── ReplaceSMResp_test.go
│   ├── ReplaceSM_test.go
│   ├── ShortMessage.go
│   ├── ShortMessage_test.go
│   ├── SubmitMulti.go
│   ├── SubmitMultiResp.go
│   ├── SubmitMultiResp_test.go
│   ├── SubmitMulti_test.go
│   ├── SubmitSM.go
│   ├── SubmitSMResp.go
│   ├── SubmitSMResp_test.go
│   ├── SubmitSM_test.go
│   ├── TLV.go
│   ├── UDH.go
│   ├── UDH_test.go
│   ├── Unbind.go
│   ├── UnbindResp.go
│   ├── UnbindResp_test.go
│   ├── Unbind_test.go
│   ├── UnsuccessSME.go
│   ├── UnsuccessSME_test.go
│   └── helper_test.go
├── pkg.go
├── receivable.go
├── receivable_test.go
├── request_store.go
├── session.go
├── session_test.go
├── state.go
├── state_test.go
├── transceivable.go
├── transceivable_test.go
├── transmittable.go
├── transmittable_test.go
└── types.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: "gomod" # See documentation for possible values
    directory: "/" # Location of package manifests
    schedule:
      interval: "weekly"


================================================
FILE: .github/workflows/go.yml
================================================
name: Build
on: [push, pull_request]
jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      - name: Check out
        uses: actions/checkout@v5
      - name: Set up GCC
        run: |
          sudo apt install gcc g++ -y
        shell: bash
      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version: 1.24
      # - name: Linter
      #   uses: golangci/golangci-lint-action@v8
      #   with:
      #     version: latest
      - name: Start SMSC
        run: |
          g++ example/smsc_simulator/smsc.cpp -o smsc
          ./smsc &
        shell: bash
      - name: Test Coverage
        run: go test -v -race -count=1 -coverprofile=coverage.out
      - name: Convert coverage to lcov
        uses: jandelgado/gcov2lcov-action@v1
        with:
          version: latest
          infile: coverage.out
          outfile: coverage.lcov
      - name: Coveralls
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.github_token }}
          path-to-lcov: coverage.lcov


================================================
FILE: .gitignore
================================================
.idea/
vendor/
*DS_Store
*.out
smsc


================================================
FILE: .golangci.yml
================================================
version: "2"
linters:
  # Default set of linters.
  # The value can be:
  # - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
  # - `all`: enables all linters by default.
  # - `none`: disables all linters by default.
  # - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
  # Default: standard
  default: all
  # Enable specific linter.
  enable:
    - arangolint
    - asasalint
    - asciicheck
    - bidichk
    - bodyclose
    - canonicalheader
    - containedctx
    - contextcheck
    - copyloopvar
    - cyclop
    - decorder
    - depguard
    - dogsled
    - dupl
    - dupword
    - durationcheck
    - embeddedstructfieldcheck
    - err113
    - errcheck
    - errchkjson
    - errname
    - errorlint
    - exhaustive
    - exhaustruct
    - exptostd
    - fatcontext
    - forbidigo
    - forcetypeassert
    - funcorder
    - funlen
    - ginkgolinter
    - gocheckcompilerdirectives
    - gochecknoglobals
    - gochecknoinits
    - gochecksumtype
    - gocognit
    - goconst
    - gocritic
    - gocyclo
    - godot
    - godox
    - goheader
    - gomoddirectives
    - gomodguard
    - goprintffuncname
    - gosec
    - gosmopolitan
    - govet
    - grouper
    - iface
    - importas
    - inamedparam
    - ineffassign
    - interfacebloat
    - intrange
    - ireturn
    - lll
    - loggercheck
    - maintidx
    - makezero
    - mirror
    - misspell
    - mnd
    - musttag
    - nakedret
    - nestif
    - nilerr
    - nilnesserr
    - nilnil
    - nlreturn
    - noctx
    - noinlineerr
    - nolintlint
    - nonamedreturns
    - nosprintfhostport
    - paralleltest
    - perfsprint
    - prealloc
    - predeclared
    - promlinter
    - protogetter
    - reassign
    - recvcheck
    - revive
    - rowserrcheck
    - sloglint
    - spancheck
    - sqlclosecheck
    - tagalign
    - tagliatelle
    - testableexamples
    - testifylint
    - testpackage
    - thelper
    - tparallel
    - unconvert
    - unparam
    - unused
    - usestdlibvars
    - usetesting
    - varnamelen
    - wastedassign
    - whitespace
    - wrapcheck
    - wsl
    - wsl_v5
    - zerologlint
  # Disable specific linters.
  disable:
    - staticcheck
    - arangolint
    - asasalint
    - asciicheck
    - bidichk
    - bodyclose
    - canonicalheader
    - containedctx
    - contextcheck
    - copyloopvar
    - cyclop
    - decorder
    - depguard
    - dogsled
    - dupl
    - dupword
    - durationcheck
    - embeddedstructfieldcheck
    - err113
    - errcheck
    - errchkjson
    - errname
    - errorlint
    - exhaustive
    - exhaustruct
    - exptostd
    - fatcontext
    - forbidigo
    - forcetypeassert
    - funcorder
    - funlen
    - ginkgolinter
    - gocheckcompilerdirectives
    - gochecknoglobals
    - gochecknoinits
    - gochecksumtype
    - gocognit
    - goconst
    - gocritic
    - gocyclo
    - godot
    - godox
    - goheader
    - gomoddirectives
    - gomodguard
    - goprintffuncname
    - gosec
    - gosmopolitan
    - govet
    - grouper
    - iface
    - importas
    - inamedparam
    - ineffassign
    - interfacebloat
    - intrange
    - ireturn
    - lll
    - loggercheck
    - maintidx
    - makezero
    - mirror
    - misspell
    - mnd
    - musttag
    - nakedret
    - nestif
    - nilerr
    - nilnesserr
    - nilnil
    - nlreturn
    - noctx
    - noinlineerr
    - nolintlint
    - nonamedreturns
    - nosprintfhostport
    - paralleltest
    - perfsprint
    - prealloc
    - predeclared
    - promlinter
    - protogetter
    - reassign
    - recvcheck
    - revive
    - rowserrcheck
    - sloglint
    - spancheck
    - sqlclosecheck
    - staticcheck
    - tagalign
    - tagliatelle
    - testableexamples
    - testifylint
    - testpackage
    - thelper
    - tparallel
    - unconvert
    - unparam
    - unused
    - usestdlibvars
    - usetesting
    - varnamelen
    - wastedassign
    - whitespace
    - wrapcheck
    - wsl
    - wsl_v5
    - zerologlint


================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# gosmpp

[![](https://github.com/linxGnu/gosmpp/workflows/Build/badge.svg)]()
[![Go Report Card](https://goreportcard.com/badge/github.com/linxGnu/gosmpp)](https://goreportcard.com/report/github.com/linxGnu/gosmpp)
[![Coverage Status](https://coveralls.io/repos/github/linxGnu/gosmpp/badge.svg?branch=master)](https://coveralls.io/github/linxGnu/gosmpp?branch=master)
[![godoc](https://img.shields.io/badge/docs-GoDoc-green.svg)](https://godoc.org/github.com/linxGnu/gosmpp)

SMPP (3.4) Client Library in pure Go.

This library is well tested with SMSC simulators:
- [Melroselabs SMSC](https://melroselabs.com/services/smsc-simulator/#smsc-simulator-try)

## Installation
```
go get -u github.com/linxGnu/gosmpp
```

## Usage

### Highlight

- From `v0.1.4`, gosmpp is written in event-based style and fully-manage your smpp session, connection, error, rebinding, etc. You only need to implement some hooks:

```go
		trans, err := gosmpp.NewSession(
		gosmpp.TRXConnector(gosmpp.NonTLSDialer, auth),
		gosmpp.Settings{
			EnquireLink: 5 * time.Second,

			ReadTimeout: 10 * time.Second,

			OnSubmitError: func(_ pdu.PDU, err error) {
				log.Fatal("SubmitPDU error:", err)
			},

			OnReceivingError: func(err error) {
				fmt.Println("Receiving PDU/Network error:", err)
			},

			OnRebindingError: func(err error) {
				fmt.Println("Rebinding but error:", err)
			},

			OnPDU: handlePDU(),

			OnClosed: func(state gosmpp.State) {
				fmt.Println(state)
			},
		}, 5*time.Second)
		if err != nil {
		  log.Println(err)
		}
		defer func() {
		  _ = trans.Close()
		}()
```

### Version (0.1.4.RC+)

- Full example could be found: [here](https://github.com/linxGnu/gosmpp/blob/master/example)
  - In this example, you should run smsc first:
    - Build and run SMSC Simulator:
	```bash
	g++ -std=c++11 example/smsc_simulator/smsc.cpp -o smsc
	./smsc &
	```
    - Run smpp client in the example: https://github.com/linxGnu/gosmpp/blob/master/example/main.go
    ```bash
	go run example/main.go
	```

### Old version (0.1.3 and previous)
Full example could be found: [gist](https://gist.github.com/linxGnu/b488997a0e62b3f6a7060ba2af6391ea)

## Supported PDUs

- [x] bind_transmitter
- [x] bind_transmitter_resp
- [x] bind_receiver
- [x] bind_receiver_resp
- [x] bind_transceiver
- [x] bind_transceiver_resp
- [x] outbind
- [x] unbind
- [x] unbind_resp
- [x] submit_sm
- [x] submit_sm_resp
- [x] submit_sm_multi
- [x] submit_sm_multi_resp
- [x] data_sm
- [x] data_sm_resp
- [x] deliver_sm
- [x] deliver_sm_resp
- [x] query_sm
- [x] query_sm_resp
- [x] cancel_sm
- [x] cancel_sm_resp
- [x] replace_sm
- [x] replace_sm_resp
- [x] enquire_link
- [x] enquire_link_resp
- [x] alert_notification
- [x] generic_nack


================================================
FILE: connect.go
================================================
package gosmpp

import (
	"fmt"
	"net"

	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

var (
	// NonTLSDialer is non-tls connection dialer.
	NonTLSDialer = func(addr string) (net.Conn, error) {
		return net.Dial("tcp", addr)
	}
)

// Dialer is connection dialer.
type Dialer func(addr string) (net.Conn, error)

// Auth represents basic authentication to SMSC.
type Auth struct {
	// SMSC is SMSC address.
	SMSC       string
	SystemID   string
	Password   string
	SystemType string
}

type BindError struct {
	CommandStatus data.CommandStatusType
}

func (err BindError) Error() string {
	return fmt.Sprintf("binding error (%s): %s", err.CommandStatus, err.CommandStatus.Desc())
}

func newBindRequest(s Auth, bindingType pdu.BindingType, addressRange pdu.AddressRange) (bindReq *pdu.BindRequest) {
	bindReq = pdu.NewBindRequest(bindingType)
	bindReq.SystemID = s.SystemID
	bindReq.Password = s.Password
	bindReq.SystemType = s.SystemType
	bindReq.AddressRange = addressRange
	return
}

// Connector is connection factory interface.
type Connector interface {
	Connect() (conn *Connection, err error)
	GetBindType() pdu.BindingType
}

type connector struct {
	dialer       Dialer
	auth         Auth
	bindingType  pdu.BindingType
	addressRange pdu.AddressRange
}

func (c *connector) GetBindType() pdu.BindingType {
	return c.bindingType
}

func (c *connector) Connect() (conn *Connection, err error) {
	conn, err = connect(c.dialer, c.auth.SMSC, newBindRequest(c.auth, c.bindingType, c.addressRange))
	return
}

func connect(dialer Dialer, addr string, bindReq *pdu.BindRequest) (c *Connection, err error) {
	conn, err := dialer(addr)
	if err != nil {
		return
	}

	// create wrapped connection
	c = NewConnection(conn)

	// send binding request
	_, err = c.WritePDU(bindReq)
	if err != nil {
		_ = conn.Close()
		return
	}

	// catching response
	var (
		p    pdu.PDU
		resp *pdu.BindResp
	)

	for {
		if p, err = pdu.Parse(c); err != nil {
			_ = conn.Close()
			return
		}

		if pd, ok := p.(*pdu.BindResp); ok {
			resp = pd
			break
		}
	}

	if resp.CommandStatus != data.ESME_ROK {
		err = BindError{CommandStatus: resp.CommandStatus}
		_ = conn.Close()
	} else {
		c.systemID = resp.SystemID
	}

	return
}

// TXConnector returns a Transmitter (TX) connector.
func TXConnector(dialer Dialer, auth Auth) Connector {
	return &connector{
		dialer:      dialer,
		auth:        auth,
		bindingType: pdu.Transmitter,
	}
}

// RXConnector returns a Receiver (RX) connector.
func RXConnector(dialer Dialer, auth Auth, opts ...connectorOption) Connector {
	c := &connector{
		dialer:      dialer,
		auth:        auth,
		bindingType: pdu.Receiver,
	}
	for _, opt := range opts {
		opt(c)
	}
	return c
}

// TRXConnector returns a Transceiver (TRX) connector.
func TRXConnector(dialer Dialer, auth Auth, opts ...connectorOption) Connector {
	c := &connector{
		dialer:      dialer,
		auth:        auth,
		bindingType: pdu.Transceiver,
	}
	for _, opt := range opts {
		opt(c)
	}
	return c
}

type connectorOption func(c *connector)

func WithAddressRange(addressRange pdu.AddressRange) connectorOption {
	return func(c *connector) {
		c.addressRange = addressRange
	}
}


================================================
FILE: connect_test.go
================================================
package gosmpp

import (
	"github.com/linxGnu/gosmpp/pdu"
	"sync/atomic"
	"testing"

	"github.com/stretchr/testify/require"
)

var currentAuth int32

var auths = [][2]string{
	{"689528", "1a97ae"},
}

const (
	smscAddr = "127.0.0.1:2775"
	mess     = "Thử nghiệm: chuẩn bị nế mễ"
)

func nextAuth() Auth {
	pair := int(atomic.AddInt32(&currentAuth, 1)) % len(auths)
	return Auth{
		SMSC:       smscAddr,
		SystemID:   auths[pair][0],
		Password:   auths[pair][1],
		SystemType: "",
	}
}

func TestBindingSMSC(t *testing.T) {
	checker := func(t *testing.T, c Connector) {
		conn, err := c.Connect()
		require.Nil(t, err)
		require.NotNil(t, conn)
		_ = conn.Close()
	}

	t.Run("TX", func(t *testing.T) {
		checker(t, TXConnector(NonTLSDialer, nextAuth()))
	})

	t.Run("RX", func(t *testing.T) {
		checker(t, RXConnector(NonTLSDialer, nextAuth()))
	})
	t.Run("RX", func(t *testing.T) {
		addrRange := pdu.AddressRange{}
		addrRange.AddressRange = "31218"
		checker(t, RXConnector(NonTLSDialer, nextAuth(), WithAddressRange(addrRange)))
	})

	t.Run("TRX", func(t *testing.T) {
		checker(t, TRXConnector(NonTLSDialer, nextAuth()))
	})

	t.Run("TRX", func(t *testing.T) {
		addrRange := pdu.AddressRange{}
		addrRange.AddressRange = "31218"
		checker(t, TRXConnector(NonTLSDialer, nextAuth(), WithAddressRange(addrRange)))
	})
}

func TestBindingSMSC_Error(t *testing.T) {
	auth := Auth{SMSC: smscAddr, SystemID: "invalid"}
	checker := func(t *testing.T, c Connector) {
		conn, err := c.Connect()
		require.ErrorContains(t, err, "Invalid System ID")
		_ = conn.Close()
	}

	t.Run("TX", func(t *testing.T) {
		checker(t, TXConnector(NonTLSDialer, auth))
	})

	t.Run("RX", func(t *testing.T) {
		checker(t, RXConnector(NonTLSDialer, auth))
	})

	t.Run("TRX", func(t *testing.T) {
		checker(t, TRXConnector(NonTLSDialer, auth))
	})
}

func TestBindingType(t *testing.T) {
	auth := Auth{SMSC: smscAddr, SystemID: "invalid"}

	t.Run("TX", func(t *testing.T) {
		c := TXConnector(NonTLSDialer, auth)
		require.Equal(t, c.GetBindType(), pdu.Transmitter)
	})

	t.Run("RX", func(t *testing.T) {
		c := RXConnector(NonTLSDialer, auth)
		require.Equal(t, c.GetBindType(), pdu.Receiver)
	})

	t.Run("TRX", func(t *testing.T) {
		c := TRXConnector(NonTLSDialer, auth)
		require.Equal(t, c.GetBindType(), pdu.Transceiver)
	})
}


================================================
FILE: connection.go
================================================
package gosmpp

import (
	"bufio"
	"net"
	"time"

	"github.com/linxGnu/gosmpp/pdu"
)

// Connection wraps over net.Conn with buffered data reader.
type Connection struct {
	systemID string
	conn     net.Conn
	reader   *bufio.Reader
}

// NewConnection returns a Connection.
func NewConnection(conn net.Conn) (c *Connection) {
	c = &Connection{
		conn:   conn,
		reader: bufio.NewReaderSize(conn, 128<<10),
	}
	return
}

// Read reads data from the connection.
// Read can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
func (c *Connection) Read(b []byte) (n int, err error) {
	n, err = c.reader.Read(b)
	return
}

// Write writes data to the connection.
// Write can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
func (c *Connection) Write(b []byte) (n int, err error) {
	n, err = c.conn.Write(b)
	return
}

// WritePDU data to the connection.
func (c *Connection) WritePDU(p pdu.PDU) (n int, err error) {
	buf := pdu.NewBuffer(make([]byte, 0, 64))
	p.Marshal(buf)
	n, err = c.conn.Write(buf.Bytes())
	return
}

// Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors.
func (c *Connection) Close() error {
	return c.conn.Close()
}

// LocalAddr returns the local network address.
func (c *Connection) LocalAddr() net.Addr {
	return c.conn.LocalAddr()
}

// RemoteAddr returns the remote network address.
func (c *Connection) RemoteAddr() net.Addr {
	return c.conn.RemoteAddr()
}

// SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline.
//
// A deadline is an absolute time after which I/O operations
// fail with a timeout (see type Error) instead of
// blocking. The deadline applies to all future and pending
// I/O, not just the immediately following call to Read or
// Write. After a deadline has been exceeded, the connection
// can be refreshed by setting a deadline in the future.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful Read or Write calls.
//
// A zero value for t means I/O operations will not time out.
//
// Note that if a TCP connection has keep-alive turned on,
// which is the default unless overridden by Dialer.KeepAlive
// or ListenConfig.KeepAlive, then a keep-alive failure may
// also return a timeout error. On Unix systems a keep-alive
// failure on I/O can be detected using
// errors.Is(err, syscall.ETIMEDOUT).
func (c *Connection) SetDeadline(t time.Time) error {
	return c.conn.SetDeadline(t)
}

// SetReadDeadline sets the deadline for future Read calls
// and any currently-blocked Read call.
// A zero value for t means Read will not time out.
func (c *Connection) SetReadDeadline(t time.Time) error {
	return c.conn.SetReadDeadline(t)
}

// SetReadTimeout is equivalent to ReadDeadline(now + timeout)
func (c *Connection) SetReadTimeout(t time.Duration) error {
	return c.conn.SetReadDeadline(time.Now().Add(t))
}

// SetWriteDeadline sets the deadline for future Write calls
// and any currently-blocked Write call.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
func (c *Connection) SetWriteDeadline(t time.Time) error {
	return c.conn.SetWriteDeadline(t)
}

// SetWriteTimeout is equivalent to WriteDeadline(now + timeout)
func (c *Connection) SetWriteTimeout(t time.Duration) error {
	return c.conn.SetWriteDeadline(time.Now().Add(t))
}


================================================
FILE: connection_test.go
================================================
package gosmpp

import (
	"net"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

func TestConnection(t *testing.T) {
	conn, err := net.Dial("tcp", "smscsim.melroselabs.com:2775")
	require.Nil(t, err)

	c := NewConnection(conn)
	defer func() {
		_ = c.Close()
	}()
	t.Log(c.LocalAddr())
	t.Log(c.RemoteAddr())

	require.Nil(t, c.SetDeadline(time.Now().Add(5*time.Second)))
	require.Nil(t, c.SetWriteDeadline(time.Now().Add(5*time.Second)))
	require.Nil(t, c.SetReadDeadline(time.Now().Add(5*time.Second)))
}


================================================
FILE: data/7bit.go
================================================
package data

// Source code in this file is copied from: https://github.com/fiorix/go-smpp/master/smpp/encoding/gsm7.go
import (
	"bytes"
	"errors"
	"math"

	"golang.org/x/text/encoding"
	"golang.org/x/text/transform"
)

// ErrInvalidCharacter means a given character can not be represented in GSM 7-bit encoding.
//
// This can only happen during encoding.
var ErrInvalidCharacter = errors.New("invalid gsm7 character")

// ErrInvalidByte means that a given byte is outside of the GSM 7-bit encoding range.
//
// This can only happen during decoding.
var ErrInvalidByte = errors.New("invalid gsm7 byte")

/*
GSM 7-bit default alphabet and extension table
Source: https://en.wikipedia.org/wiki/GSM_03.38#GSM_7-bit_default_alphabet_and_extension_table_of_3GPP_TS_23.038_/_GSM_03.38
*/
const escapeSequence = 0x1B

var forwardLookup = map[rune]byte{
	'@': 0x00, '£': 0x01, '$': 0x02, '¥': 0x03, 'è': 0x04, 'é': 0x05, 'ù': 0x06, 'ì': 0x07,
	'ò': 0x08, 'Ç': 0x09, '\n': 0x0a, 'Ø': 0x0b, 'ø': 0x0c, '\r': 0x0d, 'Å': 0x0e, 'å': 0x0f,
	'Δ': 0x10, '_': 0x11, 'Φ': 0x12, 'Γ': 0x13, 'Λ': 0x14, 'Ω': 0x15, 'Π': 0x16, 'Ψ': 0x17,
	'Σ': 0x18, 'Θ': 0x19, 'Ξ': 0x1a /* 0x1B */, 'Æ': 0x1c, 'æ': 0x1d, 'ß': 0x1e, 'É': 0x1f,
	' ': 0x20, '!': 0x21, '"': 0x22, '#': 0x23, '¤': 0x24, '%': 0x25, '&': 0x26, '\'': 0x27,
	'(': 0x28, ')': 0x29, '*': 0x2a, '+': 0x2b, ',': 0x2c, '-': 0x2d, '.': 0x2e, '/': 0x2f,
	'0': 0x30, '1': 0x31, '2': 0x32, '3': 0x33, '4': 0x34, '5': 0x35, '6': 0x36, '7': 0x37,
	'8': 0x38, '9': 0x39, ':': 0x3a, ';': 0x3b, '<': 0x3c, '=': 0x3d, '>': 0x3e, '?': 0x3f,
	'¡': 0x40, 'A': 0x41, 'B': 0x42, 'C': 0x43, 'D': 0x44, 'E': 0x45, 'F': 0x46, 'G': 0x47,
	'H': 0x48, 'I': 0x49, 'J': 0x4a, 'K': 0x4b, 'L': 0x4c, 'M': 0x4d, 'N': 0x4e, 'O': 0x4f,
	'P': 0x50, 'Q': 0x51, 'R': 0x52, 'S': 0x53, 'T': 0x54, 'U': 0x55, 'V': 0x56, 'W': 0x57,
	'X': 0x58, 'Y': 0x59, 'Z': 0x5a, 'Ä': 0x5b, 'Ö': 0x5c, 'Ñ': 0x5d, 'Ü': 0x5e, '§': 0x5f,
	'¿': 0x60, 'a': 0x61, 'b': 0x62, 'c': 0x63, 'd': 0x64, 'e': 0x65, 'f': 0x66, 'g': 0x67,
	'h': 0x68, 'i': 0x69, 'j': 0x6a, 'k': 0x6b, 'l': 0x6c, 'm': 0x6d, 'n': 0x6e, 'o': 0x6f,
	'p': 0x70, 'q': 0x71, 'r': 0x72, 's': 0x73, 't': 0x74, 'u': 0x75, 'v': 0x76, 'w': 0x77,
	'x': 0x78, 'y': 0x79, 'z': 0x7a, 'ä': 0x7b, 'ö': 0x7c, 'ñ': 0x7d, 'ü': 0x7e, 'à': 0x7f,
}
var forwardEscape = map[rune]byte{
	'\f': 0x0A, '^': 0x14, '{': 0x28, '}': 0x29, '\\': 0x2F, '[': 0x3C, '~': 0x3D, ']': 0x3E, '|': 0x40, '€': 0x65,
}
var reverseLookup = map[byte]rune{
	0x00: '@', 0x01: '£', 0x02: '$', 0x03: '¥', 0x04: 'è', 0x05: 'é', 0x06: 'ù', 0x07: 'ì',
	0x08: 'ò', 0x09: 'Ç', 0x0a: '\n', 0x0b: 'Ø', 0x0c: 'ø', 0x0d: '\r', 0x0e: 'Å', 0x0f: 'å',
	0x10: 'Δ', 0x11: '_', 0x12: 'Φ', 0x13: 'Γ', 0x14: 'Λ', 0x15: 'Ω', 0x16: 'Π', 0x17: 'Ψ',
	0x18: 'Σ', 0x19: 'Θ', 0x1a: 'Ξ' /* 0x1B */, 0x1c: 'Æ', 0x1d: 'æ', 0x1e: 'ß', 0x1f: 'É',
	0x20: ' ', 0x21: '!', 0x22: '"', 0x23: '#', 0x24: '¤', 0x25: '%', 0x26: '&', 0x27: '\'',
	0x28: '(', 0x29: ')', 0x2a: '*', 0x2b: '+', 0x2c: ',', 0x2d: '-', 0x2e: '.', 0x2f: '/',
	0x30: '0', 0x31: '1', 0x32: '2', 0x33: '3', 0x34: '4', 0x35: '5', 0x36: '6', 0x37: '7',
	0x38: '8', 0x39: '9', 0x3a: ':', 0x3b: ';', 0x3c: '<', 0x3d: '=', 0x3e: '>', 0x3f: '?',
	0x40: '¡', 0x41: 'A', 0x42: 'B', 0x43: 'C', 0x44: 'D', 0x45: 'E', 0x46: 'F', 0x47: 'G',
	0x48: 'H', 0x49: 'I', 0x4a: 'J', 0x4b: 'K', 0x4c: 'L', 0x4d: 'M', 0x4e: 'N', 0x4f: 'O',
	0x50: 'P', 0x51: 'Q', 0x52: 'R', 0x53: 'S', 0x54: 'T', 0x55: 'U', 0x56: 'V', 0x57: 'W',
	0x58: 'X', 0x59: 'Y', 0x5a: 'Z', 0x5b: 'Ä', 0x5c: 'Ö', 0x5d: 'Ñ', 0x5e: 'Ü', 0x5f: '§',
	0x60: '¿', 0x61: 'a', 0x62: 'b', 0x63: 'c', 0x64: 'd', 0x65: 'e', 0x66: 'f', 0x67: 'g',
	0x68: 'h', 0x69: 'i', 0x6a: 'j', 0x6b: 'k', 0x6c: 'l', 0x6d: 'm', 0x6e: 'n', 0x6f: 'o',
	0x70: 'p', 0x71: 'q', 0x72: 'r', 0x73: 's', 0x74: 't', 0x75: 'u', 0x76: 'v', 0x77: 'w',
	0x78: 'x', 0x79: 'y', 0x7a: 'z', 0x7b: 'ä', 0x7c: 'ö', 0x7d: 'ñ', 0x7e: 'ü', 0x7f: 'à',
}
var reverseEscape = map[byte]rune{
	0x0A: '\f', 0x14: '^', 0x28: '{', 0x29: '}', 0x2F: '\\', 0x3C: '[', 0x3D: '~', 0x3E: ']', 0x40: '|', 0x65: '€',
}

// ValidateGSM7String returns the characters, in the given text, that can not be represented in GSM 7-bit encoding.
func ValidateGSM7String(text string) []rune {
	invalidChars := make([]rune, 0, 4)
	for _, r := range text {
		if _, ok := forwardLookup[r]; !ok {
			if _, ok := forwardEscape[r]; !ok {
				invalidChars = append(invalidChars, r)
			}
		}
	}
	return invalidChars
}

// ValidateGSM7Buffer returns the bytes, in the given buffer, that are outside of the GSM 7-bit encoding range.
func ValidateGSM7Buffer(buffer []byte) []byte {
	invalidBytes := make([]byte, 0, 4)
	count := 0
	for count < len(buffer) {
		b := buffer[count]
		if b == escapeSequence {
			count++
			if count >= len(buffer) {
				invalidBytes = append(invalidBytes, b)
				break
			}
			e := buffer[count]
			if _, ok := reverseEscape[e]; !ok {
				invalidBytes = append(invalidBytes, b, e)
			}
		} else if _, ok := reverseLookup[b]; !ok {
			invalidBytes = append(invalidBytes, b)
		}
		count++
	}
	return invalidBytes
}

// GetEscapeChars returns the escape characters in the given text, that doesn't exist in GSM 7-bit DEFAULT alphabet table
func GetEscapeChars(runeText []rune) []rune {
	eChars := make([]rune, 0, 4)
	for _, r := range runeText {
		if _, ok := forwardEscape[r]; ok {
			eChars = append(eChars, r)
		}
	}
	return eChars
}

// IsEscapeChar checks if the given rune is an escape char
func IsEscapeChar(c rune) bool {
	_, exists := forwardEscape[c]
	return exists
}

// GSM7 returns a GSM 7-bit Bit Encoding.
//
// Set the packed flag to true if you wish to convert septets to octets,
// this should be false for most SMPP providers.
func GSM7(packed bool) encoding.Encoding {
	return gsm7Encoding{packed: packed}
}

type gsm7Encoding struct {
	packed bool
}

func (g gsm7Encoding) NewDecoder() *encoding.Decoder {
	return &encoding.Decoder{Transformer: &gsm7Decoder{
		packed: g.packed,
	}}
}

func (g gsm7Encoding) NewEncoder() *encoding.Encoder {
	return &encoding.Encoder{Transformer: &gsm7Encoder{
		packed: g.packed,
	}}
}

func (g gsm7Encoding) String() string {
	if g.packed {
		return "GSM 7-bit (Packed)"
	}
	return "GSM 7-bit (Unpacked)"
}

type gsm7Decoder struct {
	packed bool
}

func (g *gsm7Decoder) Reset() { /* not needed */ }

func unpack(src []byte, packed bool) (septets []byte) {
	septets = src
	if packed {
		septets = make([]byte, 0, len(src))
		count := 0
		for remain := len(src) - count; remain > 0; {
			// Unpack by converting octets into septets.
			switch {
			case remain >= 7:
				septets = append(septets, src[count+0]&0x7F<<0)
				septets = append(septets, (src[count+1]&0x3F<<1)|(src[count+0]&0x80>>7))
				septets = append(septets, (src[count+2]&0x1F<<2)|(src[count+1]&0xC0>>6))
				septets = append(septets, (src[count+3]&0x0F<<3)|(src[count+2]&0xE0>>5))
				septets = append(septets, (src[count+4]&0x07<<4)|(src[count+3]&0xF0>>4))
				septets = append(septets, (src[count+5]&0x03<<5)|(src[count+4]&0xF8>>3))
				septets = append(septets, (src[count+6]&0x01<<6)|(src[count+5]&0xFC>>2))
				if src[count+6] > 0 {
					septets = append(septets, src[count+6]&0xFE>>1)
				}
				count += 7
			case remain >= 6:
				septets = append(septets, src[count+0]&0x7F<<0)
				septets = append(septets, (src[count+1]&0x3F<<1)|(src[count+0]&0x80>>7))
				septets = append(septets, (src[count+2]&0x1F<<2)|(src[count+1]&0xC0>>6))
				septets = append(septets, (src[count+3]&0x0F<<3)|(src[count+2]&0xE0>>5))
				septets = append(septets, (src[count+4]&0x07<<4)|(src[count+3]&0xF0>>4))
				septets = append(septets, (src[count+5]&0x03<<5)|(src[count+4]&0xF8>>3))
				count += 6
			case remain >= 5:
				septets = append(septets, src[count+0]&0x7F<<0)
				septets = append(septets, (src[count+1]&0x3F<<1)|(src[count+0]&0x80>>7))
				septets = append(septets, (src[count+2]&0x1F<<2)|(src[count+1]&0xC0>>6))
				septets = append(septets, (src[count+3]&0x0F<<3)|(src[count+2]&0xE0>>5))
				septets = append(septets, (src[count+4]&0x07<<4)|(src[count+3]&0xF0>>4))
				count += 5
			case remain >= 4:
				septets = append(septets, src[count+0]&0x7F<<0)
				septets = append(septets, (src[count+1]&0x3F<<1)|(src[count+0]&0x80>>7))
				septets = append(septets, (src[count+2]&0x1F<<2)|(src[count+1]&0xC0>>6))
				septets = append(septets, (src[count+3]&0x0F<<3)|(src[count+2]&0xE0>>5))
				count += 4
			case remain >= 3:
				septets = append(septets, src[count+0]&0x7F<<0)
				septets = append(septets, (src[count+1]&0x3F<<1)|(src[count+0]&0x80>>7))
				septets = append(septets, (src[count+2]&0x1F<<2)|(src[count+1]&0xC0>>6))
				count += 3
			case remain >= 2:
				septets = append(septets, src[count+0]&0x7F<<0)
				septets = append(septets, (src[count+1]&0x3F<<1)|(src[count+0]&0x80>>7))
				count += 2
			case remain >= 1:
				septets = append(septets, src[count+0]&0x7F<<0)
				count++
			default:
				return
			}
			remain = len(src) - count
		}
	}
	return
}

func (g *gsm7Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	if len(src) == 0 {
		return 0, 0, nil
	}

	septets := unpack(src, g.packed)

	nSeptet := 0
	builder := bytes.NewBufferString("")
	for nSeptet < len(septets) {
		b := septets[nSeptet]
		if b == escapeSequence {
			nSeptet++
			if nSeptet >= len(septets) {
				return 0, 0, ErrInvalidByte
			}
			e := septets[nSeptet]
			if r, ok := reverseEscape[e]; ok {
				builder.WriteRune(r)
			} else {
				return 0, 0, ErrInvalidByte
			}
		} else if r, ok := reverseLookup[b]; ok {
			builder.WriteRune(r)
		} else {
			return 0, 0, ErrInvalidByte
		}
		nSeptet++
	}
	text := builder.Bytes()
	nDst = len(text)

	if len(dst) < nDst {
		return 0, 0, transform.ErrShortDst
	}

	copy(dst, text)
	return
}

type gsm7Encoder struct {
	packed bool
}

func (g *gsm7Encoder) Reset() {
	/* no needed */
}

func pack(dst []byte, septets []byte) (nDst int) {
	nSeptet := 0
	for remain := len(septets); remain > 0; {
		// Pack by converting septets into octets.
		switch {
		case remain >= 8:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = (septets[nSeptet+1] & 0x7E >> 1) | (septets[nSeptet+2] & 0x03 << 6)
			dst[nDst+2] = (septets[nSeptet+2] & 0x7C >> 2) | (septets[nSeptet+3] & 0x07 << 5)
			dst[nDst+3] = (septets[nSeptet+3] & 0x78 >> 3) | (septets[nSeptet+4] & 0x0F << 4)
			dst[nDst+4] = (septets[nSeptet+4] & 0x70 >> 4) | (septets[nSeptet+5] & 0x1F << 3)
			dst[nDst+5] = (septets[nSeptet+5] & 0x60 >> 5) | (septets[nSeptet+6] & 0x3F << 2)
			dst[nDst+6] = (septets[nSeptet+6] & 0x40 >> 6) | (septets[nSeptet+7] & 0x7F << 1)
			nSeptet += 8
			nDst += 7
		case remain >= 7:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = (septets[nSeptet+1] & 0x7E >> 1) | (septets[nSeptet+2] & 0x03 << 6)
			dst[nDst+2] = (septets[nSeptet+2] & 0x7C >> 2) | (septets[nSeptet+3] & 0x07 << 5)
			dst[nDst+3] = (septets[nSeptet+3] & 0x78 >> 3) | (septets[nSeptet+4] & 0x0F << 4)
			dst[nDst+4] = (septets[nSeptet+4] & 0x70 >> 4) | (septets[nSeptet+5] & 0x1F << 3)
			dst[nDst+5] = (septets[nSeptet+5] & 0x60 >> 5) | (septets[nSeptet+6] & 0x3F << 2)
			dst[nDst+6] = septets[nSeptet+6] & 0x40 >> 6
			nSeptet += 7
			nDst += 7
		case remain >= 6:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = (septets[nSeptet+1] & 0x7E >> 1) | (septets[nSeptet+2] & 0x03 << 6)
			dst[nDst+2] = (septets[nSeptet+2] & 0x7C >> 2) | (septets[nSeptet+3] & 0x07 << 5)
			dst[nDst+3] = (septets[nSeptet+3] & 0x78 >> 3) | (septets[nSeptet+4] & 0x0F << 4)
			dst[nDst+4] = (septets[nSeptet+4] & 0x70 >> 4) | (septets[nSeptet+5] & 0x1F << 3)
			dst[nDst+5] = septets[nSeptet+5] & 0x60 >> 5
			nSeptet += 6
			nDst += 6
		case remain >= 5:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = (septets[nSeptet+1] & 0x7E >> 1) | (septets[nSeptet+2] & 0x03 << 6)
			dst[nDst+2] = (septets[nSeptet+2] & 0x7C >> 2) | (septets[nSeptet+3] & 0x07 << 5)
			dst[nDst+3] = (septets[nSeptet+3] & 0x78 >> 3) | (septets[nSeptet+4] & 0x0F << 4)
			dst[nDst+4] = septets[nSeptet+4] & 0x70 >> 4
			nSeptet += 5
			nDst += 5
		case remain >= 4:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = (septets[nSeptet+1] & 0x7E >> 1) | (septets[nSeptet+2] & 0x03 << 6)
			dst[nDst+2] = (septets[nSeptet+2] & 0x7C >> 2) | (septets[nSeptet+3] & 0x07 << 5)
			dst[nDst+3] = septets[nSeptet+3] & 0x78 >> 3
			nSeptet += 4
			nDst += 4
		case remain >= 3:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = (septets[nSeptet+1] & 0x7E >> 1) | (septets[nSeptet+2] & 0x03 << 6)
			dst[nDst+2] = septets[nSeptet+2] & 0x7C >> 2
			nSeptet += 3
			nDst += 3
		case remain >= 2:
			dst[nDst+0] = (septets[nSeptet+0] & 0x7F >> 0) | (septets[nSeptet+1] & 0x01 << 7)
			dst[nDst+1] = septets[nSeptet+1] & 0x7E >> 1
			nSeptet += 2
			nDst += 2
		case remain >= 1:
			dst[nDst+0] = septets[nSeptet+0] & 0x7F >> 0
			nSeptet++
			nDst++
		default:
			return
		}
		remain = len(septets) - nSeptet
	}
	return
}

func (g *gsm7Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
	if len(src) == 0 {
		return 0, 0, nil
	}

	text := string(src) // work with []rune (a.k.a string) instead of []byte
	septets := make([]byte, 0, len(text))
	for _, r := range text {
		if v, ok := forwardLookup[r]; ok {
			septets = append(septets, v)
		} else if v, ok := forwardEscape[r]; ok {
			septets = append(septets, escapeSequence, v)
		} else {
			return 0, 0, ErrInvalidCharacter
		}
		nSrc++
	}

	nDst = len(septets)
	if g.packed {
		nDst = int(math.Ceil(float64(len(septets)) * 7 / 8))
	}
	if len(dst) < nDst {
		return 0, 0, transform.ErrShortDst
	}

	if !g.packed {
		copy(dst, septets)
		return nDst, nSrc, nil
	}

	nDst = pack(dst, septets)
	return
}


================================================
FILE: data/7bit_test.go
================================================
package data

// Source code in this file is copied from: https://github.com/fiorix
import (
	"encoding/hex"
	"fmt"
	"reflect"
	"testing"

	"golang.org/x/text/transform"
)

var validationStringTests = []struct {
	Text     string
	Expected []rune
}{
	{Text: "12345678", Expected: []rune{}},
	{Text: "12345[6]", Expected: []rune{}},
	{Text: "@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞ\f^{}\\[~]|€ÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà", Expected: []rune{}},
	{Text: "你", Expected: []rune{'你'}},
}

var validationBufferTests = []struct {
	Buffer   []byte
	Expected []byte
}{
	{Buffer: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, Expected: []byte{}},
	{Buffer: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x1B, 0x3C, 0x36, 0x1B, 0x3E}, Expected: []byte{}},
	{Buffer: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x1B}, Expected: []byte{0x1B}},
	{Buffer: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x1B, 0x00}, Expected: []byte{0x1B, 0x00}},
	{Buffer: []byte{0x80, 0x81, 0x82, 0x83}, Expected: []byte{0x80, 0x81, 0x82, 0x83}},
}

var packedTests = []struct {
	Text string
	Buff []byte
}{
	{Text: "", Buff: []byte{}},
	{Text: "1", Buff: []byte{0x31}},
	{Text: "12", Buff: []byte{0x31, 0x19}},
	{Text: "123", Buff: []byte{0x31, 0xD9, 0x0C}},
	{Text: "1234", Buff: []byte{0x31, 0xD9, 0x8C, 0x06}},
	{Text: "12345", Buff: []byte{0x31, 0xD9, 0x8C, 0x56, 0x03}},
	{Text: "123456", Buff: []byte{0x31, 0xD9, 0x8C, 0x56, 0xB3, 0x01}},
	{Text: "1234567", Buff: []byte{0x31, 0xD9, 0x8C, 0x56, 0xB3, 0xDD, 0x00}},
	{Text: "12345678", Buff: []byte{0x31, 0xD9, 0x8C, 0x56, 0xB3, 0xDD, 0x70}},
	{Text: "123456789", Buff: []byte{0x31, 0xD9, 0x8C, 0x56, 0xB3, 0xDD, 0x70, 0x39}},
	{Text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nec nunc venenatis, ultricies ipsum id, volutpat ante. Sed pretium ac metus a interdum metus.", Buff: []byte("\xCC\xB7\xBC\xDC\x06\xA5\xE1\xF3\x7A\x1B\x44\x7E\xB3\xDF\x72\xD0\x3C\x4D\x07\x85\xDB\x65\x3A\x0B\x34\x7E\xBB\xE7\xE5\x31\xBD\x4C\xAF\xCB\x41\x61\x72\x1A\x9E\x9E\x8F\xD3\xEE\x33\xA8\xCC\x4E\xD3\x5D\xA0\x61\x5D\x1E\x16\xA7\xE9\x75\x39\xC8\x5D\x1E\x83\xDC\x75\xF7\x18\x64\x2F\xBB\xCB\xEE\x30\x3D\x3D\x67\x81\xEA\x6C\xBA\x3C\x3D\x4E\x97\xE7\xA0\x34\x7C\x5E\x6F\x83\xD2\x64\x16\xC8\xFE\x66\xD7\xE9\xF0\x30\x1D\x14\x76\xD3\xCB\x2E\xD0\xB4\x4C\x06\xC1\xE5\x65\x7A\xBA\xDE\x06\x85\xC7\xA0\x76\x99\x5E\x9F\x83\xC2\xA0\xB4\x9B\x5E\x96\x93\xEB\x6D\x50\xBB\x4C\xAF\xCF\x5D")},
	{Text: "\n", Buff: []byte{0x0A}},
	{Text: "\r", Buff: []byte{0x0D}},
	{Text: "\f", Buff: []byte{0x1B, 0x05}},
	{Text: "^{}\\[~]|€", Buff: []byte{0x1B, 0xCA, 0x06, 0xB5, 0x49, 0x6D, 0x5E, 0x1B, 0xDE, 0xA6, 0xB7, 0xF1, 0x6D, 0x80, 0x9B, 0x32}},
	{Text: "@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà", Buff: []byte("\x80\x80\x60\x40\x28\x18\x0E\x88\xC4\x82\xE1\x78\x40\x22\x92\x09\xA5\x62\xB9\x60\x32\x1A\x4E\xC7\xF3\x01\x85\x44\x23\x52\xC9\x74\x42\xA5\x54\x2B\x56\xCB\xF5\x82\xC5\x64\x33\x5A\xCD\x76\xC3\xE5\x74\x3B\x5E\xCF\xF7\x03\x06\x85\x43\x62\xD1\x78\x44\x26\x95\x4B\x66\xD3\xF9\x84\x46\xA5\x53\x6A\xD5\x7A\xC5\x66\xB5\x5B\x6E\xD7\xFB\x05\x87\xC5\x63\x72\xD9\x7C\x46\xA7\xD5\x6B\x76\xDB\xFD\x86\xC7\xE5\x73\x7A\xDD\x7E\xC7\xE7\xF5\x7B\x7E\xDF\xFF\x07")},
}

var unpackedTests = []struct {
	Text string
	Buff []byte
}{
	{Text: "", Buff: []byte{}},
	{Text: "1", Buff: []byte{0x31}},
	{Text: "12", Buff: []byte{0x31, 0x32}},
	{Text: "123", Buff: []byte{0x31, 0x32, 0x33}},
	{Text: "1234", Buff: []byte{0x31, 0x32, 0x33, 0x34}},
	{Text: "12345", Buff: []byte{0x31, 0x32, 0x33, 0x34, 0x35}},
	{Text: "123456", Buff: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36}},
	{Text: "1234567", Buff: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37}},
	{Text: "12345678", Buff: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}},
	{Text: "123456789", Buff: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39}},
	{Text: "12345[6", Buff: []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x1B, 0x3C, 0x36}},
	{Text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nec nunc venenatis, ultricies ipsum id, volutpat ante. Sed pretium ac metus a interdum metus.", Buff: []byte("\x4C\x6F\x72\x65\x6D\x20\x69\x70\x73\x75\x6D\x20\x64\x6F\x6C\x6F\x72\x20\x73\x69\x74\x20\x61\x6D\x65\x74\x2C\x20\x63\x6F\x6E\x73\x65\x63\x74\x65\x74\x75\x72\x20\x61\x64\x69\x70\x69\x73\x63\x69\x6E\x67\x20\x65\x6C\x69\x74\x2E\x20\x43\x75\x72\x61\x62\x69\x74\x75\x72\x20\x6E\x65\x63\x20\x6E\x75\x6E\x63\x20\x76\x65\x6E\x65\x6E\x61\x74\x69\x73\x2C\x20\x75\x6C\x74\x72\x69\x63\x69\x65\x73\x20\x69\x70\x73\x75\x6D\x20\x69\x64\x2C\x20\x76\x6F\x6C\x75\x74\x70\x61\x74\x20\x61\x6E\x74\x65\x2E\x20\x53\x65\x64\x20\x70\x72\x65\x74\x69\x75\x6D\x20\x61\x63\x20\x6D\x65\x74\x75\x73\x20\x61\x20\x69\x6E\x74\x65\x72\x64\x75\x6D\x20\x6D\x65\x74\x75\x73\x2E")},
	{Text: "\n", Buff: []byte{0x0A}},
	{Text: "\r", Buff: []byte{0x0D}},
	{Text: "\f", Buff: []byte{0x1B, 0x0A}},
	{Text: "^{}\\[~]|€", Buff: []byte{0x1B, 0x14, 0x1B, 0x28, 0x1B, 0x29, 0x1B, 0x2F, 0x1B, 0x3C, 0x1B, 0x3D, 0x1B, 0x3E, 0x1B, 0x40, 0x1B, 0x65}},
	{Text: "@£$¥èéùìòÇØøÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà", Buff: []byte("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1C\x1D\x1E\x1F\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F")},
}

var invalidCharacterTests = []struct {
	Packed bool
	Text   string
}{
	{Packed: true, Text: "你"},
	{Packed: false, Text: "你"},
}

var invalidByteTests = []struct {
	Packed bool
	Buff   []byte
}{
	{Packed: false, Buff: []byte{0x80}},
	{Packed: false, Buff: []byte{0x1B}},
	{Packed: false, Buff: []byte{0x1B, 0x80}},
}

func TestGSM7EncodingString(t *testing.T) {
	tests := []struct {
		Packed   bool
		Expected string
	}{
		{Packed: true, Expected: "GSM 7-bit (Packed)"},
		{Packed: false, Expected: "GSM 7-bit (Unpacked)"},
	}

	for index, row := range tests {
		actual := fmt.Sprint(GSM7(row.Packed))
		if actual != row.Expected {
			t.Fatalf("%d: expected '%s' but got '%s'", index, row.Expected, actual)
		}
	}
}

func TestValidateGSM7String(t *testing.T) {
	for index, row := range validationStringTests {
		actual := ValidateGSM7String(row.Text)
		if !reflect.DeepEqual(actual, row.Expected) {
			t.Fatalf("%2d: actual did not equal expected.\nactual: %s\nexpect: %s", index, string(actual), string(row.Expected))
		}
	}
}

func TestValidateGSM7Buffer(t *testing.T) {
	for index, row := range validationBufferTests {
		actual := ValidateGSM7Buffer(row.Buffer)
		if !reflect.DeepEqual(actual, row.Expected) {
			t.Fatalf("%2d: actual did not equal expected.\nactual: %s\nexpect: %s", index, hex.EncodeToString(actual), hex.EncodeToString(row.Expected))
		}
	}
}

func TestPackedEncoder(t *testing.T) {
	encoder := GSM7(true).NewEncoder()
	for index, row := range packedTests {
		es, _, err := transform.Bytes(encoder, []byte(row.Text))
		if err != nil {
			t.Fatalf("%2d: unexpected error: '%s'", index, err.Error())
		}
		if !reflect.DeepEqual(es, row.Buff) {
			t.Fatalf("%2d: actual did not equal expected.\nactual: %s\nexpect: %s", index, hex.EncodeToString(es), hex.EncodeToString(row.Buff))
		}
	}
}

func TestUnpackedEncoder(t *testing.T) {
	encoder := GSM7(false).NewEncoder()
	for index, row := range unpackedTests {
		es, _, err := transform.Bytes(encoder, []byte(row.Text))
		if err != nil {
			t.Fatalf("%2d: unexpected error: '%s'", index, err.Error())
		}
		if !reflect.DeepEqual(es, row.Buff) {
			t.Fatalf("%2d: actual did not equal expected.\nactual: %s\nexpect: %s", index, hex.EncodeToString(es), hex.EncodeToString(row.Buff))
		}
	}
}

func TestPackedDecoder(t *testing.T) {
	decoder := GSM7(true).NewDecoder()
	for index, row := range packedTests {
		es, _, err := transform.Bytes(decoder, row.Buff)
		if err != nil {
			t.Fatalf("%2d: unexpected error: '%s'", index, err.Error())
		}
		if string(es) != row.Text {
			t.Fatalf("%2d: actual did not equal expected.\nactual: %s\nexpect: %s", index, string(es), row.Text)
		}
	}
}

func TestUnpackedDecoder(t *testing.T) {
	encoder := GSM7(false).NewDecoder()
	for index, row := range unpackedTests {
		es, _, err := transform.Bytes(encoder, row.Buff)
		if err != nil {
			t.Fatalf("%2d: unexpected error: '%s'", index, err.Error())
		}
		if string(es) != row.Text {
			t.Fatalf("%2d: actual did not equal expected.\nactual: %s\nexpect: %s", index, string(es), row.Text)
		}
	}
}

func TestInvalidCharacter(t *testing.T) {
	for index, row := range invalidCharacterTests {
		encoder := GSM7(row.Packed).NewEncoder()
		_, _, err := transform.Bytes(encoder, []byte(row.Text))
		if err == nil {
			t.Fatalf("%2d: expected error but got no error", index)
		}
		if err != ErrInvalidCharacter {
			t.Fatalf("%2d: expected '%s' but got '%s'", index, ErrInvalidCharacter, err.Error())
		}
	}
}

func TestInvalidByte(t *testing.T) {
	for index, row := range invalidByteTests {
		decoder := GSM7(row.Packed).NewDecoder()
		_, _, err := transform.Bytes(decoder, row.Buff)
		if err == nil {
			t.Fatalf("%2d: expected error but got no error", index)
		}
		if err != ErrInvalidByte {
			t.Fatalf("%2d: expected '%s' but got '%s'", index, ErrInvalidByte, err.Error())
		}
	}
}


================================================
FILE: data/codings.go
================================================
package data

import (
	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/encoding/unicode"
)

const (
	// GSM7BITCoding is gsm-7bit coding
	GSM7BITCoding byte = 0x00
	// ASCIICoding is ascii coding
	ASCIICoding byte = 0x01
	// BINARY8BIT1Coding is 8-bit binary coding
	BINARY8BIT1Coding byte = 0x02
	// LATIN1Coding is iso-8859-1 coding
	LATIN1Coding byte = 0x03
	// BINARY8BIT2Coding is 8-bit binary coding
	BINARY8BIT2Coding byte = 0x04
	// CYRILLICCoding is iso-8859-5 coding
	CYRILLICCoding byte = 0x06
	// HEBREWCoding is iso-8859-8 coding
	HEBREWCoding byte = 0x07
	// UCS2Coding is UCS2 coding
	UCS2Coding byte = 0x08
)

// EncDec wraps encoder and decoder interface.
type EncDec interface {
	Encode(str string) ([]byte, error)
	Decode([]byte) (string, error)
}

// Encoding interface.
type Encoding interface {
	EncDec
	DataCoding() byte
}

func encode(str string, encoder *encoding.Encoder) ([]byte, error) {
	return encoder.Bytes([]byte(str))
}

func decode(data []byte, decoder *encoding.Decoder) (st string, err error) {
	tmp, err := decoder.Bytes(data)
	if err == nil {
		st = string(tmp)
	}
	return
}

// CustomEncoding is wrapper for user-defined data encoding.
type CustomEncoding struct {
	encDec EncDec
	coding byte
}

// NewCustomEncoding creates new custom encoding.
func NewCustomEncoding(coding byte, encDec EncDec) Encoding {
	return &CustomEncoding{
		coding: coding,
		encDec: encDec,
	}
}

// Encode string.
func (c *CustomEncoding) Encode(str string) ([]byte, error) {
	return c.encDec.Encode(str)
}

// Decode data to string.
func (c *CustomEncoding) Decode(data []byte) (string, error) {
	return c.encDec.Decode(data)
}

// DataCoding flag.
func (c *CustomEncoding) DataCoding() byte {
	return c.coding
}

type gsm7bit struct {
	packed bool
}

func (c *gsm7bit) Encode(str string) ([]byte, error) {
	return encode(str, GSM7(c.packed).NewEncoder())
}

func (c *gsm7bit) Decode(data []byte) (string, error) {
	return decode(data, GSM7(c.packed).NewDecoder())
}

func (c *gsm7bit) DataCoding() byte { return GSM7BITCoding }

func (c *gsm7bit) ShouldSplit(text string, octetLimit uint) (shouldSplit bool) {
	if c.packed {
		return uint((len(text)*7+7)/8) > octetLimit
	} else {
		return uint(len(text)) > octetLimit
	}
}

func (c *gsm7bit) EncodeSplit(text string, octetLimit uint) (allSeg [][]byte, err error) {
	if octetLimit < 64 {
		octetLimit = 134
	}

	allSeg = [][]byte{}
	runeSlice := []rune(text)

	fr, to := 0, int(octetLimit)
	for fr < len(runeSlice) {
		if to > len(runeSlice) {
			to = len(runeSlice)
		}
		seg, err := c.Encode(string(runeSlice[fr:to]))
		if err != nil {
			return nil, err
		}
		allSeg = append(allSeg, seg)
		fr, to = to, to+int(octetLimit)
	}

	return
}

type gsm7bitPacked struct {
}

func (c *gsm7bitPacked) Encode(str string) ([]byte, error) {
	return encode(str, GSM7(true).NewEncoder())
}

func (c *gsm7bitPacked) Decode(data []byte) (string, error) {
	return decode(data, GSM7(true).NewDecoder())
}

func (c *gsm7bitPacked) DataCoding() byte { return GSM7BITCoding }

func (c *gsm7bitPacked) ShouldSplit(text string, octetLimit uint) (shouldSplit bool) {
	runeSlice := []rune(text)
	tLen := len(runeSlice)
	escCharsLen := len(GetEscapeChars(runeSlice))
	regCharsLen := tLen - escCharsLen
	// Esacpe characters occupy 2 octets/septets
	// https://en.wikipedia.org/wiki/GSM_03.38
	// https://www.developershome.com/sms/gsmAlphabet.asp
	return uint((regCharsLen*7+escCharsLen*2*7+7)/8) > octetLimit
}

func (c *gsm7bitPacked) GetSeptetCount(runeSlice []rune) int {
	tLen := len(runeSlice)
	escCharsLen := len(GetEscapeChars(runeSlice))
	regCharsLen := tLen - escCharsLen
	return escCharsLen*2 + regCharsLen
}

func (c *gsm7bitPacked) EncodeSplit(text string, octetLimit uint) (allSeg [][]byte, err error) {
	if octetLimit < 64 {
		octetLimit = 134
	}

	allSeg = [][]byte{}
	runeSlice := []rune(text)
	lim := int(octetLimit * 8 / 7)

	fr, to := 0, lim
	for fr < len(runeSlice) {
		if to > len(runeSlice) {
			to = len(runeSlice)
		}

		to = determineTo(fr, to, lim, runeSlice)

		seg, err := c.Encode(string(runeSlice[fr:to]))
		if err != nil {
			return nil, err
		}

		includeLSB := false
		nSeptet := c.GetSeptetCount(runeSlice[fr:to])
		if nSeptet != lim && nSeptet%8 == 0 { // The last octet's LSB should be included during shift
			includeLSB = true
		}

		seg = shiftBitsLeftOne(seg, includeLSB)

		allSeg = append(allSeg, seg)
		fr, to = to, to+lim
	}

	return
}

func determineTo(from int, to int, lim int, runeSlice []rune) int {
	nSeptet := 0
	for nSeptet < lim {
		if IsEscapeChar(runeSlice[from]) { // esc chars counted as 2 septes
			nSeptet += 2
		} else {
			nSeptet++
		}
		from++
		if from == to {
			break
		}
	}
	to = from

	if IsEscapeChar(runeSlice[to-1]) { // 9.2.3.24.1 Concatenated Short Messages  "A character represented by an escape-sequence shall not be split in the middle."
		if nSeptet > lim {
			to--
		}
	}
	return to
}

// Shifts the given byte stream one position left, in order to put a padding bit in between UDH and the beginning of the septets of an actual message
// Ref1: https://www.etsi.org/deliver/etsi_ts/123000_123099/123040/16.00.00_60/ts_123040v160000p.pdf Page 74
// Ref2: https://help.goacoustic.com/hc/en-us/articles/360043843154--How-character-encoding-affects-SMS-message-length Pls. ref. to the note "..It is added as padding so that the actual 7-bit encoding data begins on a septet boundary—the 50th bit."
// Ref3: https://en.wikipedia.org/wiki/Concatenated_SMS "..This means up to 6 bits of zeros need to be inserted at the start of the [message]."
func shiftBitsLeftOne(input []byte, includeLSB bool) []byte {
	shifted := make([]byte, len(input))
	for i, b := range input {
		shifted[i] = b << 1
		if i > 0 {
			shifted[i] |= input[i-1] >> 7
		}
	}

	if includeLSB {
		lastOctet := (input[len(input)-1] >> 7 & 0x01) | (0x0D << 1) /* https://en.wikipedia.org/wiki/GSM_03.38 Ref tekst: "..When there are 7 spare bits in the last octet of a message..."*/
		shifted = append(shifted, lastOctet)
	}

	return shifted
}

type ascii struct{}

func (*ascii) Encode(str string) ([]byte, error) {
	return []byte(str), nil
}

func (*ascii) Decode(data []byte) (string, error) {
	return string(data), nil
}

func (*ascii) DataCoding() byte { return ASCIICoding }

type iso88591 struct{}

func (*iso88591) Encode(str string) ([]byte, error) {
	return encode(str, charmap.ISO8859_1.NewEncoder())
}

func (*iso88591) Decode(data []byte) (string, error) {
	return decode(data, charmap.ISO8859_1.NewDecoder())
}

func (*iso88591) DataCoding() byte { return LATIN1Coding }

type binary8bit1 struct{}

func (*binary8bit1) Encode(_ string) ([]byte, error) {
	return []byte{}, ErrNotImplEncode
}

func (*binary8bit1) Decode(_ []byte) (string, error) {
	return "", ErrNotImplDecode
}

func (*binary8bit1) DataCoding() byte { return BINARY8BIT1Coding }

type binary8bit2 struct{}

func (*binary8bit2) Encode(_ string) ([]byte, error) {
	return []byte{}, ErrNotImplEncode
}

func (*binary8bit2) Decode(_ []byte) (string, error) {
	return "", ErrNotImplDecode
}

func (*binary8bit2) DataCoding() byte { return BINARY8BIT2Coding }

type iso88595 struct{}

func (*iso88595) Encode(str string) ([]byte, error) {
	return encode(str, charmap.ISO8859_5.NewEncoder())
}

func (*iso88595) Decode(data []byte) (string, error) {
	return decode(data, charmap.ISO8859_5.NewDecoder())
}

func (*iso88595) DataCoding() byte { return CYRILLICCoding }

type iso88598 struct{}

func (*iso88598) Encode(str string) ([]byte, error) {
	return encode(str, charmap.ISO8859_8.NewEncoder())
}

func (*iso88598) Decode(data []byte) (string, error) {
	return decode(data, charmap.ISO8859_8.NewDecoder())
}

func (*iso88598) DataCoding() byte { return HEBREWCoding }

type ucs2 struct{}

func (*ucs2) Encode(str string) ([]byte, error) {
	tmp := unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
	return encode(str, tmp.NewEncoder())
}

func (*ucs2) Decode(data []byte) (string, error) {
	tmp := unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
	return decode(data, tmp.NewDecoder())
}

func (*ucs2) ShouldSplit(text string, octetLimit uint) (shouldSplit bool) {
	runeSlice := []rune(text)
	return uint(len(runeSlice)*2) > octetLimit
}

func (c *ucs2) EncodeSplit(text string, octetLimit uint) (allSeg [][]byte, err error) {
	if octetLimit < 64 {
		octetLimit = 134
	}

	allSeg = [][]byte{}
	runeSlice := []rune(text)
	hextetLim := int(octetLimit / 2) // round down

	// hextet = 16 bits, the correct terms should be hexadectet
	fr, to := 0, hextetLim
	for fr < len(runeSlice) {
		if to > len(runeSlice) {
			to = len(runeSlice)
		}

		seg, err := c.Encode(string(runeSlice[fr:to]))
		if err != nil {
			return nil, err
		}
		allSeg = append(allSeg, seg)

		fr, to = to, to+hextetLim
	}

	return
}

func (*ucs2) DataCoding() byte { return UCS2Coding }

var (
	// GSM7BIT is gsm-7bit encoding.
	GSM7BIT Encoding = &gsm7bit{packed: false}

	// GSM7BITPACKED is packed gsm-7bit encoding.
	// Most of SMSC(s) use unpack version.
	// Should be tested before using.
	GSM7BITPACKED Encoding = &gsm7bitPacked{}

	// ASCII is ascii encoding.
	ASCII Encoding = &ascii{}

	// BINARY8BIT1 is binary 8-bit encoding.
	BINARY8BIT1 Encoding = &binary8bit1{}

	// LATIN1 encoding.
	LATIN1 Encoding = &iso88591{}

	// BINARY8BIT2 is binary 8-bit encoding.
	BINARY8BIT2 Encoding = &binary8bit2{}

	// CYRILLIC encoding.
	CYRILLIC Encoding = &iso88595{}

	// HEBREW encoding.
	HEBREW Encoding = &iso88598{}

	// UCS2 encoding.
	UCS2 Encoding = &ucs2{}
)

var codingMap = map[byte]Encoding{
	GSM7BITCoding:     GSM7BIT,
	ASCIICoding:       ASCII,
	BINARY8BIT1Coding: BINARY8BIT1,
	LATIN1Coding:      LATIN1,
	BINARY8BIT2Coding: BINARY8BIT2,
	CYRILLICCoding:    CYRILLIC,
	HEBREWCoding:      HEBREW,
	UCS2Coding:        UCS2,
}

// FromDataCoding returns encoding from DataCoding value.
func FromDataCoding(code byte) (enc Encoding) {
	enc, ok := codingMap[code]
	if !ok { // if encoding is reserved (custom)
		enc = NewCustomEncoding(code, GSM7BIT) // GSM7BIT is a temporary patch to apply to Encode/Decode methods
	}
	return
}

// Splitter extend encoding object by defining a split function
// that split a string into multiple segments
// Each segment string, when encoded, must be within a certain octet limit
type Splitter interface {
	// ShouldSplit check if the encoded data of given text should be splitted under octetLimit
	ShouldSplit(text string, octetLimit uint) (should bool)
	EncodeSplit(text string, octetLimit uint) ([][]byte, error)
}


================================================
FILE: data/codings_test.go
================================================
package data

import (
	"encoding/hex"
	"log"
	"testing"

	"github.com/stretchr/testify/require"
)

func fromHex(h string) (v []byte) {
	var err error
	v, err = hex.DecodeString(h)
	if err != nil {
		log.Fatal(err)
	}
	return
}

func testEncoding(t *testing.T, enc EncDec, original, expected string) {
	encoded, err := enc.Encode(original)
	require.Nil(t, err)
	require.Equal(t, fromHex(expected), encoded)

	decoded, err := enc.Decode(encoded)
	require.Nil(t, err)
	require.Equal(t, original, decoded)
}

func testEncodingSplit(t *testing.T, enc EncDec, octetLim uint, original string, expected []string, expectDecode []string) {
	splitter, ok := enc.(Splitter)
	require.Truef(t, ok, "Encoding must implement Splitter interface")

	segEncoded, err := splitter.EncodeSplit(original, octetLim)
	require.Nil(t, err)

	for i, seg := range segEncoded {
		require.Equal(t, fromHex(expected[i]), seg)
		require.LessOrEqualf(t, uint(len(seg)), octetLim,
			"Segment len must be less than or equal to %d, got %d", octetLim, len(seg))

		if enc == GSM7BITPACKED {
			seg = shiftBitsOneRight(seg)
		}
		decoded, err := enc.Decode(seg)
		require.Nil(t, err)
		require.Equal(t, expectDecode[i], decoded)
	}
}

func shiftBitsOneRight(input []byte) []byte {
	carry := byte(0)
	for i := len(input) - 1; i >= 0; i-- {
		// Save the carry bit from the previous byte
		nextCarry := input[i] & 0b00000001
		// Shift the current byte to the right
		input[i] >>= 1
		// Apply the carry from the previous byte to the current byte
		input[i] |= carry << 7
		// Update the carry for the next byte
		carry = nextCarry
	}
	return input
}

func TestCoding(t *testing.T) {
	require.Nil(t, FromDataCoding(12))
	require.Equal(t, GSM7BIT, FromDataCoding(0))
	require.Equal(t, ASCII, FromDataCoding(1))
	require.Equal(t, UCS2, FromDataCoding(8))
	require.Equal(t, LATIN1, FromDataCoding(3))
	require.Equal(t, CYRILLIC, FromDataCoding(6))
	require.Equal(t, HEBREW, FromDataCoding(7))
}

func TestGSM7Bit(t *testing.T) {
	require.EqualValues(t, 0, GSM7BITPACKED.DataCoding())
	testEncoding(t, GSM7BITPACKED, "gjwklgjkwP123+?", "67f57dcd3eabd777684c365bfd00")
}

func TestShouldSplit(t *testing.T) {
	t.Run("testShouldSplit_GSM7BIT", func(t *testing.T) {
		octetLim := uint(140)
		expect := map[string]bool{
			"":  false,
			"1": false,
			"12312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311234121212":  false,
			"123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112342212121": true,
		}

		splitter, _ := GSM7BIT.(Splitter)
		for k, v := range expect {
			ok := splitter.ShouldSplit(k, octetLim)
			require.Equalf(t, ok, v, "Test case %s", k)
		}
	})

	t.Run("testShouldSplit_UCS2", func(t *testing.T) {
		octetLim := uint(140)
		expect := map[string]bool{
			"":  false,
			"1": false,
			"ởỀÊộẩừỰÉÊỗọễệớỡồỰỬỪựởặỬ̀ỵổẤỨợỶẰỢộứẶHữẹ̃ẾỆằỄéậÃỡẰộ̀ỀỗứẲữỪữộÊỵòALữộòC":  false, /* 70 UCS2 chars */
			"ợÁÊGỷẹííỡỮÂIỆàúễẠỮỊệÂỖÍắẵYẠừẲíộờíẵỠựẤằờởể̃ởỵởềệổồUỡỵầễÁÝởÝNè̉ỚổôỊộợKỨệ́": true,  /* 71 UCS2 chars */
		}

		splitter, _ := UCS2.(Splitter)
		for k, v := range expect {
			ok := splitter.ShouldSplit(k, octetLim)
			require.Equalf(t, ok, v, "Test case %s", k)
		}
	})

	t.Run("testShouldSplit_GSM7BITPACKED", func(t *testing.T) {
		octetLim := uint(140)
		expect := map[string]bool{
			"":  false,
			"1": false,
			"12312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311234121212":                      false,
			"gjwklgjkwP123+?sasdasdaqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdqwdqwDQWdqwdqwdqwdqwwqwdqwdqwddqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdwqdqwqwdqwdqwqwdqw":  false, /* 160 regular basic alphabet chars */
			"gjwklgjkwP123+?sasdasdaqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdqwdqwDQWdqwdqwdqwdqwwqwdqwdqwddqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdwqdqwqwdqwdqwqwdqwd": true,  /* 161 regular basic alphabet chars */
			"gjwklgjkwP123+?sasdasdaqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdqwdqwDQWdqwdqwdqwdqwwqwdqwdqwddqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdwqdqwqwdqwdqwqwdqw{": true,  /* 159 regular basic alphabet chars + 1 escape char at the end */
			"|}€€|]|€[~€^]€~{~^{|]]|[{|~€^|]^[[{€^]^{€}}^~~]€]~€[€€[]~~[}}]{^}{|}~~]]€^{^|€{^":                                                                                  false, /* 80 escape chars */
			"|}€€|]|€[~€^]€~{~^{|]]|[{|~€^|]^[[{€^]^{€}}^~~]€]~€[€€[]~~[}}]{^}{|}~~]]€^{^|€{^{":                                                                                 true,  /* 81 escape chars */
		}

		splitter, _ := GSM7BITPACKED.(Splitter)
		for k, v := range expect {
			ok := splitter.ShouldSplit(k, octetLim)
			require.Equalf(t, ok, v, "Test case %s", k)
		}
	})
}
func TestSplit(t *testing.T) {
	require.EqualValues(t, 0o0, GSM7BITPACKED.DataCoding())

	t.Run("testSplitGSM7Empty", func(t *testing.T) {
		testEncodingSplit(t, GSM7BIT,
			134,
			"",
			[]string{
				"",
			},
			[]string{
				"",
			})
	})

	t.Run("testSplitUCS2", func(t *testing.T) {
		testEncodingSplit(t, UCS2,
			134,
			"biggest gift của Christmas là có nhiều big/challenging/meaningful problems để sấp mặt làm",
			[]string{
				"006200690067006700650073007400200067006900660074002000631ee700610020004300680072006900730074006d006100730020006c00e00020006300f30020006e006800691ec100750020006200690067002f006300680061006c006c0065006e00670069006e0067002f006d00650061006e0069006e006700660075006c00200070",
				"0072006f0062006c0065006d0073002001111ec3002000731ea500700020006d1eb700740020006c00e0006d",
			},
			[]string{
				"biggest gift của Christmas là có nhiều big/challenging/meaningful p",
				"roblems để sấp mặt làm",
			})
	})

	t.Run("testSplitUCS2Empty", func(t *testing.T) {
		testEncodingSplit(t, UCS2,
			134,
			"",
			[]string{
				"",
			},
			[]string{
				"",
			})
	})

	// UCS2 character should not be splitted in the middle
	// here 54 character is encoded to 108 octet, but since there are 107 octet limit,
	// a whole 2 octet has to be carried over to the next segment
	t.Run("testSplit_Middle_UCS2", func(t *testing.T) {
		testEncodingSplit(t, UCS2,
			107,
			"biggest gift của Christmas là có nhiều big/challenging",
			[]string{
				"006200690067006700650073007400200067006900660074002000631ee700610020004300680072006900730074006d006100730020006c00e00020006300f30020006e006800691ec100750020006200690067002f006300680061006c006c0065006e00670069006e",
				"0067", // 0x00 0x67 is "g"
			},
			[]string{
				"biggest gift của Christmas là có nhiều big/challengin",
				"g",
			})
	})
}

func TestSplit_GSM7BITPACKED(t *testing.T) {
	require.EqualValues(t, 0o0, GSM7BITPACKED.DataCoding())

	t.Run("testSplit_Escape_GSM7BITPACKED", func(t *testing.T) {
		testEncodingSplit(t, GSM7BITPACKED,
			134,
			"gjwklgjkwP123+?sasdasdaqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdqwdqwDQWdqwdqwdqwdqwwqwdqwdqwddqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdwqdqwqwdqwdqwqwdqw{",
			[]string{
				"ceeafb9a7d56afefd0986cb6facdc37372784e0ec7efe4f89d1cbf93e37772fc4e8edfc9f13b397e27c7efe4f89d1cbf93e37772fc4e8edfc9f13b397e27c7efe438397e27c7efc4e8951cbf93e37772fc4e8edfeff13b397e27c7ef6472fc4e8edfc9f13b397e27c7efe4f89d1cbf93e37772fc4e8edfc9f13b394ebec7c9f17bfc4e8edfc9",
				"e2f7f89d1cbf6f50",
			},
			[]string{
				"gjwklgjkwP123+?sasdasdaqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdqwdqwDQWdqwdqwdqwdqwwqwdqwdqwddqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqwdqdwqdqwqwdqwd",
				"qwqwdqw{",
			})
	})

	/*
		Total char count = 160,
		Esc char count = 1,
		Regular char count = 159,
		Seg1 => 153->€
		Expected behaviour: Should not split in the middle of ESC chars
	*/
	t.Run("testSplit_EscEndOfSeg1_GSM7BITPACKED", func(t *testing.T) {
		testEncodingSplit(t, GSM7BITPACKED,
			134,
			"pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp€ppppppp",
			[]string{
				"e070381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c31b",
				"3665381c0e87c3e1",
			},
			[]string{
				"pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp\r",
				"€ppppppp",
			})
	})

	/*
		Total char count = 160,
		Esc char count = 2,
		Regular char count = 158,
		Seg1 => 152-> ....{
		Seg2 => 1-> ....{
		Expected behaviour: Should not split in the middle of ESC chars
	*/
	t.Run("testSplit_EscEndOfSeg1AndSeg2_1_GSM7BITPACKED", func(t *testing.T) {
		testEncodingSplit(t, GSM7BITPACKED,
			134,
			"pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp{{pppppppp",
			[]string{
				"e070381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0edfa01a",
				"3628381c0e87c3e170",
			},
			[]string{
				"pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp{\r",
				"{pppppppp",
			})
	})

	/*
		Total char count = 160,
		Esc char count = 2,
		Regular char count = 158,
		Seg1 => 152-> ....€
		Seg2 => 1-> ....€
		Expected behaviour: Should not split in the middle of ESC chars
	*/
	t.Run("testSplit_EscEndOfSeg1AndSeg2_2_GSM7BITPACKED", func(t *testing.T) {
		testEncodingSplit(t, GSM7BITPACKED,
			134,
			"pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp€€pppppppp",
			[]string{
				"e070381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0e87c3e170381c0edf941b",
				"3665381c0e87c3e170",
			},
			[]string{
				"pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp€\r",
				"€pppppppp",
			})
	})

	/*
		Total char count = 162,
		Esc char count = 0,
		Regular char count = 162,
		Seg1 => 153
		Seg2 => 9
		Scenario: All charcters in the GSM7Bit Basic Character Set table (non-escape chars) https://en.wikipedia.org/wiki/GSM_03.38
	*/
	t.Run("testSplit_AllGSM7BitBasicCharset_GSM7BITPACKED", func(t *testing.T) {
		testEncodingSplit(t, GSM7BITPACKED,
			134,
			"ΩØ;19Ξòå1-¤6aΞΘANanΣ¡>)òΦ3L;aøΛ-o@>I¥1=-ü!N¤&o9Hmda3jΞ@ÅΣlhEE§/:Çù0Θ&:_&Π;KLÅÅ@fÜ-kFH?ΠB5/ÆΓ?55=<Ω¡N2ñ¥*L¤aÖ! ÖΘ+øF£_Ç?øΔΓ-lèòCìnEBmhÉF*<Åi/aΩ¥CDøfGÇ$/=Λ'ÅA3ò#fkù",
			[]string{
				"2a8b5d2ca7413c622d922dacc9049d613706e84b212433e62ecca0b4de005f7210ebb5fc2127c9f4ce21dbe4f04cad0138306c74b1f87de9120658c6a48b982cbb25d3e10098bdadb511f9b3086b2fcee457abf57815a053d61fa898a4303704e266560c632092f8312093169b80181edc45611bfd31aa788ef42b5c190c890cf3312178f528",
				"4e8ee00c3132af0d",
			},
			[]string{
				"ΩØ;19Ξòå1-¤6aΞΘANanΣ¡>)òΦ3L;aøΛ-o@>I¥1=-ü!N¤&o9Hmda3jΞ@ÅΣlhEE§/:Çù0Θ&:_&Π;KLÅÅ@fÜ-kFH?ΠB5/ÆΓ?55=<Ω¡N2ñ¥*L¤aÖ! ÖΘ+øF£_Ç?øΔΓ-lèòCìnEBmhÉF*<Åi/aΩ¥CDøfGÇ$/=Λ",
				"'ÅA3ò#fkù",
			})
	})

	/*
		Total char count = 81,
		Esc char count = 81,
		Regular char count = 0,
		Seg1 => 153
		Seg2 => 9
		Scenario: All charcters in the GSM7Bit Escape Character Set table https://en.wikipedia.org/wiki/GSM_03.38
	*/
	t.Run("testSplit_AllGSM7BitBasicCharset_GSM7BITPACKED", func(t *testing.T) {
		testEncodingSplit(t, GSM7BITPACKED,
			134,
			"|{[€|^€[{|€{[|^{~[}€|}|^|^[^]€{[]~}€]{{^|^][€]|€~€^[~}^]{]~{^^€^[~|^]|€~|^€{]{~|}",
			[]string{
				"36c00d6ac3db9437c00d6553def036a80d7053dea036bc0d7043d9a036bd0d6f93da9437c04d6a03dc5036c00d65c3db5036be4d7983daf036be4d6f93da9437be0d6a83da5036c00d65e3dbf036e58d6f03dc9437bd4d7943d9f036bd4d6a43d9f836a88d6fd3dba036940d6553de5036bc4d6f03dc5036be0d7053def436c00d6553dea01a",
				"36be0d6ad3db003729",
			},
			[]string{
				"|{[€|^€[{|€{[|^{~[}€|}|^|^[^]€{[]~}€]{{^|^][€]|€~€^[~}^]{]~{^^€^[~|^]|€~|^€{\r",
				"]{~|}",
			})
	})
}

func TestAscii(t *testing.T) {
	require.EqualValues(t, 1, ASCII.DataCoding())
	testEncoding(t, ASCII, "agjwklgjkwP", "61676a776b6c676a6b7750")
}

func TestUCS2(t *testing.T) {
	require.EqualValues(t, 8, UCS2.DataCoding())
	testEncoding(t, UCS2, "agjwklgjkwP", "00610067006a0077006b006c0067006a006b00770050")
}

func TestLatin1(t *testing.T) {
	require.EqualValues(t, 3, LATIN1.DataCoding())
	testEncoding(t, LATIN1, "agjwklgjkwPÓ", "61676a776b6c676a6b7750d3")
}

func TestCYRILLIC(t *testing.T) {
	require.EqualValues(t, 6, CYRILLIC.DataCoding())
	testEncoding(t, CYRILLIC, "agjwklgjkwPф", "61676A776B6C676A6B7750E4")
}

func TestHebrew(t *testing.T) {
	require.EqualValues(t, 7, HEBREW.DataCoding())
	testEncoding(t, HEBREW, "agjwklgjkwPץ", "61676A776B6C676A6B7750F5")
}

func TestOtherCodings(t *testing.T) {
	testEncoding(t, UTF16BEM, "ngưỡng cứa cuỗc đợi", "feff006e006701b01ee1006e0067002000631ee900610020006300751ed70063002001111ee30069")
	testEncoding(t, UTF16LEM, "ngưỡng cứa cuỗc đợi", "fffe6e006700b001e11e6e00670020006300e91e6100200063007500d71e630020001101e31e6900")
	testEncoding(t, UTF16BE, "ngưỡng cứa cuỗc đợi", "006e006701b01ee1006e0067002000631ee900610020006300751ed70063002001111ee30069")
	testEncoding(t, UTF16LE, "ngưỡng cứa cuỗc đợi", "6e006700b001e11e6e00670020006300e91e6100200063007500d71e630020001101e31e6900")
}

type noOpEncDec struct{}

func (*noOpEncDec) Encode(str string) ([]byte, error) {
	return []byte(str), nil
}

func (*noOpEncDec) Decode(data []byte) (string, error) {
	return string(data), nil
}

func TestCustomEncoding(t *testing.T) {
	enc := NewCustomEncoding(GSM7BITCoding, &noOpEncDec{})
	require.EqualValues(t, GSM7BITCoding, enc.DataCoding())

	encoded, err := enc.Encode("abc")
	require.NoError(t, err)
	require.Equal(t, []byte("abc"), encoded)

	decoded, err := enc.Decode(encoded)
	require.NoError(t, err)
	require.Equal(t, "abc", decoded)
}


================================================
FILE: data/header_data.go
================================================
//go:generate stringer -type=CommandStatusType,CommandIDType -output header_data_string.go

package data

// CommandStatusType is type of command status
type CommandStatusType int32

// CommandIDType is type of command id.
type CommandIDType int32

// nolint
const (
	// SMPP Command ID Set
	GENERIC_NACK          = CommandIDType(-2147483648)
	BIND_RECEIVER         = CommandIDType(0x00000001)
	BIND_RECEIVER_RESP    = CommandIDType(-2147483647)
	BIND_TRANSMITTER      = CommandIDType(0x00000002)
	BIND_TRANSMITTER_RESP = CommandIDType(-2147483646)
	QUERY_SM              = CommandIDType(0x00000003)
	QUERY_SM_RESP         = CommandIDType(-2147483645)
	SUBMIT_SM             = CommandIDType(0x00000004)
	SUBMIT_SM_RESP        = CommandIDType(-2147483644)
	DELIVER_SM            = CommandIDType(0x00000005)
	DELIVER_SM_RESP       = CommandIDType(-2147483643)
	UNBIND                = CommandIDType(0x00000006)
	UNBIND_RESP           = CommandIDType(-2147483642)
	REPLACE_SM            = CommandIDType(0x00000007)
	REPLACE_SM_RESP       = CommandIDType(-2147483641)
	CANCEL_SM             = CommandIDType(0x00000008)
	CANCEL_SM_RESP        = CommandIDType(-2147483640)
	BIND_TRANSCEIVER      = CommandIDType(0x00000009)
	BIND_TRANSCEIVER_RESP = CommandIDType(-2147483639)
	OUTBIND               = CommandIDType(0x0000000B)
	ENQUIRE_LINK          = CommandIDType(0x00000015)
	ENQUIRE_LINK_RESP     = CommandIDType(-2147483627)
	SUBMIT_MULTI          = CommandIDType(0x00000021)
	SUBMIT_MULTI_RESP     = CommandIDType(-2147483615)
	ALERT_NOTIFICATION    = CommandIDType(0x00000102)
	DATA_SM               = CommandIDType(0x00000103)
	DATA_SM_RESP          = CommandIDType(-2147483389)
)

// nolint
const (
	// Command_Status Error Codes
	ESME_ROK           = CommandStatusType(0x00000000) // No Error
	ESME_RINVMSGLEN    = CommandStatusType(0x00000001) // Message Length is invalid
	ESME_RINVCMDLEN    = CommandStatusType(0x00000002) // Command Length is invalid
	ESME_RINVCMDID     = CommandStatusType(0x00000003) // Invalid Command ID
	ESME_RINVBNDSTS    = CommandStatusType(0x00000004) // Incorrect BIND Status for given command
	ESME_RALYBND       = CommandStatusType(0x00000005) // ESME Already in Bound State
	ESME_RINVPRTFLG    = CommandStatusType(0x00000006) // Invalid Priority Flag
	ESME_RINVREGDLVFLG = CommandStatusType(0x00000007) // Invalid Registered Delivery Flag
	ESME_RSYSERR       = CommandStatusType(0x00000008) // System Error
	ESME_RINVSRCADR    = CommandStatusType(0x0000000A) // Invalid Source Address
	ESME_RINVDSTADR    = CommandStatusType(0x0000000B) // Invalid Dest Addr
	ESME_RINVMSGID     = CommandStatusType(0x0000000C) // Message ID is invalid
	ESME_RBINDFAIL     = CommandStatusType(0x0000000D) // Bind Failed
	ESME_RINVPASWD     = CommandStatusType(0x0000000E) // Invalid Password
	ESME_RINVSYSID     = CommandStatusType(0x0000000F) // Invalid System ID
	ESME_RCANCELFAIL   = CommandStatusType(0x00000011) // Cancel SM Failed
	ESME_RREPLACEFAIL  = CommandStatusType(0x00000013) // Replace SM Failed
	ESME_RMSGQFUL      = CommandStatusType(0x00000014) // Message Queue Full
	ESME_RINVSERTYP    = CommandStatusType(0x00000015) // Invalid Service Type

	ESME_RADDCUSTFAIL  = CommandStatusType(0x00000019) // Failed to Add Customer
	ESME_RDELCUSTFAIL  = CommandStatusType(0x0000001A) // Failed to delete Customer
	ESME_RMODCUSTFAIL  = CommandStatusType(0x0000001B) // Failed to modify customer
	ESME_RENQCUSTFAIL  = CommandStatusType(0x0000001C) // Failed to Enquire Customer
	ESME_RINVCUSTID    = CommandStatusType(0x0000001D) // Invalid Customer ID
	ESME_RINVCUSTNAME  = CommandStatusType(0x0000001F) // Invalid Customer Name
	ESME_RINVCUSTADR   = CommandStatusType(0x00000021) // Invalid Customer Address
	ESME_RINVADR       = CommandStatusType(0x00000022) // Invalid Address
	ESME_RCUSTEXIST    = CommandStatusType(0x00000023) // Customer Exists
	ESME_RCUSTNOTEXIST = CommandStatusType(0x00000024) // Customer does not exist
	ESME_RADDDLFAIL    = CommandStatusType(0x00000026) // Failed to Add DL
	ESME_RMODDLFAIL    = CommandStatusType(0x00000027) // Failed to modify DL
	ESME_RDELDLFAIL    = CommandStatusType(0x00000028) // Failed to Delete DL
	ESME_RVIEWDLFAIL   = CommandStatusType(0x00000029) // Failed to View DL
	ESME_RLISTDLSFAIL  = CommandStatusType(0x00000030) // Failed to list DLs
	ESME_RPARAMRETFAIL = CommandStatusType(0x00000031) // Param Retrieve Failed
	ESME_RINVPARAM     = CommandStatusType(0x00000032) // Invalid Param

	ESME_RINVNUMDESTS = CommandStatusType(0x00000033) // Invalid number of destinations
	ESME_RINVDLNAME   = CommandStatusType(0x00000034) // Invalid Distribution List name

	ESME_RINVDLMEMBDESC = CommandStatusType(0x00000035) // Invalid DL Member Description
	ESME_RINVDLMEMBTYP  = CommandStatusType(0x00000038) // Invalid DL Member Type
	ESME_RINVDLMODOPT   = CommandStatusType(0x00000039) // Invalid DL Modify Option

	ESME_RINVDESTFLAG = CommandStatusType(0x00000040) // Destination flag is invalid (submit_multi)
	ESME_RINVSUBREP   = CommandStatusType(0x00000042) // Invalid ‘submit with replace’ request (i.e. submit_sm with replace_if_present_flag set)
	ESME_RINVESMCLASS = CommandStatusType(0x00000043) // Invalid esm_class field data
	ESME_RCNTSUBDL    = CommandStatusType(0x00000044) // Cannot Submit to Distribution List
	ESME_RSUBMITFAIL  = CommandStatusType(0x00000045) // submit_sm or submit_multi failed
	ESME_RINVSRCTON   = CommandStatusType(0x00000048) // Invalid Source address TON
	ESME_RINVSRCNPI   = CommandStatusType(0x00000049) // Invalid Source address NPI
	ESME_RINVDSTTON   = CommandStatusType(0x00000050) // Invalid Destination address TON
	ESME_RINVDSTNPI   = CommandStatusType(0x00000051) // Invalid Destination address NPI
	ESME_RINVSYSTYP   = CommandStatusType(0x00000053) // Invalid system_type field
	ESME_RINVREPFLAG  = CommandStatusType(0x00000054) // Invalid replace_if_present flag
	ESME_RINVNUMMSGS  = CommandStatusType(0x00000055) // Invalid number of messages
	ESME_RTHROTTLED   = CommandStatusType(0x00000058) // Throttling error (ESME has exceeded allowed message limits)

	ESME_RPROVNOTALLWD = CommandStatusType(0x00000059) // Provisioning Not Allowed

	ESME_RINVSCHED    = CommandStatusType(0x00000061) // Invalid Scheduled Delivery Time
	ESME_RINVEXPIRY   = CommandStatusType(0x00000062) // Invalid message validity period (Expiry time)
	ESME_RINVDFTMSGID = CommandStatusType(0x00000063) // Predefined Message Invalid or Not Found
	ESME_RX_T_APPN    = CommandStatusType(0x00000064) // ESME Receiver Temporary App Error Code
	ESME_RX_P_APPN    = CommandStatusType(0x00000065) // ESME Receiver Permanent App Error Code
	ESME_RX_R_APPN    = CommandStatusType(0x00000066) // ESME Receiver Reject Message Error Code
	ESME_RQUERYFAIL   = CommandStatusType(0x00000067) // query_sm request failed

	ESME_RINVPGCUSTID      = CommandStatusType(0x00000080) // Paging Customer ID Invalid No such subscriber
	ESME_RINVPGCUSTIDLEN   = CommandStatusType(0x00000081) // Paging Customer ID length Invalid
	ESME_RINVCITYLEN       = CommandStatusType(0x00000082) // City Length Invalid
	ESME_RINVSTATELEN      = CommandStatusType(0x00000083) // State Length Invalid
	ESME_RINVZIPPREFIXLEN  = CommandStatusType(0x00000084) // Zip Prefix Length Invalid
	ESME_RINVZIPPOSTFIXLEN = CommandStatusType(0x00000085) // Zip Postfix Length Invalid
	ESME_RINVMINLEN        = CommandStatusType(0x00000086) // MIN Length Invalid
	ESME_RINVMIN           = CommandStatusType(0x00000087) // MIN Invalid (i.e. No such MIN)
	ESME_RINVPINLEN        = CommandStatusType(0x00000088) // PIN Length Invalid
	ESME_RINVTERMCODELEN   = CommandStatusType(0x00000089) // Terminal Code Length Invalid
	ESME_RINVCHANNELLEN    = CommandStatusType(0x0000008A) // Channel Length Invalid
	ESME_RINVCOVREGIONLEN  = CommandStatusType(0x0000008B) // Coverage Region Length Invalid
	ESME_RINVCAPCODELEN    = CommandStatusType(0x0000008C) // Cap Code Length Invalid
	ESME_RINVMDTLEN        = CommandStatusType(0x0000008D) // Message delivery time Length Invalid
	ESME_RINVPRIORMSGLEN   = CommandStatusType(0x0000008E) // Priority Message Length Invalid
	ESME_RINVPERMSGLEN     = CommandStatusType(0x0000008F) // Periodic Messages Length Invalid
	ESME_RINVPGALERTLEN    = CommandStatusType(0x00000090) // Paging Alerts Length Invalid
	ESME_RINVSMUSERLEN     = CommandStatusType(0x00000091) // int16 Message User Group Length Invalid
	ESME_RINVRTDBLEN       = CommandStatusType(0x00000092) // Real Time Data broadcasts Length Invalid
	ESME_RINVREGDELLEN     = CommandStatusType(0x00000093) // Registered Delivery Length Invalid
	ESME_RINVMSGDISTLEN    = CommandStatusType(0x00000094) // Message Distribution Length Invalid
	ESME_RINVPRIORMSG      = CommandStatusType(0x00000095) // Priority Message Length Invalid
	ESME_RINVMDT           = CommandStatusType(0x00000096) // Message delivery time Invalid
	ESME_RINVPERMSG        = CommandStatusType(0x00000097) // Periodic Messages Invalid
	ESME_RINVMSGDIST       = CommandStatusType(0x00000098) // Message Distribution Invalid
	ESME_RINVPGALERT       = CommandStatusType(0x00000099) // Paging Alerts Invalid
	ESME_RINVSMUSER        = CommandStatusType(0x0000009A) // int16 Message User Group Invalid
	ESME_RINVRTDB          = CommandStatusType(0x0000009B) // Real Time Data broadcasts Invalid
	ESME_RINVREGDEL        = CommandStatusType(0x0000009C) // Registered Delivery Invalid
	ESME_RINVOPTPARLEN     = CommandStatusType(0x0000009F) // Invalid Optional Parameter Length
	ESME_RINVOPTPARSTREAM  = CommandStatusType(0x000000C0) // KIF IW Field out of data
	ESME_ROPTPARNOTALLWD   = CommandStatusType(0x000000C1) // Optional Parameter not allowed
	ESME_RINVPARLEN        = CommandStatusType(0x000000C2) // Invalid Parameter Length.
	ESME_RMISSINGOPTPARAM  = CommandStatusType(0x000000C3) // Expected Optional Parameter missing
	ESME_RINVOPTPARAMVAL   = CommandStatusType(0x000000C4) // Invalid Optional Parameter Value
	ESME_RDELIVERYFAILURE  = CommandStatusType(0x000000FE) // Delivery Failure (used for data_sm_resp)
	ESME_RUNKNOWNERR       = CommandStatusType(0x000000FF) // Unknown Error

	ESME_LAST_ERROR = CommandStatusType(0x0000012C) // THE VALUE OF THE LAST ERROR CODE
)


================================================
FILE: data/header_data_string.go
================================================
// Code generated by "stringer -type=CommandStatusType,CommandIDType -output header_data_string.go"; DO NOT EDIT.

package data

import "strconv"

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[ESME_ROK-0]
	_ = x[ESME_RINVMSGLEN-1]
	_ = x[ESME_RINVCMDLEN-2]
	_ = x[ESME_RINVCMDID-3]
	_ = x[ESME_RINVBNDSTS-4]
	_ = x[ESME_RALYBND-5]
	_ = x[ESME_RINVPRTFLG-6]
	_ = x[ESME_RINVREGDLVFLG-7]
	_ = x[ESME_RSYSERR-8]
	_ = x[ESME_RINVSRCADR-10]
	_ = x[ESME_RINVDSTADR-11]
	_ = x[ESME_RINVMSGID-12]
	_ = x[ESME_RBINDFAIL-13]
	_ = x[ESME_RINVPASWD-14]
	_ = x[ESME_RINVSYSID-15]
	_ = x[ESME_RCANCELFAIL-17]
	_ = x[ESME_RREPLACEFAIL-19]
	_ = x[ESME_RMSGQFUL-20]
	_ = x[ESME_RINVSERTYP-21]
	_ = x[ESME_RADDCUSTFAIL-25]
	_ = x[ESME_RDELCUSTFAIL-26]
	_ = x[ESME_RMODCUSTFAIL-27]
	_ = x[ESME_RENQCUSTFAIL-28]
	_ = x[ESME_RINVCUSTID-29]
	_ = x[ESME_RINVCUSTNAME-31]
	_ = x[ESME_RINVCUSTADR-33]
	_ = x[ESME_RINVADR-34]
	_ = x[ESME_RCUSTEXIST-35]
	_ = x[ESME_RCUSTNOTEXIST-36]
	_ = x[ESME_RADDDLFAIL-38]
	_ = x[ESME_RMODDLFAIL-39]
	_ = x[ESME_RDELDLFAIL-40]
	_ = x[ESME_RVIEWDLFAIL-41]
	_ = x[ESME_RLISTDLSFAIL-48]
	_ = x[ESME_RPARAMRETFAIL-49]
	_ = x[ESME_RINVPARAM-50]
	_ = x[ESME_RINVNUMDESTS-51]
	_ = x[ESME_RINVDLNAME-52]
	_ = x[ESME_RINVDLMEMBDESC-53]
	_ = x[ESME_RINVDLMEMBTYP-56]
	_ = x[ESME_RINVDLMODOPT-57]
	_ = x[ESME_RINVDESTFLAG-64]
	_ = x[ESME_RINVSUBREP-66]
	_ = x[ESME_RINVESMCLASS-67]
	_ = x[ESME_RCNTSUBDL-68]
	_ = x[ESME_RSUBMITFAIL-69]
	_ = x[ESME_RINVSRCTON-72]
	_ = x[ESME_RINVSRCNPI-73]
	_ = x[ESME_RINVDSTTON-80]
	_ = x[ESME_RINVDSTNPI-81]
	_ = x[ESME_RINVSYSTYP-83]
	_ = x[ESME_RINVREPFLAG-84]
	_ = x[ESME_RINVNUMMSGS-85]
	_ = x[ESME_RTHROTTLED-88]
	_ = x[ESME_RPROVNOTALLWD-89]
	_ = x[ESME_RINVSCHED-97]
	_ = x[ESME_RINVEXPIRY-98]
	_ = x[ESME_RINVDFTMSGID-99]
	_ = x[ESME_RX_T_APPN-100]
	_ = x[ESME_RX_P_APPN-101]
	_ = x[ESME_RX_R_APPN-102]
	_ = x[ESME_RQUERYFAIL-103]
	_ = x[ESME_RINVPGCUSTID-128]
	_ = x[ESME_RINVPGCUSTIDLEN-129]
	_ = x[ESME_RINVCITYLEN-130]
	_ = x[ESME_RINVSTATELEN-131]
	_ = x[ESME_RINVZIPPREFIXLEN-132]
	_ = x[ESME_RINVZIPPOSTFIXLEN-133]
	_ = x[ESME_RINVMINLEN-134]
	_ = x[ESME_RINVMIN-135]
	_ = x[ESME_RINVPINLEN-136]
	_ = x[ESME_RINVTERMCODELEN-137]
	_ = x[ESME_RINVCHANNELLEN-138]
	_ = x[ESME_RINVCOVREGIONLEN-139]
	_ = x[ESME_RINVCAPCODELEN-140]
	_ = x[ESME_RINVMDTLEN-141]
	_ = x[ESME_RINVPRIORMSGLEN-142]
	_ = x[ESME_RINVPERMSGLEN-143]
	_ = x[ESME_RINVPGALERTLEN-144]
	_ = x[ESME_RINVSMUSERLEN-145]
	_ = x[ESME_RINVRTDBLEN-146]
	_ = x[ESME_RINVREGDELLEN-147]
	_ = x[ESME_RINVMSGDISTLEN-148]
	_ = x[ESME_RINVPRIORMSG-149]
	_ = x[ESME_RINVMDT-150]
	_ = x[ESME_RINVPERMSG-151]
	_ = x[ESME_RINVMSGDIST-152]
	_ = x[ESME_RINVPGALERT-153]
	_ = x[ESME_RINVSMUSER-154]
	_ = x[ESME_RINVRTDB-155]
	_ = x[ESME_RINVREGDEL-156]
	_ = x[ESME_RINVOPTPARLEN-159]
	_ = x[ESME_RINVOPTPARSTREAM-192]
	_ = x[ESME_ROPTPARNOTALLWD-193]
	_ = x[ESME_RINVPARLEN-194]
	_ = x[ESME_RMISSINGOPTPARAM-195]
	_ = x[ESME_RINVOPTPARAMVAL-196]
	_ = x[ESME_RDELIVERYFAILURE-254]
	_ = x[ESME_RUNKNOWNERR-255]
	_ = x[ESME_LAST_ERROR-300]
}

const _CommandStatusType_name = "ESME_ROKESME_RINVMSGLENESME_RINVCMDLENESME_RINVCMDIDESME_RINVBNDSTSESME_RALYBNDESME_RINVPRTFLGESME_RINVREGDLVFLGESME_RSYSERRESME_RINVSRCADRESME_RINVDSTADRESME_RINVMSGIDESME_RBINDFAILESME_RINVPASWDESME_RINVSYSIDESME_RCANCELFAILESME_RREPLACEFAILESME_RMSGQFULESME_RINVSERTYPESME_RADDCUSTFAILESME_RDELCUSTFAILESME_RMODCUSTFAILESME_RENQCUSTFAILESME_RINVCUSTIDESME_RINVCUSTNAMEESME_RINVCUSTADRESME_RINVADRESME_RCUSTEXISTESME_RCUSTNOTEXISTESME_RADDDLFAILESME_RMODDLFAILESME_RDELDLFAILESME_RVIEWDLFAILESME_RLISTDLSFAILESME_RPARAMRETFAILESME_RINVPARAMESME_RINVNUMDESTSESME_RINVDLNAMEESME_RINVDLMEMBDESCESME_RINVDLMEMBTYPESME_RINVDLMODOPTESME_RINVDESTFLAGESME_RINVSUBREPESME_RINVESMCLASSESME_RCNTSUBDLESME_RSUBMITFAILESME_RINVSRCTONESME_RINVSRCNPIESME_RINVDSTTONESME_RINVDSTNPIESME_RINVSYSTYPESME_RINVREPFLAGESME_RINVNUMMSGSESME_RTHROTTLEDESME_RPROVNOTALLWDESME_RINVSCHEDESME_RINVEXPIRYESME_RINVDFTMSGIDESME_RX_T_APPNESME_RX_P_APPNESME_RX_R_APPNESME_RQUERYFAILESME_RINVPGCUSTIDESME_RINVPGCUSTIDLENESME_RINVCITYLENESME_RINVSTATELENESME_RINVZIPPREFIXLENESME_RINVZIPPOSTFIXLENESME_RINVMINLENESME_RINVMINESME_RINVPINLENESME_RINVTERMCODELENESME_RINVCHANNELLENESME_RINVCOVREGIONLENESME_RINVCAPCODELENESME_RINVMDTLENESME_RINVPRIORMSGLENESME_RINVPERMSGLENESME_RINVPGALERTLENESME_RINVSMUSERLENESME_RINVRTDBLENESME_RINVREGDELLENESME_RINVMSGDISTLENESME_RINVPRIORMSGESME_RINVMDTESME_RINVPERMSGESME_RINVMSGDISTESME_RINVPGALERTESME_RINVSMUSERESME_RINVRTDBESME_RINVREGDELESME_RINVOPTPARLENESME_RINVOPTPARSTREAMESME_ROPTPARNOTALLWDESME_RINVPARLENESME_RMISSINGOPTPARAMESME_RINVOPTPARAMVALESME_RDELIVERYFAILUREESME_RUNKNOWNERRESME_LAST_ERROR"

var _CommandStatusType_map = map[CommandStatusType]string{
	0:   _CommandStatusType_name[0:8],
	1:   _CommandStatusType_name[8:23],
	2:   _CommandStatusType_name[23:38],
	3:   _CommandStatusType_name[38:52],
	4:   _CommandStatusType_name[52:67],
	5:   _CommandStatusType_name[67:79],
	6:   _CommandStatusType_name[79:94],
	7:   _CommandStatusType_name[94:112],
	8:   _CommandStatusType_name[112:124],
	10:  _CommandStatusType_name[124:139],
	11:  _CommandStatusType_name[139:154],
	12:  _CommandStatusType_name[154:168],
	13:  _CommandStatusType_name[168:182],
	14:  _CommandStatusType_name[182:196],
	15:  _CommandStatusType_name[196:210],
	17:  _CommandStatusType_name[210:226],
	19:  _CommandStatusType_name[226:243],
	20:  _CommandStatusType_name[243:256],
	21:  _CommandStatusType_name[256:271],
	25:  _CommandStatusType_name[271:288],
	26:  _CommandStatusType_name[288:305],
	27:  _CommandStatusType_name[305:322],
	28:  _CommandStatusType_name[322:339],
	29:  _CommandStatusType_name[339:354],
	31:  _CommandStatusType_name[354:371],
	33:  _CommandStatusType_name[371:387],
	34:  _CommandStatusType_name[387:399],
	35:  _CommandStatusType_name[399:414],
	36:  _CommandStatusType_name[414:432],
	38:  _CommandStatusType_name[432:447],
	39:  _CommandStatusType_name[447:462],
	40:  _CommandStatusType_name[462:477],
	41:  _CommandStatusType_name[477:493],
	48:  _CommandStatusType_name[493:510],
	49:  _CommandStatusType_name[510:528],
	50:  _CommandStatusType_name[528:542],
	51:  _CommandStatusType_name[542:559],
	52:  _CommandStatusType_name[559:574],
	53:  _CommandStatusType_name[574:593],
	56:  _CommandStatusType_name[593:611],
	57:  _CommandStatusType_name[611:628],
	64:  _CommandStatusType_name[628:645],
	66:  _CommandStatusType_name[645:660],
	67:  _CommandStatusType_name[660:677],
	68:  _CommandStatusType_name[677:691],
	69:  _CommandStatusType_name[691:707],
	72:  _CommandStatusType_name[707:722],
	73:  _CommandStatusType_name[722:737],
	80:  _CommandStatusType_name[737:752],
	81:  _CommandStatusType_name[752:767],
	83:  _CommandStatusType_name[767:782],
	84:  _CommandStatusType_name[782:798],
	85:  _CommandStatusType_name[798:814],
	88:  _CommandStatusType_name[814:829],
	89:  _CommandStatusType_name[829:847],
	97:  _CommandStatusType_name[847:861],
	98:  _CommandStatusType_name[861:876],
	99:  _CommandStatusType_name[876:893],
	100: _CommandStatusType_name[893:907],
	101: _CommandStatusType_name[907:921],
	102: _CommandStatusType_name[921:935],
	103: _CommandStatusType_name[935:950],
	128: _CommandStatusType_name[950:967],
	129: _CommandStatusType_name[967:987],
	130: _CommandStatusType_name[987:1003],
	131: _CommandStatusType_name[1003:1020],
	132: _CommandStatusType_name[1020:1041],
	133: _CommandStatusType_name[1041:1063],
	134: _CommandStatusType_name[1063:1078],
	135: _CommandStatusType_name[1078:1090],
	136: _CommandStatusType_name[1090:1105],
	137: _CommandStatusType_name[1105:1125],
	138: _CommandStatusType_name[1125:1144],
	139: _CommandStatusType_name[1144:1165],
	140: _CommandStatusType_name[1165:1184],
	141: _CommandStatusType_name[1184:1199],
	142: _CommandStatusType_name[1199:1219],
	143: _CommandStatusType_name[1219:1237],
	144: _CommandStatusType_name[1237:1256],
	145: _CommandStatusType_name[1256:1274],
	146: _CommandStatusType_name[1274:1290],
	147: _CommandStatusType_name[1290:1308],
	148: _CommandStatusType_name[1308:1327],
	149: _CommandStatusType_name[1327:1344],
	150: _CommandStatusType_name[1344:1356],
	151: _CommandStatusType_name[1356:1371],
	152: _CommandStatusType_name[1371:1387],
	153: _CommandStatusType_name[1387:1403],
	154: _CommandStatusType_name[1403:1418],
	155: _CommandStatusType_name[1418:1431],
	156: _CommandStatusType_name[1431:1446],
	159: _CommandStatusType_name[1446:1464],
	192: _CommandStatusType_name[1464:1485],
	193: _CommandStatusType_name[1485:1505],
	194: _CommandStatusType_name[1505:1520],
	195: _CommandStatusType_name[1520:1541],
	196: _CommandStatusType_name[1541:1561],
	254: _CommandStatusType_name[1561:1582],
	255: _CommandStatusType_name[1582:1598],
	300: _CommandStatusType_name[1598:1613],
}

func (i CommandStatusType) String() string {
	if str, ok := _CommandStatusType_map[i]; ok {
		return str
	}
	return "CommandStatusType(" + strconv.FormatInt(int64(i), 10) + ")"
}

func (i CommandStatusType) Desc() string {
	switch i {
	case ESME_ROK:
		return "No Error"
	case ESME_RINVMSGLEN:
		return "Message Length is invalid"
	case ESME_RINVCMDLEN:
		return "Command Length is invalid"
	case ESME_RINVCMDID:
		return "Invalid Command ID"
	case ESME_RINVBNDSTS:
		return "Incorrect BIND Status for given command"
	case ESME_RALYBND:
		return "ESME Already in Bound State"
	case ESME_RINVPRTFLG:
		return "Invalid Priority Flag"
	case ESME_RINVREGDLVFLG:
		return "Invalid Registered Delivery Flag"
	case ESME_RSYSERR:
		return "System Error"
	case ESME_RINVSRCADR:
		return "Invalid Source Address"
	case ESME_RINVDSTADR:
		return "Invalid Dest Addr"
	case ESME_RINVMSGID:
		return "Message ID is invalid"
	case ESME_RBINDFAIL:
		return "Bind Failed"
	case ESME_RINVPASWD:
		return "Invalid Password"
	case ESME_RINVSYSID:
		return "Invalid System ID"
	case ESME_RCANCELFAIL:
		return "Cancel SM Failed"
	case ESME_RREPLACEFAIL:
		return "Replace SM Failed"
	case ESME_RMSGQFUL:
		return "Message Queue Full"
	case ESME_RINVSERTYP:
		return "Invalid Service Type"
	case ESME_RADDCUSTFAIL:
		return "Failed to Add Customer"
	case ESME_RDELCUSTFAIL:
		return "Failed to delete Customer"
	case ESME_RMODCUSTFAIL:
		return "Failed to modify customer"
	case ESME_RENQCUSTFAIL:
		return "Failed to Enquire Customer"
	case ESME_RINVCUSTID:
		return "Invalid Customer ID"
	case ESME_RINVCUSTNAME:
		return "Invalid Customer Name"
	case ESME_RINVCUSTADR:
		return "Invalid Customer Address"
	case ESME_RINVADR:
		return "Invalid Address"
	case ESME_RCUSTEXIST:
		return "Customer Exists"
	case ESME_RCUSTNOTEXIST:
		return "Customer does not exist"
	case ESME_RADDDLFAIL:
		return "Failed to Add DL"
	case ESME_RMODDLFAIL:
		return "Failed to modify DL"
	case ESME_RDELDLFAIL:
		return "Failed to Delete DL"
	case ESME_RVIEWDLFAIL:
		return "Failed to View DL"
	case ESME_RLISTDLSFAIL:
		return "Failed to list DLs"
	case ESME_RPARAMRETFAIL:
		return "Param Retrieve Failed"
	case ESME_RINVPARAM:
		return "Invalid Param"
	case ESME_RINVNUMDESTS:
		return "Invalid number of destinations"
	case ESME_RINVDLNAME:
		return "Invalid Distribution List name"
	case ESME_RINVDLMEMBDESC:
		return "Invalid DL Member Description"
	case ESME_RINVDLMEMBTYP:
		return "Invalid DL Member Type"
	case ESME_RINVDLMODOPT:
		return "Invalid DL Modify Option"
	case ESME_RINVDESTFLAG:
		return "Destination flag is invalid (submit_multi)"
	case ESME_RINVSUBREP:
		return "Invalid ‘submit with replace’ request (i.e. submit_sm with replace_if_present_flag set)"
	case ESME_RINVESMCLASS:
		return "Invalid esm_class field data"
	case ESME_RCNTSUBDL:
		return "Cannot Submit to Distribution List"
	case ESME_RSUBMITFAIL:
		return "submit_sm or submit_multi failed"
	case ESME_RINVSRCTON:
		return "Invalid Source address TON"
	case ESME_RINVSRCNPI:
		return "Invalid Source address NPI"
	case ESME_RINVDSTTON:
		return "Invalid Destination address TON"
	case ESME_RINVDSTNPI:
		return "Invalid Destination address NPI"
	case ESME_RINVSYSTYP:
		return "Invalid system_type field"
	case ESME_RINVREPFLAG:
		return "Invalid replace_if_present flag"
	case ESME_RINVNUMMSGS:
		return "Invalid number of messages"
	case ESME_RTHROTTLED:
		return "Throttling error (ESME has exceeded allowed message limits)"
	case ESME_RPROVNOTALLWD:
		return "Provisioning Not Allowed"
	case ESME_RINVSCHED:
		return "Invalid Scheduled Delivery Time"
	case ESME_RINVEXPIRY:
		return "Invalid message validity period (Expiry time)"
	case ESME_RINVDFTMSGID:
		return "Predefined Message Invalid or Not Found"
	case ESME_RX_T_APPN:
		return "ESME Receiver Temporary App Error Code"
	case ESME_RX_P_APPN:
		return "ESME Receiver Permanent App Error Code"
	case ESME_RX_R_APPN:
		return "ESME Receiver Reject Message Error Code"
	case ESME_RQUERYFAIL:
		return "query_sm request failed"
	case ESME_RINVPGCUSTID:
		return "Paging Customer ID Invalid No such subscriber"
	case ESME_RINVPGCUSTIDLEN:
		return "Paging Customer ID length Invalid"
	case ESME_RINVCITYLEN:
		return "City Length Invalid"
	case ESME_RINVSTATELEN:
		return "State Length Invalid"
	case ESME_RINVZIPPREFIXLEN:
		return "Zip Prefix Length Invalid"
	case ESME_RINVZIPPOSTFIXLEN:
		return "Zip Postfix Length Invalid"
	case ESME_RINVMINLEN:
		return "MIN Length Invalid"
	case ESME_RINVMIN:
		return "MIN Invalid (i.e. No such MIN)"
	case ESME_RINVPINLEN:
		return "PIN Length Invalid"
	case ESME_RINVTERMCODELEN:
		return "Terminal Code Length Invalid"
	case ESME_RINVCHANNELLEN:
		return "Channel Length Invalid"
	case ESME_RINVCOVREGIONLEN:
		return "Coverage Region Length Invalid"
	case ESME_RINVCAPCODELEN:
		return "Cap Code Length Invalid"
	case ESME_RINVMDTLEN:
		return "Message delivery time Length Invalid"
	case ESME_RINVPRIORMSGLEN:
		return "Priority Message Length Invalid"
	case ESME_RINVPERMSGLEN:
		return "Periodic Messages Length Invalid"
	case ESME_RINVPGALERTLEN:
		return "Paging Alerts Length Invalid"
	case ESME_RINVSMUSERLEN:
		return "int16 Message User Group Length Invalid"
	case ESME_RINVRTDBLEN:
		return "Real Time Data broadcasts Length Invalid"
	case ESME_RINVREGDELLEN:
		return "Registered Delivery Length Invalid"
	case ESME_RINVMSGDISTLEN:
		return "Message Distribution Length Invalid"
	case ESME_RINVPRIORMSG:
		return "Priority Message Length Invalid"
	case ESME_RINVMDT:
		return "Message delivery time Invalid"
	case ESME_RINVPERMSG:
		return "Periodic Messages Invalid"
	case ESME_RINVMSGDIST:
		return "Message Distribution Invalid"
	case ESME_RINVPGALERT:
		return "Paging Alerts Invalid"
	case ESME_RINVSMUSER:
		return "int16 Message User Group Invalid"
	case ESME_RINVRTDB:
		return "Real Time Data broadcasts Invalid"
	case ESME_RINVREGDEL:
		return "Registered Delivery Invalid"
	case ESME_RINVOPTPARLEN:
		return "Invalid Optional Parameter Length"
	case ESME_RINVOPTPARSTREAM:
		return "Error in the optional part of the PDU Body."
	case ESME_ROPTPARNOTALLWD:
		return "Optional Parameter not allowed"
	case ESME_RINVPARLEN:
		return "Invalid Parameter Length."
	case ESME_RMISSINGOPTPARAM:
		return "Expected Optional Parameter missing"
	case ESME_RINVOPTPARAMVAL:
		return "Invalid Optional Parameter Value"
	case ESME_RDELIVERYFAILURE:
		return "Delivery Failure (used for data_sm_resp)"
	case ESME_RUNKNOWNERR:
		return "Unknown Error"
	case ESME_LAST_ERROR:
		return "The value of the last error code"
	}
	return i.String()
}

func _() {
	// An "invalid array index" compiler error signifies that the constant values have changed.
	// Re-run the stringer command to generate them again.
	var x [1]struct{}
	_ = x[GENERIC_NACK - -2147483648]
	_ = x[BIND_RECEIVER-1]
	_ = x[BIND_RECEIVER_RESP - -2147483647]
	_ = x[BIND_TRANSMITTER-2]
	_ = x[BIND_TRANSMITTER_RESP - -2147483646]
	_ = x[QUERY_SM-3]
	_ = x[QUERY_SM_RESP - -2147483645]
	_ = x[SUBMIT_SM-4]
	_ = x[SUBMIT_SM_RESP - -2147483644]
	_ = x[DELIVER_SM-5]
	_ = x[DELIVER_SM_RESP - -2147483643]
	_ = x[UNBIND-6]
	_ = x[UNBIND_RESP - -2147483642]
	_ = x[REPLACE_SM-7]
	_ = x[REPLACE_SM_RESP - -2147483641]
	_ = x[CANCEL_SM-8]
	_ = x[CANCEL_SM_RESP - -2147483640]
	_ = x[BIND_TRANSCEIVER-9]
	_ = x[BIND_TRANSCEIVER_RESP - -2147483639]
	_ = x[OUTBIND-11]
	_ = x[ENQUIRE_LINK-21]
	_ = x[ENQUIRE_LINK_RESP - -2147483627]
	_ = x[SUBMIT_MULTI-33]
	_ = x[SUBMIT_MULTI_RESP - -2147483615]
	_ = x[ALERT_NOTIFICATION-258]
	_ = x[DATA_SM-259]
	_ = x[DATA_SM_RESP - -2147483389]
}

const (
	_CommandIDType_name_0 = "GENERIC_NACKBIND_RECEIVER_RESPBIND_TRANSMITTER_RESPQUERY_SM_RESPSUBMIT_SM_RESPDELIVER_SM_RESPUNBIND_RESPREPLACE_SM_RESPCANCEL_SM_RESPBIND_TRANSCEIVER_RESP"
	_CommandIDType_name_1 = "ENQUIRE_LINK_RESP"
	_CommandIDType_name_2 = "SUBMIT_MULTI_RESP"
	_CommandIDType_name_3 = "DATA_SM_RESP"
	_CommandIDType_name_4 = "BIND_RECEIVERBIND_TRANSMITTERQUERY_SMSUBMIT_SMDELIVER_SMUNBINDREPLACE_SMCANCEL_SMBIND_TRANSCEIVER"
	_CommandIDType_name_5 = "OUTBIND"
	_CommandIDType_name_6 = "ENQUIRE_LINK"
	_CommandIDType_name_7 = "SUBMIT_MULTI"
	_CommandIDType_name_8 = "ALERT_NOTIFICATIONDATA_SM"
)

var (
	_CommandIDType_index_0 = [...]uint8{0, 12, 30, 51, 64, 78, 93, 104, 119, 133, 154}
	_CommandIDType_index_4 = [...]uint8{0, 13, 29, 37, 46, 56, 62, 72, 81, 97}
	_CommandIDType_index_8 = [...]uint8{0, 18, 25}
)

func (i CommandIDType) String() string {
	switch {
	case -2147483648 <= i && i <= -2147483639:
		i -= -2147483648
		return _CommandIDType_name_0[_CommandIDType_index_0[i]:_CommandIDType_index_0[i+1]]
	case i == -2147483627:
		return _CommandIDType_name_1
	case i == -2147483615:
		return _CommandIDType_name_2
	case i == -2147483389:
		return _CommandIDType_name_3
	case 1 <= i && i <= 9:
		i -= 1
		return _CommandIDType_name_4[_CommandIDType_index_4[i]:_CommandIDType_index_4[i+1]]
	case i == 11:
		return _CommandIDType_name_5
	case i == 21:
		return _CommandIDType_name_6
	case i == 33:
		return _CommandIDType_name_7
	case 258 <= i && i <= 259:
		i -= 258
		return _CommandIDType_name_8[_CommandIDType_index_8[i]:_CommandIDType_index_8[i+1]]
	default:
		return "CommandIDType(" + strconv.FormatInt(int64(i), 10) + ")"
	}
}


================================================
FILE: data/other_codings.go
================================================
package data

import (
	"golang.org/x/text/encoding/unicode"
)

var (
	// UTF16BEM is UTF-16 Big Endian with BOM (byte order mark).
	UTF16BEM = &utf16BEM{}

	// UTF16LEM is UTF-16 Little Endian with BOM.
	UTF16LEM = &utf16LEM{}

	// UTF16BE is UTF-16 Big Endian without BOM.
	UTF16BE = &utf16BE{}

	// UTF16LE is UTF-16 Little Endian without BOM.
	UTF16LE = &utf16LE{}
)

type utf16BEM struct{}

func (c utf16BEM) Encode(str string) ([]byte, error) {
	tmp := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
	return encode(str, tmp.NewEncoder())
}

func (c utf16BEM) Decode(data []byte) (string, error) {
	tmp := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
	return decode(data, tmp.NewDecoder())
}

type utf16LEM struct{}

func (c utf16LEM) Encode(str string) ([]byte, error) {
	tmp := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
	return encode(str, tmp.NewEncoder())
}

func (c utf16LEM) Decode(data []byte) (string, error) {
	tmp := unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
	return decode(data, tmp.NewDecoder())
}

type utf16BE struct{}

func (c utf16BE) Encode(str string) ([]byte, error) {
	tmp := unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
	return encode(str, tmp.NewEncoder())
}

func (c utf16BE) Decode(data []byte) (string, error) {
	tmp := unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
	return decode(data, tmp.NewDecoder())
}

type utf16LE struct{}

func (c utf16LE) Encode(str string) ([]byte, error) {
	tmp := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
	return encode(str, tmp.NewEncoder())
}

func (c utf16LE) Decode(data []byte) (string, error) {
	tmp := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
	return decode(data, tmp.NewDecoder())
}


================================================
FILE: data/pkg.go
================================================
package data

import (
	"fmt"
	"sync/atomic"
)

//nolint
const (
	SM_CONNID_LEN        = 16
	SM_MSG_LEN           = 254
	SM_SYSID_LEN         = 16
	SM_MSGID_LEN         = 64
	SM_PASS_LEN          = 9
	SM_DATE_LEN          = 17
	SM_SRVTYPE_LEN       = 6
	SM_SYSTYPE_LEN       = 13
	SM_ADDR_LEN          = 21
	SM_DATA_ADDR_LEN     = 65
	SM_ADDR_RANGE_LEN    = 41
	SM_TYPE_LEN          = 13
	SM_DL_NAME_LEN       = 21
	SM_PARAM_NAME_LEN    = 10
	SM_PARAM_VALUE_LEN   = 10
	SM_MAX_CNT_DEST_ADDR = 254

	// GSM specific, short message must be no larger than 140 octets
	SM_GSM_MSG_LEN = 140

	CONNECTION_CLOSED = 0
	CONNECTION_OPENED = 1

	SM_ACK            = 1
	SM_NO_ACK         = 0
	SM_RESPONSE_ACK   = 0
	SM_RESPONSE_TNACK = 1
	SM_RESPONSE_PNACK = 2

	// Interface_Version
	SMPP_V33 int8 = int8(-0x33)
	SMPP_V34      = byte(0x34)

	// Address_TON
	GSM_TON_UNKNOWN       = byte(0x00)
	GSM_TON_INTERNATIONAL = byte(0x01)
	GSM_TON_NATIONAL      = byte(0x02)
	GSM_TON_NETWORK       = byte(0x03)
	GSM_TON_SUBSCRIBER    = byte(0x04)
	GSM_TON_ALPHANUMERIC  = byte(0x05)
	GSM_TON_ABBREVIATED   = byte(0x06)
	GSM_TON_RESERVED_EXTN = byte(0x07)

	// Address_NPI
	GSM_NPI_UNKNOWN       = byte(0x00)
	GSM_NPI_E164          = byte(0x01)
	GSM_NPI_ISDN          = GSM_NPI_E164
	GSM_NPI_X121          = byte(0x03)
	GSM_NPI_TELEX         = byte(0x04)
	GSM_NPI_LAND_MOBILE   = byte(0x06)
	GSM_NPI_NATIONAL      = byte(0x08)
	GSM_NPI_PRIVATE       = byte(0x09)
	GSM_NPI_ERMES         = byte(0x0A)
	GSM_NPI_INTERNET      = byte(0x0E)
	GSM_NPI_WAP_CLIENT_ID = byte(0x12)
	GSM_NPI_RESERVED_EXTN = byte(0x0F)

	// Service_Type
	SERVICE_NULL string = ""
	SERVICE_CMT  string = "CMT"
	SERVICE_CPT  string = "CPT"
	SERVICE_VMN  string = "VMN"
	SERVICE_VMA  string = "VMA"
	SERVICE_WAP  string = "WAP"
	SERVICE_USSD string = "USSD"

	SMPP_PROTOCOL                 = byte(1)
	SMPPP_PROTOCOL                = byte(2)
	SM_SERVICE_MOBILE_TERMINATED  = byte(0)
	SM_SERVICE_MOBILE_ORIGINATED  = byte(1)
	SM_SERVICE_MOBILE_TRANSCEIVER = byte(2)

	// State of message at SMSC
	SM_STATE_EN_ROUTE      = 1 // default state for messages in transit
	SM_STATE_DELIVERED     = 2 // message is delivered
	SM_STATE_EXPIRED       = 3 // validity period expired
	SM_STATE_DELETED       = 4 // message has been deleted
	SM_STATE_UNDELIVERABLE = 5 // undeliverable
	SM_STATE_ACCEPTED      = 6 // message is in accepted state
	SM_STATE_INVALID       = 7 // message is in invalid state
	SM_STATE_REJECTED      = 8 // message is in rejected state

	//******************
	// ESMClass Defines
	//******************

	// Messaging Mode
	SM_ESM_DEFAULT        = 0x00 // Default SMSC Mode or Message Type
	SM_DATAGRAM_MODE      = 0x01 // Use one-shot express mode
	SM_FORWARD_MODE       = 0x02 // Do not use
	SM_STORE_FORWARD_MODE = 0x03 // Use store & forward

	// Send/Receive TDMA & CDMA Message Type
	SM_SMSC_DLV_RCPT_TYPE     = 0x04 // Recv Msg contains SMSC delivery receipt
	SM_ESME_DLV_ACK_TYPE      = 0x08 // Send/Recv Msg contains ESME delivery acknowledgement
	SM_ESME_MAN_USER_ACK_TYPE = 0x10 // Send/Recv Msg contains manual/user acknowledgment
	SM_CONV_ABORT_TYPE        = 0x18 // Recv Msg contains conversation abort (Korean CDMA)
	SM_INTMD_DLV_NOTIFY_TYPE  = 0x20 // Recv Msg contains intermediate notification

	// GSM Network features
	SM_NONE_GSM           = 0x00 // No specific features selected
	SM_UDH_GSM            = 0x40 // User Data Header indicator set
	SM_REPLY_PATH_GSM     = 0x80 // Reply path set
	SM_UDH_REPLY_PATH_GSM = 0xC0 // Both UDH & Reply path

	// Optional Parameter Tags, Min and Max Lengths
	// Following are the 2 byte tag and min/max lengths for
	// supported optional parameter (declann)

	OPT_PAR_MSG_WAIT = 2

	// Privacy Indicator
	OPT_PAR_PRIV_IND = 0x0201

	// Source Subaddress
	OPT_PAR_SRC_SUBADDR     = 0x0202
	OPT_PAR_SRC_SUBADDR_MIN = 2
	OPT_PAR_SRC_SUBADDR_MAX = 23

	// Destination Subaddress
	OPT_PAR_DEST_SUBADDR     = 0x0203
	OPT_PAR_DEST_SUBADDR_MIN = 2
	OPT_PAR_DEST_SUBADDR_MAX = 23

	// User Message Reference
	OPT_PAR_USER_MSG_REF = 0x0204

	// User Response Code
	OPT_PAR_USER_RESP_CODE = 0x0205

	// Language Indicator
	OPT_PAR_LANG_IND = 0x020D

	// Source Port
	OPT_PAR_SRC_PORT = 0x020A

	// Destination Port
	OPT_PAR_DST_PORT = 0x020B

	// Concat Msg Ref Num
	OPT_PAR_SAR_MSG_REF_NUM = 0x020C

	// Concat Total Segments
	OPT_PAR_SAR_TOT_SEG = 0x020E

	// Concat Segment Seqnums
	OPT_PAR_SAR_SEG_SNUM = 0x020F

	// SC Interface Version
	OPT_PAR_SC_IF_VER = 0x0210

	// Display Time
	OPT_PAR_DISPLAY_TIME = 0x1201

	// Validity Information
	OPT_PAR_MS_VALIDITY = 0x1204

	// DPF Result
	OPT_PAR_DPF_RES = 0x0420

	// Set DPF
	OPT_PAR_SET_DPF = 0x0421

	// MS Availability Status
	OPT_PAR_MS_AVAIL_STAT = 0x0422

	// Network Error Code
	OPT_PAR_NW_ERR_CODE     = 0x0423
	OPT_PAR_NW_ERR_CODE_MIN = 3
	OPT_PAR_NW_ERR_CODE_MAX = 3

	// Extended int16 Message has no size limit

	// Delivery Failure Reason
	OPT_PAR_DEL_FAIL_RSN = 0x0425

	// More Messages to Follow
	OPT_PAR_MORE_MSGS = 0x0426

	// Message State
	OPT_PAR_MSG_STATE = 0x0427

	// Callback Number
	OPT_PAR_CALLBACK_NUM     = 0x0381
	OPT_PAR_CALLBACK_NUM_MIN = 4
	OPT_PAR_CALLBACK_NUM_MAX = 19

	// Callback Number Presentation  Indicator
	OPT_PAR_CALLBACK_NUM_PRES_IND = 0x0302

	// Callback Number Alphanumeric Tag
	OPT_PAR_CALLBACK_NUM_ATAG     = 0x0303
	OPT_PAR_CALLBACK_NUM_ATAG_MIN = 1
	OPT_PAR_CALLBACK_NUM_ATAG_MAX = 65

	// Number of messages in Mailbox
	OPT_PAR_NUM_MSGS = 0x0304

	// SMS Received Alert
	OPT_PAR_SMS_SIGNAL = 0x1203

	// Message Delivery Alert
	OPT_PAR_ALERT_ON_MSG_DELIVERY = 0x130C

	// ITS Reply Type
	OPT_PAR_ITS_REPLY_TYPE = 0x1380

	// ITS Session Info
	OPT_PAR_ITS_SESSION_INFO = 0x1383

	// USSD Service Op
	OPT_PAR_USSD_SER_OP = 0x0501

	// Priority
	SM_NOPRIORITY = 0
	SM_PRIORITY   = 1

	// Registered delivery
	//   SMSC Delivery Receipt (bits 1 & 0)
	SM_SMSC_RECEIPT_MASK          = byte(0x03)
	SM_SMSC_RECEIPT_NOT_REQUESTED = byte(0x00)
	SM_SMSC_RECEIPT_REQUESTED     = byte(0x01)
	SM_SMSC_RECEIPT_ON_FAILURE    = byte(0x02)
	//   SME originated acknowledgement (bits 3 & 2)
	SM_SME_ACK_MASK               = byte(0x0c)
	SM_SME_ACK_NOT_REQUESTED      = byte(0x00)
	SM_SME_ACK_DELIVERY_REQUESTED = byte(0x04)
	SM_SME_ACK_MANUAL_REQUESTED   = byte(0x08)
	SM_SME_ACK_BOTH_REQUESTED     = byte(0x0c)
	//   Intermediate notification (bit 5)
	SM_NOTIF_MASK          = byte(0x010)
	SM_NOTIF_NOT_REQUESTED = byte(0x000)
	SM_NOTIF_REQUESTED     = byte(0x010)

	// Replace if Present flag
	SM_NOREPLACE = 0
	SM_REPLACE   = 1

	// Destination flag
	SM_DEST_SME_ADDRESS = 1
	SM_DEST_DL_NAME     = 2

	// Higher Layer Message Type
	SM_LAYER_WDP  = 0
	SM_LAYER_WCMP = 1

	// Operation Class
	SM_OPCLASS_DATAGRAM    = 0
	SM_OPCLASS_TRANSACTION = 3

	// Originating MSC Address
	OPT_PAR_ORIG_MSC_ADDR     = -32639 // int16(0x8081)
	OPT_PAR_ORIG_MSC_ADDR_MIN = 1
	OPT_PAR_ORIG_MSC_ADDR_MAX = 24

	// Destination MSC Address
	OPT_PAR_DEST_MSC_ADDR     = -32638 // int16(0x8082)
	OPT_PAR_DEST_MSC_ADDR_MIN = 1
	OPT_PAR_DEST_MSC_ADDR_MAX = 24

	// Unused Tag
	OPT_PAR_UNUSED = 0xffff

	// Destination Address Subunit
	OPT_PAR_DST_ADDR_SUBUNIT = 0x0005

	// Destination Network Type
	OPT_PAR_DST_NW_TYPE = 0x0006

	// Destination Bearer Type
	OPT_PAR_DST_BEAR_TYPE = 0x0007

	// Destination Telematics ID
	OPT_PAR_DST_TELE_ID = 0x0008

	// Source Address Subunit
	OPT_PAR_SRC_ADDR_SUBUNIT = 0x000D

	// Source Network Type
	OPT_PAR_SRC_NW_TYPE = 0x000E

	// Source Bearer Type
	OPT_PAR_SRC_BEAR_TYPE = 0x000F

	// Source Telematics ID
	OPT_PAR_SRC_TELE_ID = 0x0010

	// QOS Time to Live
	OPT_PAR_QOS_TIME_TO_LIVE     = 0x0017
	OPT_PAR_QOS_TIME_TO_LIVE_MIN = 1
	OPT_PAR_QOS_TIME_TO_LIVE_MAX = 4

	// Payload Type
	OPT_PAR_PAYLOAD_TYPE = 0x0019

	// Additional Status Info Text
	OPT_PAR_ADD_STAT_INFO     = 0x001D
	OPT_PAR_ADD_STAT_INFO_MIN = 1
	OPT_PAR_ADD_STAT_INFO_MAX = 256

	// Receipted Message ID
	OPT_PAR_RECP_MSG_ID     = 0x001E
	OPT_PAR_RECP_MSG_ID_MIN = 1
	OPT_PAR_RECP_MSG_ID_MAX = 65

	// Message Payload
	OPT_PAR_MSG_PAYLOAD     = 0x0424
	OPT_PAR_MSG_PAYLOAD_MIN = 1
	OPT_PAR_MSG_PAYLOAD_MAX = 1500

	// User Data Header
	UDH_CONCAT_MSG_8_BIT_REF  = byte(0x00)
	UDH_CONCAT_MSG_16_BIT_REF = byte(0x08)

	/**
	 * @deprecated As of version 1.3 of the library there are defined
	 * new encoding constants for base set of encoding supported by Java Runtime.
	 * The <code>CHAR_ENC</code> is replaced by <code>ENC_ASCII</code>
	 * and redefined in this respect.
	 */

	DFLT_MSGID         string = ""
	DFLT_MSG           string = ""
	DFLT_SRVTYPE       string = ""
	DFLT_SYSID         string = ""
	DFLT_PASS          string = ""
	DFLT_SYSTYPE       string = ""
	DFLT_ADDR_RANGE    string = ""
	DFLT_DATE          string = ""
	DFLT_ADDR          string = ""
	DFLT_MSG_STATE     byte   = 0
	DFLT_ERR           byte   = 0
	DFLT_SCHEDULE      string = ""
	DFLT_VALIDITY      string = ""
	DFLT_REG_DELIVERY         = SM_SMSC_RECEIPT_NOT_REQUESTED | SM_SME_ACK_NOT_REQUESTED | SM_NOTIF_NOT_REQUESTED
	DFLT_DFLTMSGID            = byte(0)
	DFLT_MSG_LEN              = byte(0)
	DFLT_ESM_CLASS            = byte(0)
	DFLT_DATA_CODING          = byte(0)
	DFLT_PROTOCOLID           = byte(0)
	DFLT_PRIORITY_FLAG        = byte(0)
	DFTL_REPLACE_IFP          = byte(0)
	DFLT_DL_NAME       string = ""
	DFLT_GSM_TON              = GSM_TON_UNKNOWN
	DFLT_GSM_NPI              = GSM_NPI_UNKNOWN
	DFLT_DEST_FLAG            = byte(0) // not set
	MAX_PDU_LEN               = 64 << 10

	PDU_HEADER_SIZE = 16 // 4 integers
	TLV_HEADER_SIZE = 4  // 2 int16s: tag & length

	// all times in milliseconds
	RECEIVER_TIMEOUT           int64 = 60000
	CONNECTION_RECEIVE_TIMEOUT int64 = 10000
	UNBIND_RECEIVE_TIMEOUT     int64 = 5000
	CONNECTION_SEND_TIMEOUT    int64 = 20000
	COMMS_TIMEOUT              int64 = 60000
	QUEUE_TIMEOUT              int64 = 10000
	ACCEPT_TIMEOUT             int64 = 60000

	RECEIVE_BLOCKING int64 = -1

	MAX_VALUE_PORT     = 65535
	MIN_VALUE_PORT     = 100
	MIN_LENGTH_ADDRESS = 7
)

var (
	// ErrNotImplSplitterInterface indicates that encoding does not support Splitter interface
	ErrNotImplSplitterInterface = fmt.Errorf("Encoding not implementing Splitter interface")
	// ErrNotImplDecode indicates that encoding does not support Decode method
	ErrNotImplDecode = fmt.Errorf("Decode is not implemented in this Encoding")
	// ErrNotImplEncode indicates that encoding does not support Encode method
	ErrNotImplEncode = fmt.Errorf("Encode is not implemented in this Encoding")
)

var defaultTon atomic.Value
var defaultNpi atomic.Value

func init() {
	defaultTon.Store(DFLT_GSM_TON)
	defaultNpi.Store(DFLT_GSM_NPI)
}

// SetDefaultTon set default ton.
func SetDefaultTon(dfltTon byte) {
	defaultTon.Store(dfltTon)
}

// GetDefaultTon get default ton.
func GetDefaultTon() byte {
	return defaultTon.Load().(byte)
}

// SetDefaultNpi set default npi.
func SetDefaultNpi(dfltNpi byte) {
	defaultNpi.Store(dfltNpi)
}

// GetDefaultNpi get default npi.
func GetDefaultNpi() byte {
	return defaultNpi.Load().(byte)
}


================================================
FILE: data/pkg_test.go
================================================
package data

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestDefaultNpi(t *testing.T) {
	SetDefaultNpi(13)
	require.EqualValues(t, 13, GetDefaultNpi())
}

func TestDefaultTon(t *testing.T) {
	SetDefaultTon(19)
	require.EqualValues(t, 19, GetDefaultTon())
}


================================================
FILE: data/utils.go
================================================
package data

import "unicode"

// FindEncoding returns suitable encoding for a string.
// If string is ascii, then GSM7Bit. If not, then UCS2.
func FindEncoding(s string) (enc Encoding) {
	if isASCII(s) {
		enc = GSM7BIT
	} else {
		enc = UCS2
	}
	return
}

func isASCII(s string) bool {
	for i := 0; i < len(s); i++ {
		if s[i] > unicode.MaxASCII {
			return false
		}
	}
	return true
}


================================================
FILE: data/utils_test.go
================================================
package data

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestFindEncoding(t *testing.T) {
	require.Equal(t, GSM7BIT, FindEncoding("abc30hb3bk2lopzSD=2-^"))
	require.Equal(t, UCS2, FindEncoding("Trần Lập và ban nhạc Bức tường huyền thoại"))
	require.Equal(t, UCS2, FindEncoding("Đừng buồn thế dù ngoài kia vẫn mưa nghiễng rợi tý tỵ"))
}


================================================
FILE: errors/pkg.go
================================================
package errors

import (
	"fmt"

	"github.com/linxGnu/gosmpp/data"
)

// SmppErr indicates smpp error(s), compatible with OpenSMPP.
type SmppErr struct {
	err              string
	serialVersionUID int64
}

// Error interface.
func (s *SmppErr) Error() string {
	return fmt.Sprintf("Error happened: [%s]. SerialVersionUID: [%d]", s.err, s.serialVersionUID)
}

var (
	// ErrInvalidPDU indicates invalid pdu payload.
	ErrInvalidPDU error = &SmppErr{err: "PDU payload is invalid", serialVersionUID: -6985061862208729984}

	// ErrUnknownCommandID indicates unknown command id.
	ErrUnknownCommandID error = &SmppErr{err: "Unknown command id", serialVersionUID: -5091873576710864441}

	// ErrWrongDateFormat indicates wrong date format.
	ErrWrongDateFormat error = &SmppErr{err: "Wrong date format", serialVersionUID: 5831937612139037591}

	// ErrShortMessageLengthTooLarge indicates short message length is too large.
	ErrShortMessageLengthTooLarge error = &SmppErr{err: fmt.Sprintf("Encoded short message data exceeds size of %d", data.SM_MSG_LEN), serialVersionUID: 78237205927624}

	// ErrUDHTooLong UDH-L is larger than total length of short message data
	ErrUDHTooLong = fmt.Errorf("User Data Header is too long for PDU short message")
)


================================================
FILE: errors/pkg_test.go
================================================
package errors

import (
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestErr(t *testing.T) {
	require.True(t, strings.HasPrefix(ErrInvalidPDU.Error(), "Error happened: ["))
}


================================================
FILE: example/smsc_simulator/smsc.cpp
================================================
//
//  smscsimulator.cpp
//  SMPPLib
//
//  Created by Mark Hay on 12/05/2019.
//  Copyright © 2019 Melrose Labs. All rights reserved.
//

// Build: g++ smscsimulator.cpp -o MLSMSCSimulator && ./MLSMSCSimulator

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <string>
#include <exception>
#include <map>
#include <list>

using namespace std;

#include <unistd.h>

#include <sys/ioctl.h>
#include <time.h>
#include <sys/time.h>

#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define TRUE (1 == 1)
#define FALSE (!TRUE)

//

uint64_t session_id_next = 0;  // ID for each session

// General

uint64_t currentUSecsSinceEpoch(void) {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
}

// Client config

class ClientConfig {
 private:
  ClientConfig() {}

  ~ClientConfig() {}

 public:
  static ClientConfig& instance() {
    static ClientConfig c;
    return c;
  }

  typedef enum { BINDRESP_WITH_SC_INTERACE_VERSION_TLV } ConfigEntry;

  bool is(string esme_id, ConfigEntry entry) { return false; }
};

// Message deliverer

class MessageDeliverer {
 public:
  class Message {
   public:
    uint8_t source_addr_ton;
    uint8_t source_addr_npi;
    char source_addr[32];
    uint8_t dest_addr_ton;
    uint8_t dest_addr_npi;
    char destination_addr[32];
    uint8_t esm_class;
    uint8_t protocol_id;
    uint8_t priority_flag;
    char schedule_delivery_time[32];
    char validity_period[32];
    uint8_t registered_delivery;
    uint8_t replace_if_present_flag;
    uint8_t data_coding;
    uint8_t sm_default_msg_id;
    uint8_t sm_length;
    uint8_t short_message[160];

    string smscMessageID;

   private:
    string content;

   public:
    Message() {}
    Message(char* in) { content = in; }
    ~Message() {}

    string getContent(void) { return content; }

    void setSource(uint8_t ton, uint8_t npi, char* addr) {
      source_addr_ton = ton;
      source_addr_npi = npi;
      strcpy(source_addr, addr);
    }
    void setDestination(uint8_t ton, uint8_t npi, char* addr) {
      dest_addr_ton = ton;
      dest_addr_npi = npi;
      strcpy(destination_addr, addr);
    }
    void setRegisteredDelivery(uint8_t val) { registered_delivery = val; }
    void setShortMessage(uint8_t* sm_in, uint8_t sm_len_in) {
      memcpy(short_message, sm_in, sm_len_in);
      sm_length = sm_len_in;
    }
    void setSMSCMessageID(char* id) { smscMessageID = id; }
  };

 private:
  // time-ordered list [using STL map] of lists containing messages
  typedef map<uint64_t /*time*/, list<Message>> MessageQueue;
  MessageQueue mq;

  MessageDeliverer() {}

  typedef map<string, MessageDeliverer*> MDMap;
  static MDMap mapInstance;

  bool empty(void) { return (mq.size() == 0); }

  bool get(Message& msgout) {
    if (mq.size() == 0) return false;  // no time-lists

    uint64_t firstListTime = (*mq.begin()).first;
    uint64_t now = currentUSecsSinceEpoch();
    if (firstListTime > now) return false;  // nothing due to be deliverered

    // we have a message (or messages) that are due to be delivered

    msgout = (*mq.begin()).second.front();

    (*mq.begin()).second.pop_front();  // remove from list

    if ((*mq.begin()).second.size() == 0)  // now empty - remove list
      mq.erase(mq.begin());

    return true;
  }

 public:
  ~MessageDeliverer() {}

  static MessageDeliverer* getInstance(string& systemID) {
    MDMap::iterator it = mapInstance.find(systemID);
    if (it == mapInstance.end()) {
      std::pair<MDMap::iterator, bool> res =
          mapInstance.insert(MDMap::value_type(systemID, new MessageDeliverer));
      return (res.first)->second;
    } else
      return (*it).second;
  }

  static bool getInstance_get(string& systemID, Message& msgout) {
    MDMap::iterator it = mapInstance.find(systemID);
    if (it == mapInstance.end()) {
      return false;
    }

    bool found = (*it).second->get(msgout);

    if ((*it).second->empty()) {
      delete (*it).second;
      mapInstance.erase(systemID);
    }

    return found;
  }

  void add(uint64_t timeDeliver, Message msg) {
    MessageQueue::iterator it = mq.find(timeDeliver);
    if (it == mq.end()) {
      // no time-list exists - create
      list<Message> msgList;  // empty message list
      std::pair<MessageQueue::iterator, bool> ret;
      ret = mq.insert({timeDeliver, msgList});
      if (ret.second == false) return;  // failed to insert
      it = ret.first;                   // iterator to newly inserted time-list
    }

    (*it).second.push_back(msg);  // add message to time-list
  }
};

MessageDeliverer::MDMap MessageDeliverer::mapInstance;

// Sub-SMPP layer

class SMPPSocket {
 protected:
  int socket;

 public:
  SMPPSocket() {}
  virtual ~SMPPSocket() {}

  virtual bool recvA(uint8_t&) = 0;
  virtual void recv(void) = 0;
  virtual bool send(uint8_t*, int len) = 0;

  virtual long bytes_to_read(void) = 0;
};

class SMPPSocketUnencrypted : public SMPPSocket {
 private:
 public:
  SMPPSocketUnencrypted() {}
  SMPPSocketUnencrypted(int socket_in) { socket = socket_in; }
  ~SMPPSocketUnencrypted() {}

  long bytes_to_read(void) {
    long count = 0;
    ioctl((int)socket, FIONREAD, &count);
    return count;
  }

  bool recvA(uint8_t& oct) {
    int n = (int)::recv(socket, (void*)&oct, 1, 0);
    return (n > 0);
  }
  void recv(void) {}
  bool send(uint8_t* buf, int len) {
    return ::send(socket, (void*)buf, len, 0);
  }
};

// SMPP

class SMPP {
 public:
  class CmdStatus {
   public:
    static const uint64_t ESME_ROK = 0x00000000;
    static const uint64_t ESME_RINVBNDSTS = 0x00000004;
    static const uint64_t ESME_INVDSTADR = 0x0000000B;
    static const uint64_t ESME_RBINDFAIL = 0x0000000D;
    static const uint64_t ESME_RINVSYSID = 0x0000000F;
    static const uint64_t ESME_RSUBMITFAIL = 0x00000045;
    static const uint64_t ESME_RINVSCHED = 0x00000061;
  };

  class CmdID {
   public:
    static const uint64_t BindReceiver = 0x00000001;
    static const uint64_t BindTransmitter = 0x00000002;
    static const uint64_t QuerySM = 0x00000003;
    static const uint64_t SubmitSM = 0x00000004;
    static const uint64_t DeliverSM = 0x00000005;
    static const uint64_t Unbind = 0x00000006;
    static const uint64_t ReplaceSM = 0x00000007;
    static const uint64_t CancelSM = 0x00000008;
    static const uint64_t BindTransceiver = 0x00000009;
    static const uint64_t Outbind = 0x0000000B;
    static const uint64_t EnquireLink = 0x00000015;
    static const uint64_t SubmitMulti = 0x00000021;
    static const uint64_t AlertNotification = 0x00000102;
    static const uint64_t DataSM = 0x00000103;
    static const uint64_t BroadcastSM = 0x00000111;
    static const uint64_t QueryBroadcastSM = 0x00000112;
    static const uint64_t CancelBroadcastSM = 0x00000113;
    static const uint64_t GenericNack = 0x80000000;
    static const uint64_t BindReceiverResp = 0x80000001;
    static const uint64_t BindTransmitterResp = 0x80000002;
    static const uint64_t QuerySMResp = 0x80000003;
    static const uint64_t SubmitSMResp = 0x80000004;
    static const uint64_t DeliverSMResp = 0x80000005;
    static const uint64_t UnbindResp = 0x80000006;
    static const uint64_t ReplaceSMResp = 0x80000007;
    static const uint64_t CancelSMResp = 0x80000008;
    static const uint64_t BindTransceiverResp = 0x80000009;
    static const uint64_t EnquireLinkResp = 0x80000015;
    static const uint64_t SubmitMultiResp = 0x80000021;
    static const uint64_t DataSMResp = 0x80000103;
    static const uint64_t BroadcastSMResp = 0x80000111;
    static const uint64_t QueryBroadcastSMResp = 0x80000112;
    static const uint64_t CancelBroadcastSMResp = 0x80000113;
  };

  typedef struct {
    uint64_t cmdid;
    const char* name;
  } CmdStrings;

#define CMDEXP(A) CmdID::A, #A

  CmdStrings cmdStrings[34] = {{CMDEXP(BindReceiver)},
                               {CMDEXP(BindTransmitter)},
                               {CMDEXP(QuerySM)},
                               {CMDEXP(SubmitSM)},
                               {CMDEXP(DeliverSM)},
                               {CMDEXP(Unbind)},
                               {CMDEXP(ReplaceSM)},
                               {CMDEXP(CancelSM)},
                               {CMDEXP(BindTransceiver)},
                               {CMDEXP(Outbind)},
                               {CMDEXP(EnquireLink)},
                               {CMDEXP(SubmitMulti)},
                               {CMDEXP(AlertNotification)},
                               {CMDEXP(DataSM)},
                               {CMDEXP(BroadcastSM)},
                               {CMDEXP(QueryBroadcastSM)},
                               {CMDEXP(CancelBroadcastSM)},
                               {CMDEXP(GenericNack)},
                               {CMDEXP(BindReceiverResp)},
                               {CMDEXP(BindTransmitterResp)},
                               {CMDEXP(QuerySMResp)},
                               {CMDEXP(SubmitSMResp)},
                               {CMDEXP(DeliverSMResp)},
                               {CMDEXP(UnbindResp)},
                               {CMDEXP(ReplaceSMResp)},
                               {CMDEXP(CancelSMResp)},
                               {CMDEXP(BindTransceiverResp)},
                               {CMDEXP(EnquireLinkResp)},
                               {CMDEXP(SubmitMultiResp)},
                               {CMDEXP(DataSMResp)},
                               {CMDEXP(BroadcastSMResp)},
                               {CMDEXP(QueryBroadcastSMResp)},
                               {CMDEXP(CancelBroadcastSMResp)}};

  const char* cmdString(uint64_t id) {
    for (int i = 0; i < 34; i++) {
      if (cmdStrings[i].cmdid == id) return cmdStrings[i].name;
    }
    return "";
  }

  static void GSMTimeStringShort(time_t& t, char* szTimestamp, int nLen) {
    if (t < 0) return;

    szTimestamp[0] = 0x00;

    tm* ptm = gmtime(&t);

    if (ptm == NULL)
      szTimestamp[0] = 0x00;
    else
      strftime(szTimestamp, nLen, "%y%m%d%H%M", ptm);
  }

  static time_t GSMStringTime(const char* szBuf) {
    tm atm;
    int tdif = 0;
    char chDir = 0;

    memset(&atm, 0, sizeof(tm));

    int nRead = sscanf(szBuf, "%02d%02d%02d%02d%02d%02d%*1d%02d%c",
                       &atm.tm_year, &atm.tm_mon, &atm.tm_mday, &atm.tm_hour,
                       &atm.tm_min, &atm.tm_sec, &tdif, &chDir);

    time_t t = 0;

    if (nRead == 5) {
      if (atm.tm_year >= 70)
        atm.tm_year += 1900;
      else
        atm.tm_year += 2000;

      t = timegm(&atm);

      if (t == -1) {  // invalid time
        t = 0;
      }

      if (chDir == '+') {
        t = t - (tdif * 15 * 60);
      }
      if (chDir == '-') {
        t = t + (tdif * 15 * 60);
      }
    }

    return t;
  }

  static time_t GSMRelativeTime(char* szBuf) {
    time_t t = 0;
    int mday, hour, min, sec;
    int nRead = sscanf(szBuf, "%*02d%*02d%02d%02d%02d%02d%*1d%*02d%*c", &mday,
                       &hour, &min, &sec);
    if (nRead == 4) t = ((mday * 24 + hour) * 60 + min) * 60 + sec;
    return t;
  }
};

class SMPPConnection {
 public:
  class SMPPException {};

 private:
  const int max_command_body_length = 1024;

  bool debug = false;

  SMPPSocket* socket = NULL;

  char ip[64];

  typedef enum { PV_INVALID, PV_LENGTH, PV_ALL } PDUValidity;

  typedef struct {
    PDUValidity valid;  // indicate if this header structure has valid contents
    uint64_t command_length;
    uint64_t command_id;
    uint64_t command_status;
    uint64_t sequence_number;
  } PDUHeader;

  typedef struct {
    bool valid;
    uint8_t* body;
  } PDUBody;

  PDUHeader command_received_header = {PV_INVALID, 0, 0, 0, 0};
  PDUBody command_received_body = {false, NULL};

  // configuration
  int enquire_link_period = 0;  // seconds

  // methods

  uint64_t getInteger(void) {
    if (socket->bytes_to_read() < 4) throw SMPPException();
    uint8_t v0, v1, v2, v3;
    socket->recvA(v0);
    socket->recvA(v1);
    socket->recvA(v2);
    socket->recvA(v3);
    return (uint64_t)(((v0 << 8) | v1) << 8 | v2) << 8 | v3;
  }

  uint64_t getBytes(uint64_t len, uint8_t* mem) {
    if (socket->bytes_to_read() < len) throw SMPPException();
    for (int i = 0; i < len; i++) {
      if (socket->recvA(mem[i]) == 0) throw SMPPException();
    }
    return 0;
  }

 public:
  SMPPConnection() {
    socket = NULL;
    command_received_header.valid = PV_INVALID;
    command_received_body.body = new uint8_t[max_command_body_length];
    ip[0] = '\0';
  }

  ~SMPPConnection() {
    if (command_received_body.body) delete[] command_received_body.body;

    if (socket) delete socket;
  }

  void setDebug(bool val) { debug = val; }

  void allocateSocket(void) { socket = new SMPPSocketUnencrypted; }

  void allocateSocket(int fdsocket) {
    socket = new SMPPSocketUnencrypted(fdsocket);
  }

  void setIP(char* ip_in) {
    if (ip_in != NULL)
      strcpy(ip, ip_in);
    else
      strcpy(ip, "");
  }

  char* getIP() { return ip; }

  uint64_t endian(uint64_t a) {
    uint64_t b;
    ((uint8_t*)&b)[0] = ((uint8_t*)&a)[3];
    ((uint8_t*)&b)[1] = ((uint8_t*)&a)[2];
    ((uint8_t*)&b)[2] = ((uint8_t*)&a)[1];
    ((uint8_t*)&b)[3] = ((uint8_t*)&a)[0];
    return b;
  }

  bool put(uint64_t sequence_number, uint64_t cmdID, uint64_t status,
           uint8_t* param, int len) {
    int pdu_len = 16 + len;
    uint8_t buf[pdu_len];

    *((uint64_t*)(buf + 0)) = endian(pdu_len);           // command length
    *((uint64_t*)(buf + 4)) = endian(cmdID);             // command ID
    *((uint64_t*)(buf + 8)) = endian(status);            // command status
    *((uint64_t*)(buf + 12)) = endian(sequence_number);  // sequence number
    if ((param != NULL) && (len != 0)) memcpy((char*)(buf + 16), param, len);

    // for(int i=0;i<pdu_len;i++) printf("%02x ",buf[i]);
    // printf("\n");

    return socket->send(buf, pdu_len);
  }

  uint8_t* getBodyPointer(int& len) {
    len = (int)(command_received_header.command_length - 16);
    return command_received_body.body;
  }

  bool get() {
    // require "socket"

    if (socket == NULL) return false;

    // get header

    if (command_received_header.valid != PV_ALL) {
      // don't have any of the header yet

      try {
        command_received_header.command_length = getInteger();
        command_received_header.command_id = getInteger();
        command_received_header.command_status = getInteger();
        command_received_header.sequence_number = getInteger();
        command_received_header.valid =
            PV_ALL;  // all header values are now valid

      } catch (SMPPException e) {
        // no data
        if (debug) std::cout << "HEADER No data - ABORT!" << std::endl;
        return false;
      }
    }

    if (command_received_header.valid != PV_ALL)
      return false;  // don't let past here until we have the header

    // get body (if present)

    command_received_body.valid = false;

    uint64_t body_length = command_received_header.command_length - 16;

    if (body_length > 0) {
      try {
        getBytes(body_length, command_received_body.body);
      } catch (SMPPException e) {
        if (debug) std::cout << "BODY No data" << std::endl;
        return false;
      }
      command_received_body.valid = true;
      command_received_header.valid = PV_INVALID;

      return true;
    } else {
      // empty body
      command_received_body.valid = true;  // empty body (valid)
      command_received_body.body = NULL;
      command_received_header.valid = PV_INVALID;

      return true;
    }

    return false;
  }

  uint64_t pduCommandID(void) { return command_received_header.command_id; }
  uint64_t pduSequenceNo(void) {
    return command_received_header.sequence_number;
  }
};

class Session {
 protected:
  int sessionType;

 public:
  Session() {}
  virtual ~Session() {}

  virtual bool timedCheck(void) = 0;
  virtual bool run(void) = 0;
};

class AdminSession : public Session {
 public:
  AdminSession() { sessionType = 0; }
  AdminSession(int fdsocket) {
    // conn.allocateSocket(fdsocket);
  }
  ~AdminSession() {}

  bool timedCheck(void) {
    // return true if to close
    return true;
  }

  bool run(void) { return true; }
};

class SMPPSession : public Session {
 private:
  SMPPConnection conn;

  uint64_t session_id;

  // session state
  string system_id;
  string system_type;
  long sequence_number_in = -1;
  long sequence_number_out = 1;
  uint64_t lastPDUFromESMETime = 0;
  uint64_t enquireLinkRespPending = 0;
  uint64_t closingTime = 0;

 public:
  typedef enum { BS_NONE, BS_TRX, BS_TX, BS_RX } BindState;
  uint8_t version;

  BindState bindState;

 public:
  SMPPSession() {
    sessionType = 1;

    bindState = BS_NONE;
    version = 0x00;

    session_id = session_id_next++;
  }

  SMPPSession(int fdsocket, char* ip) {
    bindState = BS_NONE;
    version = 0x00;
    conn.allocateSocket(fdsocket);
    conn.setIP(ip);

    session_id = session_id_next++;
  }

  ~SMPPSession() {
    if (bindState != BS_NONE) {
      logCommand("session aborted", "--");
    }
  }

  void setDebug(bool val) { conn.setDebug(val); }

  bool getCOctetString(uint8_t* buf_ptr, int buf_len, int& idx, string& strout,
                       int max_param_len) {
    char str[max_param_len];
    int i = 0;
    while (idx != buf_len) {
      str[i++] = buf_ptr[idx++];
      if (str[i - 1] == '\0') {
        strout.assign(str);
        return true;
      }
      if (i == max_param_len) return false;
    }
    return false;
  }

  bool timedCheck(void) {
    // return true if session to close

    uint64_t now = currentUSecsSinceEpoch();

    // session management
    //

    if ((closingTime != 0) && (now >= closingTime))
      return true;  // session was due to close now

    if ((lastPDUFromESMETime != 0) &&
        ((now - lastPDUFromESMETime) >
         (120 *
          1000000L)))  // wait up to 2 mins of inactivity before enquire link
    {
      if (enquireLinkRespPending == 0) {
        // issue enquire link
        send(sequence_number_out++, SMPP::CmdID::EnquireLink,
             SMPP::CmdStatus::ESME_ROK, NULL, 0);
        enquireLinkRespPending = now;
        closingTime = 0;
      } else {
        if (closingTime == 0) {
          // waiting on enquire link
          uint64_t tsinceenquirelinksent = now - enquireLinkRespPending;
          if (tsinceenquirelinksent >
              (60 * 1000000L))  // wait up to 1 min on enquire_link response
          {
            send(sequence_number_out++, SMPP::CmdID::Unbind,
                 SMPP::CmdStatus::ESME_ROK, NULL, 0);

            closingTime =
                now + 5 * 1000000L;  // close session in 5 seconds time
          }
        }
      }
    }

    // simulate message delivery + delivery receipt generation
    //

    if ((system_id.length() > 0) &&
        ((bindState == SMPPSession::BindState::BS_TRX) ||
         (bindState == SMPPSession::BindState::BS_RX))) {
      MessageDeliverer::Message msg;
      while (MessageDeliverer::getInstance_get(system_id, msg)) {
        // indicate message delivered

        if (msg.registered_delivery !=
            0)  // ESME requested receipt so generate one
        {
          uint8_t source_addr_ton = msg.source_addr_ton,
                  source_addr_npi = msg.source_addr_npi;
          string destination_addr = msg.destination_addr;
          uint8_t dest_addr_ton = msg.dest_addr_ton,
                  dest_addr_npi = msg.dest_addr_npi;
          string source_addr = msg.source_addr;
          string msgid = msg.smscMessageID;

          generateReceipt(source_addr_ton, source_addr_npi, source_addr,
                          dest_addr_ton, dest_addr_npi, destination_addr,
                          msgid);
        }

        if (strstr(msg.destination_addr, system_id.c_str()) !=
            NULL) {  // system_id is in destination address - assume MO for
                     // testing purposes
          generateMO(msg.source_addr_ton, msg.source_addr_npi, msg.source_addr,
                     msg.dest_addr_ton, msg.dest_addr_npi, msg.destination_addr,
                     msg.short_message, msg.sm_length, msg.data_coding);
        }
      }
    }

    return false;
  }

  void generateMO(uint8_t source_addr_ton, uint8_t source_addr_npi,
                  string source_addr, uint8_t dest_addr_ton,
                  uint8_t dest_addr_npi, string destination_addr,
                  uint8_t* short_message, uint8_t sm_length,
                  uint8_t data_coding) {
    uint8_t sbuf[1024];

    int sidx = 0;

    sbuf[sidx++] = 0x00;  // service type

    sbuf[sidx++] = source_addr_ton;  //
    sbuf[sidx++] = source_addr_npi;  //
    memcpy(sbuf + sidx, source_addr.c_str(),
           source_addr.length() + 1);  // destination_addr
    sidx += source_addr.length() + 1;

    sbuf[sidx++] = dest_addr_ton;  //
    sbuf[sidx++] = dest_addr_npi;  //
    memcpy(sbuf + sidx, destination_addr.c_str(),
           destination_addr.length() + 1);  // source_addr
    sidx += destination_addr.length() + 1;

    sbuf[sidx++] = 0x00;         // esm_class
    sbuf[sidx++] = 0x00;         // protocol_id
    sbuf[sidx++] = 0x00;         // priority_flag
    sbuf[sidx++] = 0x00;         // schedule_delivery_time
    sbuf[sidx++] = 0x00;         // validity_period
    sbuf[sidx++] = 0x00;         // registered_delivery
    sbuf[sidx++] = 0x00;         // replace_if_present_flag
    sbuf[sidx++] = data_coding;  // data_coding
    sbuf[sidx++] = 0x00;         // sm_default_msg_id

    sbuf[sidx++] = sm_length;  // sm_length

    memcpy((char*)(sbuf + sidx), short_message, sm_length);

    sidx += sm_length;

    send(sequence_number_out++, SMPP::CmdID::DeliverSM,
         SMPP::CmdStatus::ESME_ROK, sbuf, sidx);
  }

  void generateReceipt(uint8_t source_addr_ton, uint8_t source_addr_npi,
                       string source_addr, uint8_t dest_addr_ton,
                       uint8_t dest_addr_npi, string destination_addr,
                       string msgid) {
    // receipt

    if ((bindState == SMPPSession::BindState::BS_TRX) ||
        (bindState == SMPPSession::BindState::BS_RX)) {
      uint8_t sbuf[1024];

      int sidx = 0;
      sbuf[sidx++] = 0x00;           // service type
      sbuf[sidx++] = dest_addr_ton;  // source_addr_ton
      sbuf[sidx++] = dest_addr_npi;  // source_addr_npi
      memcpy(sbuf + sidx, destination_addr.c_str(),
             destination_addr.length() + 1);  // source_addr
      sidx += destination_addr.length() + 1;
      sbuf[sidx++] = source_addr_ton;  // dest_addr_ton
      sbuf[sidx++] = source_addr_npi;  // dest_addr_npi
      memcpy(sbuf + sidx, source_addr.c_str(),
             source_addr.length() + 1);  // destination_addr
      sidx += source_addr.length() + 1;
      sbuf[sidx++] =
          0x04;  // esm_class [0x04 Short Message contains MC delivery report]
      sbuf[sidx++] = 0x00;  // protocol_id
      sbuf[sidx++] = 0x00;  // priority_flag
      sbuf[sidx++] = 0x00;  // schedule_delivery_time
      sbuf[sidx++] = 0x00;  // validity_period
      sbuf[sidx++] = 0x00;  // registered_delivery
      sbuf[sidx++] = 0x00;  // replace_if_present_flag
      sbuf[sidx++] = 0x00;  // data_coding
      sbuf[sidx++] = 0x00;  // sm_default_msg_id

      // - short_message containing receipt in text format
      time_t tSubmitStamp = time(NULL);
      time_t tDoneStamp = time(NULL);
      char szSubmitStamp[32];
      char szDoneStamp[32];
      SMPP::GSMTimeStringShort(tSubmitStamp, szSubmitStamp,
                               sizeof(szSubmitStamp));
      SMPP::GSMTimeStringShort(tDoneStamp, szDoneStamp, sizeof(szDoneStamp));

      char short_message[160];
      sprintf(short_message,
              "id:%s sub:000 dlvrd:%03d submit date:%s done date:%s stat:%s "
              "err:%03d text:",
              msgid.c_str(), 1 /* 1 message delivered */, szSubmitStamp,
              szDoneStamp, "DELIVRD", 0 /*error*/);

      sbuf[sidx++] = strlen(short_message) + 1;  // sm_length

      memcpy((char*)(sbuf + sidx), short_message,
             (int)(strlen(short_message) + 1));

      sidx += strlen(short_message) + 1;

      // TLVs

      if (bindState == SMPPSession::BindState::BS_TRX) {
        uint8_t params1[] = {
            // message_state TLV
            0x04, 0x27,  // tag
            0x00, 0x01,  // length
            0x02,        // value - delivered

            // network_error TLV
            0x04, 0x23,        // tag
            0x00, 0x03,        // length
            0x03, 0x00, 0x00,  // value - GSM, 0, 0

            // receipted_message_id TLV
            0x00, 0x1e,  // tag
            0x00, 0x41,  // length
                         // .. message_id (to be appended)
        };

        memcpy(sbuf + sidx, params1, sizeof(params1));
        sidx += sizeof(params1);
        memcpy(sbuf + sidx, msgid.c_str(), msgid.length() + 1);
        sidx += msgid.length() + 1;
      }

      send(sequence_number_out++, SMPP::CmdID::DeliverSM,
           SMPP::CmdStatus::ESME_ROK, sbuf, sidx);
    }
  }

  bool run(void) {
    // return true if closed

    uint64_t now = currentUSecsSinceEpoch();

    if ((closingTime != 0) && (now >= closingTime))
      return true;  // session was due to close now

    // handle PDUs from ESME
    //

    bool allowBind = true;

    uint64_t cmdid, seqno;
    uint8_t sbuf[1024];

    if (recv(cmdid, seqno)) {
      // SMPP b;
      // printf("<< 0x%08llx %s\n",cmdid,b.cmdString(cmdid));

      lastPDUFromESMETime = now;

      if ((cmdid == SMPP::CmdID::BindTransceiver) ||
          (cmdid == SMPP::CmdID::BindReceiver) ||
          (cmdid == SMPP::CmdID::BindTransmitter)) {
        if (bindState !=
            SMPPSession::BindState::BS_NONE)  // PROTOCOL must be in unbound
                                              // state for ESME to send bind
                                              // command
        {
          send(seqno, cmdid + 0x80000000, SMPP::CmdStatus::ESME_RINVBNDSTS,
               NULL, 0);
        } else {
          string esme_system_id = "";
          string esme_password = "";
          string esme_system_type = "";
          uint8_t esme_smpp_ver = 0x00;

          int ptr_max = 0;
          uint8_t* ptr = conn.getBodyPointer(ptr_max);

          int idx = 0;
          if (!getCOctetString(ptr, ptr_max, idx, esme_system_id, 16)) {
            allowBind = false;
            goto parse_complete;
          }
          if (!getCOctetString(ptr, ptr_max, idx, esme_password, 9)) {
            allowBind = false;
            goto parse_complete;
          }
          if (!getCOctetString(ptr, ptr_max, idx, esme_system_type, 13)) {
            allowBind = false;
            goto parse_complete;
          }

          if (idx < ptr_max)
            esme_smpp_ver = ptr[idx++];
          else {
            allowBind = false;
            goto parse_complete;
          }

          if ((esme_smpp_ver < 0x34) && (cmdid == SMPP::CmdID::BindTransceiver))
            allowBind =
                false;  // PROTOCOL transceiver bind only allowed for v3.4+

        parse_complete:  // parse complete label

          if (allowBind) {
            system_id = esme_system_id;

            char smsc_system_id[] = "MelroseLabsSMSC";
            uint64_t cmdStatus = SMPP::CmdStatus::ESME_ROK;
            if (system_id == "invalid") {
                cmdStatus = SMPP::CmdStatus::ESME_RINVSYSID;
                // If there is an error in the bind_transmitter or bind_receiver request,
                // the SMSC system_id is not returned (see SMPP reference 4.1.2 and 4.1.4).
                if (cmdid == SMPP::CmdID::BindTransmitter || cmdid == SMPP::CmdID::BindReceiver) {
                    std::fill_n(sbuf, 1024, 0);
                } else {
                    memcpy(sbuf, smsc_system_id, strlen(smsc_system_id) + 1);
                }
            } else {
                memcpy(sbuf, smsc_system_id, strlen(smsc_system_id) + 1);
            }

            if (ClientConfig::instance().is(
                    esme_system_id,
                    ClientConfig::ConfigEntry::
                        BINDRESP_WITH_SC_INTERACE_VERSION_TLV)) {
              uint8_t params[] = {
                  // sc_interface_version TLV
                  0x02, 0x10,  // tag
                  0x00, 0x01,  // length
                  0x34,        // value [v3.4 supported]
              };

              memcpy(sbuf + strlen(smsc_system_id) + 1, params, sizeof(params));
              send(seqno, cmdid + 0x80000000, cmdStatus, sbuf,
                   strlen(smsc_system_id) + 1 + sizeof(params));
            } else
              send(seqno, cmdid + 0x80000000, cmdStatus, sbuf,
                   strlen(smsc_system_id) + 1);

            if (cmdid == SMPP::CmdID::BindTransceiver)
              bindState = SMPPSession::BindState::BS_TRX;
            else if (cmdid == SMPP::CmdID::BindTransmitter)
              bindState = SMPPSession::BindState::BS_TX;
            else if (cmdid == SMPP::CmdID::BindReceiver)
              bindState = SMPPSession::BindState::BS_RX;
            else
              bindState = SMPPSession::BindState::BS_NONE;

            version = esme_smpp_ver;
          } else {
            send(seqno, SMPP::CmdID::BindTransceiverResp,
                 SMPP::CmdStatus::ESME_RBINDFAIL, NULL,
                 0);  // responding indicating bind unsuccessful
            bindState = SMPPSession::BindState::BS_NONE;
          }
        }
      } else if (cmdid == SMPP::CmdID::Unbind) {
        if (bindState != SMPPSession::BindState::BS_NONE) {
          send(seqno, SMPP::CmdID::UnbindResp, SMPP::CmdStatus::ESME_ROK, NULL,
               0);
          bindState = SMPPSession::BindState::BS_NONE;
        } else {
          send(seqno, SMPP::CmdID::UnbindResp, SMPP::CmdStatus::ESME_RINVBNDSTS,
               NULL, 0);
        }
      } else if (cmdid == SMPP::CmdID::EnquireLinkResp) {
        enquireLinkRespPending = 0;  // received pending enquire link
      } else if (cmdid == SMPP::CmdID::EnquireLink) {
        send(seqno, SMPP::CmdID::EnquireLinkResp, SMPP::CmdStatus::ESME_ROK,
             NULL, 0);
      } else if (cmdid == SMPP::CmdID::GenericNack) {
        // no response to GenericNack
      } else if (cmdid == SMPP::CmdID::SubmitSM) {
        if ((bindState == SMPPSession::BindState::BS_NONE) ||
            (bindState == SMPPSession::BindState::BS_RX)) {
          send(seqno, SMPP::CmdID::SubmitSMResp,
               SMPP::CmdStatus::ESME_RINVBNDSTS, NULL, 0);
        } else {
          // process requested

          uint64_t tNow = currentUSecsSinceEpoch();

          uint64_t tESMEDeliveryTimeRequired =
              tNow;  // default to immediate delivery

          bool allowSubmit = true;
          uint64_t smppSubmitError = SMPP::CmdStatus::ESME_RSUBMITFAIL;

          string service_type = "";
          uint8_t source_addr_ton = 0;
          uint8_t source_addr_npi = 0;
          string source_addr = "";
          uint8_t dest_addr_ton = 0;
          uint8_t dest_addr_npi = 0;
          string destination_addr = "";
          string schedule_delivery_time = "";
          string validity_period = "";
          uint8_t registered_delivery = 0;
          uint8_t sm_length;
          uint8_t short_message[160];
          uint8_t data_coding;

          int ptr_max = 0;
          uint8_t* ptr = conn.getBodyPointer(ptr_max);

          int idx = 0;
          if (!getCOctetString(ptr, ptr_max, idx, service_type, 6)) {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (idx < ptr_max) {
            source_addr_ton = ptr[idx++];
          } else {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (idx < ptr_max) {
            source_addr_npi = ptr[idx++];
          } else {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (!getCOctetString(ptr, ptr_max, idx, source_addr, 21)) {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (idx < ptr_max) {
            dest_addr_ton = ptr[idx++];
          } else {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (idx < ptr_max) {
            dest_addr_npi = ptr[idx++];
          } else {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (!getCOctetString(ptr, ptr_max, idx, destination_addr, 21)) {
            allowSubmit = false;
            goto parse_complete_submit;
          }

          idx++;  // esm_class
          idx++;  // protocol_id
          idx++;  // priority_flag
          if (!getCOctetString(ptr, ptr_max, idx, schedule_delivery_time, 17)) {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          if (!getCOctetString(ptr, ptr_max, idx, validity_period, 17)) {
            allowSubmit = false;
            goto parse_complete_submit;
          }
          registered_delivery = ptr[idx++];  // registered_delivery
          idx++;                             // replace_if_present_flag
          data_coding = ptr[idx++];          // data_coding
          idx++;                             // sm_default_msg_id
          sm_length = ptr[idx++];
          memcpy(short_message, ptr + idx, sm_length);
          idx += sm_length;

          if (schedule_delivery_time.length() > 0)  // scheduled delivery
          {
            if (schedule_delivery_time[schedule_delivery_time.length() - 1] ==
                'R')  // relative
              tESMEDeliveryTimeRequired =
                  tNow +
                  SMPP::GSMRelativeTime((char*)schedule_delivery_time.c_str()) *
                      1000000L;
            else
              tESMEDeliveryTimeRequired =
                  (SMPP::GSMStringTime(schedule_delivery_time.c_str()) + 3 +
                   (rand() % 10)) *
                  1000000L;

            if (tESMEDeliveryTimeRequired <
                tNow)  // scheduled delivery time is before now
            {
              allowSubmit = false;
              smppSubmitError = SMPP::CmdStatus::ESME_RINVSCHED;
              goto parse_complete_submit;
            }
          }

          // ...

          if (destination_addr == "333") {
            allowSubmit = false;
            goto parse_complete_submit;
          }  // force ESME_RSUBMITFAIL

          if (destination_addr.length() < 8) {
            allowSubmit = false;
            smppSubmitError = SMPP::CmdStatus::ESME_INVDSTADR;
            goto parse_complete_submit;
          }

        parse_complete_submit:

          // send response

          if (allowSubmit) {
            // accept message and send message ID back to ESME

            int msgid_len =
                64;  // PROTOCOL v3.4 message_id field is COctet String of up to
                     // 65 chars (inc NULL terminator)
            if (version < 0x34)
              msgid_len =
                  8;  // PROTOCOL v3.3 message_id field is COctet String (hex)
                      // of up to 9 characters (inc NULL terminator)

            char msgid[msgid_len + 1];
            for (int i = 0; i < msgid_len; i++)
              msgid[i] =
                  (rand() % 16) < 10 ? ('0' + rand() % 10) : ('a' + rand() % 6);
            msgid[msgid_len] = 0;
            send(seqno, SMPP::CmdID::SubmitSMResp, SMPP::CmdStatus::ESME_ROK,
                 (uint8_t*)msgid, msgid_len + 1);

            // sending back MO
            generateMO(5, 0, "FakeFrom", 1, 1, "FakeTo", short_message,
                       sm_length, data_coding);

            // add message to deliverer so that receipt will then be sent to
            // ESME

            uint64_t timeDeliver =
                tESMEDeliveryTimeRequired + (3 + (rand() % 10)) * 1000000L;

            MessageDeliverer::Message msg;
            msg.setSource(source_addr_ton, source_addr_npi,
                          (char*)source_addr.c_str());
            msg.setDestination(dest_addr_ton, dest_addr_npi,
                               (char*)destination_addr.c_str());
            msg.setRegisteredDelivery(registered_delivery);
            msg.setShortMessage(short_message, sm_length);
            msg.setSMSCMessageID(msgid);
            MessageDeliverer::getInstance(system_id)->add(timeDeliver, msg);
          } else
            send(seqno, SMPP::CmdID::SubmitSMResp, smppSubmitError, NULL,
                 0);  // don't accept message and send NAK back to ESME
        }
      }
    } else {
      // error or closed
      return true;
    }
    return false;
  }

  uint8_t getVersion(void) { return version; }
  void setVersion(uint8_t version_in) { version = version_in; }

  void logCommand(uint64_t cmdID, const char* direction) {
    char buf[640];
    SMPP b;
    sprintf(buf, "0x%08llx %s", cmdID, b.cmdString(cmdID));
    logCommand(buf, direction);
  }

  void logCommand(char* logline, const char* direction) {
    time_t rawtime;
    struct tm* timeinfo;
    char buffer[80];

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(buffer, 80, "%F %X ", timeinfo);

    printf("%s %s [s%06llx:%-15s] %s\n", buffer, direction, session_id,
           conn.getIP(), logline);
  }

  bool recv(uint64_t& cmdID, uint64_t& seqNo) {
    bool ret = conn.get();
    if (ret) {
      cmdID = conn.pduCommandID();
      seqNo = conn.pduSequenceNo();
      logCommand(cmdID, ">>");
    }
    return ret;
  }

  bool send(uint64_t seqNo, uint64_t cmdID, uint64_t cmdStatus, uint8_t* param,
            int len) {
    // SMPP b;
    // printf("<< 0x%08llx %s\n",cmdID,b.cmdString(cmdID));
    logCommand(cmdID, "<<");

    return conn.put(seqNo, cmdID, cmdStatus, param, len);
  }
};

// Sockets reference:
// https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/rzab6/xnonblock.htm

int dolisten(int portno) {
  struct sockaddr_in serv_addr;

  /* First call to socket() function */
  int listensockfd = socket(AF_INET, SOCK_STREAM, 0);

  if (listensockfd < 0) {
    perror("ERROR opening socket");
    return -1;
  }

  int rc, on = 1;

  /*************************************************************/
  /* Allow socket descriptor to be reuseable                   */
  /*************************************************************/
  rc = setsockopt(listensockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on,
                  sizeof(on));
  if (rc < 0) {
    perror("setsockopt() failed");
    close(listensockfd);
    exit(-1);
  }

  /*************************************************************/
  /* Set socket to be nonblocking. All of the sockets for      */
  /* the incoming connections will also be nonblocking since   */
  /* they will inherit that state from the listening socket.   */
  /*************************************************************/
  rc = ioctl(listensockfd, FIONBIO, (char*)&on);
  if (rc < 0) {
    perror("ioctl() failed");
    close(listensockfd);
    exit(-1);
  }

  /* Initialize socket structure */
  bzero((char*)&serv_addr, sizeof(serv_addr));

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  serv_addr.sin_port = htons(portno);

  /* Now bind the host address using bind() call.*/
  if (::bind(listensockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) <
      0) {
    perror("ERROR on binding");
    return -1;
  }

  /* Now start listening for the clients, here
   * process will go in sleep mode and will wait
   * for the incoming connection
   */

  listen(listensockfd, 32);

  return listensockfd;
}

Session* sessionSockMap[32000];  // array of SMPP session by socket

int main(int argc, const char* argv[]) {
  printf("%s build time: %s %s\n", argv[0], __DATE__, __TIME__);

  //

  int portSMPP = 2775;

  int listensockfdSMPP = dolisten(portSMPP);

  if (listensockfdSMPP == -1) {
    perror("Failed to listen on SMPP port");
    exit(1);
  }

  std::cout << "Listening for SMPP on port " << portSMPP << std::endl;

  //

  int portAdmin = 8775;

  int listensockfdAdmin = dolisten(portAdmin);

  if (listensockfdAdmin == -1) {
    perror("Failed to listen on admin port");
    exit(1);
  }

  std::cout << "Listening for admin on port " << portAdmin << std::endl;

  // Initialize the master fd_set
  fd_set master_set, working_set;
  FD_ZERO(&master_set);
  int max_sd = listensockfdSMPP;
  FD_SET(listensockfdSMPP, &master_set);
  if (listensockfdAdmin > max_sd) max_sd = listensockfdAdmin;
  FD_SET(listensockfdAdmin, &master_set);

  //

  int rc, i, desc_ready;
  int end_server = FALSE;
  int new_sd;
  int close_conn;
  struct timeval timeout;

  // Loop waiting for incoming connects or for incoming data
  do {
    // Copy the master fd_set over to the working fd_set.
    memcpy(&working_set, &master_set, sizeof(master_set));

    // Initialize the timeval struct to 1 second.  If no
    // activity after 1 second then wake-up and cycle.
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    // Call select() and wait for it to complete.
    rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);

    // Check to see if the select call failed.
    if (rc < 0) {
      perror("  select() failed");
      break;
    }

    // Check to see if select call timed out.
    if (rc == 0) {
      // perform periodic session tasks

      for (i = 0; i <= max_sd; ++i) {
        if (sessionSockMap[i] != NULL)
          if (sessionSockMap[i]->timedCheck()) {
            printf("  %ld Force close on connection - %d.\n", time(NULL), i);

            if (sessionSockMap[i] != NULL) {
              delete sessionSockMap[i];
              sessionSockMap[i] = NULL;
            }

            /*
             If the close_conn flag was turned on, we need
             to clean up this active connection.  This
             clean up process includes removing the
             descriptor from the master set and
             determining the new maximum descriptor value
             based on the bits that are still turned on in
             the master set.
            */

            close(i);
            FD_CLR(i, &master_set);
            if (i == max_sd) {
              while (FD_ISSET(max_sd, &master_set) == FALSE) {
                max_sd -= 1;
              }
            }
          }
      }

      continue;
    }

    /**********************************************************/
    /* One or more descriptors are readable.  Need to         */
    /* determine which ones they are.                         */
    /**********************************************************/
    desc_ready = rc;
    for (i = 0; i <= max_sd && desc_ready > 0; ++i) {
      /*******************************************************/
      /* Check to see if this descriptor is ready            */
      /*******************************************************/
      if (FD_ISSET(i, &working_set)) {
        /****************************************************/
        /* A descriptor was found that was readable - one   */
        /* less has to be looked for.  This is being done   */
        /* so that we can stop looking at the working set   */
        /* once we have found all of the descriptors that   */
        /* were ready.                                      */
        /****************************************************/
        desc_ready -= 1;

        /***********************************************************/
        /* Check to see if this is the listening socket (SMPP)     */
        /***********************************************************/
        if (i == listensockfdSMPP) {
          // printf("  Listening socket (SMPP) is readable\n");

          /*************************************************/
          /* Accept all incoming connections that are      */
          /* queued up on the listening socket before we   */
          /* loop back and call select again.              */
          /*************************************************/
          do {
            /**********************************************/
            /* Accept each incoming connection.  If       */
            /* accept fails with EWOULDBLOCK, then we     */
            /* have accepted all of them.  Any other      */
            /* failure on accept will cause us to end the */
            /* server.                                    */
            /**********************************************/
            struct sockaddr_in client_addr;
            int clen = sizeof(sockaddr_in);
            new_sd = accept(listensockfdSMPP, (struct sockaddr*)&client_addr,
                            (socklen_t*)&clen);
            if (new_sd < 0) {
              if (errno != EWOULDBLOCK) {
                perror("  accept() failed (SMPP)");
                if (errno != EMFILE) end_server = TRUE;
              }
              break;
            }

            char* ip = inet_ntoa(client_addr.sin_addr);

            //

            SMPPSession* newsession = new SMPPSession(new_sd, ip);

            sessionSockMap[new_sd] = newsession;

            /**********************************************/
            /* Add the new incoming connection to the     */
            /* master read set                            */
            /**********************************************/
            // printf("  New incoming connection - %d\n", new_sd);
            FD_SET(new_sd, &master_set);
            if (new_sd > max_sd) max_sd = new_sd;

            /**********************************************/
            /* Loop back up and accept another incoming   */
            /* connection                                 */
            /**********************************************/
          } while (new_sd != -1);
        } else
            /***********************************************************/
            /* Check to see if this is the listening socket (admin)    */
            /***********************************************************/
            if (i == listensockfdAdmin) {
          // printf("  Listening socket (admin) is readable\n");
          /*************************************************/
          /* Accept all incoming connections that are      */
          /* queued up on the listening socket before we   */
          /* loop back and call select again.              */
          /*************************************************/
          do {
            /**********************************************/
            /* Accept each incoming connection.  If       */
            /* accept fails with EWOULDBLOCK, then we     */
            /* have accepted all of them.  Any other      */
            /* failure on accept will cause us to end the */
            /* server.                                    */
            /**********************************************/
            new_sd = accept(listensockfdAdmin, NULL, NULL);
            if (new_sd < 0) {
              if (errno != EWOULDBLOCK) {
                perror("  accept() failed (admin)");
                if (errno != EMFILE) end_server = TRUE;
              }
              break;
            }

            //

            AdminSession* newsession = new AdminSession(new_sd);

            sessionSockMap[new_sd] = newsession;

            /**********************************************/
            /* Add the new incoming connection to the     */
            /* master read set                            */
            /**********************************************/
            // printf("  New incoming connection (Admin) - %d\n", new_sd);
            FD_SET(new_sd, &master_set);
            if (new_sd > max_sd) max_sd = new_sd;

            /**********************************************/
            /* Loop back up and accept another incoming   */
            /* connection                                 */
            /**********************************************/
          } while (new_sd != -1);
        }

        /****************************************************/
        /* This is not the listening socket, therefore an   */
        /* existing connection must be readable             */
        /****************************************************/
        else {
          // printf("  Descriptor %d is readable\n", i);
          close_conn = FALSE;

          bool closed = sessionSockMap[i]->run();

          if (closed) {
            // printf("  Closing connection - %d\n", i);

            if (sessionSockMap[i] != NULL) {
              delete sessionSockMap[i];
              sessionSockMap[i] = NULL;
            }

            close_conn = TRUE;
          } else
            close_conn = FALSE;

          /*************************************************/
          /* If the close_conn flag was turned on, we need */
          /* to clean up this active connection.  This     */
          /* clean up process includes removing the        */
          /* descriptor from the master set and            */
          /* determining the new maximum descriptor value  */
          /* based on the bits that are still turned on in */
          /* the master set.                               */
          /*************************************************/
          if (close_conn) {
            close(i);
            FD_CLR(i, &master_set);
            if (i == max_sd) {
              while (FD_ISSET(max_sd, &master_set) == FALSE) max_sd -= 1;
            }
          }
        } /* End of existing connection is readable */
      }   /* End of if (FD_ISSET(i, &working_set)) */
    }     /* End of loop through selectable descriptors */

  } while (end_server == FALSE);

  //

  close(listensockfdSMPP);

  close(listensockfdAdmin);

  std::cout << "No longer listening on port " << portSMPP << std::endl;

  return 0;
}


================================================
FILE: example/transceiver_with_auto_response/main.go
================================================
package main

import (
	"fmt"
	"log"
	"strings"
	"sync"
	"time"

	"github.com/linxGnu/gosmpp"
	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

func main() {
	var wg sync.WaitGroup

	wg.Add(1)
	go sendingAndReceiveSMS(&wg)

	wg.Wait()
}

func sendingAndReceiveSMS(wg *sync.WaitGroup) {
	defer wg.Done()

	auth := gosmpp.Auth{
		SMSC:       "localhost:2775",
		SystemID:   "169994",
		Password:   "EDXPJU",
		SystemType: "",
	}

	trans, err := gosmpp.NewSession(
		gosmpp.TRXConnector(gosmpp.NonTLSDialer, auth),
		gosmpp.Settings{
			EnquireLink: 5 * time.Second,

			ReadTimeout: 10 * time.Second,

			OnSubmitError: func(_ pdu.PDU, err error) {
				log.Fatal("SubmitPDU error:", err)
			},

			OnReceivingError: func(err error) {
				fmt.Println("Receiving PDU/Network error:", err)
			},

			OnRebindingError: func(err error) {
				fmt.Println("Rebinding but error:", err)
			},

			OnPDU: handlePDU(),

			OnClosed: func(state gosmpp.State) {
				fmt.Println(state)
			},
		}, 5*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		_ = trans.Close()
	}()

	// sending SMS(s)
	for i := 0; i < 1800; i++ {
		if err = trans.Transceiver().Submit(newSubmitSM()); err != nil {
			fmt.Println(err)
		}
		time.Sleep(time.Second)
	}
}

func handlePDU() func(pdu.PDU, bool) {
	concatenated := map[uint8][]string{}
	return func(p pdu.PDU, _ bool) {
		switch pd := p.(type) {
		case *pdu.SubmitSMResp:
			fmt.Printf("SubmitSMResp:%+v\n", pd)

		case *pdu.GenericNack:
			fmt.Println("GenericNack Received")

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")

		case *pdu.DataSM:
			fmt.Printf("DataSM:%+v\n", pd)

		case *pdu.DeliverSM:
			fmt.Printf("DeliverSM:%+v\n", pd)
			log.Println(pd.Message.GetMessage())
			// region concatenated sms (sample code)
			message, err := pd.Message.GetMessage()
			if err != nil {
				log.Fatal(err)
			}
			totalParts, sequence, reference, found := pd.Message.UDH().GetConcatInfo()
			if found {
				if _, ok := concatenated[reference]; !ok {
					concatenated[reference] = make([]string, totalParts)
				}
				concatenated[reference][sequence-1] = message
			}
			if !found {
				log.Println(message)
			} else if parts, ok := concatenated[reference]; ok && isConcatenatedDone(parts, totalParts) {
				log.Println(strings.Join(parts, ""))
				delete(concatenated, reference)
			}
			// endregion
		}
	}
}

func newSubmitSM() *pdu.SubmitSM {
	// build up submitSM
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	_ = srcAddr.SetAddress("00" + "522241")

	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	_ = destAddr.SetAddress("99" + "522241")

	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	_ = submitSM.Message.SetMessageWithEncoding("Đừng buồn thế dù ngoài kia vẫn mưa nghiễng rợi tý tỵ", data.UCS2)
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0

	return submitSM
}

func isConcatenatedDone(parts []string, total byte) bool {
	for _, part := range parts {
		if part != "" {
			total--
		}
	}
	return total == 0
}


================================================
FILE: example/transceiver_with_manual_response/main.go
================================================
package main

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/linxGnu/gosmpp"
	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

func main() {
	var wg sync.WaitGroup

	wg.Add(1)
	go sendingAndReceiveSMS(&wg)

	wg.Wait()
}

func sendingAndReceiveSMS(wg *sync.WaitGroup) {
	defer wg.Done()

	auth := gosmpp.Auth{
		SMSC:       "localhost:2775",
		SystemID:   "169994",
		Password:   "EDXPJU",
		SystemType: "",
	}

	trans, err := gosmpp.NewSession(
		gosmpp.TRXConnector(gosmpp.NonTLSDialer, auth),
		gosmpp.Settings{
			EnquireLink: 5 * time.Second,

			ReadTimeout: 10 * time.Second,

			OnSubmitError: func(_ pdu.PDU, err error) {
				log.Fatal("SubmitPDU error:", err)
			},

			OnReceivingError: func(err error) {
				fmt.Println("Receiving PDU/Network error:", err)
			},

			OnRebindingError: func(err error) {
				fmt.Println("Rebinding but error:", err)
			},

			OnAllPDU: handlePDU(),

			OnClosed: func(state gosmpp.State) {
				fmt.Println(state)
			},
		}, 5*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		_ = trans.Close()
	}()

	// sending SMS(s)
	for i := 0; i < 30; i++ {
		if err = trans.Transceiver().Submit(newSubmitSM()); err != nil {
			fmt.Println(err)
		}
		time.Sleep(time.Second)
	}
}

func handlePDU() func(pdu.PDU) (pdu.PDU, bool) {
	return func(p pdu.PDU) (pdu.PDU, bool) {
		switch pd := p.(type) {
		case *pdu.Unbind:
			fmt.Println("Unbind Received")
			return pd.GetResponse(), true

		case *pdu.UnbindResp:
			fmt.Println("UnbindResp Received")

		case *pdu.SubmitSMResp:
			fmt.Println("SubmitSMResp Received")

		case *pdu.GenericNack:
			fmt.Println("GenericNack Received")

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")

		case *pdu.EnquireLink:
			fmt.Println("EnquireLink Received")
			return pd.GetResponse(), false

		case *pdu.DataSM:
			fmt.Println("DataSM receiver")
			return pd.GetResponse(), false

		case *pdu.DeliverSM:
			fmt.Println("DeliverSM receiver")
			return pd.GetResponse(), false
		}
		return nil, false
	}
}

func newSubmitSM() *pdu.SubmitSM {
	// build up submitSM
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	_ = srcAddr.SetAddress("00" + "522241")

	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	_ = destAddr.SetAddress("99" + "522241")

	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	_ = submitSM.Message.SetMessageWithEncoding("Đừng buồn thế dù ngoài kia vẫn mưa nghiễng rợi tý tỵ", data.UCS2)
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0

	return submitSM
}


================================================
FILE: example/transeiver_with_custom_store/CustomStore.go
================================================
package main

import (
	"bytes"
	"context"
	"encoding/gob"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/allegro/bigcache/v3"
	"github.com/linxGnu/gosmpp/pdu"

	"github.com/linxGnu/gosmpp"
)

// This is a just an example how to implement a custom store.
//
// Your implementation must be concurrency safe
//
// In this example we use bigcache https://github.com/allegro/bigcache
// Warning:
//  - This is just an example and should be tested before using in production
//	- We are serializing with gob, some field cannot be serialized for simplicity
//  - We recommend you implement your own serialization/deserialization if you choose to use bigcache

type CustomStore struct {
	store *bigcache.BigCache
}

func NewCustomStore() CustomStore {
	cache, _ := bigcache.New(context.Background(), bigcache.DefaultConfig(30*time.Second))
	return CustomStore{
		store: cache,
	}
}

func (s CustomStore) Set(ctx context.Context, request gosmpp.Request) error {
	select {
	case <-ctx.Done():
		fmt.Println("Task cancelled")
		return ctx.Err()
	default:
		b, _ := serialize(request)
		err := s.store.Set(strconv.Itoa(int(request.PDU.GetSequenceNumber())), b)
		if err != nil {
			return err
		}
		return nil
	}
}

func (s CustomStore) Get(ctx context.Context, sequenceNumber int32) (gosmpp.Request, bool) {
	select {
	case <-ctx.Done():
		fmt.Println("Task cancelled")
		return gosmpp.Request{}, false
	default:
		bRequest, err := s.store.Get(strconv.Itoa(int(sequenceNumber)))
		if err != nil {
			return gosmpp.Request{}, false
		}
		request, err := deserialize(bRequest)
		if err != nil {
			return gosmpp.Request{}, false
		}
		return request, true
	}
}

func (s CustomStore) List(ctx context.Context) []gosmpp.Request {
	var requests []gosmpp.Request
	select {
	case <-ctx.Done():
		return requests
	default:
		it := s.store.Iterator()
		for it.SetNext() {
			value, err := it.Value()
			if err != nil {
				return requests
			}
			request, _ := deserialize(value.Value())
			requests = append(requests, request)
		}
		return requests
	}
}

func (s CustomStore) Delete(ctx context.Context, sequenceNumber int32) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
		err := s.store.Delete(strconv.Itoa(int(sequenceNumber)))
		if err != nil {
			return err
		}
		return nil
	}
}

func (s CustomStore) Clear(ctx context.Context) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
		err := s.store.Reset()
		if err != nil {
			return err
		}
		return nil
	}
}

func (s CustomStore) Length(ctx context.Context) (int, error) {
	select {
	case <-ctx.Done():
		return 0, ctx.Err()
	default:
		return s.store.Len(), nil
	}
}

func serialize(request gosmpp.Request) ([]byte, error) {
	buf := pdu.NewBuffer(make([]byte, 0, 64))
	request.PDU.Marshal(buf)
	b := bytes.Buffer{}
	e := gob.NewEncoder(&b)
	err := e.Encode(requestGob{
		Pdu:      buf.Bytes(),
		TimeSent: time.Time{},
	})
	if err != nil {
		return b.Bytes()[:], errors.New("serialization failed")
	}
	return b.Bytes(), nil
}

func deserialize(bRequest []byte) (request gosmpp.Request, err error) {
	r := requestGob{}
	b := bytes.Buffer{}
	_, err = b.Write(bRequest)
	if err != nil {
		return request, errors.New("deserialization failed")
	}
	d := gob.NewDecoder(&b)
	err = d.Decode(&r)
	if err != nil {
		return request, errors.New("deserialization failed")
	}
	p, err := pdu.Parse(bytes.NewReader(r.Pdu))
	if err != nil {
		return gosmpp.Request{}, err
	}
	return gosmpp.Request{
		PDU:      p,
		TimeSent: r.TimeSent,
	}, nil
}

type requestGob struct {
	Pdu      []byte
	TimeSent time.Time
}


================================================
FILE: example/transeiver_with_custom_store/main.go
================================================
package main

import (
	"errors"
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/linxGnu/gosmpp"
	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

func main() {
	var wg sync.WaitGroup

	wg.Add(1)
	go sendingAndReceiveSMS(&wg)

	wg.Wait()
}

func sendingAndReceiveSMS(wg *sync.WaitGroup) {
	defer wg.Done()

	auth := gosmpp.Auth{
		SMSC:       "localhost:2775",
		SystemID:   "169994",
		Password:   "EDXPJU",
		SystemType: "",
	}

	trans, err := gosmpp.NewSession(
		gosmpp.TRXConnector(gosmpp.NonTLSDialer, auth),
		gosmpp.Settings{
			EnquireLink: 5 * time.Second,

			ReadTimeout: 10 * time.Second,

			OnSubmitError: func(p pdu.PDU, err error) {
				if errors.Is(err, gosmpp.ErrWindowsFull) {
					log.Println("SubmitPDU error:", err)
				} else {
					log.Fatal("SubmitPDU error:", err)
				}
			},

			OnReceivingError: func(err error) {
				fmt.Println("Receiving PDU/Network error:", err)
			},

			OnRebindingError: func(err error) {
				fmt.Println("Rebinding but error:", err)
			},

			OnClosed: func(state gosmpp.State) {
				fmt.Println(state)
			},

			WindowedRequestTracking: &gosmpp.WindowedRequestTracking{
				OnReceivedPduRequest:  handleReceivedPduRequest(),
				OnExpectedPduResponse: handleExpectedPduResponse(),
				OnExpiredPduRequest:   handleExpirePduRequest(),
				OnClosePduRequest:     handleOnClosePduRequest(),
				PduExpireTimeOut:      30 * time.Second,
				ExpireCheckTimer:      10 * time.Second,
				MaxWindowSize:         30,
				EnableAutoRespond:     false,
			},
		},
		5*time.Second,
		gosmpp.WithRequestStore(NewCustomStore()),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		_ = trans.Close()
	}()

	// sending SMS(s)
	for i := 0; i < 60; i++ {
		var size int
		size, err = trans.GetWindowSize()
		if err != nil {
			fmt.Println("could not get window size: ", err)
		} else {
			fmt.Println("Current window size: ", size)
		}
		p := newSubmitSM()
		if err = trans.Transceiver().Submit(p); err != nil {
			fmt.Println(err)
		}
		fmt.Printf("Sent SubmitSM with id: %+v\n", p)
		time.Sleep(1 * time.Second)
	}
	time.Sleep(1 * time.Second)
}

func handleExpirePduRequest() func(pdu.PDU) bool {
	return func(p pdu.PDU) bool {
		switch p.(type) {

		case *pdu.SubmitSM:
			fmt.Printf("Expired SubmitSM: %+v\n", p)

		case *pdu.EnquireLink:
			fmt.Printf("Expired EnquireLink: %+v\n", p)
			return true // if the enquire_link expired, usually means the bind is stale

		case *pdu.DataSM:
			fmt.Printf("Expired DataSM: %+v\n", p)

		default:
			fmt.Printf("Expired PDU: %+v\n", p)
		}

		return false
	}
}

func handleOnClosePduRequest() func(pdu.PDU) {
	return func(p pdu.PDU) {
		switch p.(type) {
		case *pdu.Unbind:
			fmt.Printf("OnClose Unbind: %+v\n", p)

		case *pdu.SubmitSM:
			fmt.Printf("OnClose SubmitSM: %+v\n", p)

		case *pdu.EnquireLink:
			fmt.Printf("OnClose EnquireLink: %+v\n", p)

		case *pdu.DataSM:
			fmt.Printf("OnClose DataSM: %+v\n", p)
		}
	}
}

func handleExpectedPduResponse() func(response gosmpp.Response) {
	return func(response gosmpp.Response) {
		switch response.PDU.(type) {
		case *pdu.UnbindResp:
			fmt.Println("UnbindResp Received")
			fmt.Printf("OriginalSM id:%+v\n", response.OriginalRequest.PDU)

		case *pdu.SubmitSMResp:
			fmt.Printf("SubmitSMResp Received: %+v\n", response.PDU)
			fmt.Printf("OriginalSM SubmitSM:%+v\n", response.OriginalRequest.PDU)

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")
			fmt.Printf("Original EnquireLink:%+v\n", response.OriginalRequest.PDU)

		}
	}
}

func handleReceivedPduRequest() func(pdu.PDU) (pdu.PDU, bool) {
	return func(p pdu.PDU) (pdu.PDU, bool) {
		switch pd := p.(type) {
		case *pdu.Unbind:
			fmt.Println("Unbind Received")
			return pd.GetResponse(), true

		case *pdu.GenericNack:
			fmt.Println("GenericNack Received")

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")

		case *pdu.EnquireLink:
			fmt.Println("EnquireLink Received")
			return pd.GetResponse(), false

		case *pdu.DataSM:
			fmt.Println("DataSM Received")
			return pd.GetResponse(), false

		case *pdu.DeliverSM:
			fmt.Println("DeliverSM Received")
			return pd.GetResponse(), false
		}
		return nil, false
	}
}

func newSubmitSM() *pdu.SubmitSM {
	// build up submitSM
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	_ = srcAddr.SetAddress("00" + "522241")

	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	_ = destAddr.SetAddress("99" + "522241")

	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	_ = submitSM.Message.SetMessageWithEncoding("Đừng buồn thế dù ngoài kia vẫn mưa nghiễng rợi tý tỵ", data.UCS2)
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0

	return submitSM
}


================================================
FILE: example/transeiver_with_request_window_and_custom_submitSm/CustomSubmitSM.go
================================================
package main

import (
	"math/rand"
	"strconv"

	"github.com/linxGnu/gosmpp/pdu"
)

// CustomSubmitSM by embedding the PDU interface
// and adding messageId as an extra field to SubmitSM
type CustomSubmitSM struct {
	pdu.PDU
	messageId string
}

// newCustomSubmitSM returns CustomSubmitSM PDU.
// Using rand.Int to generate new id for each CustomSubmitSM
func newCustomSubmitSM() CustomSubmitSM {
	return CustomSubmitSM{
		PDU:       newSubmitSM(),
		messageId: strconv.Itoa(rand.Int()),
	}
}


================================================
FILE: example/transeiver_with_request_window_and_custom_submitSm/main.go
================================================
package main

import (
	"errors"
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/linxGnu/gosmpp"
	"github.com/linxGnu/gosmpp/data"
	"github.com/linxGnu/gosmpp/pdu"
)

func main() {
	var wg sync.WaitGroup

	wg.Add(1)
	go sendingAndReceiveSMS(&wg)

	wg.Wait()
}

func sendingAndReceiveSMS(wg *sync.WaitGroup) {
	defer wg.Done()

	auth := gosmpp.Auth{
		SMSC:       "localhost:2775",
		SystemID:   "169994",
		Password:   "EDXPJU",
		SystemType: "",
	}

	trans, err := gosmpp.NewSession(
		gosmpp.TRXConnector(gosmpp.NonTLSDialer, auth),
		gosmpp.Settings{
			EnquireLink: 5 * time.Second,

			ReadTimeout: 10 * time.Second,

			OnSubmitError: func(p pdu.PDU, err error) {
				if errors.Is(err, gosmpp.ErrWindowsFull) {
					log.Println("SubmitPDU error: ", err)
				} else {
					log.Fatal("SubmitPDU error: ", err)
				}
			},

			OnReceivingError: func(err error) {
				fmt.Println("Receiving PDU/Network error: ", err)
			},

			OnRebindingError: func(err error) {
				fmt.Println("Rebinding but error: ", err)
			},

			OnClosed: func(state gosmpp.State) {
				fmt.Println("Bind has been closed: ", state.String())
			},

			WindowedRequestTracking: &gosmpp.WindowedRequestTracking{
				OnReceivedPduRequest:  handleReceivedPduRequest(),
				OnExpectedPduResponse: handleExpectedPduResponse(),
				OnExpiredPduRequest:   handleExpirePduRequest(),
				OnClosePduRequest:     handleOnClosePduRequest(),
				PduExpireTimeOut:      30 * time.Second,
				ExpireCheckTimer:      10 * time.Second,
				MaxWindowSize:         30,
				StoreAccessTimeOut:    1 * time.Second,
				EnableAutoRespond:     false,
			},
		}, 5*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		_ = trans.Close()
	}()

	// sending SMS(s)
	for i := 0; i < 60; i++ {
		var size int
		size, err = trans.GetWindowSize()
		if err != nil {
			fmt.Println("could not get window size: ", err)
		} else {
			fmt.Println("Current window size: ", size)
		}
		p := newCustomSubmitSM()
		if err = trans.Transceiver().Submit(p); err != nil {
			fmt.Println(err)
		}
		fmt.Printf("Sent CustomSubmitSM with id: %+v\n", p.messageId)
		time.Sleep(1 * time.Second)
	}
	time.Sleep(1 * time.Second)
}

func handleExpirePduRequest() func(pdu.PDU) bool {
	return func(p pdu.PDU) bool {
		switch p.(type) {
		case *pdu.Unbind:
			fmt.Printf("Expired Unbind :%+v\n", p)
			fmt.Println("Unbind Expired")

		case *pdu.SubmitSM:
			fmt.Printf("Expired SubmitSM :%+v\n", p)

		case *pdu.EnquireLink:
			fmt.Printf("Expired EnquireLink:%+v\n", p)
			return true // if the enquire_link expired, usually means the bind is stale

		case *pdu.DataSM:
			fmt.Printf("Expired DataSM:%+v\n", p)
		}
		return false
	}
}

func handleOnClosePduRequest() func(pdu.PDU) {
	return func(p pdu.PDU) {
		switch p.(type) {
		case *pdu.Unbind:
			fmt.Printf("OnClose Unbind:%+v\n", p)

		case *pdu.SubmitSM:
			fmt.Printf("OnClose SubmitSM:%+v\n", p)

		case *pdu.EnquireLink:
			fmt.Printf("OnClose EnquireLink:%+v\n", p)

		case *pdu.DataSM:
			fmt.Printf("OnClose DataSM:%+v\n", p)
		}
	}
}

func handleExpectedPduResponse() func(response gosmpp.Response) {
	return func(response gosmpp.Response) {
		switch response.PDU.(type) {
		case *pdu.UnbindResp:
			fmt.Println("UnbindResp Received")
			fmt.Printf("OriginalSM id:%+v\n", response.OriginalRequest.PDU)

		case *pdu.SubmitSMResp:
			fmt.Printf("SubmitSMResp Received: %+v\n", response.PDU)
			fmt.Printf("OriginalSM SubmitSM:%+v\n", response.OriginalRequest.PDU)

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")
			fmt.Printf("Original EnquireLink:%+v\n", response.OriginalRequest.PDU)

		}
	}
}

func handleReceivedPduRequest() func(pdu.PDU) (pdu.PDU, bool) {
	return func(p pdu.PDU) (pdu.PDU, bool) {
		switch pd := p.(type) {
		case *pdu.Unbind:
			fmt.Println("Unbind Received")
			return pd.GetResponse(), true

		case *pdu.GenericNack:
			fmt.Println("GenericNack Received")

		case *pdu.EnquireLinkResp:
			fmt.Println("EnquireLinkResp Received")

		case *pdu.EnquireLink:
			fmt.Println("EnquireLink Received")
			return pd.GetResponse(), false

		case *pdu.DataSM:
			fmt.Println("DataSM Received")
			return pd.GetResponse(), false

		case *pdu.DeliverSM:
			fmt.Println("DeliverSM Received")
			return pd.GetResponse(), false
		}
		return nil, false
	}
}

func newSubmitSM() *pdu.SubmitSM {
	// build up submitSM
	srcAddr := pdu.NewAddress()
	srcAddr.SetTon(5)
	srcAddr.SetNpi(0)
	_ = srcAddr.SetAddress("00" + "522241")

	destAddr := pdu.NewAddress()
	destAddr.SetTon(1)
	destAddr.SetNpi(1)
	_ = destAddr.SetAddress("99" + "522241")

	submitSM := pdu.NewSubmitSM().(*pdu.SubmitSM)
	submitSM.SourceAddr = srcAddr
	submitSM.DestAddr = destAddr
	_ = submitSM.Message.SetMessageWithEncoding("Đừng buồn thế dù ngoài kia vẫn mưa nghiễng rợi tý tỵ", data.UCS2)
	submitSM.ProtocolID = 0
	submitSM.RegisteredDelivery = 1
	submitSM.ReplaceIfPresentFlag = 0
	submitSM.EsmClass = 0

	return submitSM
}


================================================
FILE: go.mod
================================================
module github.com/linxGnu/gosmpp

go 1.24.0

require (
	github.com/allegro/bigcache/v3 v3.1.0
	github.com/orcaman/concurrent-map/v2 v2.0.1
	github.com/stretchr/testify v1.11.1
	golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b
	golang.org/x/text v0.33.0
)

require (
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)


================================================
FILE: go.sum
================================================
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/orcaman/concurrent-map/v2 v2.0.1 h1:jOJ5Pg2w1oeB6PeDurIYf6k9PQ+aTITr/6lP/L/zp6c=
github.com/orcaman/concurrent-map/v2 v2.0.1/go.mod h1:9Eq3TG2oBe5FirmYWQfYO5iH1q0Jv47PLaNK++uCdOM=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b h1:DXr+pvt3nC887026GRP39Ej11UATqWDmWuS99x26cD0=
golang.org/x/exp v0.0.0-20250819193227-8b4c13bb791b/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=


================================================
FILE: pdu/Address.go
================================================
package pdu

import (
	"fmt"

	"github.com/linxGnu/gosmpp/data"
)

// Address smpp address of src and dst.
type Address struct {
	ton     byte
	npi     byte
	address string
}

// NewAddress returns new address with default max length.
func NewAddress() Address {
	return Address{ton: data.GetDefaultTon(), npi: data.GetDefaultNpi()}
}

// NewAddressWithAddr returns new address.
func NewAddressWithAddr(addr string) (a Address, err error) {
	a = NewAddress()
	err = a.SetAddress(addr)
	return
}

// NewAddressWithTonNpi returns new address with ton, npi.
func NewAddressWithTonNpi(ton, npi byte) Address {
	return Address{ton: ton, npi: npi}
}

// NewAddressWithTonNpiAddr returns new address with ton, npi, addr string.
func NewAddressWithTonNpiAddr(ton, npi byte, addr string) (a Address, err error) {
	a = NewAddressWithTonNpi(ton, npi)
	err = a.SetAddress(addr)
	return
}

// Unmarshal from buffer.
func (c *Address) Unmarshal(b *ByteBuffer) (err error) {
	if c.ton, err = b.ReadByte(); err == nil {
		if c.npi, err = b.ReadByte(); err == nil {
			c.address, err = b.ReadCString()
		}
	}
	return
}

// Marshal to buffer.
func (c *Address) Marshal(b *ByteBuffer) {
	b.Grow(3 + len(c.address))

	_ = b.WriteByte(c.ton)
	_ = b.WriteByte(c.npi)
	_ = b.WriteCString(c.address)
}

// SetTon sets ton.
func (c *Address) SetTon(ton byte) {
	c.ton = ton
}

// SetNpi sets npi.
func (c *Address) SetNpi(npi byte) {
	c.npi = npi
}

// SetAddress sets address.
func (c *Address) SetAddress(addr string) (err error) {
	if len(addr) > data.SM_ADDR_LEN {
		err = fmt.Errorf("Address len exceed limit. (%d > %d)", len(addr), data.SM_ADDR_LEN)
	} else {
		c.address = addr
	}
	return
}

// Ton returns assigned ton.
func (c Address) Ton() byte {
	return c.ton
}

// Npi returns assigned npi.
func (c Address) Npi() byte {
	return c.npi
}

// Address returns assigned address (in string).
func (c Address) Address() string {
	return c.address
}

// String implement stringer interface
func (c Address) String() string {
	return c.address
}


================================================
FILE: pdu/AddressRange.go
================================================
package pdu

import "github.com/linxGnu/gosmpp/data"

// AddressRange smpp address range of src and dst.
type AddressRange struct {
	Ton          byte
	Npi          byte
	AddressRange string
}

// NewAddressRange create new AddressRange with default max length.
func NewAddressRange() AddressRange {
	return AddressRange{Ton: data.GetDefaultTon(), Npi: data.GetDefaultNpi()}
}

// NewAddressRangeWithAddr create new AddressRange.
func NewAddressRangeWithAddr(addr string) AddressRange {
Download .txt
gitextract_d637zljl/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       └── go.yml
├── .gitignore
├── .golangci.yml
├── LICENSE
├── README.md
├── connect.go
├── connect_test.go
├── connection.go
├── connection_test.go
├── data/
│   ├── 7bit.go
│   ├── 7bit_test.go
│   ├── codings.go
│   ├── codings_test.go
│   ├── header_data.go
│   ├── header_data_string.go
│   ├── other_codings.go
│   ├── pkg.go
│   ├── pkg_test.go
│   ├── utils.go
│   └── utils_test.go
├── errors/
│   ├── pkg.go
│   └── pkg_test.go
├── example/
│   ├── smsc_simulator/
│   │   └── smsc.cpp
│   ├── transceiver_with_auto_response/
│   │   └── main.go
│   ├── transceiver_with_manual_response/
│   │   └── main.go
│   ├── transeiver_with_custom_store/
│   │   ├── CustomStore.go
│   │   └── main.go
│   └── transeiver_with_request_window_and_custom_submitSm/
│       ├── CustomSubmitSM.go
│       └── main.go
├── go.mod
├── go.sum
├── pdu/
│   ├── Address.go
│   ├── AddressRange.go
│   ├── AddressRange_test.go
│   ├── Address_test.go
│   ├── AlertNotification.go
│   ├── AlertNotification_test.go
│   ├── BindRequest.go
│   ├── BindRequest_test.go
│   ├── BindResponse.go
│   ├── BindResponse_test.go
│   ├── Buffer.go
│   ├── Buffer_test.go
│   ├── CancelSM.go
│   ├── CancelSMResp.go
│   ├── CancelSMResp_test.go
│   ├── CancelSM_test.go
│   ├── DataSM.go
│   ├── DataSMResp.go
│   ├── DataSMResp_test.go
│   ├── DataSM_test.go
│   ├── DeliverSM.go
│   ├── DeliverSMResp.go
│   ├── DeliverSMResp_test.go
│   ├── DeliverSM_test.go
│   ├── DestinationAddress.go
│   ├── DestinationAddress_test.go
│   ├── DistributionList.go
│   ├── DistributionList_test.go
│   ├── EnquireLink.go
│   ├── EnquireLinkResp.go
│   ├── EnquireLinkResp_test.go
│   ├── EnquireLink_test.go
│   ├── GenericNack.go
│   ├── GenericNack_test.go
│   ├── Outbind.go
│   ├── Outbind_test.go
│   ├── PDU.go
│   ├── PDUFactory.go
│   ├── PDUFactory_test.go
│   ├── PDUHeader.go
│   ├── PDUHeader_test.go
│   ├── PDU_test.go
│   ├── QuerySM.go
│   ├── QuerySMResp.go
│   ├── QuerySMResp_test.go
│   ├── QuerySM_test.go
│   ├── ReplaceSM.go
│   ├── ReplaceSMResp.go
│   ├── ReplaceSMResp_test.go
│   ├── ReplaceSM_test.go
│   ├── ShortMessage.go
│   ├── ShortMessage_test.go
│   ├── SubmitMulti.go
│   ├── SubmitMultiResp.go
│   ├── SubmitMultiResp_test.go
│   ├── SubmitMulti_test.go
│   ├── SubmitSM.go
│   ├── SubmitSMResp.go
│   ├── SubmitSMResp_test.go
│   ├── SubmitSM_test.go
│   ├── TLV.go
│   ├── UDH.go
│   ├── UDH_test.go
│   ├── Unbind.go
│   ├── UnbindResp.go
│   ├── UnbindResp_test.go
│   ├── Unbind_test.go
│   ├── UnsuccessSME.go
│   ├── UnsuccessSME_test.go
│   └── helper_test.go
├── pkg.go
├── receivable.go
├── receivable_test.go
├── request_store.go
├── session.go
├── session_test.go
├── state.go
├── state_test.go
├── transceivable.go
├── transceivable_test.go
├── transmittable.go
├── transmittable_test.go
└── types.go
Download .txt
SYMBOL INDEX (1106 symbols across 107 files)

FILE: connect.go
  type Dialer (line 19) | type Dialer
  type Auth (line 22) | type Auth struct
  type BindError (line 30) | type BindError struct
    method Error (line 34) | func (err BindError) Error() string {
  function newBindRequest (line 38) | func newBindRequest(s Auth, bindingType pdu.BindingType, addressRange pd...
  type Connector (line 48) | type Connector interface
  type connector (line 53) | type connector struct
    method GetBindType (line 60) | func (c *connector) GetBindType() pdu.BindingType {
    method Connect (line 64) | func (c *connector) Connect() (conn *Connection, err error) {
  function connect (line 69) | func connect(dialer Dialer, addr string, bindReq *pdu.BindRequest) (c *C...
  function TXConnector (line 114) | func TXConnector(dialer Dialer, auth Auth) Connector {
  function RXConnector (line 123) | func RXConnector(dialer Dialer, auth Auth, opts ...connectorOption) Conn...
  function TRXConnector (line 136) | func TRXConnector(dialer Dialer, auth Auth, opts ...connectorOption) Con...
  type connectorOption (line 148) | type connectorOption
  function WithAddressRange (line 150) | func WithAddressRange(addressRange pdu.AddressRange) connectorOption {

FILE: connect_test.go
  constant smscAddr (line 18) | smscAddr = "127.0.0.1:2775"
  constant mess (line 19) | mess     = "Thử nghiệm: chuẩn bị nế mễ"
  function nextAuth (line 22) | func nextAuth() Auth {
  function TestBindingSMSC (line 32) | func TestBindingSMSC(t *testing.T) {
  function TestBindingSMSC_Error (line 64) | func TestBindingSMSC_Error(t *testing.T) {
  function TestBindingType (line 85) | func TestBindingType(t *testing.T) {

FILE: connection.go
  type Connection (line 12) | type Connection struct
    method Read (line 30) | func (c *Connection) Read(b []byte) (n int, err error) {
    method Write (line 38) | func (c *Connection) Write(b []byte) (n int, err error) {
    method WritePDU (line 44) | func (c *Connection) WritePDU(p pdu.PDU) (n int, err error) {
    method Close (line 53) | func (c *Connection) Close() error {
    method LocalAddr (line 58) | func (c *Connection) LocalAddr() net.Addr {
    method RemoteAddr (line 63) | func (c *Connection) RemoteAddr() net.Addr {
    method SetDeadline (line 89) | func (c *Connection) SetDeadline(t time.Time) error {
    method SetReadDeadline (line 96) | func (c *Connection) SetReadDeadline(t time.Time) error {
    method SetReadTimeout (line 101) | func (c *Connection) SetReadTimeout(t time.Duration) error {
    method SetWriteDeadline (line 110) | func (c *Connection) SetWriteDeadline(t time.Time) error {
    method SetWriteTimeout (line 115) | func (c *Connection) SetWriteTimeout(t time.Duration) error {
  function NewConnection (line 19) | func NewConnection(conn net.Conn) (c *Connection) {

FILE: connection_test.go
  function TestConnection (line 11) | func TestConnection(t *testing.T) {

FILE: data/7bit.go
  constant escapeSequence (line 27) | escapeSequence = 0x1B
  function ValidateGSM7String (line 73) | func ValidateGSM7String(text string) []rune {
  function ValidateGSM7Buffer (line 86) | func ValidateGSM7Buffer(buffer []byte) []byte {
  function GetEscapeChars (line 110) | func GetEscapeChars(runeText []rune) []rune {
  function IsEscapeChar (line 121) | func IsEscapeChar(c rune) bool {
  function GSM7 (line 130) | func GSM7(packed bool) encoding.Encoding {
  type gsm7Encoding (line 134) | type gsm7Encoding struct
    method NewDecoder (line 138) | func (g gsm7Encoding) NewDecoder() *encoding.Decoder {
    method NewEncoder (line 144) | func (g gsm7Encoding) NewEncoder() *encoding.Encoder {
    method String (line 150) | func (g gsm7Encoding) String() string {
  type gsm7Decoder (line 157) | type gsm7Decoder struct
    method Reset (line 161) | func (g *gsm7Decoder) Reset() { /* not needed */ }
    method Transform (line 225) | func (g *gsm7Decoder) Transform(dst, src []byte, atEOF bool) (nDst, nS...
  function unpack (line 163) | func unpack(src []byte, packed bool) (septets []byte) {
  type gsm7Encoder (line 265) | type gsm7Encoder struct
    method Reset (line 269) | func (g *gsm7Encoder) Reset() {
    method Transform (line 345) | func (g *gsm7Encoder) Transform(dst, src []byte, atEOF bool) (nDst, nS...
  function pack (line 273) | func pack(dst []byte, septets []byte) (nDst int) {

FILE: data/7bit_test.go
  function TestGSM7EncodingString (line 96) | func TestGSM7EncodingString(t *testing.T) {
  function TestValidateGSM7String (line 113) | func TestValidateGSM7String(t *testing.T) {
  function TestValidateGSM7Buffer (line 122) | func TestValidateGSM7Buffer(t *testing.T) {
  function TestPackedEncoder (line 131) | func TestPackedEncoder(t *testing.T) {
  function TestUnpackedEncoder (line 144) | func TestUnpackedEncoder(t *testing.T) {
  function TestPackedDecoder (line 157) | func TestPackedDecoder(t *testing.T) {
  function TestUnpackedDecoder (line 170) | func TestUnpackedDecoder(t *testing.T) {
  function TestInvalidCharacter (line 183) | func TestInvalidCharacter(t *testing.T) {
  function TestInvalidByte (line 196) | func TestInvalidByte(t *testing.T) {

FILE: data/codings.go
  constant GSM7BITCoding (line 11) | GSM7BITCoding byte = 0x00
  constant ASCIICoding (line 13) | ASCIICoding byte = 0x01
  constant BINARY8BIT1Coding (line 15) | BINARY8BIT1Coding byte = 0x02
  constant LATIN1Coding (line 17) | LATIN1Coding byte = 0x03
  constant BINARY8BIT2Coding (line 19) | BINARY8BIT2Coding byte = 0x04
  constant CYRILLICCoding (line 21) | CYRILLICCoding byte = 0x06
  constant HEBREWCoding (line 23) | HEBREWCoding byte = 0x07
  constant UCS2Coding (line 25) | UCS2Coding byte = 0x08
  type EncDec (line 29) | type EncDec interface
  type Encoding (line 35) | type Encoding interface
  function encode (line 40) | func encode(str string, encoder *encoding.Encoder) ([]byte, error) {
  function decode (line 44) | func decode(data []byte, decoder *encoding.Decoder) (st string, err erro...
  type CustomEncoding (line 53) | type CustomEncoding struct
    method Encode (line 67) | func (c *CustomEncoding) Encode(str string) ([]byte, error) {
    method Decode (line 72) | func (c *CustomEncoding) Decode(data []byte) (string, error) {
    method DataCoding (line 77) | func (c *CustomEncoding) DataCoding() byte {
  function NewCustomEncoding (line 59) | func NewCustomEncoding(coding byte, encDec EncDec) Encoding {
  type gsm7bit (line 81) | type gsm7bit struct
    method Encode (line 85) | func (c *gsm7bit) Encode(str string) ([]byte, error) {
    method Decode (line 89) | func (c *gsm7bit) Decode(data []byte) (string, error) {
    method DataCoding (line 93) | func (c *gsm7bit) DataCoding() byte { return GSM7BITCoding }
    method ShouldSplit (line 95) | func (c *gsm7bit) ShouldSplit(text string, octetLimit uint) (shouldSpl...
    method EncodeSplit (line 103) | func (c *gsm7bit) EncodeSplit(text string, octetLimit uint) (allSeg []...
  type gsm7bitPacked (line 127) | type gsm7bitPacked struct
    method Encode (line 130) | func (c *gsm7bitPacked) Encode(str string) ([]byte, error) {
    method Decode (line 134) | func (c *gsm7bitPacked) Decode(data []byte) (string, error) {
    method DataCoding (line 138) | func (c *gsm7bitPacked) DataCoding() byte { return GSM7BITCoding }
    method ShouldSplit (line 140) | func (c *gsm7bitPacked) ShouldSplit(text string, octetLimit uint) (sho...
    method GetSeptetCount (line 151) | func (c *gsm7bitPacked) GetSeptetCount(runeSlice []rune) int {
    method EncodeSplit (line 158) | func (c *gsm7bitPacked) EncodeSplit(text string, octetLimit uint) (all...
  function determineTo (line 195) | func determineTo(from int, to int, lim int, runeSlice []rune) int {
  function shiftBitsLeftOne (line 222) | func shiftBitsLeftOne(input []byte, includeLSB bool) []byte {
  type ascii (line 239) | type ascii struct
    method Encode (line 241) | func (*ascii) Encode(str string) ([]byte, error) {
    method Decode (line 245) | func (*ascii) Decode(data []byte) (string, error) {
    method DataCoding (line 249) | func (*ascii) DataCoding() byte { return ASCIICoding }
  type iso88591 (line 251) | type iso88591 struct
    method Encode (line 253) | func (*iso88591) Encode(str string) ([]byte, error) {
    method Decode (line 257) | func (*iso88591) Decode(data []byte) (string, error) {
    method DataCoding (line 261) | func (*iso88591) DataCoding() byte { return LATIN1Coding }
  type binary8bit1 (line 263) | type binary8bit1 struct
    method Encode (line 265) | func (*binary8bit1) Encode(_ string) ([]byte, error) {
    method Decode (line 269) | func (*binary8bit1) Decode(_ []byte) (string, error) {
    method DataCoding (line 273) | func (*binary8bit1) DataCoding() byte { return BINARY8BIT1Coding }
  type binary8bit2 (line 275) | type binary8bit2 struct
    method Encode (line 277) | func (*binary8bit2) Encode(_ string) ([]byte, error) {
    method Decode (line 281) | func (*binary8bit2) Decode(_ []byte) (string, error) {
    method DataCoding (line 285) | func (*binary8bit2) DataCoding() byte { return BINARY8BIT2Coding }
  type iso88595 (line 287) | type iso88595 struct
    method Encode (line 289) | func (*iso88595) Encode(str string) ([]byte, error) {
    method Decode (line 293) | func (*iso88595) Decode(data []byte) (string, error) {
    method DataCoding (line 297) | func (*iso88595) DataCoding() byte { return CYRILLICCoding }
  type iso88598 (line 299) | type iso88598 struct
    method Encode (line 301) | func (*iso88598) Encode(str string) ([]byte, error) {
    method Decode (line 305) | func (*iso88598) Decode(data []byte) (string, error) {
    method DataCoding (line 309) | func (*iso88598) DataCoding() byte { return HEBREWCoding }
  type ucs2 (line 311) | type ucs2 struct
    method Encode (line 313) | func (*ucs2) Encode(str string) ([]byte, error) {
    method Decode (line 318) | func (*ucs2) Decode(data []byte) (string, error) {
    method ShouldSplit (line 323) | func (*ucs2) ShouldSplit(text string, octetLimit uint) (shouldSplit bo...
    method EncodeSplit (line 328) | func (c *ucs2) EncodeSplit(text string, octetLimit uint) (allSeg [][]b...
    method DataCoding (line 356) | func (*ucs2) DataCoding() byte { return UCS2Coding }
  function FromDataCoding (line 401) | func FromDataCoding(code byte) (enc Encoding) {
  type Splitter (line 412) | type Splitter interface

FILE: data/codings_test.go
  function fromHex (line 11) | func fromHex(h string) (v []byte) {
  function testEncoding (line 20) | func testEncoding(t *testing.T, enc EncDec, original, expected string) {
  function testEncodingSplit (line 30) | func testEncodingSplit(t *testing.T, enc EncDec, octetLim uint, original...
  function shiftBitsOneRight (line 51) | func shiftBitsOneRight(input []byte) []byte {
  function TestCoding (line 66) | func TestCoding(t *testing.T) {
  function TestGSM7Bit (line 76) | func TestGSM7Bit(t *testing.T) {
  function TestShouldSplit (line 81) | func TestShouldSplit(t *testing.T) {
  function TestSplit (line 134) | func TestSplit(t *testing.T) {
  function TestSplit_GSM7BITPACKED (line 193) | func TestSplit_GSM7BITPACKED(t *testing.T) {
  function TestAscii (line 320) | func TestAscii(t *testing.T) {
  function TestUCS2 (line 325) | func TestUCS2(t *testing.T) {
  function TestLatin1 (line 330) | func TestLatin1(t *testing.T) {
  function TestCYRILLIC (line 335) | func TestCYRILLIC(t *testing.T) {
  function TestHebrew (line 340) | func TestHebrew(t *testing.T) {
  function TestOtherCodings (line 345) | func TestOtherCodings(t *testing.T) {
  type noOpEncDec (line 352) | type noOpEncDec struct
    method Encode (line 354) | func (*noOpEncDec) Encode(str string) ([]byte, error) {
    method Decode (line 358) | func (*noOpEncDec) Decode(data []byte) (string, error) {
  function TestCustomEncoding (line 362) | func TestCustomEncoding(t *testing.T) {

FILE: data/header_data.go
  type CommandStatusType (line 6) | type CommandStatusType
  type CommandIDType (line 9) | type CommandIDType
  constant GENERIC_NACK (line 14) | GENERIC_NACK          = CommandIDType(-2147483648)
  constant BIND_RECEIVER (line 15) | BIND_RECEIVER         = CommandIDType(0x00000001)
  constant BIND_RECEIVER_RESP (line 16) | BIND_RECEIVER_RESP    = CommandIDType(-2147483647)
  constant BIND_TRANSMITTER (line 17) | BIND_TRANSMITTER      = CommandIDType(0x00000002)
  constant BIND_TRANSMITTER_RESP (line 18) | BIND_TRANSMITTER_RESP = CommandIDType(-2147483646)
  constant QUERY_SM (line 19) | QUERY_SM              = CommandIDType(0x00000003)
  constant QUERY_SM_RESP (line 20) | QUERY_SM_RESP         = CommandIDType(-2147483645)
  constant SUBMIT_SM (line 21) | SUBMIT_SM             = CommandIDType(0x00000004)
  constant SUBMIT_SM_RESP (line 22) | SUBMIT_SM_RESP        = CommandIDType(-2147483644)
  constant DELIVER_SM (line 23) | DELIVER_SM            = CommandIDType(0x00000005)
  constant DELIVER_SM_RESP (line 24) | DELIVER_SM_RESP       = CommandIDType(-2147483643)
  constant UNBIND (line 25) | UNBIND                = CommandIDType(0x00000006)
  constant UNBIND_RESP (line 26) | UNBIND_RESP           = CommandIDType(-2147483642)
  constant REPLACE_SM (line 27) | REPLACE_SM            = CommandIDType(0x00000007)
  constant REPLACE_SM_RESP (line 28) | REPLACE_SM_RESP       = CommandIDType(-2147483641)
  constant CANCEL_SM (line 29) | CANCEL_SM             = CommandIDType(0x00000008)
  constant CANCEL_SM_RESP (line 30) | CANCEL_SM_RESP        = CommandIDType(-2147483640)
  constant BIND_TRANSCEIVER (line 31) | BIND_TRANSCEIVER      = CommandIDType(0x00000009)
  constant BIND_TRANSCEIVER_RESP (line 32) | BIND_TRANSCEIVER_RESP = CommandIDType(-2147483639)
  constant OUTBIND (line 33) | OUTBIND               = CommandIDType(0x0000000B)
  constant ENQUIRE_LINK (line 34) | ENQUIRE_LINK          = CommandIDType(0x00000015)
  constant ENQUIRE_LINK_RESP (line 35) | ENQUIRE_LINK_RESP     = CommandIDType(-2147483627)
  constant SUBMIT_MULTI (line 36) | SUBMIT_MULTI          = CommandIDType(0x00000021)
  constant SUBMIT_MULTI_RESP (line 37) | SUBMIT_MULTI_RESP     = CommandIDType(-2147483615)
  constant ALERT_NOTIFICATION (line 38) | ALERT_NOTIFICATION    = CommandIDType(0x00000102)
  constant DATA_SM (line 39) | DATA_SM               = CommandIDType(0x00000103)
  constant DATA_SM_RESP (line 40) | DATA_SM_RESP          = CommandIDType(-2147483389)
  constant ESME_ROK (line 46) | ESME_ROK           = CommandStatusType(0x00000000)
  constant ESME_RINVMSGLEN (line 47) | ESME_RINVMSGLEN    = CommandStatusType(0x00000001)
  constant ESME_RINVCMDLEN (line 48) | ESME_RINVCMDLEN    = CommandStatusType(0x00000002)
  constant ESME_RINVCMDID (line 49) | ESME_RINVCMDID     = CommandStatusType(0x00000003)
  constant ESME_RINVBNDSTS (line 50) | ESME_RINVBNDSTS    = CommandStatusType(0x00000004)
  constant ESME_RALYBND (line 51) | ESME_RALYBND       = CommandStatusType(0x00000005)
  constant ESME_RINVPRTFLG (line 52) | ESME_RINVPRTFLG    = CommandStatusType(0x00000006)
  constant ESME_RINVREGDLVFLG (line 53) | ESME_RINVREGDLVFLG = CommandStatusType(0x00000007)
  constant ESME_RSYSERR (line 54) | ESME_RSYSERR       = CommandStatusType(0x00000008)
  constant ESME_RINVSRCADR (line 55) | ESME_RINVSRCADR    = CommandStatusType(0x0000000A)
  constant ESME_RINVDSTADR (line 56) | ESME_RINVDSTADR    = CommandStatusType(0x0000000B)
  constant ESME_RINVMSGID (line 57) | ESME_RINVMSGID     = CommandStatusType(0x0000000C)
  constant ESME_RBINDFAIL (line 58) | ESME_RBINDFAIL     = CommandStatusType(0x0000000D)
  constant ESME_RINVPASWD (line 59) | ESME_RINVPASWD     = CommandStatusType(0x0000000E)
  constant ESME_RINVSYSID (line 60) | ESME_RINVSYSID     = CommandStatusType(0x0000000F)
  constant ESME_RCANCELFAIL (line 61) | ESME_RCANCELFAIL   = CommandStatusType(0x00000011)
  constant ESME_RREPLACEFAIL (line 62) | ESME_RREPLACEFAIL  = CommandStatusType(0x00000013)
  constant ESME_RMSGQFUL (line 63) | ESME_RMSGQFUL      = CommandStatusType(0x00000014)
  constant ESME_RINVSERTYP (line 64) | ESME_RINVSERTYP    = CommandStatusType(0x00000015)
  constant ESME_RADDCUSTFAIL (line 66) | ESME_RADDCUSTFAIL  = CommandStatusType(0x00000019)
  constant ESME_RDELCUSTFAIL (line 67) | ESME_RDELCUSTFAIL  = CommandStatusType(0x0000001A)
  constant ESME_RMODCUSTFAIL (line 68) | ESME_RMODCUSTFAIL  = CommandStatusType(0x0000001B)
  constant ESME_RENQCUSTFAIL (line 69) | ESME_RENQCUSTFAIL  = CommandStatusType(0x0000001C)
  constant ESME_RINVCUSTID (line 70) | ESME_RINVCUSTID    = CommandStatusType(0x0000001D)
  constant ESME_RINVCUSTNAME (line 71) | ESME_RINVCUSTNAME  = CommandStatusType(0x0000001F)
  constant ESME_RINVCUSTADR (line 72) | ESME_RINVCUSTADR   = CommandStatusType(0x00000021)
  constant ESME_RINVADR (line 73) | ESME_RINVADR       = CommandStatusType(0x00000022)
  constant ESME_RCUSTEXIST (line 74) | ESME_RCUSTEXIST    = CommandStatusType(0x00000023)
  constant ESME_RCUSTNOTEXIST (line 75) | ESME_RCUSTNOTEXIST = CommandStatusType(0x00000024)
  constant ESME_RADDDLFAIL (line 76) | ESME_RADDDLFAIL    = CommandStatusType(0x00000026)
  constant ESME_RMODDLFAIL (line 77) | ESME_RMODDLFAIL    = CommandStatusType(0x00000027)
  constant ESME_RDELDLFAIL (line 78) | ESME_RDELDLFAIL    = CommandStatusType(0x00000028)
  constant ESME_RVIEWDLFAIL (line 79) | ESME_RVIEWDLFAIL   = CommandStatusType(0x00000029)
  constant ESME_RLISTDLSFAIL (line 80) | ESME_RLISTDLSFAIL  = CommandStatusType(0x00000030)
  constant ESME_RPARAMRETFAIL (line 81) | ESME_RPARAMRETFAIL = CommandStatusType(0x00000031)
  constant ESME_RINVPARAM (line 82) | ESME_RINVPARAM     = CommandStatusType(0x00000032)
  constant ESME_RINVNUMDESTS (line 84) | ESME_RINVNUMDESTS = CommandStatusType(0x00000033)
  constant ESME_RINVDLNAME (line 85) | ESME_RINVDLNAME   = CommandStatusType(0x00000034)
  constant ESME_RINVDLMEMBDESC (line 87) | ESME_RINVDLMEMBDESC = CommandStatusType(0x00000035)
  constant ESME_RINVDLMEMBTYP (line 88) | ESME_RINVDLMEMBTYP  = CommandStatusType(0x00000038)
  constant ESME_RINVDLMODOPT (line 89) | ESME_RINVDLMODOPT   = CommandStatusType(0x00000039)
  constant ESME_RINVDESTFLAG (line 91) | ESME_RINVDESTFLAG = CommandStatusType(0x00000040)
  constant ESME_RINVSUBREP (line 92) | ESME_RINVSUBREP   = CommandStatusType(0x00000042)
  constant ESME_RINVESMCLASS (line 93) | ESME_RINVESMCLASS = CommandStatusType(0x00000043)
  constant ESME_RCNTSUBDL (line 94) | ESME_RCNTSUBDL    = CommandStatusType(0x00000044)
  constant ESME_RSUBMITFAIL (line 95) | ESME_RSUBMITFAIL  = CommandStatusType(0x00000045)
  constant ESME_RINVSRCTON (line 96) | ESME_RINVSRCTON   = CommandStatusType(0x00000048)
  constant ESME_RINVSRCNPI (line 97) | ESME_RINVSRCNPI   = CommandStatusType(0x00000049)
  constant ESME_RINVDSTTON (line 98) | ESME_RINVDSTTON   = CommandStatusType(0x00000050)
  constant ESME_RINVDSTNPI (line 99) | ESME_RINVDSTNPI   = CommandStatusType(0x00000051)
  constant ESME_RINVSYSTYP (line 100) | ESME_RINVSYSTYP   = CommandStatusType(0x00000053)
  constant ESME_RINVREPFLAG (line 101) | ESME_RINVREPFLAG  = CommandStatusType(0x00000054)
  constant ESME_RINVNUMMSGS (line 102) | ESME_RINVNUMMSGS  = CommandStatusType(0x00000055)
  constant ESME_RTHROTTLED (line 103) | ESME_RTHROTTLED   = CommandStatusType(0x00000058)
  constant ESME_RPROVNOTALLWD (line 105) | ESME_RPROVNOTALLWD = CommandStatusType(0x00000059)
  constant ESME_RINVSCHED (line 107) | ESME_RINVSCHED    = CommandStatusType(0x00000061)
  constant ESME_RINVEXPIRY (line 108) | ESME_RINVEXPIRY   = CommandStatusType(0x00000062)
  constant ESME_RINVDFTMSGID (line 109) | ESME_RINVDFTMSGID = CommandStatusType(0x00000063)
  constant ESME_RX_T_APPN (line 110) | ESME_RX_T_APPN    = CommandStatusType(0x00000064)
  constant ESME_RX_P_APPN (line 111) | ESME_RX_P_APPN    = CommandStatusType(0x00000065)
  constant ESME_RX_R_APPN (line 112) | ESME_RX_R_APPN    = CommandStatusType(0x00000066)
  constant ESME_RQUERYFAIL (line 113) | ESME_RQUERYFAIL   = CommandStatusType(0x00000067)
  constant ESME_RINVPGCUSTID (line 115) | ESME_RINVPGCUSTID      = CommandStatusType(0x00000080)
  constant ESME_RINVPGCUSTIDLEN (line 116) | ESME_RINVPGCUSTIDLEN   = CommandStatusType(0x00000081)
  constant ESME_RINVCITYLEN (line 117) | ESME_RINVCITYLEN       = CommandStatusType(0x00000082)
  constant ESME_RINVSTATELEN (line 118) | ESME_RINVSTATELEN      = CommandStatusType(0x00000083)
  constant ESME_RINVZIPPREFIXLEN (line 119) | ESME_RINVZIPPREFIXLEN  = CommandStatusType(0x00000084)
  constant ESME_RINVZIPPOSTFIXLEN (line 120) | ESME_RINVZIPPOSTFIXLEN = CommandStatusType(0x00000085)
  constant ESME_RINVMINLEN (line 121) | ESME_RINVMINLEN        = CommandStatusType(0x00000086)
  constant ESME_RINVMIN (line 122) | ESME_RINVMIN           = CommandStatusType(0x00000087)
  constant ESME_RINVPINLEN (line 123) | ESME_RINVPINLEN        = CommandStatusType(0x00000088)
  constant ESME_RINVTERMCODELEN (line 124) | ESME_RINVTERMCODELEN   = CommandStatusType(0x00000089)
  constant ESME_RINVCHANNELLEN (line 125) | ESME_RINVCHANNELLEN    = CommandStatusType(0x0000008A)
  constant ESME_RINVCOVREGIONLEN (line 126) | ESME_RINVCOVREGIONLEN  = CommandStatusType(0x0000008B)
  constant ESME_RINVCAPCODELEN (line 127) | ESME_RINVCAPCODELEN    = CommandStatusType(0x0000008C)
  constant ESME_RINVMDTLEN (line 128) | ESME_RINVMDTLEN        = CommandStatusType(0x0000008D)
  constant ESME_RINVPRIORMSGLEN (line 129) | ESME_RINVPRIORMSGLEN   = CommandStatusType(0x0000008E)
  constant ESME_RINVPERMSGLEN (line 130) | ESME_RINVPERMSGLEN     = CommandStatusType(0x0000008F)
  constant ESME_RINVPGALERTLEN (line 131) | ESME_RINVPGALERTLEN    = CommandStatusType(0x00000090)
  constant ESME_RINVSMUSERLEN (line 132) | ESME_RINVSMUSERLEN     = CommandStatusType(0x00000091)
  constant ESME_RINVRTDBLEN (line 133) | ESME_RINVRTDBLEN       = CommandStatusType(0x00000092)
  constant ESME_RINVREGDELLEN (line 134) | ESME_RINVREGDELLEN     = CommandStatusType(0x00000093)
  constant ESME_RINVMSGDISTLEN (line 135) | ESME_RINVMSGDISTLEN    = CommandStatusType(0x00000094)
  constant ESME_RINVPRIORMSG (line 136) | ESME_RINVPRIORMSG      = CommandStatusType(0x00000095)
  constant ESME_RINVMDT (line 137) | ESME_RINVMDT           = CommandStatusType(0x00000096)
  constant ESME_RINVPERMSG (line 138) | ESME_RINVPERMSG        = CommandStatusType(0x00000097)
  constant ESME_RINVMSGDIST (line 139) | ESME_RINVMSGDIST       = CommandStatusType(0x00000098)
  constant ESME_RINVPGALERT (line 140) | ESME_RINVPGALERT       = CommandStatusType(0x00000099)
  constant ESME_RINVSMUSER (line 141) | ESME_RINVSMUSER        = CommandStatusType(0x0000009A)
  constant ESME_RINVRTDB (line 142) | ESME_RINVRTDB          = CommandStatusType(0x0000009B)
  constant ESME_RINVREGDEL (line 143) | ESME_RINVREGDEL        = CommandStatusType(0x0000009C)
  constant ESME_RINVOPTPARLEN (line 144) | ESME_RINVOPTPARLEN     = CommandStatusType(0x0000009F)
  constant ESME_RINVOPTPARSTREAM (line 145) | ESME_RINVOPTPARSTREAM  = CommandStatusType(0x000000C0)
  constant ESME_ROPTPARNOTALLWD (line 146) | ESME_ROPTPARNOTALLWD   = CommandStatusType(0x000000C1)
  constant ESME_RINVPARLEN (line 147) | ESME_RINVPARLEN        = CommandStatusType(0x000000C2)
  constant ESME_RMISSINGOPTPARAM (line 148) | ESME_RMISSINGOPTPARAM  = CommandStatusType(0x000000C3)
  constant ESME_RINVOPTPARAMVAL (line 149) | ESME_RINVOPTPARAMVAL   = CommandStatusType(0x000000C4)
  constant ESME_RDELIVERYFAILURE (line 150) | ESME_RDELIVERYFAILURE  = CommandStatusType(0x000000FE)
  constant ESME_RUNKNOWNERR (line 151) | ESME_RUNKNOWNERR       = CommandStatusType(0x000000FF)
  constant ESME_LAST_ERROR (line 153) | ESME_LAST_ERROR = CommandStatusType(0x0000012C)

FILE: data/header_data_string.go
  function _ (line 7) | func _() {
  constant _CommandStatusType_name (line 113) | _CommandStatusType_name = "ESME_ROKESME_RINVMSGLENESME_RINVCMDLENESME_RI...
  method String (line 218) | func (i CommandStatusType) String() string {
  method Desc (line 225) | func (i CommandStatusType) Desc() string {
  function _ (line 431) | func _() {
  constant _CommandIDType_name_0 (line 465) | _CommandIDType_name_0 = "GENERIC_NACKBIND_RECEIVER_RESPBIND_TRANSMITTER_...
  constant _CommandIDType_name_1 (line 466) | _CommandIDType_name_1 = "ENQUIRE_LINK_RESP"
  constant _CommandIDType_name_2 (line 467) | _CommandIDType_name_2 = "SUBMIT_MULTI_RESP"
  constant _CommandIDType_name_3 (line 468) | _CommandIDType_name_3 = "DATA_SM_RESP"
  constant _CommandIDType_name_4 (line 469) | _CommandIDType_name_4 = "BIND_RECEIVERBIND_TRANSMITTERQUERY_SMSUBMIT_SMD...
  constant _CommandIDType_name_5 (line 470) | _CommandIDType_name_5 = "OUTBIND"
  constant _CommandIDType_name_6 (line 471) | _CommandIDType_name_6 = "ENQUIRE_LINK"
  constant _CommandIDType_name_7 (line 472) | _CommandIDType_name_7 = "SUBMIT_MULTI"
  constant _CommandIDType_name_8 (line 473) | _CommandIDType_name_8 = "ALERT_NOTIFICATIONDATA_SM"
  method String (line 482) | func (i CommandIDType) String() string {

FILE: data/other_codings.go
  type utf16BEM (line 21) | type utf16BEM struct
    method Encode (line 23) | func (c utf16BEM) Encode(str string) ([]byte, error) {
    method Decode (line 28) | func (c utf16BEM) Decode(data []byte) (string, error) {
  type utf16LEM (line 33) | type utf16LEM struct
    method Encode (line 35) | func (c utf16LEM) Encode(str string) ([]byte, error) {
    method Decode (line 40) | func (c utf16LEM) Decode(data []byte) (string, error) {
  type utf16BE (line 45) | type utf16BE struct
    method Encode (line 47) | func (c utf16BE) Encode(str string) ([]byte, error) {
    method Decode (line 52) | func (c utf16BE) Decode(data []byte) (string, error) {
  type utf16LE (line 57) | type utf16LE struct
    method Encode (line 59) | func (c utf16LE) Encode(str string) ([]byte, error) {
    method Decode (line 64) | func (c utf16LE) Decode(data []byte) (string, error) {

FILE: data/pkg.go
  constant SM_CONNID_LEN (line 10) | SM_CONNID_LEN        = 16
  constant SM_MSG_LEN (line 11) | SM_MSG_LEN           = 254
  constant SM_SYSID_LEN (line 12) | SM_SYSID_LEN         = 16
  constant SM_MSGID_LEN (line 13) | SM_MSGID_LEN         = 64
  constant SM_PASS_LEN (line 14) | SM_PASS_LEN          = 9
  constant SM_DATE_LEN (line 15) | SM_DATE_LEN          = 17
  constant SM_SRVTYPE_LEN (line 16) | SM_SRVTYPE_LEN       = 6
  constant SM_SYSTYPE_LEN (line 17) | SM_SYSTYPE_LEN       = 13
  constant SM_ADDR_LEN (line 18) | SM_ADDR_LEN          = 21
  constant SM_DATA_ADDR_LEN (line 19) | SM_DATA_ADDR_LEN     = 65
  constant SM_ADDR_RANGE_LEN (line 20) | SM_ADDR_RANGE_LEN    = 41
  constant SM_TYPE_LEN (line 21) | SM_TYPE_LEN          = 13
  constant SM_DL_NAME_LEN (line 22) | SM_DL_NAME_LEN       = 21
  constant SM_PARAM_NAME_LEN (line 23) | SM_PARAM_NAME_LEN    = 10
  constant SM_PARAM_VALUE_LEN (line 24) | SM_PARAM_VALUE_LEN   = 10
  constant SM_MAX_CNT_DEST_ADDR (line 25) | SM_MAX_CNT_DEST_ADDR = 254
  constant SM_GSM_MSG_LEN (line 28) | SM_GSM_MSG_LEN = 140
  constant CONNECTION_CLOSED (line 30) | CONNECTION_CLOSED = 0
  constant CONNECTION_OPENED (line 31) | CONNECTION_OPENED = 1
  constant SM_ACK (line 33) | SM_ACK            = 1
  constant SM_NO_ACK (line 34) | SM_NO_ACK         = 0
  constant SM_RESPONSE_ACK (line 35) | SM_RESPONSE_ACK   = 0
  constant SM_RESPONSE_TNACK (line 36) | SM_RESPONSE_TNACK = 1
  constant SM_RESPONSE_PNACK (line 37) | SM_RESPONSE_PNACK = 2
  constant SMPP_V33 (line 40) | SMPP_V33 int8 = int8(-0x33)
  constant SMPP_V34 (line 41) | SMPP_V34      = byte(0x34)
  constant GSM_TON_UNKNOWN (line 44) | GSM_TON_UNKNOWN       = byte(0x00)
  constant GSM_TON_INTERNATIONAL (line 45) | GSM_TON_INTERNATIONAL = byte(0x01)
  constant GSM_TON_NATIONAL (line 46) | GSM_TON_NATIONAL      = byte(0x02)
  constant GSM_TON_NETWORK (line 47) | GSM_TON_NETWORK       = byte(0x03)
  constant GSM_TON_SUBSCRIBER (line 48) | GSM_TON_SUBSCRIBER    = byte(0x04)
  constant GSM_TON_ALPHANUMERIC (line 49) | GSM_TON_ALPHANUMERIC  = byte(0x05)
  constant GSM_TON_ABBREVIATED (line 50) | GSM_TON_ABBREVIATED   = byte(0x06)
  constant GSM_TON_RESERVED_EXTN (line 51) | GSM_TON_RESERVED_EXTN = byte(0x07)
  constant GSM_NPI_UNKNOWN (line 54) | GSM_NPI_UNKNOWN       = byte(0x00)
  constant GSM_NPI_E164 (line 55) | GSM_NPI_E164          = byte(0x01)
  constant GSM_NPI_ISDN (line 56) | GSM_NPI_ISDN          = GSM_NPI_E164
  constant GSM_NPI_X121 (line 57) | GSM_NPI_X121          = byte(0x03)
  constant GSM_NPI_TELEX (line 58) | GSM_NPI_TELEX         = byte(0x04)
  constant GSM_NPI_LAND_MOBILE (line 59) | GSM_NPI_LAND_MOBILE   = byte(0x06)
  constant GSM_NPI_NATIONAL (line 60) | GSM_NPI_NATIONAL      = byte(0x08)
  constant GSM_NPI_PRIVATE (line 61) | GSM_NPI_PRIVATE       = byte(0x09)
  constant GSM_NPI_ERMES (line 62) | GSM_NPI_ERMES         = byte(0x0A)
  constant GSM_NPI_INTERNET (line 63) | GSM_NPI_INTERNET      = byte(0x0E)
  constant GSM_NPI_WAP_CLIENT_ID (line 64) | GSM_NPI_WAP_CLIENT_ID = byte(0x12)
  constant GSM_NPI_RESERVED_EXTN (line 65) | GSM_NPI_RESERVED_EXTN = byte(0x0F)
  constant SERVICE_NULL (line 68) | SERVICE_NULL string = ""
  constant SERVICE_CMT (line 69) | SERVICE_CMT  string = "CMT"
  constant SERVICE_CPT (line 70) | SERVICE_CPT  string = "CPT"
  constant SERVICE_VMN (line 71) | SERVICE_VMN  string = "VMN"
  constant SERVICE_VMA (line 72) | SERVICE_VMA  string = "VMA"
  constant SERVICE_WAP (line 73) | SERVICE_WAP  string = "WAP"
  constant SERVICE_USSD (line 74) | SERVICE_USSD string = "USSD"
  constant SMPP_PROTOCOL (line 76) | SMPP_PROTOCOL                 = byte(1)
  constant SMPPP_PROTOCOL (line 77) | SMPPP_PROTOCOL                = byte(2)
  constant SM_SERVICE_MOBILE_TERMINATED (line 78) | SM_SERVICE_MOBILE_TERMINATED  = byte(0)
  constant SM_SERVICE_MOBILE_ORIGINATED (line 79) | SM_SERVICE_MOBILE_ORIGINATED  = byte(1)
  constant SM_SERVICE_MOBILE_TRANSCEIVER (line 80) | SM_SERVICE_MOBILE_TRANSCEIVER = byte(2)
  constant SM_STATE_EN_ROUTE (line 83) | SM_STATE_EN_ROUTE      = 1
  constant SM_STATE_DELIVERED (line 84) | SM_STATE_DELIVERED     = 2
  constant SM_STATE_EXPIRED (line 85) | SM_STATE_EXPIRED       = 3
  constant SM_STATE_DELETED (line 86) | SM_STATE_DELETED       = 4
  constant SM_STATE_UNDELIVERABLE (line 87) | SM_STATE_UNDELIVERABLE = 5
  constant SM_STATE_ACCEPTED (line 88) | SM_STATE_ACCEPTED      = 6
  constant SM_STATE_INVALID (line 89) | SM_STATE_INVALID       = 7
  constant SM_STATE_REJECTED (line 90) | SM_STATE_REJECTED      = 8
  constant SM_ESM_DEFAULT (line 97) | SM_ESM_DEFAULT        = 0x00
  constant SM_DATAGRAM_MODE (line 98) | SM_DATAGRAM_MODE      = 0x01
  constant SM_FORWARD_MODE (line 99) | SM_FORWARD_MODE       = 0x02
  constant SM_STORE_FORWARD_MODE (line 100) | SM_STORE_FORWARD_MODE = 0x03
  constant SM_SMSC_DLV_RCPT_TYPE (line 103) | SM_SMSC_DLV_RCPT_TYPE     = 0x04
  constant SM_ESME_DLV_ACK_TYPE (line 104) | SM_ESME_DLV_ACK_TYPE      = 0x08
  constant SM_ESME_MAN_USER_ACK_TYPE (line 105) | SM_ESME_MAN_USER_ACK_TYPE = 0x10
  constant SM_CONV_ABORT_TYPE (line 106) | SM_CONV_ABORT_TYPE        = 0x18
  constant SM_INTMD_DLV_NOTIFY_TYPE (line 107) | SM_INTMD_DLV_NOTIFY_TYPE  = 0x20
  constant SM_NONE_GSM (line 110) | SM_NONE_GSM           = 0x00
  constant SM_UDH_GSM (line 111) | SM_UDH_GSM            = 0x40
  constant SM_REPLY_PATH_GSM (line 112) | SM_REPLY_PATH_GSM     = 0x80
  constant SM_UDH_REPLY_PATH_GSM (line 113) | SM_UDH_REPLY_PATH_GSM = 0xC0
  constant OPT_PAR_MSG_WAIT (line 119) | OPT_PAR_MSG_WAIT = 2
  constant OPT_PAR_PRIV_IND (line 122) | OPT_PAR_PRIV_IND = 0x0201
  constant OPT_PAR_SRC_SUBADDR (line 125) | OPT_PAR_SRC_SUBADDR     = 0x0202
  constant OPT_PAR_SRC_SUBADDR_MIN (line 126) | OPT_PAR_SRC_SUBADDR_MIN = 2
  constant OPT_PAR_SRC_SUBADDR_MAX (line 127) | OPT_PAR_SRC_SUBADDR_MAX = 23
  constant OPT_PAR_DEST_SUBADDR (line 130) | OPT_PAR_DEST_SUBADDR     = 0x0203
  constant OPT_PAR_DEST_SUBADDR_MIN (line 131) | OPT_PAR_DEST_SUBADDR_MIN = 2
  constant OPT_PAR_DEST_SUBADDR_MAX (line 132) | OPT_PAR_DEST_SUBADDR_MAX = 23
  constant OPT_PAR_USER_MSG_REF (line 135) | OPT_PAR_USER_MSG_REF = 0x0204
  constant OPT_PAR_USER_RESP_CODE (line 138) | OPT_PAR_USER_RESP_CODE = 0x0205
  constant OPT_PAR_LANG_IND (line 141) | OPT_PAR_LANG_IND = 0x020D
  constant OPT_PAR_SRC_PORT (line 144) | OPT_PAR_SRC_PORT = 0x020A
  constant OPT_PAR_DST_PORT (line 147) | OPT_PAR_DST_PORT = 0x020B
  constant OPT_PAR_SAR_MSG_REF_NUM (line 150) | OPT_PAR_SAR_MSG_REF_NUM = 0x020C
  constant OPT_PAR_SAR_TOT_SEG (line 153) | OPT_PAR_SAR_TOT_SEG = 0x020E
  constant OPT_PAR_SAR_SEG_SNUM (line 156) | OPT_PAR_SAR_SEG_SNUM = 0x020F
  constant OPT_PAR_SC_IF_VER (line 159) | OPT_PAR_SC_IF_VER = 0x0210
  constant OPT_PAR_DISPLAY_TIME (line 162) | OPT_PAR_DISPLAY_TIME = 0x1201
  constant OPT_PAR_MS_VALIDITY (line 165) | OPT_PAR_MS_VALIDITY = 0x1204
  constant OPT_PAR_DPF_RES (line 168) | OPT_PAR_DPF_RES = 0x0420
  constant OPT_PAR_SET_DPF (line 171) | OPT_PAR_SET_DPF = 0x0421
  constant OPT_PAR_MS_AVAIL_STAT (line 174) | OPT_PAR_MS_AVAIL_STAT = 0x0422
  constant OPT_PAR_NW_ERR_CODE (line 177) | OPT_PAR_NW_ERR_CODE     = 0x0423
  constant OPT_PAR_NW_ERR_CODE_MIN (line 178) | OPT_PAR_NW_ERR_CODE_MIN = 3
  constant OPT_PAR_NW_ERR_CODE_MAX (line 179) | OPT_PAR_NW_ERR_CODE_MAX = 3
  constant OPT_PAR_DEL_FAIL_RSN (line 184) | OPT_PAR_DEL_FAIL_RSN = 0x0425
  constant OPT_PAR_MORE_MSGS (line 187) | OPT_PAR_MORE_MSGS = 0x0426
  constant OPT_PAR_MSG_STATE (line 190) | OPT_PAR_MSG_STATE = 0x0427
  constant OPT_PAR_CALLBACK_NUM (line 193) | OPT_PAR_CALLBACK_NUM     = 0x0381
  constant OPT_PAR_CALLBACK_NUM_MIN (line 194) | OPT_PAR_CALLBACK_NUM_MIN = 4
  constant OPT_PAR_CALLBACK_NUM_MAX (line 195) | OPT_PAR_CALLBACK_NUM_MAX = 19
  constant OPT_PAR_CALLBACK_NUM_PRES_IND (line 198) | OPT_PAR_CALLBACK_NUM_PRES_IND = 0x0302
  constant OPT_PAR_CALLBACK_NUM_ATAG (line 201) | OPT_PAR_CALLBACK_NUM_ATAG     = 0x0303
  constant OPT_PAR_CALLBACK_NUM_ATAG_MIN (line 202) | OPT_PAR_CALLBACK_NUM_ATAG_MIN = 1
  constant OPT_PAR_CALLBACK_NUM_ATAG_MAX (line 203) | OPT_PAR_CALLBACK_NUM_ATAG_MAX = 65
  constant OPT_PAR_NUM_MSGS (line 206) | OPT_PAR_NUM_MSGS = 0x0304
  constant OPT_PAR_SMS_SIGNAL (line 209) | OPT_PAR_SMS_SIGNAL = 0x1203
  constant OPT_PAR_ALERT_ON_MSG_DELIVERY (line 212) | OPT_PAR_ALERT_ON_MSG_DELIVERY = 0x130C
  constant OPT_PAR_ITS_REPLY_TYPE (line 215) | OPT_PAR_ITS_REPLY_TYPE = 0x1380
  constant OPT_PAR_ITS_SESSION_INFO (line 218) | OPT_PAR_ITS_SESSION_INFO = 0x1383
  constant OPT_PAR_USSD_SER_OP (line 221) | OPT_PAR_USSD_SER_OP = 0x0501
  constant SM_NOPRIORITY (line 224) | SM_NOPRIORITY = 0
  constant SM_PRIORITY (line 225) | SM_PRIORITY   = 1
  constant SM_SMSC_RECEIPT_MASK (line 229) | SM_SMSC_RECEIPT_MASK          = byte(0x03)
  constant SM_SMSC_RECEIPT_NOT_REQUESTED (line 230) | SM_SMSC_RECEIPT_NOT_REQUESTED = byte(0x00)
  constant SM_SMSC_RECEIPT_REQUESTED (line 231) | SM_SMSC_RECEIPT_REQUESTED     = byte(0x01)
  constant SM_SMSC_RECEIPT_ON_FAILURE (line 232) | SM_SMSC_RECEIPT_ON_FAILURE    = byte(0x02)
  constant SM_SME_ACK_MASK (line 234) | SM_SME_ACK_MASK               = byte(0x0c)
  constant SM_SME_ACK_NOT_REQUESTED (line 235) | SM_SME_ACK_NOT_REQUESTED      = byte(0x00)
  constant SM_SME_ACK_DELIVERY_REQUESTED (line 236) | SM_SME_ACK_DELIVERY_REQUESTED = byte(0x04)
  constant SM_SME_ACK_MANUAL_REQUESTED (line 237) | SM_SME_ACK_MANUAL_REQUESTED   = byte(0x08)
  constant SM_SME_ACK_BOTH_REQUESTED (line 238) | SM_SME_ACK_BOTH_REQUESTED     = byte(0x0c)
  constant SM_NOTIF_MASK (line 240) | SM_NOTIF_MASK          = byte(0x010)
  constant SM_NOTIF_NOT_REQUESTED (line 241) | SM_NOTIF_NOT_REQUESTED = byte(0x000)
  constant SM_NOTIF_REQUESTED (line 242) | SM_NOTIF_REQUESTED     = byte(0x010)
  constant SM_NOREPLACE (line 245) | SM_NOREPLACE = 0
  constant SM_REPLACE (line 246) | SM_REPLACE   = 1
  constant SM_DEST_SME_ADDRESS (line 249) | SM_DEST_SME_ADDRESS = 1
  constant SM_DEST_DL_NAME (line 250) | SM_DEST_DL_NAME     = 2
  constant SM_LAYER_WDP (line 253) | SM_LAYER_WDP  = 0
  constant SM_LAYER_WCMP (line 254) | SM_LAYER_WCMP = 1
  constant SM_OPCLASS_DATAGRAM (line 257) | SM_OPCLASS_DATAGRAM    = 0
  constant SM_OPCLASS_TRANSACTION (line 258) | SM_OPCLASS_TRANSACTION = 3
  constant OPT_PAR_ORIG_MSC_ADDR (line 261) | OPT_PAR_ORIG_MSC_ADDR     = -32639
  constant OPT_PAR_ORIG_MSC_ADDR_MIN (line 262) | OPT_PAR_ORIG_MSC_ADDR_MIN = 1
  constant OPT_PAR_ORIG_MSC_ADDR_MAX (line 263) | OPT_PAR_ORIG_MSC_ADDR_MAX = 24
  constant OPT_PAR_DEST_MSC_ADDR (line 266) | OPT_PAR_DEST_MSC_ADDR     = -32638
  constant OPT_PAR_DEST_MSC_ADDR_MIN (line 267) | OPT_PAR_DEST_MSC_ADDR_MIN = 1
  constant OPT_PAR_DEST_MSC_ADDR_MAX (line 268) | OPT_PAR_DEST_MSC_ADDR_MAX = 24
  constant OPT_PAR_UNUSED (line 271) | OPT_PAR_UNUSED = 0xffff
  constant OPT_PAR_DST_ADDR_SUBUNIT (line 274) | OPT_PAR_DST_ADDR_SUBUNIT = 0x0005
  constant OPT_PAR_DST_NW_TYPE (line 277) | OPT_PAR_DST_NW_TYPE = 0x0006
  constant OPT_PAR_DST_BEAR_TYPE (line 280) | OPT_PAR_DST_BEAR_TYPE = 0x0007
  constant OPT_PAR_DST_TELE_ID (line 283) | OPT_PAR_DST_TELE_ID = 0x0008
  constant OPT_PAR_SRC_ADDR_SUBUNIT (line 286) | OPT_PAR_SRC_ADDR_SUBUNIT = 0x000D
  constant OPT_PAR_SRC_NW_TYPE (line 289) | OPT_PAR_SRC_NW_TYPE = 0x000E
  constant OPT_PAR_SRC_BEAR_TYPE (line 292) | OPT_PAR_SRC_BEAR_TYPE = 0x000F
  constant OPT_PAR_SRC_TELE_ID (line 295) | OPT_PAR_SRC_TELE_ID = 0x0010
  constant OPT_PAR_QOS_TIME_TO_LIVE (line 298) | OPT_PAR_QOS_TIME_TO_LIVE     = 0x0017
  constant OPT_PAR_QOS_TIME_TO_LIVE_MIN (line 299) | OPT_PAR_QOS_TIME_TO_LIVE_MIN = 1
  constant OPT_PAR_QOS_TIME_TO_LIVE_MAX (line 300) | OPT_PAR_QOS_TIME_TO_LIVE_MAX = 4
  constant OPT_PAR_PAYLOAD_TYPE (line 303) | OPT_PAR_PAYLOAD_TYPE = 0x0019
  constant OPT_PAR_ADD_STAT_INFO (line 306) | OPT_PAR_ADD_STAT_INFO     = 0x001D
  constant OPT_PAR_ADD_STAT_INFO_MIN (line 307) | OPT_PAR_ADD_STAT_INFO_MIN = 1
  constant OPT_PAR_ADD_STAT_INFO_MAX (line 308) | OPT_PAR_ADD_STAT_INFO_MAX = 256
  constant OPT_PAR_RECP_MSG_ID (line 311) | OPT_PAR_RECP_MSG_ID     = 0x001E
  constant OPT_PAR_RECP_MSG_ID_MIN (line 312) | OPT_PAR_RECP_MSG_ID_MIN = 1
  constant OPT_PAR_RECP_MSG_ID_MAX (line 313) | OPT_PAR_RECP_MSG_ID_MAX = 65
  constant OPT_PAR_MSG_PAYLOAD (line 316) | OPT_PAR_MSG_PAYLOAD     = 0x0424
  constant OPT_PAR_MSG_PAYLOAD_MIN (line 317) | OPT_PAR_MSG_PAYLOAD_MIN = 1
  constant OPT_PAR_MSG_PAYLOAD_MAX (line 318) | OPT_PAR_MSG_PAYLOAD_MAX = 1500
  constant UDH_CONCAT_MSG_8_BIT_REF (line 321) | UDH_CONCAT_MSG_8_BIT_REF  = byte(0x00)
  constant UDH_CONCAT_MSG_16_BIT_REF (line 322) | UDH_CONCAT_MSG_16_BIT_REF = byte(0x08)
  constant DFLT_MSGID (line 331) | DFLT_MSGID         string = ""
  constant DFLT_MSG (line 332) | DFLT_MSG           string = ""
  constant DFLT_SRVTYPE (line 333) | DFLT_SRVTYPE       string = ""
  constant DFLT_SYSID (line 334) | DFLT_SYSID         string = ""
  constant DFLT_PASS (line 335) | DFLT_PASS          string = ""
  constant DFLT_SYSTYPE (line 336) | DFLT_SYSTYPE       string = ""
  constant DFLT_ADDR_RANGE (line 337) | DFLT_ADDR_RANGE    string = ""
  constant DFLT_DATE (line 338) | DFLT_DATE          string = ""
  constant DFLT_ADDR (line 339) | DFLT_ADDR          string = ""
  constant DFLT_MSG_STATE (line 340) | DFLT_MSG_STATE     byte   = 0
  constant DFLT_ERR (line 341) | DFLT_ERR           byte   = 0
  constant DFLT_SCHEDULE (line 342) | DFLT_SCHEDULE      string = ""
  constant DFLT_VALIDITY (line 343) | DFLT_VALIDITY      string = ""
  constant DFLT_REG_DELIVERY (line 344) | DFLT_REG_DELIVERY         = SM_SMSC_RECEIPT_NOT_REQUESTED | SM_SME_ACK_N...
  constant DFLT_DFLTMSGID (line 345) | DFLT_DFLTMSGID            = byte(0)
  constant DFLT_MSG_LEN (line 346) | DFLT_MSG_LEN              = byte(0)
  constant DFLT_ESM_CLASS (line 347) | DFLT_ESM_CLASS            = byte(0)
  constant DFLT_DATA_CODING (line 348) | DFLT_DATA_CODING          = byte(0)
  constant DFLT_PROTOCOLID (line 349) | DFLT_PROTOCOLID           = byte(0)
  constant DFLT_PRIORITY_FLAG (line 350) | DFLT_PRIORITY_FLAG        = byte(0)
  constant DFTL_REPLACE_IFP (line 351) | DFTL_REPLACE_IFP          = byte(0)
  constant DFLT_DL_NAME (line 352) | DFLT_DL_NAME       string = ""
  constant DFLT_GSM_TON (line 353) | DFLT_GSM_TON              = GSM_TON_UNKNOWN
  constant DFLT_GSM_NPI (line 354) | DFLT_GSM_NPI              = GSM_NPI_UNKNOWN
  constant DFLT_DEST_FLAG (line 355) | DFLT_DEST_FLAG            = byte(0)
  constant MAX_PDU_LEN (line 356) | MAX_PDU_LEN               = 64 << 10
  constant PDU_HEADER_SIZE (line 358) | PDU_HEADER_SIZE = 16
  constant TLV_HEADER_SIZE (line 359) | TLV_HEADER_SIZE = 4
  constant RECEIVER_TIMEOUT (line 362) | RECEIVER_TIMEOUT           int64 = 60000
  constant CONNECTION_RECEIVE_TIMEOUT (line 363) | CONNECTION_RECEIVE_TIMEOUT int64 = 10000
  constant UNBIND_RECEIVE_TIMEOUT (line 364) | UNBIND_RECEIVE_TIMEOUT     int64 = 5000
  constant CONNECTION_SEND_TIMEOUT (line 365) | CONNECTION_SEND_TIMEOUT    int64 = 20000
  constant COMMS_TIMEOUT (line 366) | COMMS_TIMEOUT              int64 = 60000
  constant QUEUE_TIMEOUT (line 367) | QUEUE_TIMEOUT              int64 = 10000
  constant ACCEPT_TIMEOUT (line 368) | ACCEPT_TIMEOUT             int64 = 60000
  constant RECEIVE_BLOCKING (line 370) | RECEIVE_BLOCKING int64 = -1
  constant MAX_VALUE_PORT (line 372) | MAX_VALUE_PORT     = 65535
  constant MIN_VALUE_PORT (line 373) | MIN_VALUE_PORT     = 100
  constant MIN_LENGTH_ADDRESS (line 374) | MIN_LENGTH_ADDRESS = 7
  function init (line 389) | func init() {
  function SetDefaultTon (line 395) | func SetDefaultTon(dfltTon byte) {
  function GetDefaultTon (line 400) | func GetDefaultTon() byte {
  function SetDefaultNpi (line 405) | func SetDefaultNpi(dfltNpi byte) {
  function GetDefaultNpi (line 410) | func GetDefaultNpi() byte {

FILE: data/pkg_test.go
  function TestDefaultNpi (line 9) | func TestDefaultNpi(t *testing.T) {
  function TestDefaultTon (line 14) | func TestDefaultTon(t *testing.T) {

FILE: data/utils.go
  function FindEncoding (line 7) | func FindEncoding(s string) (enc Encoding) {
  function isASCII (line 16) | func isASCII(s string) bool {

FILE: data/utils_test.go
  function TestFindEncoding (line 9) | func TestFindEncoding(t *testing.T) {

FILE: errors/pkg.go
  type SmppErr (line 10) | type SmppErr struct
    method Error (line 16) | func (s *SmppErr) Error() string {

FILE: errors/pkg_test.go
  function TestErr (line 10) | func TestErr(t *testing.T) {

FILE: example/smsc_simulator/smsc.cpp
  function currentUSecsSinceEpoch (line 43) | uint64_t currentUSecsSinceEpoch(void) {
  class ClientConfig (line 51) | class ClientConfig {
    method ClientConfig (line 53) | ClientConfig() {}
    method ClientConfig (line 58) | static ClientConfig& instance() {
    method is (line 65) | bool is(string esme_id, ConfigEntry entry) { return false; }
  class MessageDeliverer (line 70) | class MessageDeliverer {
    class Message (line 72) | class Message {
      method Message (line 98) | Message() {}
      method Message (line 99) | Message(char* in) { content = in; }
      method string (line 102) | string getContent(void) { return content; }
      method setSource (line 104) | void setSource(uint8_t ton, uint8_t npi, char* addr) {
      method setDestination (line 109) | void setDestination(uint8_t ton, uint8_t npi, char* addr) {
      method setRegisteredDelivery (line 114) | void setRegisteredDelivery(uint8_t val) { registered_delivery = val; }
      method setShortMessage (line 115) | void setShortMessage(uint8_t* sm_in, uint8_t sm_len_in) {
      method setSMSCMessageID (line 119) | void setSMSCMessageID(char* id) { smscMessageID = id; }
    method MessageDeliverer (line 127) | MessageDeliverer() {}
    method empty (line 132) | bool empty(void) { return (mq.size() == 0); }
    method get (line 134) | bool get(Message& msgout) {
    method MessageDeliverer (line 156) | static MessageDeliverer* getInstance(string& systemID) {
    method getInstance_get (line 166) | static bool getInstance_get(string& systemID, Message& msgout) {
    method add (line 182) | void add(uint64_t timeDeliver, Message msg) {
  class SMPPSocket (line 201) | class SMPPSocket {
    method SMPPSocket (line 206) | SMPPSocket() {}
  class SMPPSocketUnencrypted (line 216) | class SMPPSocketUnencrypted : public SMPPSocket {
    method SMPPSocketUnencrypted (line 219) | SMPPSocketUnencrypted() {}
    method SMPPSocketUnencrypted (line 220) | SMPPSocketUnencrypted(int socket_in) { socket = socket_in; }
    method bytes_to_read (line 223) | long bytes_to_read(void) {
    method recvA (line 229) | bool recvA(uint8_t& oct) {
    method recv (line 233) | void recv(void) {}
    method send (line 234) | bool send(uint8_t* buf, int len) {
  class SMPP (line 241) | class SMPP {
    class CmdStatus (line 243) | class CmdStatus {
    class CmdID (line 254) | class CmdID {
    method GSMTimeStringShort (line 339) | static void GSMTimeStringShort(time_t& t, char* szTimestamp, int nLen) {
    method time_t (line 352) | static time_t GSMStringTime(const char* szBuf) {
    method time_t (line 388) | static time_t GSMRelativeTime(char* szBuf) {
  class SMPPConnection (line 398) | class SMPPConnection {
    class SMPPException (line 400) | class SMPPException {}
    method getInteger (line 434) | uint64_t getInteger(void) {
    method getBytes (line 444) | uint64_t getBytes(uint64_t len, uint8_t* mem) {
    method SMPPConnection (line 453) | SMPPConnection() {
    method setDebug (line 466) | void setDebug(bool val) { debug = val; }
    method allocateSocket (line 468) | void allocateSocket(void) { socket = new SMPPSocketUnencrypted; }
    method allocateSocket (line 470) | void allocateSocket(int fdsocket) {
    method setIP (line 474) | void setIP(char* ip_in) {
    method endian (line 483) | uint64_t endian(uint64_t a) {
    method put (line 492) | bool put(uint64_t sequence_number, uint64_t cmdID, uint64_t status,
    method get (line 514) | bool get() {
    method pduCommandID (line 571) | uint64_t pduCommandID(void) { return command_received_header.command_i...
    method pduSequenceNo (line 572) | uint64_t pduSequenceNo(void) {
  class Session (line 577) | class Session {
    method Session (line 582) | Session() {}
  class AdminSession (line 589) | class AdminSession : public Session {
    method AdminSession (line 591) | AdminSession() { sessionType = 0; }
    method AdminSession (line 592) | AdminSession(int fdsocket) {
    method timedCheck (line 597) | bool timedCheck(void) {
    method run (line 602) | bool run(void) { return true; }
  class SMPPSession (line 605) | class SMPPSession : public Session {
    method SMPPSession (line 627) | SMPPSession() {
    method SMPPSession (line 636) | SMPPSession(int fdsocket, char* ip) {
    method setDebug (line 651) | void setDebug(bool val) { conn.setDebug(val); }
    method getCOctetString (line 653) | bool getCOctetString(uint8_t* buf_ptr, int buf_len, int& idx, string& ...
    method timedCheck (line 668) | bool timedCheck(void) {
    method generateMO (line 746) | void generateMO(uint8_t source_addr_ton, uint8_t source_addr_npi,
    method generateReceipt (line 789) | void generateReceipt(uint8_t source_addr_ton, uint8_t source_addr_npi,
    method run (line 876) | bool run(void) {
    method getVersion (line 1193) | uint8_t getVersion(void) { return version; }
    method setVersion (line 1194) | void setVersion(uint8_t version_in) { version = version_in; }
    method logCommand (line 1196) | void logCommand(uint64_t cmdID, const char* direction) {
    method logCommand (line 1203) | void logCommand(char* logline, const char* direction) {
    method recv (line 1217) | bool recv(uint64_t& cmdID, uint64_t& seqNo) {
    method send (line 1227) | bool send(uint64_t seqNo, uint64_t cmdID, uint64_t cmdStatus, uint8_t*...
  function dolisten (line 1240) | int dolisten(int portno) {
  function main (line 1302) | int main(int argc, const char* argv[]) {

FILE: example/transceiver_with_auto_response/main.go
  function main (line 15) | func main() {
  function sendingAndReceiveSMS (line 24) | func sendingAndReceiveSMS(wg *sync.WaitGroup) {
  function handlePDU (line 75) | func handlePDU() func(pdu.PDU, bool) {
  function newSubmitSM (line 117) | func newSubmitSM() *pdu.SubmitSM {
  function isConcatenatedDone (line 141) | func isConcatenatedDone(parts []string, total byte) bool {

FILE: example/transceiver_with_manual_response/main.go
  function main (line 14) | func main() {
  function sendingAndReceiveSMS (line 23) | func sendingAndReceiveSMS(wg *sync.WaitGroup) {
  function handlePDU (line 74) | func handlePDU() func(pdu.PDU) (pdu.PDU, bool) {
  function newSubmitSM (line 109) | func newSubmitSM() *pdu.SubmitSM {

FILE: example/transeiver_with_custom_store/CustomStore.go
  type CustomStore (line 28) | type CustomStore struct
    method Set (line 39) | func (s CustomStore) Set(ctx context.Context, request gosmpp.Request) ...
    method Get (line 54) | func (s CustomStore) Get(ctx context.Context, sequenceNumber int32) (g...
    method List (line 72) | func (s CustomStore) List(ctx context.Context) []gosmpp.Request {
    method Delete (line 91) | func (s CustomStore) Delete(ctx context.Context, sequenceNumber int32)...
    method Clear (line 104) | func (s CustomStore) Clear(ctx context.Context) error {
    method Length (line 117) | func (s CustomStore) Length(ctx context.Context) (int, error) {
  function NewCustomStore (line 32) | func NewCustomStore() CustomStore {
  function serialize (line 126) | func serialize(request gosmpp.Request) ([]byte, error) {
  function deserialize (line 141) | func deserialize(bRequest []byte) (request gosmpp.Request, err error) {
  type requestGob (line 163) | type requestGob struct

FILE: example/transeiver_with_custom_store/main.go
  function main (line 15) | func main() {
  function sendingAndReceiveSMS (line 24) | func sendingAndReceiveSMS(wg *sync.WaitGroup) {
  function handleExpirePduRequest (line 101) | func handleExpirePduRequest() func(pdu.PDU) bool {
  function handleOnClosePduRequest (line 123) | func handleOnClosePduRequest() func(pdu.PDU) {
  function handleExpectedPduResponse (line 141) | func handleExpectedPduResponse() func(response gosmpp.Response) {
  function handleReceivedPduRequest (line 160) | func handleReceivedPduRequest() func(pdu.PDU) (pdu.PDU, bool) {
  function newSubmitSM (line 189) | func newSubmitSM() *pdu.SubmitSM {

FILE: example/transeiver_with_request_window_and_custom_submitSm/CustomSubmitSM.go
  type CustomSubmitSM (line 12) | type CustomSubmitSM struct
  function newCustomSubmitSM (line 19) | func newCustomSubmitSM() CustomSubmitSM {

FILE: example/transeiver_with_request_window_and_custom_submitSm/main.go
  function main (line 15) | func main() {
  function sendingAndReceiveSMS (line 24) | func sendingAndReceiveSMS(wg *sync.WaitGroup) {
  function handleExpirePduRequest (line 99) | func handleExpirePduRequest() func(pdu.PDU) bool {
  function handleOnClosePduRequest (line 120) | func handleOnClosePduRequest() func(pdu.PDU) {
  function handleExpectedPduResponse (line 138) | func handleExpectedPduResponse() func(response gosmpp.Response) {
  function handleReceivedPduRequest (line 157) | func handleReceivedPduRequest() func(pdu.PDU) (pdu.PDU, bool) {
  function newSubmitSM (line 186) | func newSubmitSM() *pdu.SubmitSM {

FILE: pdu/Address.go
  type Address (line 10) | type Address struct
    method Unmarshal (line 41) | func (c *Address) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 51) | func (c *Address) Marshal(b *ByteBuffer) {
    method SetTon (line 60) | func (c *Address) SetTon(ton byte) {
    method SetNpi (line 65) | func (c *Address) SetNpi(npi byte) {
    method SetAddress (line 70) | func (c *Address) SetAddress(addr string) (err error) {
    method Ton (line 80) | func (c Address) Ton() byte {
    method Npi (line 85) | func (c Address) Npi() byte {
    method Address (line 90) | func (c Address) Address() string {
    method String (line 95) | func (c Address) String() string {
  function NewAddress (line 17) | func NewAddress() Address {
  function NewAddressWithAddr (line 22) | func NewAddressWithAddr(addr string) (a Address, err error) {
  function NewAddressWithTonNpi (line 29) | func NewAddressWithTonNpi(ton, npi byte) Address {
  function NewAddressWithTonNpiAddr (line 34) | func NewAddressWithTonNpiAddr(ton, npi byte, addr string) (a Address, er...

FILE: pdu/AddressRange.go
  type AddressRange (line 6) | type AddressRange struct
    method Unmarshal (line 37) | func (c *AddressRange) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 47) | func (c *AddressRange) Marshal(b *ByteBuffer) {
  function NewAddressRange (line 13) | func NewAddressRange() AddressRange {
  function NewAddressRangeWithAddr (line 18) | func NewAddressRangeWithAddr(addr string) AddressRange {
  function NewAddressRangeWithTonNpi (line 25) | func NewAddressRangeWithTonNpi(ton, npi byte) AddressRange {
  function NewAddressRangeWithTonNpiAddr (line 30) | func NewAddressRangeWithTonNpiAddr(ton, npi byte, addr string) AddressRa...

FILE: pdu/AddressRange_test.go
  function TestAddressRange (line 9) | func TestAddressRange(t *testing.T) {

FILE: pdu/Address_test.go
  function TestAddress (line 9) | func TestAddress(t *testing.T) {

FILE: pdu/AlertNotification.go
  type AlertNotification (line 10) | type AlertNotification struct
    method CanResponse (line 26) | func (a *AlertNotification) CanResponse() bool {
    method GetResponse (line 31) | func (a *AlertNotification) GetResponse() PDU {
    method Marshal (line 36) | func (a *AlertNotification) Marshal(b *ByteBuffer) {
    method Unmarshal (line 44) | func (a *AlertNotification) Unmarshal(b *ByteBuffer) error {
  function NewAlertNotification (line 17) | func NewAlertNotification() PDU {

FILE: pdu/AlertNotification_test.go
  function TestAlertNotification (line 11) | func TestAlertNotification(t *testing.T) {

FILE: pdu/BindRequest.go
  type BindingType (line 8) | type BindingType
  constant Receiver (line 12) | Receiver BindingType = iota
  constant Transceiver (line 14) | Transceiver
  constant Transmitter (line 16) | Transmitter
  type BindRequest (line 20) | type BindRequest struct
    method CanResponse (line 72) | func (b *BindRequest) CanResponse() bool {
    method GetResponse (line 77) | func (b *BindRequest) GetResponse() PDU {
    method Marshal (line 82) | func (b *BindRequest) Marshal(w *ByteBuffer) {
    method Unmarshal (line 95) | func (b *BindRequest) Unmarshal(w *ByteBuffer) error {
  function NewBindRequest (line 31) | func NewBindRequest(t BindingType) (b *BindRequest) {
  function NewBindTransmitter (line 57) | func NewBindTransmitter() PDU {
  function NewBindTransceiver (line 62) | func NewBindTransceiver() PDU {
  function NewBindReceiver (line 67) | func NewBindReceiver() PDU {

FILE: pdu/BindRequest_test.go
  function TestBindRequest (line 11) | func TestBindRequest(t *testing.T) {

FILE: pdu/BindResponse.go
  type BindResp (line 8) | type BindResp struct
    method CanResponse (line 62) | func (c *BindResp) CanResponse() bool {
    method GetResponse (line 67) | func (c *BindResp) GetResponse() PDU {
    method Marshal (line 72) | func (c *BindResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 81) | func (c *BindResp) Unmarshal(b *ByteBuffer) error {
  function NewBindResp (line 14) | func NewBindResp(req BindRequest) (c *BindResp) {
  function NewBindTransmitterResp (line 35) | func NewBindTransmitterResp() PDU {
  function NewBindTransceiverResp (line 44) | func NewBindTransceiverResp() PDU {
  function NewBindReceiverResp (line 53) | func NewBindReceiverResp() PDU {

FILE: pdu/BindResponse_test.go
  function TestBindResponse (line 11) | func TestBindResponse(t *testing.T) {

FILE: pdu/Buffer.go
  constant SizeByte (line 13) | SizeByte = 1
  constant SizeShort (line 16) | SizeShort = 2
  constant SizeInt (line 19) | SizeInt = 4
  constant SizeLong (line 22) | SizeLong = 8
  type ByteBuffer (line 33) | type ByteBuffer struct
    method ReadN (line 46) | func (c *ByteBuffer) ReadN(n int) (r []byte, err error) {
    method ReadShort (line 59) | func (c *ByteBuffer) ReadShort() (r int16, err error) {
    method WriteShort (line 68) | func (c *ByteBuffer) WriteShort(v int16) {
    method ReadInt (line 75) | func (c *ByteBuffer) ReadInt() (r int32, err error) {
    method WriteInt (line 84) | func (c *ByteBuffer) WriteInt(v int32) {
    method WriteBuffer (line 91) | func (c *ByteBuffer) WriteBuffer(d *ByteBuffer) {
    method writeString (line 97) | func (c *ByteBuffer) writeString(st string, isCString bool, enc data.E...
    method WriteCString (line 113) | func (c *ByteBuffer) WriteCString(s string) error {
    method WriteCStringWithEnc (line 118) | func (c *ByteBuffer) WriteCStringWithEnc(s string, enc data.Encoding) ...
    method ReadCString (line 123) | func (c *ByteBuffer) ReadCString() (st string, err error) {
    method HexDump (line 132) | func (c *ByteBuffer) HexDump() string {
  function NewBuffer (line 38) | func NewBuffer(inp []byte) *ByteBuffer {

FILE: pdu/Buffer_test.go
  function TestBuffer (line 12) | func TestBuffer(t *testing.T) {

FILE: pdu/CancelSM.go
  type CancelSM (line 10) | type CancelSM struct
    method CanResponse (line 32) | func (c *CancelSM) CanResponse() bool {
    method GetResponse (line 37) | func (c *CancelSM) GetResponse() PDU {
    method Marshal (line 42) | func (c *CancelSM) Marshal(b *ByteBuffer) {
    method Unmarshal (line 54) | func (c *CancelSM) Unmarshal(b *ByteBuffer) error {
  function NewCancelSM (line 19) | func NewCancelSM() PDU {

FILE: pdu/CancelSMResp.go
  type CancelSMResp (line 8) | type CancelSMResp struct
    method CanResponse (line 31) | func (c *CancelSMResp) CanResponse() bool {
    method GetResponse (line 36) | func (c *CancelSMResp) GetResponse() PDU {
    method Marshal (line 41) | func (c *CancelSMResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 46) | func (c *CancelSMResp) Unmarshal(b *ByteBuffer) error {
  function NewCancelSMResp (line 13) | func NewCancelSMResp() PDU {
  function NewCancelSMRespFromReq (line 22) | func NewCancelSMRespFromReq(req *CancelSM) PDU {

FILE: pdu/CancelSMResp_test.go
  function TestCancelSMResp (line 11) | func TestCancelSMResp(t *testing.T) {

FILE: pdu/CancelSM_test.go
  function TestCancelSM (line 11) | func TestCancelSM(t *testing.T) {

FILE: pdu/DataSM.go
  type DataSM (line 9) | type DataSM struct
    method CanResponse (line 35) | func (c *DataSM) CanResponse() bool {
    method GetResponse (line 40) | func (c *DataSM) GetResponse() PDU {
    method Marshal (line 45) | func (c *DataSM) Marshal(b *ByteBuffer) {
    method Unmarshal (line 59) | func (c *DataSM) Unmarshal(b *ByteBuffer) error {
  function NewDataSM (line 20) | func NewDataSM() PDU {

FILE: pdu/DataSMResp.go
  type DataSMResp (line 8) | type DataSMResp struct
    method CanResponse (line 33) | func (c *DataSMResp) CanResponse() bool {
    method GetResponse (line 38) | func (c *DataSMResp) GetResponse() PDU {
    method Marshal (line 43) | func (c *DataSMResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 52) | func (c *DataSMResp) Unmarshal(b *ByteBuffer) error {
  function NewDataSMResp (line 14) | func NewDataSMResp() PDU {
  function NewDataSMRespFromReq (line 24) | func NewDataSMRespFromReq(req *DataSM) PDU {

FILE: pdu/DataSMResp_test.go
  function TestDataSMResp (line 11) | func TestDataSMResp(t *testing.T) {

FILE: pdu/DataSM_test.go
  function TestDataSM (line 11) | func TestDataSM(t *testing.T) {

FILE: pdu/DeliverSM.go
  type DeliverSM (line 9) | type DeliverSM struct
    method CanResponse (line 46) | func (c *DeliverSM) CanResponse() bool {
    method GetResponse (line 51) | func (c *DeliverSM) GetResponse() PDU {
    method Marshal (line 56) | func (c *DeliverSM) Marshal(b *ByteBuffer) {
    method Unmarshal (line 75) | func (c *DeliverSM) Unmarshal(b *ByteBuffer) error {
  function NewDeliverSM (line 25) | func NewDeliverSM() PDU {

FILE: pdu/DeliverSMResp.go
  type DeliverSMResp (line 8) | type DeliverSMResp struct
    method CanResponse (line 33) | func (c *DeliverSMResp) CanResponse() bool {
    method GetResponse (line 38) | func (c *DeliverSMResp) GetResponse() PDU {
    method Marshal (line 43) | func (c *DeliverSMResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 52) | func (c *DeliverSMResp) Unmarshal(b *ByteBuffer) error {
  function NewDeliverSMResp (line 14) | func NewDeliverSMResp() PDU {
  function NewDeliverSMRespFromReq (line 24) | func NewDeliverSMRespFromReq(req *DeliverSM) PDU {

FILE: pdu/DeliverSMResp_test.go
  function TestDeliverSMResp (line 11) | func TestDeliverSMResp(t *testing.T) {

FILE: pdu/DeliverSM_test.go
  function TestDeliverSM (line 11) | func TestDeliverSM(t *testing.T) {
  function TestDeliverSMwithUDH (line 43) | func TestDeliverSMwithUDH(t *testing.T) {

FILE: pdu/DestinationAddress.go
  type DestinationAddress (line 10) | type DestinationAddress struct
    method Unmarshal (line 23) | func (c *DestinationAddress) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 42) | func (c *DestinationAddress) Marshal(b *ByteBuffer) {
    method Address (line 55) | func (c *DestinationAddress) Address() Address {
    method DistributionList (line 60) | func (c *DestinationAddress) DistributionList() DistributionList {
    method SetAddress (line 65) | func (c *DestinationAddress) SetAddress(addr Address) {
    method SetDistributionList (line 71) | func (c *DestinationAddress) SetDistributionList(list DistributionList) {
    method HasValue (line 77) | func (c *DestinationAddress) HasValue() bool {
    method IsAddress (line 82) | func (c *DestinationAddress) IsAddress() bool {
    method IsDistributionList (line 87) | func (c *DestinationAddress) IsDistributionList() bool {
  function NewDestinationAddress (line 17) | func NewDestinationAddress() (c DestinationAddress) {
  type DestinationAddresses (line 92) | type DestinationAddresses struct
    method Add (line 103) | func (c *DestinationAddresses) Add(addresses ...DestinationAddress) {
    method Get (line 108) | func (c *DestinationAddresses) Get() []DestinationAddress {
    method Unmarshal (line 113) | func (c *DestinationAddresses) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 129) | func (c *DestinationAddresses) Marshal(b *ByteBuffer) {
  function NewDestinationAddresses (line 97) | func NewDestinationAddresses() (u DestinationAddresses) {

FILE: pdu/DestinationAddress_test.go
  function TestDestinationAddress (line 11) | func TestDestinationAddress(t *testing.T) {

FILE: pdu/DistributionList.go
  type DistributionList (line 10) | type DistributionList struct
    method Unmarshal (line 21) | func (c *DistributionList) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 27) | func (c *DistributionList) Marshal(b *ByteBuffer) {
    method SetName (line 34) | func (c *DistributionList) SetName(name string) (err error) {
    method Name (line 44) | func (c DistributionList) Name() string {
  function NewDistributionList (line 15) | func NewDistributionList(name string) (c DistributionList, err error) {

FILE: pdu/DistributionList_test.go
  function TestDistributionList (line 9) | func TestDistributionList(t *testing.T) {

FILE: pdu/EnquireLink.go
  type EnquireLink (line 13) | type EnquireLink struct
    method CanResponse (line 27) | func (c *EnquireLink) CanResponse() bool {
    method GetResponse (line 32) | func (c *EnquireLink) GetResponse() PDU {
    method Marshal (line 37) | func (c *EnquireLink) Marshal(b *ByteBuffer) {
    method Unmarshal (line 42) | func (c *EnquireLink) Unmarshal(b *ByteBuffer) error {
  function NewEnquireLink (line 18) | func NewEnquireLink() PDU {

FILE: pdu/EnquireLinkResp.go
  type EnquireLinkResp (line 8) | type EnquireLinkResp struct
    method CanResponse (line 31) | func (c *EnquireLinkResp) CanResponse() bool {
    method GetResponse (line 36) | func (c *EnquireLinkResp) GetResponse() PDU {
    method Marshal (line 41) | func (c *EnquireLinkResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 46) | func (c *EnquireLinkResp) Unmarshal(b *ByteBuffer) error {
  function NewEnquireLinkResp (line 13) | func NewEnquireLinkResp() PDU {
  function NewEnquireLinkRespFromReq (line 22) | func NewEnquireLinkRespFromReq(req *EnquireLink) PDU {

FILE: pdu/EnquireLinkResp_test.go
  function TestEnquireLinkResp (line 11) | func TestEnquireLinkResp(t *testing.T) {

FILE: pdu/EnquireLink_test.go
  function TestEnquireLink (line 11) | func TestEnquireLink(t *testing.T) {

FILE: pdu/GenericNack.go
  type GenericNack (line 17) | type GenericNack struct
    method CanResponse (line 31) | func (c *GenericNack) CanResponse() bool {
    method GetResponse (line 36) | func (c *GenericNack) GetResponse() PDU {
    method Marshal (line 41) | func (c *GenericNack) Marshal(b *ByteBuffer) {
    method Unmarshal (line 46) | func (c *GenericNack) Unmarshal(b *ByteBuffer) error {
  function NewGenericNack (line 22) | func NewGenericNack() PDU {

FILE: pdu/GenericNack_test.go
  function TestGNack (line 10) | func TestGNack(t *testing.T) {

FILE: pdu/Outbind.go
  type Outbind (line 8) | type Outbind struct
    method CanResponse (line 24) | func (c *Outbind) CanResponse() bool {
    method GetResponse (line 29) | func (c *Outbind) GetResponse() PDU {
    method Marshal (line 34) | func (c *Outbind) Marshal(b *ByteBuffer) {
    method Unmarshal (line 44) | func (c *Outbind) Unmarshal(b *ByteBuffer) error {
  function NewOutbind (line 15) | func NewOutbind() PDU {

FILE: pdu/Outbind_test.go
  function TestOutbind (line 11) | func TestOutbind(t *testing.T) {

FILE: pdu/PDU.go
  type PDU (line 11) | type PDU interface
  type base (line 49) | type base struct
    method GetHeader (line 61) | func (c *base) GetHeader() Header {
    method unmarshal (line 65) | func (c *base) unmarshal(b *ByteBuffer, bodyReader func(*ByteBuffer) e...
    method unmarshalOptionalParam (line 107) | func (c *base) unmarshalOptionalParam(optParam []byte) (err error) {
    method marshal (line 121) | func (c *base) marshal(b *ByteBuffer, bodyWriter func(*ByteBuffer)) {
    method RegisterOptionalParam (line 143) | func (c *base) RegisterOptionalParam(tlv Field) {
    method IsOk (line 148) | func (c *base) IsOk() bool {
    method IsGNack (line 153) | func (c *base) IsGNack() bool {
  function newBase (line 54) | func newBase() (v base) {
  function Parse (line 158) | func Parse(r io.Reader) (pdu PDU, err error) {

FILE: pdu/PDUFactory.go
  type pduGenerator (line 8) | type pduGenerator
  function CreatePDUFromCmdID (line 41) | func CreatePDUFromCmdID(cmdID data.CommandIDType) (PDU, error) {

FILE: pdu/PDUFactory_test.go
  function TestInvalidCmdID (line 9) | func TestInvalidCmdID(t *testing.T) {

FILE: pdu/PDUHeader.go
  function nextSequenceNumber (line 10) | func nextSequenceNumber(s *int32) (v int32) {
  type Header (line 22) | type Header struct
    method Unmarshal (line 39) | func (c *Header) Unmarshal(b *ByteBuffer) (err error) {
    method AssignSequenceNumber (line 58) | func (c *Header) AssignSequenceNumber() {
    method ResetSequenceNumber (line 63) | func (c *Header) ResetSequenceNumber() {
    method GetSequenceNumber (line 68) | func (c *Header) GetSequenceNumber() int32 {
    method SetSequenceNumber (line 73) | func (c *Header) SetSequenceNumber(v int32) {
    method Marshal (line 78) | func (c *Header) Marshal(b *ByteBuffer) {
  function ParseHeader (line 30) | func ParseHeader(v [16]byte) (h Header) {

FILE: pdu/PDUHeader_test.go
  function TestNextSeq (line 10) | func TestNextSeq(t *testing.T) {

FILE: pdu/PDU_test.go
  function TestParsePDU (line 11) | func TestParsePDU(t *testing.T) {

FILE: pdu/QuerySM.go
  type QuerySM (line 11) | type QuerySM struct
    method CanResponse (line 27) | func (c *QuerySM) CanResponse() bool {
    method GetResponse (line 32) | func (c *QuerySM) GetResponse() PDU {
    method Marshal (line 37) | func (c *QuerySM) Marshal(b *ByteBuffer) {
    method Unmarshal (line 47) | func (c *QuerySM) Unmarshal(b *ByteBuffer) error {
  function NewQuerySM (line 18) | func NewQuerySM() PDU {

FILE: pdu/QuerySMResp.go
  type QuerySMResp (line 8) | type QuerySMResp struct
    method CanResponse (line 38) | func (c *QuerySMResp) CanResponse() bool {
    method GetResponse (line 43) | func (c *QuerySMResp) GetResponse() PDU {
    method Marshal (line 48) | func (c *QuerySMResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 60) | func (c *QuerySMResp) Unmarshal(b *ByteBuffer) error {
  function NewQuerySMResp (line 17) | func NewQuerySMResp() PDU {
  function NewQuerySMRespFromReq (line 29) | func NewQuerySMRespFromReq(req *QuerySM) PDU {

FILE: pdu/QuerySMResp_test.go
  function TestQuerySMResp (line 11) | func TestQuerySMResp(t *testing.T) {

FILE: pdu/QuerySM_test.go
  function TestQuerySM (line 11) | func TestQuerySM(t *testing.T) {

FILE: pdu/ReplaceSM.go
  type ReplaceSM (line 11) | type ReplaceSM struct
    method CanResponse (line 38) | func (c *ReplaceSM) CanResponse() bool {
    method GetResponse (line 43) | func (c *ReplaceSM) GetResponse() PDU {
    method Marshal (line 48) | func (c *ReplaceSM) Marshal(b *ByteBuffer) {
    method Unmarshal (line 62) | func (c *ReplaceSM) Unmarshal(b *ByteBuffer) error {
  function NewReplaceSM (line 22) | func NewReplaceSM() PDU {

FILE: pdu/ReplaceSMResp.go
  type ReplaceSMResp (line 8) | type ReplaceSMResp struct
    method CanResponse (line 31) | func (c *ReplaceSMResp) CanResponse() bool {
    method GetResponse (line 36) | func (c *ReplaceSMResp) GetResponse() PDU {
    method Marshal (line 41) | func (c *ReplaceSMResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 46) | func (c *ReplaceSMResp) Unmarshal(b *ByteBuffer) error {
  function NewReplaceSMResp (line 13) | func NewReplaceSMResp() PDU {
  function NewReplaceSMRespFromReq (line 22) | func NewReplaceSMRespFromReq(req *ReplaceSM) PDU {

FILE: pdu/ReplaceSMResp_test.go
  function TestReplaceSMResp (line 11) | func TestReplaceSMResp(t *testing.T) {

FILE: pdu/ReplaceSM_test.go
  function TestReplaceSM (line 11) | func TestReplaceSM(t *testing.T) {

FILE: pdu/ShortMessage.go
  type ShortMessage (line 13) | type ShortMessage struct
    method SetMessageWithEncoding (line 61) | func (c *ShortMessage) SetMessageWithEncoding(message string, enc data...
    method SetLongMessageWithEnc (line 86) | func (c *ShortMessage) SetLongMessageWithEnc(message string, enc data....
    method UDH (line 93) | func (c *ShortMessage) UDH() UDH {
    method SetUDH (line 99) | func (c *ShortMessage) SetUDH(udh UDH) {
    method SetMessageDataWithEncoding (line 104) | func (c *ShortMessage) SetMessageDataWithEncoding(d []byte, enc data.E...
    method GetMessageData (line 115) | func (c *ShortMessage) GetMessageData() (d []byte, err error) {
    method GetMessage (line 120) | func (c *ShortMessage) GetMessage() (st string, err error) {
    method GetMessageWithEncoding (line 130) | func (c *ShortMessage) GetMessageWithEncoding(enc data.Encoding) (st s...
    method split (line 142) | func (c *ShortMessage) split() (multiSM []*ShortMessage, err error) {
    method Marshal (line 195) | func (c *ShortMessage) Marshal(b *ByteBuffer) {
    method Unmarshal (line 236) | func (c *ShortMessage) Unmarshal(b *ByteBuffer, udhi bool) (err error) {
    method Encoding (line 282) | func (c *ShortMessage) Encoding() data.Encoding {
  function NewShortMessage (line 23) | func NewShortMessage(message string) (s ShortMessage, err error) {
  function NewShortMessageWithEncoding (line 29) | func NewShortMessageWithEncoding(message string, enc data.Encoding) (s S...
  function NewBinaryShortMessage (line 35) | func NewBinaryShortMessage(messageData []byte) (s ShortMessage, err erro...
  function NewBinaryShortMessageWithEncoding (line 41) | func NewBinaryShortMessageWithEncoding(messageData []byte, enc data.Enco...
  function NewLongMessage (line 47) | func NewLongMessage(message string) (s []*ShortMessage, err error) {
  function NewLongMessageWithEncoding (line 52) | func NewLongMessageWithEncoding(message string, enc data.Encoding) (s []...
  function getRefNum (line 287) | func getRefNum() uint32 {

FILE: pdu/ShortMessage_test.go
  type customEncoder (line 12) | type customEncoder struct
    method Encode (line 14) | func (*customEncoder) Encode(str string) ([]byte, error) {
    method Decode (line 18) | func (*customEncoder) Decode(data []byte) (string, error) {
  function TestShortMessage (line 22) | func TestShortMessage(t *testing.T) {

FILE: pdu/SubmitMulti.go
  type SubmitMulti (line 10) | type SubmitMulti struct
    method CanResponse (line 47) | func (c *SubmitMulti) CanResponse() bool {
    method GetResponse (line 52) | func (c *SubmitMulti) GetResponse() PDU {
    method Marshal (line 57) | func (c *SubmitMulti) Marshal(b *ByteBuffer) {
    method Unmarshal (line 76) | func (c *SubmitMulti) Unmarshal(b *ByteBuffer) error {
  function NewSubmitMulti (line 26) | func NewSubmitMulti() PDU {

FILE: pdu/SubmitMultiResp.go
  type SubmitMultiResp (line 8) | type SubmitMultiResp struct
    method CanResponse (line 35) | func (c *SubmitMultiResp) CanResponse() bool {
    method GetResponse (line 40) | func (c *SubmitMultiResp) GetResponse() PDU {
    method Marshal (line 45) | func (c *SubmitMultiResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 55) | func (c *SubmitMultiResp) Unmarshal(b *ByteBuffer) error {
  function NewSubmitMultiResp (line 15) | func NewSubmitMultiResp() PDU {
  function NewSubmitMultiRespFromReq (line 26) | func NewSubmitMultiRespFromReq(req *SubmitMulti) PDU {

FILE: pdu/SubmitMultiResp_test.go
  function TestSubmitMultiResp (line 11) | func TestSubmitMultiResp(t *testing.T) {

FILE: pdu/SubmitMulti_test.go
  function TestSubmitMulti (line 11) | func TestSubmitMulti(t *testing.T) {
  function TestSubmitMultiwithUDH (line 61) | func TestSubmitMultiwithUDH(t *testing.T) {

FILE: pdu/SubmitSM.go
  type SubmitSM (line 10) | type SubmitSM struct
    method ShouldSplit (line 47) | func (c *SubmitSM) ShouldSplit() bool {
    method CanResponse (line 53) | func (c *SubmitSM) CanResponse() bool {
    method GetResponse (line 58) | func (c *SubmitSM) GetResponse() PDU {
    method Split (line 66) | func (c *SubmitSM) Split() (multiSubSM []*SubmitSM, err error) {
    method Marshal (line 99) | func (c *SubmitSM) Marshal(b *ByteBuffer) {
    method Unmarshal (line 118) | func (c *SubmitSM) Unmarshal(b *ByteBuffer) error {
  function NewSubmitSM (line 26) | func NewSubmitSM() PDU {

FILE: pdu/SubmitSMResp.go
  type SubmitSMResp (line 10) | type SubmitSMResp struct
    method CanResponse (line 35) | func (c *SubmitSMResp) CanResponse() bool {
    method GetResponse (line 40) | func (c *SubmitSMResp) GetResponse() PDU {
    method Marshal (line 45) | func (c *SubmitSMResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 54) | func (c *SubmitSMResp) Unmarshal(b *ByteBuffer) error {
  function NewSubmitSMResp (line 16) | func NewSubmitSMResp() PDU {
  function NewSubmitSMRespFromReq (line 26) | func NewSubmitSMRespFromReq(req *SubmitSM) PDU {

FILE: pdu/SubmitSMResp_test.go
  function TestSubmitSMResp (line 11) | func TestSubmitSMResp(t *testing.T) {

FILE: pdu/SubmitSM_test.go
  function TestSubmitSM (line 11) | func TestSubmitSM(t *testing.T) {

FILE: pdu/TLV.go
  type Tag (line 10) | type Tag
    method Hex (line 13) | func (t Tag) Hex() string {
  constant TagDestAddrSubunit (line 21) | TagDestAddrSubunit          Tag = 0x0005
  constant TagDestNetworkType (line 22) | TagDestNetworkType          Tag = 0x0006
  constant TagDestBearerType (line 23) | TagDestBearerType           Tag = 0x0007
  constant TagDestTelematicsID (line 24) | TagDestTelematicsID         Tag = 0x0008
  constant TagSourceAddrSubunit (line 25) | TagSourceAddrSubunit        Tag = 0x000D
  constant TagSourceNetworkType (line 26) | TagSourceNetworkType        Tag = 0x000E
  constant TagSourceBearerType (line 27) | TagSourceBearerType         Tag = 0x000F
  constant TagSourceTelematicsID (line 28) | TagSourceTelematicsID       Tag = 0x0010
  constant TagQosTimeToLive (line 29) | TagQosTimeToLive            Tag = 0x0017
  constant TagPayloadType (line 30) | TagPayloadType              Tag = 0x0019
  constant TagAdditionalStatusInfoText (line 31) | TagAdditionalStatusInfoText Tag = 0x001D
  constant TagReceiptedMessageID (line 32) | TagReceiptedMessageID       Tag = 0x001E
  constant TagMsMsgWaitFacilities (line 33) | TagMsMsgWaitFacilities      Tag = 0x0030
  constant TagPrivacyIndicator (line 34) | TagPrivacyIndicator         Tag = 0x0201
  constant TagSourceSubaddress (line 35) | TagSourceSubaddress         Tag = 0x0202
  constant TagDestSubaddress (line 36) | TagDestSubaddress           Tag = 0x0203
  constant TagUserMessageReference (line 37) | TagUserMessageReference     Tag = 0x0204
  constant TagUserResponseCode (line 38) | TagUserResponseCode         Tag = 0x0205
  constant TagSourcePort (line 39) | TagSourcePort               Tag = 0x020A
  constant TagDestinationPort (line 40) | TagDestinationPort          Tag = 0x020B
  constant TagSarMsgRefNum (line 41) | TagSarMsgRefNum             Tag = 0x020C
  constant TagLanguageIndicator (line 42) | TagLanguageIndicator        Tag = 0x020D
  constant TagSarTotalSegments (line 43) | TagSarTotalSegments         Tag = 0x020E
  constant TagSarSegmentSeqnum (line 44) | TagSarSegmentSeqnum         Tag = 0x020F
  constant TagCallbackNumPresInd (line 45) | TagCallbackNumPresInd       Tag = 0x0302
  constant TagCallbackNumAtag (line 46) | TagCallbackNumAtag          Tag = 0x0303
  constant TagNumberOfMessages (line 47) | TagNumberOfMessages         Tag = 0x0304
  constant TagCallbackNum (line 48) | TagCallbackNum              Tag = 0x0381
  constant TagDpfResult (line 49) | TagDpfResult                Tag = 0x0420
  constant TagSetDpf (line 50) | TagSetDpf                   Tag = 0x0421
  constant TagMsAvailabilityStatus (line 51) | TagMsAvailabilityStatus     Tag = 0x0422
  constant TagNetworkErrorCode (line 52) | TagNetworkErrorCode         Tag = 0x0423
  constant TagMessagePayload (line 53) | TagMessagePayload           Tag = 0x0424
  constant TagDeliveryFailureReason (line 54) | TagDeliveryFailureReason    Tag = 0x0425
  constant TagMoreMessagesToSend (line 55) | TagMoreMessagesToSend       Tag = 0x0426
  constant TagMessageStateOption (line 56) | TagMessageStateOption       Tag = 0x0427
  constant TagUssdServiceOp (line 57) | TagUssdServiceOp            Tag = 0x0501
  constant TagDisplayTime (line 58) | TagDisplayTime              Tag = 0x1201
  constant TagSmsSignal (line 59) | TagSmsSignal                Tag = 0x1203
  constant TagMsValidity (line 60) | TagMsValidity               Tag = 0x1204
  constant TagAlertOnMessageDelivery (line 61) | TagAlertOnMessageDelivery   Tag = 0x130C
  constant TagItsReplyType (line 62) | TagItsReplyType             Tag = 0x1380
  constant TagItsSessionInfo (line 63) | TagItsSessionInfo           Tag = 0x1383
  type Field (line 67) | type Field struct
    method String (line 73) | func (t *Field) String() string {
    method Marshal (line 81) | func (t *Field) Marshal(w *ByteBuffer) {
    method Unmarshal (line 92) | func (t *Field) Unmarshal(b *ByteBuffer) (err error) {

FILE: pdu/UDH.go
  type UDH (line 16) | type UDH
    method UDHL (line 21) | func (u UDH) UDHL() (l int) {
    method MarshalBinary (line 50) | func (u UDH) MarshalBinary() (b []byte, err error) {
    method UnmarshalBinary (line 101) | func (u *UDH) UnmarshalBinary(src []byte) (int, error) {
    method FindInfoElement (line 142) | func (u UDH) FindInfoElement(id byte) (ie *InfoElement, found bool) {
    method GetConcatInfo (line 152) | func (u UDH) GetConcatInfo() (totalParts, partNum, mref byte, found bo...
  type InfoElement (line 171) | type InfoElement struct
    method UnmarshalBinary (line 189) | func (ie *InfoElement) UnmarshalBinary(src []byte) (int, error) {
  function NewIEConcatMessage (line 178) | func NewIEConcatMessage(totalParts, partNum, mref byte) InfoElement {

FILE: pdu/UDH_test.go
  function TestUserDataHeader (line 9) | func TestUserDataHeader(t *testing.T) {

FILE: pdu/Unbind.go
  type Unbind (line 10) | type Unbind struct
    method CanResponse (line 24) | func (c *Unbind) CanResponse() bool {
    method GetResponse (line 29) | func (c *Unbind) GetResponse() PDU {
    method Marshal (line 34) | func (c *Unbind) Marshal(b *ByteBuffer) {
    method Unmarshal (line 39) | func (c *Unbind) Unmarshal(b *ByteBuffer) error {
  function NewUnbind (line 15) | func NewUnbind() PDU {

FILE: pdu/UnbindResp.go
  type UnbindResp (line 8) | type UnbindResp struct
    method CanResponse (line 31) | func (c *UnbindResp) CanResponse() bool {
    method GetResponse (line 36) | func (c *UnbindResp) GetResponse() PDU {
    method Marshal (line 41) | func (c *UnbindResp) Marshal(b *ByteBuffer) {
    method Unmarshal (line 46) | func (c *UnbindResp) Unmarshal(b *ByteBuffer) error {
  function NewUnbindResp (line 13) | func NewUnbindResp() PDU {
  function NewUnbindRespFromReq (line 22) | func NewUnbindRespFromReq(req *Unbind) PDU {

FILE: pdu/UnbindResp_test.go
  function TestUnbindResp (line 11) | func TestUnbindResp(t *testing.T) {

FILE: pdu/Unbind_test.go
  function TestUnbind (line 11) | func TestUnbind(t *testing.T) {

FILE: pdu/UnsuccessSME.go
  type UnsuccessSME (line 8) | type UnsuccessSME struct
    method Unmarshal (line 40) | func (c *UnsuccessSME) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 52) | func (c *UnsuccessSME) Marshal(b *ByteBuffer) {
    method SetErrorStatusCode (line 58) | func (c *UnsuccessSME) SetErrorStatusCode(v data.CommandStatusType) {
    method ErrorStatusCode (line 63) | func (c *UnsuccessSME) ErrorStatusCode() data.CommandStatusType {
  function NewUnsuccessSME (line 14) | func NewUnsuccessSME() (c UnsuccessSME) {
  function NewUnsuccessSMEWithAddr (line 23) | func NewUnsuccessSMEWithAddr(addr string, status data.CommandStatusType)...
  function NewUnsuccessSMEWithTonNpi (line 32) | func NewUnsuccessSMEWithTonNpi(ton, npi byte, status data.CommandStatusT...
  type UnsuccessSMEs (line 68) | type UnsuccessSMEs struct
    method Add (line 79) | func (c *UnsuccessSMEs) Add(us ...UnsuccessSME) {
    method Get (line 84) | func (c *UnsuccessSMEs) Get() []UnsuccessSME {
    method Unmarshal (line 89) | func (c *UnsuccessSMEs) Unmarshal(b *ByteBuffer) (err error) {
    method Marshal (line 105) | func (c *UnsuccessSMEs) Marshal(b *ByteBuffer) {
  function NewUnsuccessSMEs (line 73) | func NewUnsuccessSMEs() (u UnsuccessSMEs) {

FILE: pdu/UnsuccessSME_test.go
  function TestMalformUSME (line 9) | func TestMalformUSME(t *testing.T) {

FILE: pdu/helper_test.go
  function fromHex (line 13) | func fromHex(h string) (v []byte) {
  function toHex (line 22) | func toHex(v []byte) (h string) {
  function validate (line 27) | func validate(t *testing.T, p PDU, hexValue string, expectCommandID data...
  function expectAfterParse (line 35) | func expectAfterParse(t *testing.T, b *ByteBuffer, expect PDU, expectCom...

FILE: pkg.go
  type Transceiver (line 11) | type Transceiver interface
  type Transmitter (line 18) | type Transmitter interface
  type Receiver (line 25) | type Receiver interface
  type Settings (line 31) | type Settings struct
  type WindowedRequestTracking (line 89) | type WindowedRequestTracking struct

FILE: receivable.go
  type receivable (line 12) | type receivable struct
    method close (line 33) | func (t *receivable) close(state State) (err error) {
    method closing (line 57) | func (t *receivable) closing(state State) {
    method start (line 63) | func (t *receivable) start() {
    method loop (line 71) | func (t *receivable) loop() {
    method handleWindowPdu (line 112) | func (t *receivable) handleWindowPdu(p pdu.PDU) (closing bool) {
    method handleAllPdu (line 176) | func (t *receivable) handleAllPdu(p pdu.PDU) (closing bool) {
    method handleOrClose (line 188) | func (t *receivable) handleOrClose(p pdu.PDU) (closing bool) {
  function newReceivable (line 22) | func newReceivable(conn *Connection, settings Settings, requestStore Req...

FILE: receivable_test.go
  function TestReceive (line 14) | func TestReceive(t *testing.T) {
  function Test_receivable_handleAllPdu (line 49) | func Test_receivable_handleAllPdu(t1 *testing.T) {
  function receivableHandleAllPDU (line 121) | func receivableHandleAllPDU(t1 *testing.T) func(pdu.PDU) (pdu.PDU, bool) {
  function Test_receivable_handleOrClose (line 156) | func Test_receivable_handleOrClose(t1 *testing.T) {
  function Test_receivable_handleWindowPdu (line 212) | func Test_receivable_handleWindowPdu(t1 *testing.T) {

FILE: request_store.go
  type Request (line 14) | type Request struct
  type Response (line 20) | type Response struct
  type RequestStore (line 26) | type RequestStore interface
  type DefaultStore (line 35) | type DefaultStore struct
    method Set (line 45) | func (s DefaultStore) Set(ctx context.Context, request Request) error {
    method Get (line 56) | func (s DefaultStore) Get(ctx context.Context, sequenceNumber int32) (...
    method List (line 66) | func (s DefaultStore) List(ctx context.Context) []Request {
    method Delete (line 75) | func (s DefaultStore) Delete(ctx context.Context, sequenceNumber int32...
    method Clear (line 85) | func (s DefaultStore) Clear(ctx context.Context) error {
    method Length (line 95) | func (s DefaultStore) Length(ctx context.Context) (int, error) {
  function NewDefaultStore (line 39) | func NewDefaultStore() DefaultStore {

FILE: session.go
  type Session (line 19) | type Session struct
    method bound (line 110) | func (s *Session) bound() *transceivable {
    method Transmitter (line 116) | func (s *Session) Transmitter() Transmitter {
    method Receiver (line 121) | func (s *Session) Receiver() Receiver {
    method Transceiver (line 126) | func (s *Session) Transceiver() Transceiver {
    method GetWindowSize (line 130) | func (s *Session) GetWindowSize() (int, error) {
    method Close (line 142) | func (s *Session) Close() (err error) {
    method close (line 149) | func (s *Session) close() (err error) {
    method rebind (line 156) | func (s *Session) rebind() {
  type SessionOption (line 34) | type SessionOption
  function NewSession (line 44) | func NewSession(c Connector, settings Settings, rebindingInterval time.D...
  function WithRequestStore (line 104) | func WithRequestStore(store RequestStore) SessionOption {

FILE: session_test.go
  function TestInvalidSessionSettings (line 10) | func TestInvalidSessionSettings(t *testing.T) {
  function TestGetWindowSize (line 27) | func TestGetWindowSize(t *testing.T) {

FILE: state.go
  constant Alive (line 4) | Alive int32 = iota
  constant Closed (line 5) | Closed
  type State (line 9) | type State
    method String (line 35) | func (s *State) String() string {
  constant ExplicitClosing (line 14) | ExplicitClosing State = iota
  constant StoppingProcessOnly (line 17) | StoppingProcessOnly
  constant InvalidStreaming (line 24) | InvalidStreaming
  constant ConnectionIssue (line 28) | ConnectionIssue
  constant UnbindClosing (line 31) | UnbindClosing

FILE: state_test.go
  function TestState_String (line 8) | func TestState_String(t *testing.T) {

FILE: transceivable.go
  type transceivable (line 16) | type transceivable struct
    method start (line 98) | func (t *transceivable) start() {
    method SystemID (line 112) | func (t *transceivable) SystemID() string {
    method Close (line 117) | func (t *transceivable) Close() (err error) {
    method Submit (line 122) | func (t *transceivable) Submit(p pdu.PDU) error {
    method GetWindowSize (line 126) | func (t *transceivable) GetWindowSize() (int, error) {
    method windowCleanup (line 136) | func (t *transceivable) windowCleanup() {
    method closing (line 160) | func (t *transceivable) closing(state State) (err error) {
  type TransceivableOption (line 29) | type TransceivableOption
  function newTransceivable (line 31) | func newTransceivable(conn *Connection, settings Settings, requestStore ...

FILE: transceivable_test.go
  function handlePDU (line 19) | func handlePDU(t *testing.T) func(pdu.PDU, bool) {
  function transceivableHandleAllPDU (line 50) | func transceivableHandleAllPDU(t *testing.T) func(pdu.PDU) (pdu.PDU, boo...
  function TestTRXSubmitSM (line 84) | func TestTRXSubmitSM(t *testing.T) {
  function TestTRXSubmitSM_with_OnAllPDU (line 141) | func TestTRXSubmitSM_with_OnAllPDU(t *testing.T) {
  function newSubmitSM (line 198) | func newSubmitSM(systemID string) *pdu.SubmitSM {
  function TestTRXSubmitSM_with_WindowConfig (line 222) | func TestTRXSubmitSM_with_WindowConfig(t *testing.T) {
  function TestTRXSubmitSM_with_WindowConfig_and_AutoRespond (line 288) | func TestTRXSubmitSM_with_WindowConfig_and_AutoRespond(t *testing.T) {
  function handleReceivedPduRequest (line 354) | func handleReceivedPduRequest(t *testing.T) func(pdu.PDU) (pdu.PDU, bool) {
  function handleExpectedPduResponse (line 384) | func handleExpectedPduResponse(t *testing.T) func(response Response) {
  function Test_newTransceivable (line 402) | func Test_newTransceivable(t *testing.T) {

FILE: transmittable.go
  type transmittable (line 21) | type transmittable struct
    method close (line 47) | func (t *transmittable) close(state State) (err error) {
    method closing (line 99) | func (t *transmittable) closing(state State) {
    method Submit (line 106) | func (t *transmittable) Submit(p pdu.PDU) (err error) {
    method start (line 119) | func (t *transmittable) start() {
    method drain (line 134) | func (t *transmittable) drain() {
    method loop (line 139) | func (t *transmittable) loop() {
    method loopWithEnquireLink (line 152) | func (t *transmittable) loopWithEnquireLink() {
    method check (line 184) | func (t *transmittable) check(p pdu.PDU, n int, err error) (closing bo...
    method write (line 213) | func (t *transmittable) write(p pdu.PDU) (n int, err error) {
  function newTransmittable (line 34) | func newTransmittable(conn *Connection, settings Settings, requestStore ...
  function isAllowPDU (line 252) | func isAllowPDU(p pdu.PDU) bool {

FILE: transmittable_test.go
  function TestTransmit (line 16) | func TestTransmit(t *testing.T) {
  function TestConcurrentSubmitClose (line 122) | func TestConcurrentSubmitClose(t *testing.T) {

FILE: types.go
  type PDUCallback (line 8) | type PDUCallback
  type AllPDUCallback (line 14) | type AllPDUCallback
  type PDUErrorCallback (line 17) | type PDUErrorCallback
  type ErrorCallback (line 20) | type ErrorCallback
  type ClosedCallback (line 23) | type ClosedCallback
  type RebindCallback (line 26) | type RebindCallback
Condensed preview — 115 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (387K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 504,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/workflows/go.yml",
    "chars": 1068,
    "preview": "name: Build\non: [push, pull_request]\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n    steps:\n      - name: "
  },
  {
    "path": ".gitignore",
    "chars": 36,
    "preview": ".idea/\nvendor/\n*DS_Store\n*.out\nsmsc\n"
  },
  {
    "path": ".golangci.yml",
    "chars": 4064,
    "preview": "version: \"2\"\nlinters:\n  # Default set of linters.\n  # The value can be:\n  # - `standard`: https://golangci-lint.run/docs"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 2709,
    "preview": "# gosmpp\n\n[![](https://github.com/linxGnu/gosmpp/workflows/Build/badge.svg)]()\n[![Go Report Card](https://goreportcard.c"
  },
  {
    "path": "connect.go",
    "chars": 3188,
    "preview": "package gosmpp\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/linxGnu/gosmpp/pdu\"\n)\n\nvar (\n\t// "
  },
  {
    "path": "connect_test.go",
    "chars": 2308,
    "preview": "package gosmpp\n\nimport (\n\t\"github.com/linxGnu/gosmpp/pdu\"\n\t\"sync/atomic\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/requi"
  },
  {
    "path": "connection.go",
    "chars": 3668,
    "preview": "package gosmpp\n\nimport (\n\t\"bufio\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp/pdu\"\n)\n\n// Connection wraps over net.Conn "
  },
  {
    "path": "connection_test.go",
    "chars": 520,
    "preview": "package gosmpp\n\nimport (\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestConnection(t *tes"
  },
  {
    "path": "data/7bit.go",
    "chars": 13893,
    "preview": "package data\n\n// Source code in this file is copied from: https://github.com/fiorix/go-smpp/master/smpp/encoding/gsm7.go"
  },
  {
    "path": "data/7bit_test.go",
    "chars": 9604,
    "preview": "package data\n\n// Source code in this file is copied from: https://github.com/fiorix\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"re"
  },
  {
    "path": "data/codings.go",
    "chars": 10540,
    "preview": "package data\n\nimport (\n\t\"golang.org/x/text/encoding\"\n\t\"golang.org/x/text/encoding/charmap\"\n\t\"golang.org/x/text/encoding/"
  },
  {
    "path": "data/codings_test.go",
    "chars": 14360,
    "preview": "package data\n\nimport (\n\t\"encoding/hex\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc fromHex(h strin"
  },
  {
    "path": "data/header_data.go",
    "chars": 10181,
    "preview": "//go:generate stringer -type=CommandStatusType,CommandIDType -output header_data_string.go\n\npackage data\n\n// CommandStat"
  },
  {
    "path": "data/header_data_string.go",
    "chars": 18199,
    "preview": "// Code generated by \"stringer -type=CommandStatusType,CommandIDType -output header_data_string.go\"; DO NOT EDIT.\n\npacka"
  },
  {
    "path": "data/other_codings.go",
    "chars": 1717,
    "preview": "package data\n\nimport (\n\t\"golang.org/x/text/encoding/unicode\"\n)\n\nvar (\n\t// UTF16BEM is UTF-16 Big Endian with BOM (byte o"
  },
  {
    "path": "data/pkg.go",
    "chars": 11007,
    "preview": "package data\n\nimport (\n\t\"fmt\"\n\t\"sync/atomic\"\n)\n\n//nolint\nconst (\n\tSM_CONNID_LEN        = 16\n\tSM_MSG_LEN           = 254\n"
  },
  {
    "path": "data/pkg_test.go",
    "chars": 282,
    "preview": "package data\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDefaultNpi(t *testing.T) {\n\tSetDef"
  },
  {
    "path": "data/utils.go",
    "chars": 389,
    "preview": "package data\n\nimport \"unicode\"\n\n// FindEncoding returns suitable encoding for a string.\n// If string is ascii, then GSM7"
  },
  {
    "path": "data/utils_test.go",
    "chars": 361,
    "preview": "package data\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestFindEncoding(t *testing.T) {\n\trequ"
  },
  {
    "path": "errors/pkg.go",
    "chars": 1237,
    "preview": "package errors\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// SmppErr indicates smpp error(s), compatible wit"
  },
  {
    "path": "errors/pkg_test.go",
    "chars": 201,
    "preview": "package errors\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestErr(t *testing.T) {\n\t"
  },
  {
    "path": "example/smsc_simulator/smsc.cpp",
    "chars": 49999,
    "preview": "//\n//  smscsimulator.cpp\n//  SMPPLib\n//\n//  Created by Mark Hay on 12/05/2019.\n//  Copyright © 2019 Melrose Labs. All ri"
  },
  {
    "path": "example/transceiver_with_auto_response/main.go",
    "chars": 3178,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp\"\n\t\"github.com/linxGnu/gosmp"
  },
  {
    "path": "example/transceiver_with_manual_response/main.go",
    "chars": 2676,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp\"\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"g"
  },
  {
    "path": "example/transeiver_with_custom_store/CustomStore.go",
    "chars": 3575,
    "preview": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/allegro/big"
  },
  {
    "path": "example/transeiver_with_custom_store/main.go",
    "chars": 4829,
    "preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp\"\n\t\"github.com/linxGnu/gosmpp"
  },
  {
    "path": "example/transeiver_with_request_window_and_custom_submitSm/CustomSubmitSM.go",
    "chars": 494,
    "preview": "package main\n\nimport (\n\t\"math/rand\"\n\t\"strconv\"\n\n\t\"github.com/linxGnu/gosmpp/pdu\"\n)\n\n// CustomSubmitSM by embedding the P"
  },
  {
    "path": "example/transeiver_with_request_window_and_custom_submitSm/main.go",
    "chars": 4921,
    "preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp\"\n\t\"github.com/linxGnu/gosmpp"
  },
  {
    "path": "go.mod",
    "chars": 405,
    "preview": "module github.com/linxGnu/gosmpp\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/allegro/bigcache/v3 v3.1.0\n\tgithub.com/orcaman/concur"
  },
  {
    "path": "go.sum",
    "chars": 1615,
    "preview": "github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=\ngithub.com/allegro/bigcache/v3 v3."
  },
  {
    "path": "pdu/Address.go",
    "chars": 2026,
    "preview": "package pdu\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// Address smpp address of src and dst.\ntype Address "
  },
  {
    "path": "pdu/AddressRange.go",
    "chars": 1389,
    "preview": "package pdu\n\nimport \"github.com/linxGnu/gosmpp/data\"\n\n// AddressRange smpp address range of src and dst.\ntype AddressRan"
  },
  {
    "path": "pdu/AddressRange_test.go",
    "chars": 1256,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAddressRange(t *testing.T) {\n\tt.Run"
  },
  {
    "path": "pdu/Address_test.go",
    "chars": 1657,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestAddress(t *testing.T) {\n\tt.Run(\"new"
  },
  {
    "path": "pdu/AlertNotification.go",
    "chars": 1241,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// AlertNotification PDU is sent by the SMSC to the ESME, whe"
  },
  {
    "path": "pdu/AlertNotification_test.go",
    "chars": 531,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/BindRequest.go",
    "chars": 2517,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// BindingType indicates type of binding.\ntype BindingType by"
  },
  {
    "path": "pdu/BindRequest_test.go",
    "chars": 2057,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/BindResponse.go",
    "chars": 1750,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// BindResp PDU.\ntype BindResp struct {\n\tbase\n\tSystemID strin"
  },
  {
    "path": "pdu/BindResponse_test.go",
    "chars": 1173,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/Buffer.go",
    "chars": 2805,
    "preview": "package pdu\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\nconst (\n\t// SizeByte is s"
  },
  {
    "path": "pdu/Buffer_test.go",
    "chars": 323,
    "preview": "package pdu\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)"
  },
  {
    "path": "pdu/CancelSM.go",
    "chars": 1628,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// CancelSM PDU is issued by the ESME to cancel one or more p"
  },
  {
    "path": "pdu/CancelSMResp.go",
    "chars": 930,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// CancelSMResp PDU.\ntype CancelSMResp struct {\n\tbase\n}\n\n// N"
  },
  {
    "path": "pdu/CancelSMResp_test.go",
    "chars": 412,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/CancelSM_test.go",
    "chars": 674,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/DataSM.go",
    "chars": 1831,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// DataSM PDU is used to transfer data between the SMSC and t"
  },
  {
    "path": "pdu/DataSMResp.go",
    "chars": 1115,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// DataSMResp PDU.\ntype DataSMResp struct {\n\tbase\n\tMessageID "
  },
  {
    "path": "pdu/DataSMResp_test.go",
    "chars": 442,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/DataSM_test.go",
    "chars": 1112,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/DeliverSM.go",
    "chars": 3012,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// DeliverSM PDU is issued by the SMSC to send a message to a"
  },
  {
    "path": "pdu/DeliverSMResp.go",
    "chars": 1174,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// DeliverSMResp PDU.\ntype DeliverSMResp struct {\n\tbase\n\tMess"
  },
  {
    "path": "pdu/DeliverSMResp_test.go",
    "chars": 460,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/DeliverSM_test.go",
    "chars": 1869,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/DestinationAddress.go",
    "chars": 3203,
    "preview": "package pdu\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// DestinationAddress represents Address or Distribut"
  },
  {
    "path": "pdu/DestinationAddress_test.go",
    "chars": 1354,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/DistributionList.go",
    "chars": 970,
    "preview": "package pdu\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// DistributionList represents group of contacts.\ntyp"
  },
  {
    "path": "pdu/DistributionList_test.go",
    "chars": 201,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestDistributionList(t *testing.T) {\n\t_"
  },
  {
    "path": "pdu/EnquireLink.go",
    "chars": 1156,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// EnquireLink PDU. This message can be sent by either the ES"
  },
  {
    "path": "pdu/EnquireLinkResp.go",
    "chars": 981,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// EnquireLinkResp PDU.\ntype EnquireLinkResp struct {\n\tbase\n}"
  },
  {
    "path": "pdu/EnquireLinkResp_test.go",
    "chars": 430,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/EnquireLink_test.go",
    "chars": 426,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/GenericNack.go",
    "chars": 1301,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// GenericNack PDU is a generic negative acknowledgement to a"
  },
  {
    "path": "pdu/GenericNack_test.go",
    "chars": 383,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestG"
  },
  {
    "path": "pdu/Outbind.go",
    "chars": 1060,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// Outbind PDU is used by the SMSC to signal an ESME to origi"
  },
  {
    "path": "pdu/Outbind_test.go",
    "chars": 463,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/PDU.go",
    "chars": 3877,
    "preview": "package pdu\n\nimport (\n\t\"io\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/linxGnu/gosmpp/errors\"\n)\n\n// PDU represents "
  },
  {
    "path": "pdu/PDUFactory.go",
    "chars": 1621,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/linxGnu/gosmpp/errors\"\n)\n\ntype pduGenerator func() "
  },
  {
    "path": "pdu/PDUFactory_test.go",
    "chars": 194,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestInvalidCmdID(t *testing.T) {\n\tv, er"
  },
  {
    "path": "pdu/PDUHeader.go",
    "chars": 2087,
    "preview": "package pdu\n\nimport (\n\t\"encoding/binary\"\n\t\"sync/atomic\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\nfunc nextSequenceNumber(s "
  },
  {
    "path": "pdu/PDUHeader_test.go",
    "chars": 199,
    "preview": "package pdu\n\nimport (\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestNextSeq(t *testing.T) {\n\tva"
  },
  {
    "path": "pdu/PDU_test.go",
    "chars": 1516,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/errors\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Te"
  },
  {
    "path": "pdu/QuerySM.go",
    "chars": 1333,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// QuerySM PDU is issued by the ESME to query the status of a"
  },
  {
    "path": "pdu/QuerySMResp.go",
    "chars": 1573,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// QuerySMResp PDU.\ntype QuerySMResp struct {\n\tbase\n\tMessageI"
  },
  {
    "path": "pdu/QuerySMResp_test.go",
    "chars": 414,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/QuerySM_test.go",
    "chars": 554,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/ReplaceSM.go",
    "chars": 2255,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// ReplaceSM PDU is issued by the ESME to replace a previousl"
  },
  {
    "path": "pdu/ReplaceSMResp.go",
    "chars": 947,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// ReplaceSMResp PDU.\ntype ReplaceSMResp struct {\n\tbase\n}\n\n//"
  },
  {
    "path": "pdu/ReplaceSMResp_test.go",
    "chars": 418,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/ReplaceSM_test.go",
    "chars": 908,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/ShortMessage.go",
    "chars": 9406,
    "preview": "package pdu\n\nimport (\n\t\"sync/atomic\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/linxGnu/gosmpp/errors\"\n)\n\nvar ref ="
  },
  {
    "path": "pdu/ShortMessage_test.go",
    "chars": 7171,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/linxGnu/gosmpp/errors\"\n\n\t\"github.com/st"
  },
  {
    "path": "pdu/SubmitMulti.go",
    "chars": 3101,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// SubmitMulti PDU is used to submit an SMPP message for deli"
  },
  {
    "path": "pdu/SubmitMultiResp.go",
    "chars": 1374,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// SubmitMultiResp PDU.\ntype SubmitMultiResp struct {\n\tbase\n\t"
  },
  {
    "path": "pdu/SubmitMultiResp_test.go",
    "chars": 898,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/SubmitMulti_test.go",
    "chars": 2777,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/SubmitSM.go",
    "chars": 4461,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// SubmitSM PDU is used by an ESME to submit a short message "
  },
  {
    "path": "pdu/SubmitSMResp.go",
    "chars": 1221,
    "preview": "package pdu\n\nimport (\n\t\"errors\"\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"io\"\n)\n\n// SubmitSMResp PDU.\ntype SubmitSMResp struct"
  },
  {
    "path": "pdu/SubmitSMResp_test.go",
    "chars": 457,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/SubmitSM_test.go",
    "chars": 965,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/TLV.go",
    "chars": 2978,
    "preview": "package pdu\n\n// Source code in this file is copied from: https://github.com/fiorix\nimport (\n\t\"encoding/binary\"\n\t\"encodin"
  },
  {
    "path": "pdu/UDH.go",
    "chars": 5319,
    "preview": "package pdu\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// For now, this package only support messag"
  },
  {
    "path": "pdu/UDH_test.go",
    "chars": 1745,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestUserDataHeader(t *testing.T) {\n\tt.R"
  },
  {
    "path": "pdu/Unbind.go",
    "chars": 860,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// Unbind PDU is to deregister an instance of an ESME from th"
  },
  {
    "path": "pdu/UnbindResp.go",
    "chars": 895,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// UnbindResp PDU.\ntype UnbindResp struct {\n\tbase\n}\n\n// NewUn"
  },
  {
    "path": "pdu/UnbindResp_test.go",
    "chars": 399,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/Unbind_test.go",
    "chars": 399,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc Test"
  },
  {
    "path": "pdu/UnsuccessSME.go",
    "chars": 2505,
    "preview": "package pdu\n\nimport (\n\t\"github.com/linxGnu/gosmpp/data\"\n)\n\n// UnsuccessSME indicates submission was unsuccessful and the"
  },
  {
    "path": "pdu/UnsuccessSME_test.go",
    "chars": 389,
    "preview": "package pdu\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestMalformUSME(t *testing.T) {\n\tt.Run("
  },
  {
    "path": "pdu/helper_test.go",
    "chars": 829,
    "preview": "package pdu\n\nimport (\n\t\"encoding/hex\"\n\t\"log\"\n\t\"testing\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\n\t\"github.com/stretchr/testif"
  },
  {
    "path": "pkg.go",
    "chars": 4434,
    "preview": "package gosmpp\n\nimport (\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp/pdu\"\n)\n\n// Transceiver interface.\ntype Transceiver i"
  },
  {
    "path": "receivable.go",
    "chars": 4884,
    "preview": "package gosmpp\n\nimport (\n\t\"context\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp/pdu\"\n)\n\ntype receivable "
  },
  {
    "path": "receivable_test.go",
    "chars": 5415,
    "preview": "package gosmpp\n\nimport (\n\t\"fmt\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp/pd"
  },
  {
    "path": "request_store.go",
    "chars": 2148,
    "preview": "package gosmpp\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/linxGnu/gosmpp/pdu\"\n\tcmap \"github.com/orcaman/concurrent-map/v2\""
  },
  {
    "path": "session.go",
    "chars": 4430,
    "preview": "package gosmpp\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/linxGnu/gosmpp/pdu\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\tErrWindowSiz"
  },
  {
    "path": "session_test.go",
    "chars": 2551,
    "preview": "package gosmpp\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestInvalidSessionSettings(t"
  },
  {
    "path": "state.go",
    "chars": 1307,
    "preview": "package gosmpp\n\nconst (\n\tAlive int32 = iota\n\tClosed\n)\n\n// State represents Transmitter/Receiver/Transceiver state.\ntype "
  },
  {
    "path": "state_test.go",
    "chars": 780,
    "preview": "package gosmpp\n\nimport (\n\t\"github.com/stretchr/testify/assert\"\n\t\"testing\"\n)\n\nfunc TestState_String(t *testing.T) {\n\ttest"
  },
  {
    "path": "transceivable.go",
    "chars": 3879,
    "preview": "package gosmpp\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"github.com/linxGnu/gosmpp/pdu\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\t"
  },
  {
    "path": "transceivable_test.go",
    "chars": 9427,
    "preview": "package gosmpp\n\nimport (\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp/data\"\n\t\"github.com/linxGnu/gosmp"
  },
  {
    "path": "transmittable.go",
    "chars": 4845,
    "preview": "package gosmpp\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"runtime\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gos"
  },
  {
    "path": "transmittable_test.go",
    "chars": 3463,
    "preview": "package gosmpp\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/linxGnu/gosmpp/pdu\"\n\n\t\"gi"
  },
  {
    "path": "types.go",
    "chars": 795,
    "preview": "package gosmpp\n\nimport (\n\t\"github.com/linxGnu/gosmpp/pdu\"\n)\n\n// PDUCallback handles received PDU.\ntype PDUCallback func("
  }
]

About this extraction

This page contains the full source code of the linxGnu/gosmpp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 115 files (344.5 KB), approximately 110.8k tokens, and a symbol index with 1106 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!