@ -4,6 +4,7 @@ import (
"bytes"
"encoding/base64"
"encoding/xml"
"fmt"
"github.com/pkg/errors"
"io"
"strconv"
@ -57,6 +58,22 @@ func HandleIq(s xmpp.Sender, p stanza.Packet) {
go handleGetDiscoInfo ( s , iq )
return
}
_ , ok = iq . Payload . ( * stanza . DiscoItems )
if ok {
go handleGetDiscoItems ( s , iq )
return
}
_ , ok = iq . Payload . ( * extensions . QueryRegister )
if ok {
go handleGetQueryRegister ( s , iq )
return
}
} else if iq . Type == "set" {
query , ok := iq . Payload . ( * extensions . QueryRegister )
if ok {
go handleSetQueryRegister ( s , iq , query )
return
}
}
}
@ -91,8 +108,7 @@ func HandleMessage(s xmpp.Sender, p stanza.Packet) {
session , ok := sessions [ bare ]
if ! ok {
if msg . To == gatewayJid {
gateway . SendPresence ( component , msg . From , gateway . SPType ( "subscribe" ) )
gateway . SendPresence ( component , msg . From , gateway . SPType ( "subscribed" ) )
gateway . SubscribeToTransport ( component , msg . From )
} else {
log . Error ( "Message from stranger" )
}
@ -444,6 +460,7 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ) {
disco . AddIdentity ( "" , "account" , "registered" )
} else {
disco . AddIdentity ( "Telegram Gateway" , "gateway" , "telegram" )
disco . AddFeatures ( "jabber:iq:register" )
}
answer . Payload = disco
@ -458,6 +475,189 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ) {
_ = gateway . ResumableSend ( component , answer )
}
func handleGetDiscoItems ( s xmpp . Sender , iq * stanza . IQ ) {
answer , err := stanza . NewIQ ( stanza . Attrs {
Type : stanza . IQTypeResult ,
From : iq . To ,
To : iq . From ,
Id : iq . Id ,
Lang : "en" ,
} )
if err != nil {
log . Errorf ( "Failed to create answer IQ: %v" , err )
return
}
answer . Payload = answer . DiscoItems ( )
component , ok := s . ( * xmpp . Component )
if ! ok {
log . Error ( "Not a component" )
return
}
_ = gateway . ResumableSend ( component , answer )
}
func handleGetQueryRegister ( s xmpp . Sender , iq * stanza . IQ ) {
component , ok := s . ( * xmpp . Component )
if ! ok {
log . Error ( "Not a component" )
return
}
answer , err := stanza . NewIQ ( stanza . Attrs {
Type : stanza . IQTypeResult ,
From : iq . To ,
To : iq . From ,
Id : iq . Id ,
Lang : "en" ,
} )
if err != nil {
log . Errorf ( "Failed to create answer IQ: %v" , err )
return
}
var login string
bare , _ , ok := gateway . SplitJID ( iq . From )
if ok {
session , ok := sessions [ bare ]
if ok {
login = session . Session . Login
}
}
var query stanza . IQPayload
if login == "" {
query = extensions . QueryRegister {
Instructions : fmt . Sprintf ( "Authorization in Telegram is a multi-step process, so please accept %v to your contacts and follow further instructions (provide the authentication code there, etc.).\nFor now, please provide your login." , iq . To ) ,
}
} else {
query = extensions . QueryRegister {
Instructions : "Already logged in" ,
Username : login ,
Registered : & extensions . QueryRegisterRegistered { } ,
}
}
answer . Payload = query
log . Debugf ( "%#v" , query )
_ = gateway . ResumableSend ( component , answer )
if login == "" {
gateway . SubscribeToTransport ( component , iq . From )
}
}
func handleSetQueryRegister ( s xmpp . Sender , iq * stanza . IQ , query * extensions . QueryRegister ) {
component , ok := s . ( * xmpp . Component )
if ! ok {
log . Error ( "Not a component" )
return
}
answer , err := stanza . NewIQ ( stanza . Attrs {
Type : stanza . IQTypeResult ,
From : iq . To ,
To : iq . From ,
Id : iq . Id ,
Lang : "en" ,
} )
if err != nil {
log . Errorf ( "Failed to create answer IQ: %v" , err )
return
}
defer gateway . ResumableSend ( component , answer )
if query . Remove != nil {
iqAnswerSetError ( answer , query , 405 )
return
}
var login string
var session * telegram . Client
bare , resource , ok := gateway . SplitJID ( iq . From )
if ok {
session , ok = sessions [ bare ]
if ok {
login = session . Session . Login
}
}
if login == "" {
if ! ok {
session , ok = getTelegramInstance ( bare , & persistence . Session { } , component )
if ! ok {
iqAnswerSetError ( answer , query , 500 )
return
}
}
err := session . TryLogin ( resource , query . Username )
if err != nil {
if err . Error ( ) == telegram . TelegramAuthDone {
iqAnswerSetError ( answer , query , 406 )
} else {
iqAnswerSetError ( answer , query , 500 )
}
return
}
err = session . SetPhoneNumber ( query . Username )
if err != nil {
iqAnswerSetError ( answer , query , 500 )
return
}
// everything okay, the response should be empty with no payload/error at this point
gateway . SubscribeToTransport ( component , iq . From )
} else {
iqAnswerSetError ( answer , query , 406 )
}
}
func iqAnswerSetError ( answer * stanza . IQ , payload * extensions . QueryRegister , code int ) {
answer . Type = stanza . IQTypeError
answer . Payload = * payload
switch code {
case 400 :
answer . Error = & stanza . Err {
Code : code ,
Type : stanza . ErrorTypeModify ,
Reason : "bad-request" ,
}
case 405 :
answer . Error = & stanza . Err {
Code : code ,
Type : stanza . ErrorTypeCancel ,
Reason : "not-allowed" ,
Text : "Logging out is dangerous. If you are sure you would be able to receive the authentication code again, issue the /logout command to the transport" ,
}
case 406 :
answer . Error = & stanza . Err {
Code : code ,
Type : stanza . ErrorTypeModify ,
Reason : "not-acceptable" ,
Text : "Phone number already provided, chat with the transport for further instruction" ,
}
case 500 :
answer . Error = & stanza . Err {
Code : code ,
Type : stanza . ErrorTypeWait ,
Reason : "internal-server-error" ,
}
default :
log . Error ( "Unknown error code, falling back with empty reason" )
answer . Error = & stanza . Err {
Code : code ,
Type : stanza . ErrorTypeCancel ,
Reason : "undefined-condition" ,
}
}
}
func toToID ( to string ) ( int64 , bool ) {
toParts := strings . Split ( to , "@" )
if len ( toParts ) < 2 {