Giter Club home page Giter Club logo

go-smpp's Introduction

go-smpp

A complete implementation of SMPP v5 protocol, written in golang.

Key features

  • Message encoding auto-detection

  • Multipart SMS automatic splitting and concatenating

  • Supported encodings:

    UCS-2     GSM 7bit  ASCII      Latin-1
    Cyrillic  Hebrew    Shift-JIS  ISO-2022-JP
    EUC-JP    EUC-KR
    

Caveats

Command line tools

  1. smpp-receiver

    SMPP Simple Receiver tool

  2. smpp-repl

    SMPP Simple Test tool

LICENSE

This piece of software is released under the MIT license.

go-smpp's People

Contributors

greenyun avatar jamesits avatar septs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

jeneam

go-smpp's Issues

Introduce SMS Content length calculator for multipart messages+ auto length detector based on data encoding.

Thank you for the great library. I think it would make sense to add SMS Content length calculator after detecting the encoding.

For e.g.

For GSM 7-bit,

    coding := BestCoding("This is small test")
    // coding { TotalLength: 18, Parts: 1, MaxLength: 160, Encoding: GSM 7-bit, }

For GSM 7-bit (Multipart,

    coding := BestCoding("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent molestie eros ut ex dapibus sollicitudin in ut eros. Pellentesque venenatis vitae est e aksdhjkasjhdk")
    // coding { TotalLength: 167, Parts: 2, MaxLength: 153, Encoding: GSM 7-bit, }

Bad sms encoding

I am trying to receive SMS using your program and it usually works correctly. But instead of some messages, it shows bad message. Here is an example:

{"smsc":"10.1.2.11:7777","system_id":"krechet01","system_type":"","source":"PHONE_NUMBER","target":"krechet01","message":"tJM#G.Θ<t¿","deliver_time":"2023-07-13T15:02:52.449030921+03:00"}

I caught this message, I bring it:

Frame 478862: 131 bytes on wire (1048 bits), 147 bytes captured (1176 bits) on interface sshdump, id 0
Linux cooked capture v1
Internet Protocol Version 4, Src: 10.1.2.11, Dst: 10.1.3.164
Transmission Control Protocol, Src Port: 7777, Dst Port: 49876, Seq: 1, Ack: 1, Len: 63
Short Message Peer to Peer, Command: Deliver_sm, Seq: 100, Len: 63
    Length: 63
    Operation: Deliver_sm (0x00000005)
    Sequence #: 100
    Service type: (Default)
    Type of number (originator): Unknown (0x00)
    Numbering plan indicator (originator): Unknown (0x00)
    Originator address: PHONE_NUMPER
    Type of number (recipient): Unknown (0x00)
    Numbering plan indicator (recipient): Unknown (0x00)
    Recipient address: krechet01
    .... ..00 = Messaging mode: Default SMSC mode (0x0)
    ..00 00.. = Message type: Default message type (0x0)
    00.. .... = GSM features: No specific features selected (0x0)
    Protocol id.: 0x08
    Priority level: GSM: None      ANSI-136: Bulk         IS-95: Normal (0x00)
    Scheduled delivery time: Immediate delivery
    Validity period: SMSC default validity period
    .... ..00 = Delivery receipt: No SMSC delivery receipt requested (0x0)
    .... 00.. = Message type: No recipient SME acknowledgement requested (0x0)
    ...0 .... = Intermediate notif: No intermediate notification requested (0x0)
    .... ...0 = Replace: Don't replace (0x0)
    Data coding: SMSC default alphabet (0x00)
    Predefined message: 0
    Message length: 9
    Message bytes: 746573747465787430

Hex:

0000ffff00005e1258c7dd0a9073080045000073f2dc40007f06eef70a01020b0a0103a41e61c2d41aac67609746f175801816a0babe00000101080a033f90f1653986ea0000003f0000000500000000000000640000002b37393136373433363136370000006b726563686574303100000800000000000000097465737474657874301c980000005bddaf6471447936340000

SMPP Telegram Bridge

A simple SMPP (SMS) <-> Telegram bridge

  • Sender side

    • Send SMPP messages through a Telegram bot chat
    • WebUI for Telegram bot, using Telegram Login
  • Receiver side

    • Customizable template (?)
    • Rule-based tagging and automation
    • SMS Signature extraction (if exists)
    • Spam filter
    • Receive SMS messages from email clients
      • SMPP messages will need be routed with something like mailgun
    • Save received messages to a local database (searchable)
    • Save received messages to a logging daemon

How to send multi part messages?

Hi,

I tried to send multipart sms using following

package main

import (
	"context"
	"fmt"
	"github.com/sujit-baniya/go-smpp"
	"github.com/sujit-baniya/go-smpp/coding"
	"github.com/sujit-baniya/go-smpp/pdu"
	"math/rand"
	"net"
	"strings"
	"time"
	"unicode"
	"unicode/utf8"
)

func main() {

	connect()
	handshake(smppVersion)
	rs := send()
	fmt.Println(rs)
	wait()
}

var (
	n    = time.Duration(10)
	conn = &smpp.Conn{}
	smppVersion = pdu.SMPPVersion50
)

func connect() {
	parent, err := net.Dial("tcp", "smscsim.melroselabs.com:2775")
	if err != nil {
		panic(err)
	}
	conn = smpp.NewConn(context.Background(), parent)
	conn.WriteTimeout = n * time.Second // set write timeout (optional, default 15 minutes)
	conn.ReadTimeout = n * time.Second  // set read timeout  (optional, default 15 minutes)
	go conn.Watch()                     // start watchdog
}

func handshake(smppVersion pdu.InterfaceVersion) {
	resp, err := conn.Submit(context.Background(), &pdu.BindTransceiver{
		SystemID:   "444320",
		Password:   "5691c2",
		SystemType: "",
		Version:    smppVersion,
	})
	if err != nil {
		panic(err)
	}
	r := resp.(*pdu.BindTransceiverResp)
	if r.Header.CommandStatus == 0 {
		// start keep-alive
		go conn.EnquireLink(time.Minute, time.Minute)
	}
}

type Response interface {}

func send() []Response {
	msg := "Hello World! Hello World!Hello World! HelHello World! Hello World!Hello World! HelHello World! Hello World!Hello World! HelHello World! Hello World!Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! "
	shortMessages, err := compose(msg)
	if err != nil {
		panic(err)
	}
	var responses []Response
	ctx := context.Background()
	for key, shortMessage := range shortMessages {
		fmt.Println(key)
		packet := &pdu.SubmitSM{
			SourceAddr: parseSrcPhone("00919821"),
			DestAddr:   parseDestPhone("99919821"),
			ESMClass: pdu.ESMClass{UDHIndicator: true},
			RegisteredDelivery: pdu.RegisteredDelivery{
				MCDeliveryReceipt:           1,
				SMEOriginatedAcknowledgment: 1,
				IntermediateNotification:    true,
				Reserved:                    7,
			},
			Message: shortMessage,
		}
		resp, err := conn.Submit(ctx, packet)
		if err != nil {
			panic(err)
		}
		fmt.Println(resp)
		// responses = append(responses, resp)
	}

	return responses
}

func wait() {
	for {
		packet := <-conn.PDU()
		switch pd := packet.(type) {
		case *pdu.DeliverSM:
			fmt.Println(pd)
		case pdu.Responsable:
			fmt.Println(pd)
			err := conn.Send(pd.Resp())
			if err != nil {
				fmt.Println(err)
			}
		}
	}
}

func compose(msg string) ([]pdu.ShortMessage, error) {
	reference := uint16(rand.Intn(0xFFFF))
	var dataCoding coding.DataCoding
	if smppVersion == pdu.SMPPVersion50 {
		dataCoding = coding.BestCoding(msg)
	} else {
		dataCoding = coding.BestSafeCoding(msg)
	}
	return pdu.ComposeMultipartShortMessage(msg, dataCoding, reference)
}

func parseSrcPhone(phone string) pdu.Address {
	if strings.HasPrefix(phone, "+") {
		return pdu.Address{TON: 1, NPI: 1, No: phone}
	}

	if utf8.RuneCountInString(phone) <= 5 {
		return pdu.Address{TON: 3, NPI: 0, No: phone}
	}
	if IsLetter(phone) {
		return pdu.Address{TON: 5, NPI: 0, No: phone}
	}
	return pdu.Address{TON: 1, NPI: 1, No: phone}
}

func parseDestPhone(phone string) pdu.Address {
	if strings.HasPrefix(phone, "+") {
		return pdu.Address{TON: 1, NPI: 1, No: phone}
	}
	return pdu.Address{TON: 0, NPI: 1, No: phone}
}

func IsLetter(s string) bool {
	for _, r := range s {
		if !unicode.IsLetter(r) {
			return false
		}
	}
	return true
}

With above setup, it only send first short message and other messages are stuck on line resp, err := conn.Submit(ctx, packet).

Please suggest me how would I make it work!

SMPP Daemon

Feature set

  • Built-in message queue
  • Built-in SQLite database
  • API Service
    • HTTP (RESTful)
    • TCP Server (JSON-RPC)
    • WebSocket (JSON-RPC)
  • User Script (lua based)
  • Rule-based Router
  • Rule-based Relay
  • SMS-TPDU bridge

session.Submit seams to hang if handset if offline

I am using the latest version of that lib (commit b41f875) and it basically works if the messages can be delivered immediately.

But if the handset / mobile is offline (flight mode) it seems to be stuck:

I am using pdu.ComposeMultipartShortMessage with delivery notification on, which generates a 6 part message.
I only get the deliverySM for the first packet and it stops sending after the second packet.

My log looks like this:

2022/11/16 12:38:56 sms-activator.go:547: message size is: 356 with 6 parts
2022/11/16 12:38:56 sms-activator.go:594: part 0 submitSMResponse: messageID: 0096111E7E
2022/11/16 12:38:56 sms-activator.go:594: part 1 submitSMResponse: messageID: 0096111E8B
2022/11/16 12:39:56 sms-activator.go:482: failed to submit message packet: smpp: connection closed
2022/11/16 12:39:56 sms-activator.go:456: deliverSM: id:0096111E7E sub:001 dlvrd:001 submit date:2211161338 done date:2211161338 stat:ACCEPTD err:019 Text:-44 is delitext:

Any ideas?

GSM 7-bit showing pointer value instead of GSM 7-bit encoding

When I run tests, it works fine but I feel like something is wrong with detecting GSM 7-bit

for _, multipart := range multipartList {
		expected := strings.Join(multipart, "")
		coding := BestCoding(expected)
		fmt.Println(coding.String())
		fmt.Println(coding.Encoding()) 
                // Shouldn't it show GSM 7-bit like it's showing for others?
                // Currently it's showing {0x14695d0 0x14695d0}
		splitter := coding.Splitter()
		segments := splitter.Split(expected, limit)
		require.Equal(t, multipart, segments)
		encoder := coding.Encoding().NewEncoder()
		for _, segment := range segments {
			require.LessOrEqual(t, splitter.Len(segment), limit)
			encoded, err := encoder.Bytes([]byte(segment))
			require.NoError(t, err)
			require.Equal(t, splitter.Len(segment), len(encoded), segment)
		}
	}

Screen Shot 2020-10-06 at 00 01 10

How to receive delivery status on PDU?

I tried following code but I didn't receive delivery status

package main

import (
	"context"
	"fmt"
	"github.com/sujit-baniya/go-smpp"
	"github.com/sujit-baniya/go-smpp/pdu"
	"net"
	"time"
)

func main() {
	connect()
	handshake()
	rs := send()
	fmt.Println(rs)
	wait()
}

var (
	n = time.Duration(10)
	conn = &smpp.Conn{}
)

func connect() {
	parent, err := net.Dial("tcp", "smscsim.melroselabs.com:2775")
	if err != nil {
		panic(err)
	}
	conn = smpp.NewConn(context.Background(), parent)
	conn.WriteTimeout = n * time.Second // set write timeout (optional, default 15 minutes)
	conn.ReadTimeout =  n * time.Second // set read timeout  (optional, default 15 minutes)
	go conn.Watch()                     // start watchdog
}

func handshake() {
	resp, err := conn.Submit(context.Background(), &pdu.BindTransceiver{
		SystemID:   "444320",
		Password:   "5691c2",
		SystemType: "",
		Version:    pdu.SMPPVersion50,
	})
	if err != nil {
		panic(err)
	}
	r := resp.(*pdu.BindTransceiverResp)
	if r.Header.CommandStatus == 0 {
		// start keep-alive
		go conn.EnquireLink(time.Minute, time.Minute)
	}
}

func send() interface{} {
	packet := &pdu.SubmitSM{
		SourceAddr: pdu.Address{TON: 1, NPI: 1, No: "00919821"},
		DestAddr:   pdu.Address{TON: 1, NPI: 1, No: "99919821"},
		RegisteredDelivery: pdu.RegisteredDelivery{
			MCDeliveryReceipt:           1,
			SMEOriginatedAcknowledgment: 1,
			IntermediateNotification:    true,
			Reserved:                    7,
		},
	}
	err := packet.Message.Compose("Hello World!")
	if err != nil {
		panic(err)
	}
	resp, err := conn.Submit(context.Background(), packet)
	if err != nil {
		panic(err)
	}
	return resp // submit_sm_resp returns
}

func wait() {
	for {
		packet := <-conn.PDU()
		// reply a responsable packet
		if p, ok := packet.(pdu.Responsable); ok {
			fmt.Println(p.Resp())
			err := conn.Send(p.Resp())
			if err != nil {
				fmt.Println(err)
			}
		}
	}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.