1
0
Fork 0

Compare commits

...

50 Commits

Author SHA1 Message Date
louiz’ 1013266a09 Do not send an empty line at the start of each steam message
We shouldn’t try to include the “Subject” part of the message: it’s always
empty, because this is only sent by MUC servers to signal the room’s
topic. This is not used in one-to-one conversations.

fix #20
2016-08-12 11:33:17 +02:00
Chteufleur 699c7cb5c5 Send Ad-Hoc command depending if user is already registered. 2016-08-11 19:56:03 +02:00
Chteufleur 149c5f9117 Fix nil pointer on database.GetLine() 2016-08-11 19:49:21 +02:00
chteufleur a6281fe093 Merge branch 'master' of louiz/go-xmpp4steam into master 2016-08-11 12:04:59 +02:00
louiz’ f9dc7d6b12 Accept action="next" in the ad-hoc command, to go to the next step
From http://xmpp.org/extensions/xep-0050.html#execute-multiple the default
action should be “next” (and that’s what poezio does). I’m not sure
action='execute' should even be accepted at all. But it remains for
compatibility with the old behaviour.
2016-08-11 11:54:33 +02:00
chteufleur 30ab74c5a0 Merge branch 'master' of louiz/go-xmpp4steam into master 2016-08-11 11:50:39 +02:00
louiz’ f83354ae74 Use a text-private ad-hoc field for the password 2016-08-11 11:45:09 +02:00
Chteufleur 60e3a7c215 Change import for steamlang that moved 2016-08-10 21:22:46 +02:00
chteufleur 723a36c3fe Version 1.0 2016-07-15 09:11:23 +02:00
Chteufleur ec8ff5ee92 Add debug command to allow/diallow debug messages 2016-06-19 14:14:19 +02:00
Chteufleur 659fcba63d go fmt 2016-06-17 23:27:53 +02:00
Chteufleur 271f431de2 Disable commands on Steam user + adaptation to library modifications 2016-06-17 23:25:22 +02:00
chteufleur 0ffd5de65c Change README to add SQLite library 2016-04-27 21:06:56 +02:00
chteufleur fcaa5a01bc Fix bag remove to SQLite
Still not perfect, but the problem comming from go-sqlite3 library
2016-04-27 21:02:12 +02:00
Chteufleur 7d9cf97445 Permit remove registration. Working but can be improve 2016-04-23 22:20:56 +02:00
Chteufleur 8692512b22 Modification README 2016-04-23 18:27:12 +02:00
Chteufleur 844eddae4f Send resource also for gateway JID 2016-04-23 16:35:23 +02:00
Chteufleur 7368dce789 Add resource for Steam JID 2016-04-23 11:23:58 +02:00
Chteufleur e064b71660 Answer to presence probe type 2016-04-23 10:04:44 +02:00
Chteufleur 3e3347123f Add an Ad-Hoc command to force Steam deconnexion 2016-04-21 23:33:59 +02:00
Chteufleur 43d9c6c5c6 Modification of the library go-xmpp 2016-04-20 23:02:35 +02:00
Chteufleur 66d99eeb94 Reply to information query
- vCard
 - Soft Version
2016-04-20 21:13:29 +02:00
Chteufleur 0b04382ca0 go fmt 2016-04-19 17:13:16 +02:00
Chteufleur ade4020625 Add multi connected client support for one account 2016-04-19 17:12:36 +02:00
Chteufleur dc5027d36d Fix XMPP EOF that brake the compenent 2016-04-19 16:10:01 +02:00
Chteufleur 5109d91e35 Add warn that Steam info are stored un-encrypted 2016-04-16 22:16:00 +02:00
Chteufleur 6d1fcc1333 Modification of the README to be in compliance with the new architecture 2016-04-16 12:35:18 +02:00
Chteufleur 9103fe6ecd Fix received auth code
Fix XMPP comp out when user registrered
Send offline presence when program exit
2016-04-16 11:39:36 +02:00
Chteufleur ce3b45b492 Version 0.3.1 2016-04-15 22:58:49 +02:00
Chteufleur f9d7c619d2 User can modify it's Steam informations 2016-04-15 22:47:29 +02:00
Chteufleur 683574a814 First working version for multi Steam and XMPP users 2016-04-15 08:53:33 +02:00
Chteufleur 11b43f35bf Merge branch 'master' into mutualisation 2016-04-12 19:10:06 +02:00
Chteufleur 7b2e4df008 Save Steam servers address only if it can be json mashal 2016-04-12 13:57:34 +02:00
Chteufleur 651cc738ad Add database management 2016-04-11 22:49:07 +02:00
Chteufleur 24f1a6d7a2 Bug fix on disconnect 2016-04-09 15:54:13 +02:00
Chteufleur e98a9df154 Version 0.2.0 2016-04-09 13:51:35 +02:00
Chteufleur 7f76a35240 go fmt 2016-04-09 13:50:19 +02:00
Chteufleur abfe6de004 Finalize steam user subscribtion 2016-04-09 13:47:31 +02:00
Chteufleur 387a0b7e5a Add Ad-Hoc command to get Steam Auth Code 2016-04-06 22:24:09 +02:00
Chteufleur ce4b966c9c Do not disconnect when an account disconnect while their is an other one connected 2016-02-29 23:02:19 +01:00
Chteufleur e11f5d3f98 Fix shutdown bug 2015-11-26 18:59:19 +01:00
Chteufleur c7d1d71c95 Modification of the README to go get repository 2015-11-07 09:29:45 +01:00
chteufleur ac2d6ea575 Merge branch 'master' of https://git.kingpenguin.tk/chteufleur/go-xmpp4steam 2015-10-28 15:08:37 +01:00
chteufleur 7f319f1389 Make it go getable 2015-10-28 15:07:32 +01:00
Chteufleur bd28e5ba6c Fix an steam connecting bug 2015-10-27 00:00:12 +01:00
Chteufleur 42c3787a0a XMPP debug in config file + stability 2015-10-26 23:37:29 +01:00
chteufleur 95a589c802 Add usefull XMPP type 2015-10-23 17:05:16 +02:00
chteufleur cec14b399f Send subscribe presence 2015-10-23 14:41:11 +02:00
Chteufleur c88585fc5a Fix disconection presence bug 2015-10-22 21:17:59 +02:00
Chteufleur d66c78055a Add playing game into XMPP presence. 2015-10-22 21:06:44 +02:00
11 changed files with 1063 additions and 405 deletions

View File

@ -9,32 +9,25 @@ go-xmpp4steam is a XMPP/Steam gateway.
* [go-xmpp](https://git.kingpenguin.tk/chteufleur/go-xmpp) for the XMPP part.
* [go-steam](https://github.com/Philipp15b/go-steam) for the steam part.
* [go-sqlite3](https://github.com/mattn/go-sqlite3) for the database part.
* [cfg](https://github.com/jimlawless/cfg) for the configuration file.
Go into your $GOPATH directory and execut those two line to get the 2 dependencies (cfg and go-steam).
Download the CA at [https://kingpenguin.tk/ressources/cacert.pem](https://kingpenguin.tk/ressources/cacert.pem), then install it on your operating system.
Once installed, go into your $GOPATH directory and go get the source code.
```sh
go get github.com/Philipp15b/go-steam
go get github.com/jimlawless/cfg
go get git.kingpenguin.tk/chteufleur/go-xmpp4steam.git
```
After that, go into ``src`` directory and get the go-xmpp sources dependence.
```sh
git clone https://git.kingpenguin.tk/chteufleur/go-xmpp
```
### Download sources
Then download and compile the go-xmpp4steam gateway.
```sh
git clone https://git.kingpenguin.tk/chteufleur/go-xmpp4steam.git
cd go-xmpp4steam
go build main.go
```
A binary file will be generated.
### Configure
Configure the gateway by editing the ``xmpp4steam.cfg`` file.
The first time, let the variable ``steam_auth_code`` empty. After the first run of the gateway, Steam will send you a code that you have to give it in that variable. Then re-run the gateway and it should be OK.
Configure the gateway by editing the ``xmpp4steam.cfg`` file in order to give all XMPP component information.
### Utilization
To register, you have to send an Ad-Hoc command to the gateway in order to give your Steam login information.
When it done, send a presence to the gateway. It will try to connect to Steam, but should failed.
Steam should send you a code that you have to give to the gateway using Ad-Hoc command.
After giving the code to the gateway, send again a presence to it and it should be OK.
## Help
To get any help, please visit the XMPP conference room at ``go-xmpp4steam@muc.kingpenguin.tk`` with your prefered client, or [with your browser](https://jappix.kingpenguin.tk/?r=go-xmpp4steam@muc.kingpenguin.tk).
To get any help, please visit the XMPP conference room at [go-xmpp4steam@muc.kingpenguin.tk](xmpp://go-xmpp4steam@muc.kingpenguin.tk?join) with your prefered client, or [with your browser](https://jappix.kingpenguin.tk/?r=go-xmpp4steam@muc.kingpenguin.tk).

186
database/database.go Normal file
View File

@ -0,0 +1,186 @@
package database
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
"log"
)
const (
databaseFile = "go_xmpp4steam.db"
createDatabaseStmt = "create table if not exists users (jid text not null primary key, steamLogin text, steamPwd text, debug int);"
insertDatabaseStmt = "insert into users (jid, steamLogin, steamPwd, debug) values(?, ?, ?, ?)"
deleteDatabaseStmt = "delete from users where jid=?"
selectDatabaseStmt = "select jid, steamLogin, steamPwd, debug from users where jid=?"
updateDatabaseStmt = "update users set steamLogin=?, steamPwd=?, debug=? where jid=?"
LogInfo = "\t[SQLITE INFO]\t"
LogError = "\t[SQLITE ERROR]\t"
LogDebug = "\t[SQLITE DEBUG]\t"
)
type DatabaseLine struct {
Jid string
SteamLogin string
SteamPwd string
Debug bool
}
var (
db = new(sql.DB)
)
func init() {
d, err := sql.Open("sqlite3", databaseFile)
if err != nil {
log.Printf("%sError on openning database", LogError, err)
}
db = d
_, err = db.Exec(createDatabaseStmt)
if err != nil {
log.Printf("%sFailed to create table", LogError, err)
}
}
func Close() {
db.Close()
}
func (newLine *DatabaseLine) AddLine() bool {
log.Printf("%sAdd new line %v", LogInfo, newLine)
isUserRegistred := getLine(newLine.Jid) != nil
if isUserRegistred {
return newLine.UpdateLine()
}
stmt, err := db.Prepare(insertDatabaseStmt)
if err != nil {
log.Printf("%sError on insert jid %s", LogError, newLine.Jid, err)
return false
}
defer stmt.Close()
debug := 0
if newLine.Debug {
debug = 1
}
_, err = stmt.Exec(newLine.Jid, newLine.SteamLogin, newLine.SteamPwd, debug)
if err != nil {
log.Printf("%sError on creating SQL statement", LogError, err)
return false
}
return true
}
func (newLine *DatabaseLine) UpdateLine() bool {
log.Printf("%sUpdate line %s", LogInfo, newLine.Jid)
stmt, err := db.Prepare(updateDatabaseStmt)
if err != nil {
log.Printf("%sError on update ", LogError, err)
return false
}
defer stmt.Close()
debug := 0
if newLine.Debug {
debug = 1
}
_, err = stmt.Exec(newLine.SteamLogin, newLine.SteamPwd, debug, newLine.Jid)
if err != nil {
log.Printf("%sError on updating SQL statement", LogError, err)
return false
}
return true
}
func RemoveLine(jid string) bool {
// Update Steam login and password to blank before deleting,
// because it is not really deleted in the SQLite file.
line := new(DatabaseLine)
line.Jid = jid
line.UpdateLine()
log.Printf("%sRemove line %s", LogInfo, jid)
stmt, err := db.Prepare(deleteDatabaseStmt)
if err != nil {
log.Printf("%sError on delete jid %s", LogError, jid, err)
return false
}
defer stmt.Close()
res, err := stmt.Exec(jid)
if err != nil {
log.Printf("%sError on delete SQL statement", LogError, err)
return false
}
affect, err := res.RowsAffected()
if err != nil {
log.Printf("%sError on delete SQL statement", LogError, err)
return false
}
if affect == 0 {
log.Printf("%sNo line affected", LogDebug)
return false
}
return true
}
func GetLine(jid string) *DatabaseLine {
ret := getLine(jid)
if ret == nil || ret.SteamLogin == "" {
log.Printf("%sLine empty", LogDebug)
return nil
}
return ret
}
func getLine(jid string) *DatabaseLine {
log.Printf("%sGet line %s", LogInfo, jid)
ret := new(DatabaseLine)
stmt, err := db.Prepare(selectDatabaseStmt)
if err != nil {
log.Printf("%sError on select line", LogError, err)
return nil
}
defer stmt.Close()
debug := 0
err = stmt.QueryRow(jid).Scan(&ret.Jid, &ret.SteamLogin, &ret.SteamPwd, &debug)
if err != nil {
log.Printf("%sError on select scan", LogError, err)
return nil
}
if debug == 1 {
ret.Debug = true
} else {
ret.Debug = false
}
return ret
}
func GetAllLines() []DatabaseLine {
log.Printf("%sGet all lines", LogInfo)
var ret []DatabaseLine
rows, err := db.Query("select jid, steamLogin, steamPwd from users")
if err != nil {
log.Printf("%sError on select query", LogError, err)
}
defer rows.Close()
for rows.Next() {
user := new(DatabaseLine)
rows.Scan(&user.Jid, &user.SteamLogin, &user.SteamPwd)
if user.SteamLogin != "" {
ret = append(ret, *user)
}
}
return ret
}

53
gateway/gateway.go Normal file
View File

@ -0,0 +1,53 @@
package gateway
import (
"github.com/Philipp15b/go-steam"
)
const (
SentryDirectory = "sentries/"
resource = "go-xmpp4steam"
)
type GatewayInfo struct {
// Steam
SteamLogin string
SteamPassword string
SteamLoginInfo *steam.LogOnDetails
SteamClient *steam.Client
SentryFile string
FriendSteamId map[string]*StatusSteamFriend
SteamConnecting bool
Deleting bool
// XMPP
XMPP_JID_Client string
XMPP_Out chan interface{}
XMPP_Connected_Client map[string]bool
DebugMessage bool
}
type StatusSteamFriend struct {
XMPP_Status string
XMPP_Type string
SteamGameName string
SteamName string
}
func (g *GatewayInfo) Run() {
go g.SteamRun()
}
func (g *GatewayInfo) SetSteamAuthCode(authCode string) {
g.SteamLoginInfo.AuthCode = authCode
}
func (g *GatewayInfo) Disconnect() {
g.XMPP_Disconnect()
go g.SteamDisconnect()
}
func (g *GatewayInfo) Delete() {
g.Deleting = true
g.Disconnect()
}

226
gateway/steam.go Normal file
View File

@ -0,0 +1,226 @@
package gateway
import (
"github.com/Philipp15b/go-steam"
"github.com/Philipp15b/go-steam/protocol/steamlang"
"github.com/Philipp15b/go-steam/steamid"
"encoding/json"
"io/ioutil"
"log"
"strconv"
"time"
)
const (
serverAddrs = "servers.addr"
State_Offline = steamlang.EPersonaState_Offline
State_Online = steamlang.EPersonaState_Online
State_Busy = steamlang.EPersonaState_Busy
State_Away = steamlang.EPersonaState_Away
State_Snooze = steamlang.EPersonaState_Snooze
State_LookingToTrade = steamlang.EPersonaState_LookingToTrade
State_LookingToPlay = steamlang.EPersonaState_LookingToPlay
State_Max = steamlang.EPersonaState_Max
LogSteamInfo = "\t[STEAM INFO]\t"
LogSteamError = "\t[STEAM ERROR]\t"
LogSteamDebug = "\t[STEAM DEBUG]\t"
)
func (g *GatewayInfo) SteamRun() {
if g.Deleting {
log.Printf("%sDeleting gateway", LogSteamInfo)
return
}
log.Printf("%sRunning", LogSteamInfo)
g.setLoginInfos()
g.SteamClient = steam.NewClient()
g.SteamConnecting = false
g.SteamClient.ConnectionTimeout = 10 * time.Second
g.mainSteam()
log.Printf("%sReach main method's end", LogSteamInfo)
go g.SteamRun()
}
func (g *GatewayInfo) mainSteam() {
for event := range g.SteamClient.Events() {
switch e := event.(type) {
case *steam.ConnectedEvent:
// Connected on server
g.SteamConnecting = false
log.Printf("%sConnected on Steam serveur", LogSteamDebug)
g.SteamClient.Auth.LogOn(g.SteamLoginInfo)
case *steam.MachineAuthUpdateEvent:
// Received sentry file
ioutil.WriteFile(g.SentryFile, e.Hash, 0666)
case *steam.LoggedOnEvent:
// Logged on
g.SendSteamPresence(steamlang.EPersonaState_Online)
g.SendXmppMessage(XmppJidComponent, "", "Connected on Steam network")
case steam.FatalErrorEvent:
log.Printf("%sFatalError: ", LogSteamError, e)
g.SendXmppMessage(XmppJidComponent, "", "Steam Fatal Error : "+e.Error())
g.DisconnectAllSteamFriend()
return
case error:
log.Printf("%s", LogSteamError, e)
g.SendXmppMessage(XmppJidComponent, "", "Steam Error : "+e.Error())
case *steam.ClientCMListEvent:
// Save servers addresses
b, err := json.Marshal(*e)
if err != nil {
log.Printf("%sFailed to json.Marshal() servers list", LogSteamError)
} else {
ioutil.WriteFile(serverAddrs, b, 0666)
}
case *steam.PersonaStateEvent:
// Presenc received
steamId := e.FriendId.ToString()
name := e.Name
gameName := e.GameName
var status string
var tpye string
switch e.State {
case State_Offline:
status = Status_offline
tpye = Type_unavailable
case State_Online:
status = Status_online
tpye = Type_available
case State_Busy:
status = Status_do_not_disturb
tpye = Type_available
case State_Away:
status = Status_away
tpye = Type_available
case State_Snooze:
status = Status_extended_away
tpye = Type_available
}
if _, ok := g.FriendSteamId[steamId]; !ok {
// Send subscribsion
g.SendXmppPresence(status, Type_subscribe, "", steamId+"@"+XmppJidComponent, gameName, name)
g.FriendSteamId[steamId] = &StatusSteamFriend{XMPP_Status: status, XMPP_Type: tpye}
} else {
g.FriendSteamId[steamId].XMPP_Status = status
g.FriendSteamId[steamId].XMPP_Type = tpye
g.FriendSteamId[steamId].SteamGameName = gameName
g.FriendSteamId[steamId].SteamName = name
}
g.SendXmppPresence(status, tpye, "", steamId+"@"+XmppJidComponent, gameName, name)
case *steam.ChatMsgEvent:
// Message received
g.SendXmppMessage(e.ChatterId.ToString()+"@"+XmppJidComponent, "", e.Message)
default:
log.Printf("%s", LogSteamDebug, e)
}
}
}
func (g *GatewayInfo) setLoginInfos() {
var sentryHash steam.SentryHash
sentryHash, err := ioutil.ReadFile(g.SentryFile)
g.SteamLoginInfo = new(steam.LogOnDetails)
g.SteamLoginInfo.Username = g.SteamLogin
g.SteamLoginInfo.Password = g.SteamPassword
if err == nil {
g.SteamLoginInfo.SentryFileHash = sentryHash
}
log.Printf("%sAuthentification of (%s, %s)", LogSteamDebug, g.XMPP_JID_Client, g.SteamLoginInfo.Username)
}
func (g *GatewayInfo) IsSteamConnected() bool {
ret := g != nil
if ret {
ret = g.SteamClient != nil
if ret {
ret = g.SteamClient.Connected()
}
}
return ret
}
func (g *GatewayInfo) SteamConnect() {
if g.IsSteamConnected() {
log.Printf("%sTry to connect, but already connected", LogSteamDebug)
return
}
if g.SteamConnecting {
log.Printf("%sTry to connect, but currently connecting…", LogSteamDebug)
return
}
g.SteamConnecting = true
b, err := ioutil.ReadFile(serverAddrs)
if err == nil {
var toList steam.ClientCMListEvent
err := json.Unmarshal(b, &toList)
if err != nil {
log.Printf("%sFailed to json.Unmarshal() servers list", LogSteamError)
} else {
log.Printf("%sConnecting...", LogSteamInfo, toList.Addresses[0])
g.SteamClient.ConnectTo(toList.Addresses[0])
}
} else {
log.Printf("%sFailed to read servers list file", LogSteamError)
log.Printf("%sConnecting...", LogSteamInfo)
g.SteamClient.Connect()
}
}
func (g *GatewayInfo) SteamDisconnect() {
if !g.IsSteamConnected() {
log.Printf("%sTry to disconnect, but already disconnected", LogSteamDebug)
return
}
log.Printf("%sSteam disconnect", LogSteamInfo)
g.XMPP_Disconnect()
g.DisconnectAllSteamFriend()
go g.SteamClient.Disconnect()
}
func (g *GatewayInfo) DisconnectAllSteamFriend() {
for sid, _ := range g.FriendSteamId {
g.SendXmppPresence(Status_offline, Type_unavailable, "", sid+"@"+XmppJidComponent, "", "")
delete(g.FriendSteamId, sid)
}
}
func (g *GatewayInfo) SendSteamMessage(steamId, message string) {
if !g.IsSteamConnected() {
log.Printf("%sTry to send message, but disconnected", LogSteamDebug)
return
}
steamIdUint64, err := strconv.ParseUint(steamId, 10, 64)
if err == nil {
g.SteamClient.Social.SendMessage(steamid.SteamId(steamIdUint64), steamlang.EChatEntryType_ChatMsg, message)
} else {
log.Printf("%sFailed to get SteamId from %s", LogSteamError, steamId)
}
}
func (g *GatewayInfo) SendSteamPresence(status steamlang.EPersonaState) {
if !g.IsSteamConnected() {
log.Printf("%sTry to send presence, but disconnected", LogSteamDebug)
return
}
g.SteamClient.Social.SetPersonaState(status)
}

176
gateway/xmpp.go Normal file
View File

@ -0,0 +1,176 @@
package gateway
import (
"git.kingpenguin.tk/chteufleur/go-xmpp.git/src/xmpp"
"github.com/Philipp15b/go-steam/protocol/steamlang"
"log"
"strings"
)
const (
Status_online = ""
Status_offline = ""
Status_away = "away"
Status_chat = "chat"
Status_do_not_disturb = "dnd"
Status_extended_away = "xa"
Type_available = ""
Type_unavailable = "unavailable"
Type_subscribe = "subscribe"
Type_subscribed = "subscribed"
Type_unsubscribe = "unsubscribe"
Type_unsubscribed = "unsubscribed"
Type_probe = "probe"
Type_error = "error"
ActionConnexion = "action_xmpp_connexion"
ActionDeconnexion = "action_xmpp_deconnexion"
ActionMainMethodEnded = "action_xmpp_main_method_ended"
LogXmppInfo = "\t[XMPP INFO]\t"
LogXmppError = "\t[XMPP ERROR]\t"
LogXmppDebug = "\t[XMPP DEBUG]\t"
)
var (
XmppJidComponent = ""
)
func (g *GatewayInfo) ReceivedXMPP_Presence(presence *xmpp.Presence) {
if presence.Type == Type_error {
return
}
transfertPresence := false
jid := strings.SplitN(presence.From, "/", 2)
steamJid := strings.SplitN(strings.SplitN(presence.To, "/", 2)[0], "@", 2)
if len(jid) == 2 {
// Resource exist —> client speaking
if presence.Type == Type_available {
g.XMPP_Connected_Client[presence.From] = true
} else if presence.Type == Type_unavailable {
delete(g.XMPP_Connected_Client, presence.From)
}
}
if presence.Type == Type_probe {
steamFriendStatus := g.FriendSteamId[steamJid[0]]
if steamFriendStatus != nil {
g.SendXmppPresence(steamFriendStatus.XMPP_Status, steamFriendStatus.XMPP_Type, "", steamJid[0]+"@"+XmppJidComponent, steamFriendStatus.SteamGameName, steamFriendStatus.SteamName)
}
} else if presence.Type == Type_subscribe {
// Send presence to tell that the JID has been added to roster
g.SendXmppPresence("", Type_subscribed, presence.From, presence.To, g.XMPP_JID_Client, "")
} else if presence.Type == Type_subscribed {
} else if presence.Type == Type_unsubscribe {
} else if presence.Type == Type_unsubscribed {
} else if presence.To == XmppJidComponent {
// Destination is gateway itself
if presence.Type == Type_unavailable {
// Disconnect
if len(g.XMPP_Connected_Client) <= 0 {
g.Disconnect()
}
} else if presence.Type == Type_available {
go g.SteamConnect()
transfertPresence = true
}
} else {
// Destination is Steam user
if presence.Type == Type_unavailable {
// Disconnect
if len(g.XMPP_Connected_Client) <= 0 {
g.Disconnect()
}
} else if presence.Type == Type_available {
go g.SteamConnect()
transfertPresence = true
}
}
if transfertPresence {
// Transfert presence to Steam network
var steamStatus steamlang.EPersonaState
switch presence.Show {
case Status_online:
steamStatus = State_Online
case Status_away:
steamStatus = State_Away
case Status_chat:
steamStatus = State_Online
case Status_extended_away:
steamStatus = State_Snooze
case Status_do_not_disturb:
steamStatus = State_Busy
}
if g.IsSteamConnected() {
g.SendSteamPresence(steamStatus)
g.SendXmppPresence(presence.Show, presence.Type, presence.From, "", presence.Status, "")
}
}
}
func (g *GatewayInfo) ReceivedXMPP_Message(message *xmpp.Message) {
steamID := strings.SplitN(message.To, "@", 2)[0]
g.SendSteamMessage(steamID, message.Body)
}
func (g *GatewayInfo) XMPP_Disconnect() {
g.SendXmppPresence(Status_offline, Type_unavailable, "", "", "", "")
}
func (g *GatewayInfo) SendXmppPresence(status, tpye, to, from, message, nick string) {
p := xmpp.Presence{}
if status != "" {
p.Show = status
}
if tpye != "" {
p.Type = tpye
}
if message != "" {
p.Status = message
}
if nick != "" {
p.Nick = nick
}
if to == "" {
p.To = g.XMPP_JID_Client
} else {
p.To = to
}
if from == "" {
// TODO add an option to allow message comming directly from the gateway
p.From = XmppJidComponent + "/" + resource
} else {
p.From = from + "/" + resource
}
log.Printf("%sSend presence %v", LogXmppInfo, p)
g.XMPP_Out <- p
}
func (g *GatewayInfo) SendXmppMessage(from, subject, message string) {
if from != XmppJidComponent || from == XmppJidComponent && g.DebugMessage {
m := xmpp.Message{To: g.XMPP_JID_Client, From: from, Body: message, Type: "chat"}
if subject != "" {
m.Subject = subject
}
log.Printf("%sSend message %v", LogXmppInfo, m)
g.XMPP_Out <- m
}
}

188
main.go
View File

@ -1,31 +1,30 @@
package main
import (
"go-xmpp4steam/steam"
"go-xmpp4steam/xmpp"
"git.kingpenguin.tk/chteufleur/go-xmpp4steam.git/database"
"git.kingpenguin.tk/chteufleur/go-xmpp4steam.git/gateway"
"git.kingpenguin.tk/chteufleur/go-xmpp4steam.git/xmpp"
"github.com/Philipp15b/go-steam/internal/steamlang"
"github.com/jimlawless/cfg"
"bufio"
"log"
"os"
"strings"
"os/signal"
"syscall"
"time"
)
const (
Version = "v1.0"
configurationFilePath = "xmpp4steam.cfg"
)
var (
mapConfig = make(map[string]string)
SetSteamId = make(map[string]struct{})
mapConfig = make(map[string]string)
)
func init() {
xmpp.Version = "0.1.1"
xmpp.SoftVersion = Version
err := cfg.Load(configurationFilePath, mapConfig)
if err != nil {
log.Fatal("Failed to load configuration file.", err)
@ -35,168 +34,25 @@ func init() {
xmpp.Addr = mapConfig["xmpp_server_address"] + ":" + mapConfig["xmpp_server_port"]
xmpp.JidStr = mapConfig["xmpp_hostname"]
xmpp.Secret = mapConfig["xmpp_secret"]
xmpp.PreferedJID = mapConfig["xmpp_authorized_jid"]
// Steam config
steam.Username = mapConfig["steam_login"]
steam.Password = mapConfig["steam_password"]
steam.AuthCode = mapConfig["steam_auth_code"]
xmpp.Debug = mapConfig["xmpp_debug"] == "true"
gateway.XmppJidComponent = xmpp.JidStr
}
func main() {
go gatewayXmppSteamAction()
go gatewaySteamXmppAction()
allDbUsers := database.GetAllLines()
for _, dbUser := range allDbUsers {
xmpp.AddNewUser(dbUser.Jid, dbUser.SteamLogin, dbUser.SteamPwd, dbUser.Debug)
}
go xmpp.Run()
go gatewayXmppSteamPresence()
go gatewayXmppSteamMessage()
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, os.Interrupt)
signal.Notify(sigchan, syscall.SIGTERM)
signal.Notify(sigchan, os.Kill)
<-sigchan
go gatewaySteamXmppMessage()
go gatewaySteamXmppPresence()
go steam.Run()
xmpp.Run()
// inputStop()
steam.Disconnect()
xmpp.Disconnect()
log.Println("Exit main()")
time.Sleep(1 * time.Second)
}
// XMPP -> Steam gateways
func gatewayXmppSteamAction() {
for {
action := <-xmpp.ChanAction
switch action {
case xmpp.ActionConnexion:
if !steam.IsConnected() {
steam.Connect()
}
case xmpp.ActionDeconnexion:
if steam.IsConnected() {
steam.Disconnect()
}
}
}
}
func gatewayXmppSteamPresence() {
for {
status := <-xmpp.ChanPresence
var steamStatus steamlang.EPersonaState
switch status {
case xmpp.Status_online:
steamStatus = steam.State_Online
case xmpp.Status_away:
steamStatus = steam.State_Away
case xmpp.Status_chat:
case xmpp.Status_extended_away:
steamStatus = steam.State_Snooze
case xmpp.Status_do_not_disturb:
steamStatus = steam.State_Busy
}
steam.SendPresence(steamStatus)
}
}
func gatewayXmppSteamMessage() {
for {
steamId := <-xmpp.ChanMessage
message := <-xmpp.ChanMessage
steam.SendMessage(steamId, message)
}
}
// /XMPP -> Steam gateways
// Steam -> XMPP gateways
func gatewaySteamXmppAction() {
for {
action := <-steam.ChanAction
switch action {
case steam.ActionConnected:
xmpp.SendPresence(xmpp.CurrentStatus, xmpp.Type_available)
case steam.ActionDisconnected:
xmpp.Disconnect()
for sid, _ := range SetSteamId {
xmpp.SendPresenceFrom(xmpp.Status_offline, xmpp.Type_unavailable, sid+"@"+xmpp.JidStr)
delete(SetSteamId, sid)
}
case steam.ActionFatalError:
time.Sleep(2 * time.Second)
go steam.Run()
}
}
}
func gatewaySteamXmppMessage() {
for {
steamId := <-steam.ChanMessage
message := <-steam.ChanMessage
xmpp.SendMessage(steamId+"@"+xmpp.JidStr, message)
}
}
func gatewaySteamXmppPresence() {
for {
// name := steam.ChanPresence
steamId := <-steam.ChanPresence
stat := <-steam.ChanPresenceSteam
SetSteamId[steamId] = struct{}{}
var status string
var tpye string
switch stat {
case steam.State_Offline:
status = xmpp.Status_offline
tpye = xmpp.Type_unavailable
case steam.State_Online:
status = xmpp.Status_online
tpye = xmpp.Type_available
case steam.State_Busy:
status = xmpp.Status_do_not_disturb
tpye = xmpp.Type_available
case steam.State_Away:
status = xmpp.Status_away
tpye = xmpp.Type_available
case steam.State_Snooze:
status = xmpp.Status_extended_away
tpye = xmpp.Type_available
}
xmpp.SendPresenceFrom(status, tpye, steamId+"@"+xmpp.JidStr)
}
}
// /Steam -> XMPP gateways
func inputStop() {
for {
in := bufio.NewReader(os.Stdin)
line, err := in.ReadString('\n')
if err != nil {
continue
}
line = strings.TrimRight(line, "\n")
if line == "stop" {
return
}
}
}

View File

@ -1 +1 @@
{"Addresses":[{"IP":"162.254.196.40","Port":27020},{"IP":"162.254.196.43","Port":27021},{"IP":"162.254.196.40","Port":27019},{"IP":"162.254.196.40","Port":27017},{"IP":"146.66.152.10","Port":27017},{"IP":"162.254.196.40","Port":27021},{"IP":"162.254.196.40","Port":27018},{"IP":"162.254.196.41","Port":27018},{"IP":"162.254.196.43","Port":27018},{"IP":"162.254.196.41","Port":27020},{"IP":"162.254.196.41","Port":27021},{"IP":"162.254.196.42","Port":27017},{"IP":"162.254.196.41","Port":27017},{"IP":"162.254.196.42","Port":27021},{"IP":"162.254.197.42","Port":27017},{"IP":"146.66.152.11","Port":27020},{"IP":"162.254.196.43","Port":27019},{"IP":"162.254.196.42","Port":27018},{"IP":"162.254.196.42","Port":27019},{"IP":"162.254.196.41","Port":27019},{"IP":"162.254.197.41","Port":27021},{"IP":"162.254.197.41","Port":27020},{"IP":"162.254.197.40","Port":27019},{"IP":"162.254.197.40","Port":27021},{"IP":"162.254.197.42","Port":27018},{"IP":"162.254.197.41","Port":27019},{"IP":"146.66.152.11","Port":27018},{"IP":"146.66.152.10","Port":27018},{"IP":"162.254.196.43","Port":27017},{"IP":"162.254.196.43","Port":27020},{"IP":"146.66.152.10","Port":27020},{"IP":"162.254.197.42","Port":27021},{"IP":"162.254.197.42","Port":27019},{"IP":"162.254.197.41","Port":27017},{"IP":"162.254.197.42","Port":27020},{"IP":"162.254.196.42","Port":27020},{"IP":"162.254.197.40","Port":27017},{"IP":"162.254.197.40","Port":27018},{"IP":"146.66.152.10","Port":27019},{"IP":"146.66.152.11","Port":27017},{"IP":"146.66.152.11","Port":27019},{"IP":"162.254.197.41","Port":27018},{"IP":"162.254.197.40","Port":27020},{"IP":"185.25.180.14","Port":27019},{"IP":"146.66.155.8","Port":27018},{"IP":"185.25.180.15","Port":27020},{"IP":"185.25.180.15","Port":27018},{"IP":"155.133.242.8","Port":27018},{"IP":"155.133.242.8","Port":27019},{"IP":"155.133.242.9","Port":27020},{"IP":"185.25.182.10","Port":27018},{"IP":"185.25.182.10","Port":27017},{"IP":"185.25.180.14","Port":27018},{"IP":"185.25.180.15","Port":27017},{"IP":"155.133.242.8","Port":27017},{"IP":"185.25.180.14","Port":27017},{"IP":"146.66.155.8","Port":27017},{"IP":"185.25.182.10","Port":27019},{"IP":"185.25.182.10","Port":27020},{"IP":"155.133.242.9","Port":27019},{"IP":"185.25.180.15","Port":27019},{"IP":"185.25.180.14","Port":27020},{"IP":"146.66.155.8","Port":27019},{"IP":"146.66.155.8","Port":27020},{"IP":"155.133.242.9","Port":27017},{"IP":"155.133.242.8","Port":27020},{"IP":"155.133.242.9","Port":27018},{"IP":"208.78.164.9","Port":27019},{"IP":"208.78.164.11","Port":27018},{"IP":"208.78.164.9","Port":27017},{"IP":"208.78.164.12","Port":27019},{"IP":"208.78.164.13","Port":27017},{"IP":"208.78.164.14","Port":27017},{"IP":"208.78.164.12","Port":27017},{"IP":"208.78.164.12","Port":27018},{"IP":"208.78.164.9","Port":27018},{"IP":"208.78.164.14","Port":27019},{"IP":"208.78.164.13","Port":27018},{"IP":"208.78.164.10","Port":27019},{"IP":"208.78.164.10","Port":27018}]}
{"Addresses":[{"IP":"146.66.152.11","Port":27020},{"IP":"162.254.197.42","Port":27020},{"IP":"146.66.152.10","Port":27020},{"IP":"146.66.152.10","Port":27017},{"IP":"162.254.197.40","Port":27018},{"IP":"146.66.152.10","Port":27018},{"IP":"162.254.197.40","Port":27019},{"IP":"162.254.197.41","Port":27017},{"IP":"162.254.197.41","Port":27020},{"IP":"162.254.197.40","Port":27020},{"IP":"146.66.152.10","Port":27019},{"IP":"162.254.197.42","Port":27019},{"IP":"162.254.197.41","Port":27021},{"IP":"162.254.197.42","Port":27018},{"IP":"162.254.197.42","Port":27017},{"IP":"162.254.197.42","Port":27021},{"IP":"162.254.197.41","Port":27019},{"IP":"162.254.197.41","Port":27018},{"IP":"162.254.196.40","Port":27020},{"IP":"146.66.152.11","Port":27018},{"IP":"162.254.197.40","Port":27021},{"IP":"162.254.196.43","Port":27019},{"IP":"162.254.196.43","Port":27018},{"IP":"162.254.196.42","Port":27021},{"IP":"146.66.152.11","Port":27017},{"IP":"162.254.196.41","Port":27018},{"IP":"162.254.196.41","Port":27019},{"IP":"162.254.196.42","Port":27017},{"IP":"162.254.196.43","Port":27021},{"IP":"162.254.196.40","Port":27018},{"IP":"162.254.196.40","Port":27017},{"IP":"162.254.196.42","Port":27020},{"IP":"162.254.196.41","Port":27020},{"IP":"162.254.196.41","Port":27021},{"IP":"162.254.196.41","Port":27017},{"IP":"162.254.196.42","Port":27018},{"IP":"162.254.197.40","Port":27017},{"IP":"162.254.196.40","Port":27019},{"IP":"146.66.152.11","Port":27019},{"IP":"162.254.196.43","Port":27017},{"IP":"162.254.196.43","Port":27020},{"IP":"162.254.196.40","Port":27021},{"IP":"162.254.196.42","Port":27019},{"IP":"146.66.155.8","Port":27020},{"IP":"155.133.242.9","Port":27019},{"IP":"146.66.155.8","Port":27019},{"IP":"155.133.242.8","Port":27020},{"IP":"185.25.180.15","Port":27020},{"IP":"155.133.242.8","Port":27018},{"IP":"146.66.155.8","Port":27017},{"IP":"185.25.182.10","Port":27020},{"IP":"185.25.182.10","Port":27017},{"IP":"185.25.182.10","Port":27018},{"IP":"185.25.182.10","Port":27019},{"IP":"155.133.242.8","Port":27019},{"IP":"155.133.242.9","Port":27020},{"IP":"185.25.180.14","Port":27019},{"IP":"146.66.155.8","Port":27018},{"IP":"185.25.180.14","Port":27020},{"IP":"185.25.180.15","Port":27018},{"IP":"185.25.180.14","Port":27017},{"IP":"155.133.242.9","Port":27018},{"IP":"185.25.180.15","Port":27019},{"IP":"185.25.180.14","Port":27018},{"IP":"155.133.242.9","Port":27017},{"IP":"155.133.242.8","Port":27017},{"IP":"185.25.180.15","Port":27017},{"IP":"208.78.164.11","Port":27018},{"IP":"208.78.164.14","Port":27018},{"IP":"208.78.164.13","Port":27019},{"IP":"208.78.164.11","Port":27019},{"IP":"208.78.164.9","Port":27019},{"IP":"208.78.164.13","Port":27018},{"IP":"208.78.164.12","Port":27019},{"IP":"208.78.164.13","Port":27017},{"IP":"208.78.164.9","Port":27017},{"IP":"208.78.164.10","Port":27018},{"IP":"208.78.164.14","Port":27017},{"IP":"208.78.164.12","Port":27018},{"IP":"208.78.164.10","Port":27019}]}

View File

@ -1,164 +0,0 @@
package steam
import (
"github.com/Philipp15b/go-steam"
"github.com/Philipp15b/go-steam/internal/steamlang"
"github.com/Philipp15b/go-steam/steamid"
"encoding/json"
"io/ioutil"
"log"
"strconv"
"time"
)
const (
sentryFile = "sentry"
serverAddrs = "servers.addr"
State_Offline = steamlang.EPersonaState_Offline
State_Online = steamlang.EPersonaState_Online
State_Busy = steamlang.EPersonaState_Busy
State_Away = steamlang.EPersonaState_Away
State_Snooze = steamlang.EPersonaState_Snooze
State_LookingToTrade = steamlang.EPersonaState_LookingToTrade
State_LookingToPlay = steamlang.EPersonaState_LookingToPlay
State_Max = steamlang.EPersonaState_Max
ActionConnected = "steam_connected"
ActionDisconnected = "steam_disconnected"
ActionFatalError = "steam_fatal_error"
LogInfo = "\t[STEAM INFO]\t"
LogError = "\t[STEAM ERROR]\t"
LogDebug = "\t[STEAM DEBUG]\t"
)
var (
Username = ""
Password = ""
AuthCode = ""
myLoginInfo = new(steam.LogOnDetails)
client = steam.NewClient()
ChanPresence = make(chan string)
ChanPresenceSteam = make(chan steamlang.EPersonaState)
ChanMessage = make(chan string)
ChanAction = make(chan string)
)
func Run() {
log.Printf("%sRunning", LogInfo)
setLoginInfos()
client = steam.NewClient()
client.ConnectionTimeout = 10 * time.Second
mainSteam()
}
func mainSteam() {
for event := range client.Events() {
switch e := event.(type) {
case *steam.ConnectedEvent:
client.Auth.LogOn(myLoginInfo)
case *steam.MachineAuthUpdateEvent:
ioutil.WriteFile(sentryFile, e.Hash, 0666)
case *steam.LoggedOnEvent:
SendPresence(steamlang.EPersonaState_Online)
ChanAction <- ActionConnected
case steam.FatalErrorEvent:
log.Printf("%sFatalError: ", LogError, e)
ChanAction <- ActionFatalError
return
case error:
log.Printf("%s", LogError, e)
case *steam.ClientCMListEvent:
// Save servers addresses
b, err := json.Marshal(*e)
if err != nil {
log.Printf("%sFailed to json.Marshal() servers list", LogError)
}
ioutil.WriteFile(serverAddrs, b, 0666)
case *steam.PersonaStateEvent:
// ChanPresence <- e.Name
ChanPresence <- e.FriendId.ToString()
ChanPresenceSteam <- e.State
case *steam.ChatMsgEvent:
ChanMessage <- e.ChatterId.ToString()
ChanMessage <- e.Message
default:
log.Printf("%s", LogDebug, e)
}
}
}
func setLoginInfos() {
var sentryHash steam.SentryHash
sentryHash, err := ioutil.ReadFile(sentryFile)
myLoginInfo.Username = Username
myLoginInfo.Password = Password
if err == nil {
myLoginInfo.SentryFileHash = sentryHash
log.Printf("%sAuthentification by SentryFileHash", LogDebug)
} else if AuthCode != "" {
myLoginInfo.AuthCode = AuthCode
log.Printf("%sAuthentification by AuthCode", LogDebug)
} else {
log.Printf("%sFirst authentification", LogDebug)
}
}
func IsConnected() bool {
return client.Connected()
}
func Connect() {
if IsConnected() {
log.Printf("%sTry to connect, but already connected", LogDebug)
return
}
b, err := ioutil.ReadFile(serverAddrs)
if err == nil {
var toList steam.ClientCMListEvent
err := json.Unmarshal(b, &toList)
if err != nil {
log.Printf("%sFailed to json.Unmarshal() servers list", LogError)
} else {
log.Printf("%sConnecting...", LogInfo)
client.ConnectTo(toList.Addresses[0])
}
} else {
log.Printf("%sFailed to read servers list file", LogError)
client.Connect()
}
}
func Disconnect() {
log.Printf("%sSteam disconnect", LogInfo)
go client.Disconnect()
}
func SendMessage(steamId, message string) {
steamIdUint64, err := strconv.ParseUint(steamId, 10, 64)
if err == nil {
client.Social.SendMessage(steamid.SteamId(steamIdUint64), steamlang.EChatEntryType_ChatMsg, message)
} else {
log.Printf("%sFailed to get SteamId from %s", LogError, steamId)
}
}
func SendPresence(status steamlang.EPersonaState) {
client.Social.SetPersonaState(status)
}

231
xmpp/commands.go Normal file
View File

@ -0,0 +1,231 @@
package xmpp
import (
"git.kingpenguin.tk/chteufleur/go-xmpp.git/src/xmpp"
"git.kingpenguin.tk/chteufleur/go-xmpp4steam.git/database"
"log"
"strings"
)
const (
CommandAuthcode = "steamAuthCodeCommand"
CommandGetIdentifiants = "steamGetIdentifiants"
CommandDisconnectSteam = "disconnectSteam"
CommandRemoveRegistration = "removeRegistration"
CommandToggleDebugMode = "toggleDebugMode"
)
var (
ChanAuthCode = make(chan string)
)
func execDiscoCommand(iq *xmpp.Iq) {
log.Printf("%sDiscovery item iq received", LogInfo)
reply := iq.Response(xmpp.IQTypeResult)
discoItem := &xmpp.DiscoItems{Node: xmpp.NodeAdHocCommand}
jidBare := strings.SplitN(iq.From, "/", 2)[0]
dbUser := database.GetLine(jidBare)
// Add available commands
if dbUser == nil {
discoI := &xmpp.DiscoItem{JID: jid.Domain, Node: CommandGetIdentifiants, Name: "Steam registration"}
discoItem.Item = append(discoItem.Item, *discoI)
} else {
// Add only if user is registered
discoI := &xmpp.DiscoItem{JID: jid.Domain, Node: CommandAuthcode, Name: "Add Steam Auth Code"}
discoItem.Item = append(discoItem.Item, *discoI)
discoI = &xmpp.DiscoItem{JID: jid.Domain, Node: CommandDisconnectSteam, Name: "Force Steam deconnexion"}
discoItem.Item = append(discoItem.Item, *discoI)
discoI = &xmpp.DiscoItem{JID: jid.Domain, Node: CommandRemoveRegistration, Name: "Remove registration"}
discoItem.Item = append(discoItem.Item, *discoI)
discoI = &xmpp.DiscoItem{JID: jid.Domain, Node: CommandToggleDebugMode, Name: "Toggle debug mode"}
discoItem.Item = append(discoItem.Item, *discoI)
}
reply.PayloadEncode(discoItem)
comp.Out <- reply
}
func execCommandAdHoc(iq *xmpp.Iq) {
adHoc := &xmpp.AdHocCommand{}
iq.PayloadDecode(adHoc)
if adHoc.SessionID == "" && adHoc.Action == xmpp.ActionAdHocExecute {
// First step in the command
log.Printf("%sAd-Hoc command (Node : %s). First step.", LogInfo, adHoc.Node)
reply := iq.Response(xmpp.IQTypeResult)
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocExecute, SessionID: xmpp.SessionID()}
if adHoc.Node == CommandAuthcode {
// Command Auth Code
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocForm, Title: "Steam Auth Code", Instructions: "Please provide the auth code that Steam sended to you."}
field := &xmpp.AdHocField{Var: "code", Label: "Auth Code", Type: xmpp.TypeAdHocFieldTextSingle}
cmdXForm.Fields = append(cmdXForm.Fields, *field)
cmd.XForm = *cmdXForm
} else if adHoc.Node == CommandGetIdentifiants {
// Command Auth Code
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocForm, Title: "Steam Account Info", Instructions: "Please provide your Steam login and password."}
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo, Value: "Please, be aware that the given Steam account information will be saved into an un-encrypted SQLite database."}
field := &xmpp.AdHocField{Var: "login", Label: "Steam Login", Type: xmpp.TypeAdHocFieldTextSingle}
cmdXForm.Fields = append(cmdXForm.Fields, *field)
field = &xmpp.AdHocField{Var: "password", Label: "Steam Password", Type: xmpp.TypeAdHocFieldTextPrivate}
cmdXForm.Fields = append(cmdXForm.Fields, *field)
cmd.XForm = *cmdXForm
cmd.Note = *note
} else if adHoc.Node == CommandDisconnectSteam {
cmd.Status = xmpp.StatusAdHocCompleted
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Force Steam deconnexion"}
cmd.XForm = *cmdXForm
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
jidBare := strings.SplitN(iq.From, "/", 2)[0]
g := MapGatewayInfo[jidBare]
if g != nil {
g.Disconnect()
note.Value = "Send deconnexion on Steam network"
} else {
note.Value = "Your are not registred."
}
cmd.Note = *note
} else if adHoc.Node == CommandRemoveRegistration {
cmd.Status = xmpp.StatusAdHocCompleted
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Remove registration"}
cmd.XForm = *cmdXForm
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
jidBare := strings.SplitN(iq.From, "/", 2)[0]
if RemoveUser(jidBare) {
note.Value = "Remove registration success."
} else {
note.Value = "Failed to remove your registration."
}
cmd.Note = *note
} else if adHoc.Node == CommandToggleDebugMode {
cmd.Status = xmpp.StatusAdHocCompleted
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Toggle debug mode"}
cmd.XForm = *cmdXForm
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
jidBare := strings.SplitN(iq.From, "/", 2)[0]
dbUser := database.GetLine(jidBare)
if dbUser != nil {
dbUser.Debug = !dbUser.Debug
g := MapGatewayInfo[jidBare]
ok := dbUser.UpdateLine()
if ok && g != nil {
g.DebugMessage = dbUser.Debug
if dbUser.Debug {
note.Value = "Debug activated."
} else {
note.Value = "Debug desactivated."
}
} else {
note.Value = "Failed to update your profile. :("
}
} else {
note.Value = "Your not registered."
}
cmd.Note = *note
}
reply.PayloadEncode(cmd)
comp.Out <- reply
} else if adHoc.Action == xmpp.ActionAdHocExecute || adHoc.Action == xmpp.ActionAdHocNext {
// Last step in the command
log.Printf("%sAd-Hoc command (Node : %s). Last step.", LogInfo, adHoc.Node)
reply := iq.Response(xmpp.IQTypeResult)
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCompleted, SessionID: adHoc.SessionID}
if adHoc.Node == CommandAuthcode && adHoc.XForm.Type == xmpp.TypeAdHocSubmit {
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Steam Auth Code"}
cmd.XForm = *cmdXForm
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
// Command Auth Code
authCode := ""
fields := adHoc.XForm.Fields
for _, field := range fields {
if field.Var == "code" {
authCode = field.Value
break
}
}
if authCode != "" {
// Succeded
jidBare := strings.SplitN(iq.From, "/", 2)[0]
g := MapGatewayInfo[jidBare]
if g != nil {
g.SetSteamAuthCode(authCode)
note.Value = "Command succeded !"
} else {
note.Value = "Your are not registred. Please, register before sending Steam auth code."
}
} else {
// Failed
note.Value = "Error append while executing command"
}
cmd.Note = *note
} else if adHoc.Node == CommandGetIdentifiants {
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Steam Account Info"}
cmd.XForm = *cmdXForm
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
// Command Auth Code
steamLogin := ""
steamPwd := ""
fields := adHoc.XForm.Fields
for _, field := range fields {
if field.Var == "login" {
steamLogin = field.Value
} else if field.Var == "password" {
steamPwd = field.Value
}
}
if steamLogin != "" && steamPwd != "" {
// Succeded
jidBare := strings.SplitN(iq.From, "/", 2)[0]
dbUser := new(database.DatabaseLine)
dbUser.Jid = jidBare
dbUser.SteamLogin = steamLogin
dbUser.SteamPwd = steamPwd
dbUser.Debug = false
isUserRegistred := database.GetLine(dbUser.Jid) != nil
var isSqlSuccess bool
if isUserRegistred {
isSqlSuccess = dbUser.UpdateLine()
} else {
isSqlSuccess = dbUser.AddLine()
}
if isSqlSuccess {
AddNewUser(dbUser.Jid, dbUser.SteamLogin, dbUser.SteamPwd, dbUser.Debug)
note.Value = "Command succeded !"
} else {
note.Value = "Error append while executing command"
}
} else {
// Failed
note.Value = "Failed because Steam login or Steam password is empty."
}
cmd.Note = *note
}
reply.PayloadEncode(cmd)
comp.Out <- reply
} else if adHoc.Action == xmpp.ActionAdHocCancel {
// command canceled
log.Printf("%sAd-Hoc command (Node : %s). Command canceled.", LogInfo, adHoc.Node)
reply := iq.Response(xmpp.IQTypeResult)
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCanceled, SessionID: adHoc.SessionID}
reply.PayloadEncode(cmd)
comp.Out <- reply
}
}

View File

@ -1,30 +1,22 @@
package xmpp
import (
// "github.com/emgee/go-xmpp"
"go-xmpp"
"git.kingpenguin.tk/chteufleur/go-xmpp.git/src/xmpp"
"git.kingpenguin.tk/chteufleur/go-xmpp4steam.git/database"
"git.kingpenguin.tk/chteufleur/go-xmpp4steam.git/gateway"
"log"
"strings"
)
const (
Status_online = ""
Status_offline = ""
Status_away = "away"
Status_chat = "chat"
Status_do_not_disturb = "dnd"
Status_extended_away = "xa"
ActionConnexion = "action_xmpp_connexion"
ActionDeconnexion = "action_xmpp_deconnexion"
ActionMainMethodEnded = "action_xmpp_main_method_ended"
Type_available = ""
Type_unavailable = "unavailable"
ActionConnexion = "action_xmpp_connexion"
ActionDeconnexion = "action_xmpp_deconnexion"
LogInfo = "\t[XMPP INFO]\t"
LogError = "\t[XMPP ERROR]\t"
LogDebug = "\t[XMPP DEBUG]\t"
LogInfo = "\t[XMPP COMPONENT INFO]\t"
LogError = "\t[XMPP COMPONENT ERROR]\t"
LogDebug = "\t[XMPP COMPONENT DEBUG]\t"
)
var (
@ -32,55 +24,101 @@ var (
JidStr = ""
Secret = ""
PreferedJID = ""
SoftVersion = ""
jid xmpp.JID
stream = new(xmpp.Stream)
comp = new(xmpp.XMPP)
ChanPresence = make(chan string)
ChanMessage = make(chan string)
ChanAction = make(chan string)
ChanAction = make(chan string)
CurrentStatus = Status_offline
Debug = true
Version = ""
MapGatewayInfo = make(map[string]*gateway.GatewayInfo)
)
func Run() {
log.Printf("%sRunning", LogInfo)
// Create stream and configure it as a component connection.
jid = must(xmpp.ParseJID(JidStr)).(xmpp.JID)
stream = must(xmpp.NewStream(Addr, &xmpp.StreamConfig{LogStanzas: true})).(*xmpp.Stream)
stream = must(xmpp.NewStream(Addr, &xmpp.StreamConfig{LogStanzas: Debug})).(*xmpp.Stream)
comp = must(xmpp.NewComponentXMPP(stream, jid, Secret)).(*xmpp.XMPP)
// SendPresence(Status_online, Type_available)
mainXMPP()
log.Printf("%sReach main method's end", LogInfo)
go Run()
}
func mainXMPP() {
// Define xmpp out for all users
for _, u := range MapGatewayInfo {
u.XMPP_Out = comp.Out
}
for x := range comp.In {
switch v := x.(type) {
case *xmpp.Presence:
if strings.SplitN(v.From, "/", 2)[0] == PreferedJID && v.To == JidStr && v.Type != "probe" {
if v.Type == Type_unavailable {
log.Printf("%sPresence reçut unavailable", LogDebug)
Disconnect()
ChanAction <- ActionDeconnexion
} else {
log.Printf("%sPresence reçut", LogDebug)
CurrentStatus = v.Show
ChanAction <- ActionConnexion
jidBare := strings.SplitN(v.From, "/", 2)[0]
g := MapGatewayInfo[jidBare]
if g != nil {
log.Printf("%sPresence transfered to %s", LogDebug, jidBare)
g.ReceivedXMPP_Presence(v)
} else {
if v.Type != gateway.Type_error && v.Type != gateway.Type_probe {
SendPresence(gateway.Status_offline, gateway.Type_unavailable, jid.Domain, v.From, "Your are not registred", "")
}
ChanPresence <- v.Show
}
case *xmpp.Message:
steamID := strings.SplitN(v.To, "@", 2)[0]
ChanMessage <- steamID
ChanMessage <- v.Body
jidBare := strings.SplitN(v.From, "/", 2)[0]
g := MapGatewayInfo[jidBare]
if g != nil {
log.Printf("%sMessage transfered to %s", LogDebug, jidBare)
g.ReceivedXMPP_Message(v)
} else {
SendMessage(v.From, "", "Your are not registred. If you want to register, please, send an Ad-Hoc command.")
}
case *xmpp.Iq:
jidBare := strings.SplitN(v.To, "/", 2)[0]
switch v.PayloadName().Space {
case xmpp.NSDiscoItems:
if jidBare == jid.Domain {
execDiscoCommand(v)
} else {
sendNotSupportedFeature(v)
}
case xmpp.NodeAdHocCommand:
if jidBare == jid.Domain {
execCommandAdHoc(v)
} else {
sendNotSupportedFeature(v)
}
case xmpp.NSVCardTemp:
if jidBare == jid.Domain {
reply := v.Response(xmpp.IQTypeResult)
vcard := &xmpp.VCard{}
reply.PayloadEncode(vcard)
comp.Out <- reply
} else {
sendNotSupportedFeature(v)
}
case xmpp.NSJabberClient:
if jidBare == jid.Domain {
reply := v.Response(xmpp.IQTypeResult)
reply.PayloadEncode(&xmpp.SoftwareVersion{Name: "go-xmpp4steam", Version: SoftVersion})
comp.Out <- reply
} else {
sendNotSupportedFeature(v)
}
default:
sendNotSupportedFeature(v)
}
default:
log.Printf("%srecv: %v", LogDebug, x)
@ -88,7 +126,7 @@ func mainXMPP() {
}
// Send deconnexion
SendPresence(Status_offline, Type_unavailable)
SendPresence(gateway.Status_offline, gateway.Type_unavailable, "", "", "", "")
}
func must(v interface{}, err error) interface{} {
@ -98,18 +136,87 @@ func must(v interface{}, err error) interface{} {
return v
}
func sendNotSupportedFeature(iq *xmpp.Iq) {
reply := iq.Response(xmpp.IQTypeError)
reply.PayloadEncode(xmpp.NewError("cancel", xmpp.FeatureNotImplemented, ""))
comp.Out <- reply
}
func Disconnect() {
SendPresence(Status_offline, Type_unavailable)
log.Printf("%sXMPP disconnect", LogInfo)
for _, u := range MapGatewayInfo {
u.SteamDisconnect()
}
}
func SendPresence(status, tpye string) {
comp.Out <- xmpp.Presence{To: PreferedJID, From: jid.Domain, Show: status, Type: tpye, Status: "go-xmpp4steam v" + Version}
func SendPresence(status, tpye, from, to, message, nick string) {
p := xmpp.Presence{}
if status != "" {
p.Show = status
}
if tpye != "" {
p.Type = tpye
}
if message != "" {
p.Status = message
}
if nick != "" {
p.Nick = nick
}
if from == "" {
p.From = jid.Domain
} else {
p.From = from
}
if to != "" {
p.To = to
}
comp.Out <- p
}
func SendPresenceFrom(status, tpye, from string) {
comp.Out <- xmpp.Presence{To: PreferedJID, From: from, Show: status, Type: tpye}
func SendMessage(to, subject, message string) {
m := xmpp.Message{From: jid.Domain, To: to, Body: message, Type: "chat"}
if subject != "" {
m.Subject = subject
}
log.Printf("%sSenp message %v", LogInfo, m)
comp.Out <- m
}
func SendMessage(from, message string) {
comp.Out <- xmpp.Message{To: PreferedJID, From: from, Body: message}
func AddNewUser(jid, steamLogin, steamPwd string, debugMessage bool) {
log.Printf("%sAdd user %s to the map", LogInfo, jid)
g := new(gateway.GatewayInfo)
g.SteamLogin = steamLogin
g.SteamPassword = steamPwd
g.XMPP_JID_Client = jid
g.SentryFile = gateway.SentryDirectory + jid
g.FriendSteamId = make(map[string]*gateway.StatusSteamFriend)
g.Deleting = false
g.XMPP_Out = comp.Out
g.XMPP_Connected_Client = make(map[string]bool)
g.DebugMessage = debugMessage
MapGatewayInfo[jid] = g
go g.Run()
}
func RemoveUser(jidBare string) bool {
ret := database.RemoveLine(jidBare)
if ret {
g := MapGatewayInfo[jidBare]
ret = g != nil
if ret {
g.Delete()
MapGatewayInfo[jidBare] = nil
}
}
return ret
}

View File

@ -3,10 +3,4 @@ xmpp_server_address=192.168.1.2
xmpp_server_port=5347
xmpp_hostname=xmppsteam.kingpenguin.tk
xmpp_secret=xmpp4steam_password
xmpp_authorized_jid=chteufleur@kingpenguin.tk
# Steam informations
steam_login=toto
steam_password=toto_password123$
# steam_auth_code must be blank the first time. Then Valve will send the auth code to give here.
steam_auth_code=CXD7J
xmpp_debug=true