Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added new features #5

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Example tool saves the authkey and other data in ~/.telegram_go. If you delete/l
## install

```
$ go get -v -u github.com/sdidyk/mtproto/example/telegram
$ go get -v -u github.com/hugozhu/mtproto/example/telegram
```

## proxy setting
Socks5 proxy is supported by env variable socks5_proxy
```
$ export socks5_proxy=192.168.1.4:1080
```

## phone authorization
Expand All @@ -35,6 +41,21 @@ $ telegram list
473977 false Тимур Д******
```

## get dialogs

Shows user's dialogs.

```
$ telegram dialogs
id type top_message unread_count title
20071829 User 9425 1 Raspberry Pi(hugozhu2)
15626832 Chat 8896 0 树莓派通知
69443043 User 8872 0 Hugo Zhu(hugozhu)
777000 User 8871 0 Telegram ()
333000 User 8624 0 Telegram ()
```


## send message to contact

Sends a message to contact. Destination id should be from contact list or user himself.
Expand All @@ -43,6 +64,12 @@ Sends a message to contact. Destination id should be from contact list or user h
$ telegram msg 104842610 'Hack the planet!'
```

## send photo to contact or dialog(@dialog_id)

```
$ telegram sendmedia "@20071829" ~/Pictures/IMG_1851.JPG
```

## Library

*documentation not ready yet*
Expand Down
26 changes: 17 additions & 9 deletions example/telegram/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,30 @@ package main

import (
"fmt"
"os"
"strconv"

"github.com/sdidyk/mtproto"
"os"
)

func usage() {
fmt.Print("Telegram is a simple MTProto tool.\n\nUsage:\n\n")
fmt.Print(" ./telegram <command> [arguments]\n\n")
fmt.Print("The commands are:\n\n")
fmt.Print(" auth <phone_number> auth connection by code\n")
fmt.Print(" msg <user_id> <msgtext> send message to user\n")
fmt.Print(" msg <peer_id> <msgtext> send message to user\n")
fmt.Print(" sendmedia <peer_id> <file> send media file to user\n")
fmt.Print(" list get contact list\n")
fmt.Print(" dialogs get dialogs\n")
fmt.Println()
}

var commands = map[string]int{
"auth": 1,
"msg": 2,
"sendmedia": 2,
"list": 0,
"dialogs": 0,
}

func main() {
var err error

Expand All @@ -26,7 +34,6 @@ func main() {
os.Exit(1)
}

commands := map[string]int{"auth": 1, "msg": 2, "list": 0}
valid := false
for k, v := range commands {
if os.Args[1] == k {
Expand Down Expand Up @@ -55,16 +62,17 @@ func main() {
fmt.Printf("Connect failed: %s\n", err)
os.Exit(2)
}

switch os.Args[1] {
case "auth":
err = m.Auth(os.Args[2])
case "msg":
user_id, _ := strconv.Atoi(os.Args[2])
err = m.SendMsg(int32(user_id), os.Args[3])

err = m.SendMsg(os.Args[2], os.Args[3])
case "list":
err = m.GetContacts()
case "dialogs":
err = m.GetChats()
case "sendmedia":
err = m.SendMedia(os.Args[2], os.Args[3])
}

if err != nil {
Expand Down
171 changes: 163 additions & 8 deletions mtproto.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package mtproto

import (
"crypto/md5"
"fmt"
"github.com/k0kubun/pp"
"io/ioutil"
"math/rand"
"net"
"os"
"runtime"
"strconv"
"sync"
"time"

"github.com/k0kubun/pp"
)

const (
Expand Down Expand Up @@ -77,10 +79,24 @@ func (m *MTProto) Connect() error {
if err != nil {
return err
}
m.conn, err = net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
return err

proxy := os.Getenv("socks5_proxy")

if proxy != "" {
var d net.Dialer
socks5, err := SOCKS5("tcp", proxy, nil, d)
if err != nil {
return err
}
conn, err := socks5.Dial("tcp", tcpAddr.String())
if err != nil {
return err
}
m.conn = conn.(*net.TCPConn)
} else {
m.conn, err = net.DialTCP("tcp", nil, tcpAddr)
}

_, err = m.conn.Write([]byte{0xef})
if err != nil {
return err
Expand Down Expand Up @@ -266,12 +282,93 @@ func (m *MTProto) GetContacts() error {
return nil
}

func (m *MTProto) SendMsg(user_id int32, msg string) error {
func (m *MTProto) GetChats() error {
resp := make(chan TL, 1)
m.queueSend <- packetToSend{TL_messages_getDialogs{}, resp}
x := <-resp
list, ok := x.(TL_messages_dialogs)
if !ok {
return fmt.Errorf("RPC: %#v", x)
}

fmt.Printf(
"\033[33m\033[1m%10s %10s %-10s %-5s %-20s\033[0m\n",
"id", "type", "top_message", "unread_count", "title",
)

t := ""
i := int32(0)
title := ""
chat_idx := 0
user_idx := 0
for _, v := range list.dialogs {
v := v.(TL_dialog)
switch v.peer.(type) {
case TL_peerUser:
t = "User"
i = v.peer.(TL_peerUser).user_id
switch list.users[user_idx].(type) {
case TL_userSelf:
u := list.users[user_idx].(TL_userSelf)
title = fmt.Sprintf("%s %s(%s)", u.first_name, u.last_name, u.username)
case TL_userContact:
u := list.users[user_idx].(TL_userContact)
title = fmt.Sprintf("%s %s(%s)", u.first_name, u.last_name, u.username)
case TL_userRequest:
u := list.users[user_idx].(TL_userRequest)
title = fmt.Sprintf("%s %s(%s)", u.first_name, u.last_name, u.username)
case TL_userForeign:
u := list.users[user_idx].(TL_userForeign)
title = fmt.Sprintf("%s %s(%s)", u.first_name, u.last_name, u.username)
case TL_userDeleted:
u := list.users[user_idx].(TL_userDeleted)
title = fmt.Sprintf("%s %s(%s)", u.first_name, u.last_name, u.username)
}
user_idx = user_idx + 1
case TL_peerChat:
t = "Chat"
i = v.peer.(TL_peerChat).chat_id
title = list.chats[chat_idx].(TL_chat).title
chat_idx = chat_idx + 1
}
fmt.Printf(
"%10d %8s %-10d %-5d %-20s\n",
i, t, v.top_message, v.unread_count, title,
)
}
return nil
}

func parsePeerById(str_id string) (peer TL, err error) {
if len(str_id) > 0 {
if str_id[0:1] == "#" {
id, err := strconv.Atoi(str_id[1:])
if err == nil {
peer = TL_inputPeerChat{int32(id)}
}
} else if str_id[0:1] == "@" {
id, err := strconv.Atoi(str_id[1:])
if err == nil {
peer = TL_inputPeerContact{int32(id)}
}
} else {
id, err := strconv.Atoi(str_id)
if err == nil {
peer = TL_inputPeerContact{int32(id)}
}
}
} else {
peer = TL_inputPeerSelf{}
}
return peer, err
}

func (m *MTProto) SendMsg(peer_id string, msg string) error {
peer, _ := parsePeerById(peer_id)
resp := make(chan TL, 1)
m.queueSend <- packetToSend{
TL_messages_sendMessage{
// TL_inputPeerSelf{},
TL_inputPeerContact{user_id},
peer,
msg,
rand.Int63(),
},
Expand All @@ -286,6 +383,64 @@ func (m *MTProto) SendMsg(user_id int32, msg string) error {
return nil
}

func (m *MTProto) SendMedia(peer_id string, file string) (err error) {
_512k := 512 * 1024
peer, _ := parsePeerById(peer_id)
bytes, err := ioutil.ReadFile(file)
if err != nil {
return fmt.Errorf("Error to read file: %#v", err)
}
md5_hash := fmt.Sprintf("%x", md5.Sum(bytes))
fileId := rand.Int63()
parts := int32(len(bytes)/_512k) + 1
start := 0
for i := int32(0); i < parts; i++ {
fmt.Println(i, "/", parts)
resp := make(chan TL, 1)
end := start + _512k
if end > len(bytes) {
end = len(bytes)
}
m.queueSend <- packetToSend{
TL_upload_saveFilePart{
fileId,
i,
bytes[start:end],
},
resp,
}
x := <-resp
_, ok := x.(TL_boolTrue)
if !ok {
return fmt.Errorf("upload_saveFilePart RPC: %#v", x)
}
start = end
}

resp := make(chan TL, 1)
m.queueSend <- packetToSend{
TL_messages_sendMedia{
peer,
TL_inputMediaUploadedPhoto{
TL_inputFile{
fileId,
parts,
file,
md5_hash,
},
},
rand.Int63(),
},
resp,
}
x := <-resp
_, ok := x.(TL_messages_statedMessage)
if !ok {
return fmt.Errorf("messages_sendMedia RPC: %#v", x)
}
return nil
}

func (m *MTProto) startPing() {
// goroutine (TL_ping)
go func() {
Expand Down