aboutsummaryrefslogtreecommitdiff
path: root/telegram/connect.go
blob: 4f509d209446463f3d178cee5db595ffbd6ac5dd (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package telegram

import (
	"github.com/pkg/errors"

	"dev.narayana.im/narayana/telegabber/xmpp/gateway"

	log "github.com/sirupsen/logrus"
	"github.com/zelenin/go-tdlib/client"
)

type clientAuthorizer struct {
	TdlibParameters chan *client.TdlibParameters
	PhoneNumber     chan string
	Code            chan string
	State           chan client.AuthorizationState
	Password        chan string
}

func (stateHandler *clientAuthorizer) Handle(c *client.Client, state client.AuthorizationState) error {
	stateHandler.State <- state

	switch state.AuthorizationStateType() {
	case client.TypeAuthorizationStateWaitTdlibParameters:
		_, err := c.SetTdlibParameters(&client.SetTdlibParametersRequest{
			Parameters: <-stateHandler.TdlibParameters,
		})
		return err

	case client.TypeAuthorizationStateWaitEncryptionKey:
		_, err := c.CheckDatabaseEncryptionKey(&client.CheckDatabaseEncryptionKeyRequest{})
		return err

	case client.TypeAuthorizationStateWaitPhoneNumber:
		_, err := c.SetAuthenticationPhoneNumber(&client.SetAuthenticationPhoneNumberRequest{
			PhoneNumber: <-stateHandler.PhoneNumber,
			Settings: &client.PhoneNumberAuthenticationSettings{
				AllowFlashCall:       false,
				IsCurrentPhoneNumber: false,
				AllowSmsRetrieverApi: false,
			},
		})
		return err

	case client.TypeAuthorizationStateWaitCode:
		_, err := c.CheckAuthenticationCode(&client.CheckAuthenticationCodeRequest{
			Code: <-stateHandler.Code,
		})
		return err

	case client.TypeAuthorizationStateWaitRegistration:
		return client.ErrNotSupportedAuthorizationState

	case client.TypeAuthorizationStateWaitPassword:
		_, err := c.CheckAuthenticationPassword(&client.CheckAuthenticationPasswordRequest{
			Password: <-stateHandler.Password,
		})
		return err

	case client.TypeAuthorizationStateReady:
		return nil

	case client.TypeAuthorizationStateLoggingOut:
		return client.ErrNotSupportedAuthorizationState

	case client.TypeAuthorizationStateClosing:
		return client.ErrNotSupportedAuthorizationState

	case client.TypeAuthorizationStateClosed:
		return client.ErrNotSupportedAuthorizationState
	}

	return client.ErrNotSupportedAuthorizationState
}

func (stateHandler *clientAuthorizer) Close() {
	close(stateHandler.TdlibParameters)
	close(stateHandler.PhoneNumber)
	close(stateHandler.Code)
	close(stateHandler.State)
	close(stateHandler.Password)
}

// Connect starts TDlib connection
func (c *Client) Connect() error {
	if c.online {
		return nil
	}

	log.Warn("Connecting to Telegram network...")

	c.authorizer = &clientAuthorizer{
		TdlibParameters: make(chan *client.TdlibParameters, 1),
		PhoneNumber:     make(chan string, 1),
		Code:            make(chan string, 1),
		State:           make(chan client.AuthorizationState, 10),
		Password:        make(chan string, 1),
	}

	go c.interactor()

	c.authorizer.TdlibParameters <- c.parameters

	tdlibClient, err := client.NewClient(c.authorizer, c.logVerbosity)
	if err != nil {
		return errors.Wrap(err, "Couldn't initialize a Telegram client instance")
	}

	c.client = tdlibClient
	c.online = true

	go updateHandler(c.client)

	return nil
}

// Disconnect drops TDlib connection
func (c *Client) Disconnect() {
	if !c.online {
		return
	}

	log.Warn("Disconnecting from Telegram network...")

	// TODO: send unavailable presence to cached chats

	c.client.Stop()
	c.online = false
}

func (c *Client) interactor() {
	for {
		state, ok := <-c.authorizer.State
		if !ok {
			return
		}

		stateType := state.AuthorizationStateType()
		log.Infof("Telegram authorization state: %#v", stateType)

		switch stateType {
		case client.TypeAuthorizationStateWaitPhoneNumber:
			log.Warn("Logging in...")
			if c.Session.Login != "" {
				c.authorizer.PhoneNumber <- c.Session.Login
			} else {
				gateway.SendMessage(c.jid, "", "Please, enter your Telegram login via /login 12345", c.xmpp)
			}
		case client.TypeAuthorizationStateWaitCode:
			log.Warn("Waiting for authorization code...")
			gateway.SendMessage(c.jid, "", "Please, enter authorization code via /code 12345", c.xmpp)
		case client.TypeAuthorizationStateWaitPassword:
			log.Warn("Waiting for 2FA password...")
			gateway.SendMessage(c.jid, "", "Please, enter 2FA passphrase via /password 12345", c.xmpp)
		case client.TypeAuthorizationStateReady:
			log.Warn("Authorization successful!")
			// TODO
			return
		}
	}
}