mirror of
https://salsa.debian.org/mdosch/go-sendxmpp
synced 2024-11-18 21:25:31 +00:00
Sendxmpp compatibility
This commit is contained in:
parent
acb3759bbb
commit
b8328a0e3b
74
README.md
74
README.md
@ -14,7 +14,7 @@ A little tool to send messages to an XMPP contact or MUC inspired by (but not as
|
||||
If you have *[GOPATH](https://github.com/golang/go/wiki/SettingGOPATH)*
|
||||
set just run this commands:
|
||||
|
||||
```bash
|
||||
```plain
|
||||
$ go get salsa.debian.org/mdosch-guest/go-sendxmpp
|
||||
$ go install salsa.debian.org/mdosch-guest/go-sendxmpp
|
||||
```
|
||||
@ -23,40 +23,58 @@ You will find the binary in `$GOPATH/bin` or, if set, `$GOBIN`.
|
||||
|
||||
## usage
|
||||
|
||||
The account details for logging into your XMPP account and at least `contact`
|
||||
or `muc` must be specified.
|
||||
You can either pipe a programs output to `go-sendxmpp` or write in your terminal (put \^D in a new
|
||||
line to finish).
|
||||
|
||||
If `-message` is not specified you can either pipe a programs output to
|
||||
`go-sendxmpp` or write in your terminal (put ^D in a new line to finish).
|
||||
The account data is expected at `~/.sendxmpprc` if no other configuration file location is specified with
|
||||
`-f` or `--file`. The configuration file is expected to be in the following format:
|
||||
|
||||
If `-port` is not set, the standard port *5222* is used.
|
||||
```plain
|
||||
username: <your_username>
|
||||
jserver: <jabber_server>
|
||||
port: <jabber_port>
|
||||
password: <your_jabber_password>
|
||||
```
|
||||
|
||||
```bash
|
||||
Usage of ./go-sendxmpp:
|
||||
-contact string
|
||||
Recipient of the message. (default "alice@example.com")
|
||||
-message string
|
||||
The message you want to send. (default "Hello World!")
|
||||
-muc string
|
||||
MUC to send the message to. (default "offtopic@conference.example.com")
|
||||
-muc-nick string
|
||||
The nickname the bot uses in the MUC. (default "go-sendxmpp")
|
||||
-pass string
|
||||
Password for XMPP account. (default "ChangeThis!")
|
||||
-port string
|
||||
XMPP server port. (default "5222")
|
||||
-server string
|
||||
XMPP server address. (default "example.com")
|
||||
-user string
|
||||
Username for XMPP account. (default "bob@example.com")
|
||||
If no configuration file is present or if the values should be overridden it is possible to define the
|
||||
account details via command line options:
|
||||
|
||||
```plain
|
||||
./go-sendxmpp --help
|
||||
Usage: go-sendxmpp [-cdtx] [-f value] [--help] [-j value] [-p value] [-r value] [-u value] [parameters ...]
|
||||
-c, --chatroom Send message to a chatroom.
|
||||
-d, --debug Show debugging info.
|
||||
-f, --file=value Set configuration file. (Default: ~/.sendxmppr)
|
||||
--help Show help.
|
||||
-j, --jserver=value
|
||||
XMPP server address.
|
||||
-p, --password=value
|
||||
Password for XMPP account.
|
||||
-r, --resource=value
|
||||
Set resource. When sending to a chatroom this is used as
|
||||
'alias'. (Default: go-sendxmpp)
|
||||
-t, --tls Use TLS.
|
||||
-u, --username=value
|
||||
Username for XMPP account.
|
||||
-x, --start-tls Use StartTLS.
|
||||
```
|
||||
|
||||
### examples
|
||||
|
||||
```bash
|
||||
inxi -F | ./go-sendxmpp -pass 'ChangeThis!' -port '5222' -server 'example.com' -user 'bob@example.com' -muc 'test@conference.example.com'
|
||||
```
|
||||
Send a message to two recipients using a configuration file.
|
||||
|
||||
```bash
|
||||
./go-sendxmpp -pass 'ChangeThis!' -port '5222' -server 'example.com' -user 'bob@example.com' -muc 'test@conference.example.com' -message 'Hello World!'
|
||||
cat message.txt | ./go-sendxmpp -f ./sendxmpp recipient1@example.com recipient2@example.com
|
||||
```
|
||||
|
||||
Send a message to two recipients directly defining account credentials.
|
||||
|
||||
```bash
|
||||
cat message.txt | ./go-sendxmpp -u bob@example.com -j example.com -p swordfish recipient1@example.com recipient2@example.com
|
||||
```
|
||||
|
||||
Send a message to two groupchats (`-c`) using a configuration file.
|
||||
|
||||
```bash
|
||||
cat message.txt | ./go-sendxmpp -cf ./sendxmpp chat1@conference.example.com chat2@conference.example.com
|
||||
```
|
275
go-sendxmpp.go
275
go-sendxmpp.go
@ -1,48 +1,222 @@
|
||||
/* Copyright 2018 Martin Dosch
|
||||
|
||||
Licensed under the "MIT License" */
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/user"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-xmpp"
|
||||
"github.com/pborman/getopt/v2"
|
||||
"mellium.im/xmpp/jid"
|
||||
)
|
||||
|
||||
type configuration struct {
|
||||
username string
|
||||
jserver string
|
||||
port string
|
||||
password string
|
||||
}
|
||||
|
||||
// Check that JIDs include localpart and serverpart
|
||||
// and return it marshalled.
|
||||
func marshalJID(input string) (string, error) {
|
||||
parsedJid, err := jid.Parse(input)
|
||||
if err != nil {
|
||||
return input, err
|
||||
}
|
||||
|
||||
if parsedJid.Localpart() == "" || parsedJid.Domainpart() == "" {
|
||||
return input, errors.New("Invalid JID: " + input)
|
||||
}
|
||||
|
||||
return parsedJid.String(), err
|
||||
}
|
||||
|
||||
// Opens the config file and returns the specified values
|
||||
// for username, server and port.
|
||||
func parseConfig(configPath string) (configuration, error) {
|
||||
|
||||
var (
|
||||
output configuration
|
||||
err error
|
||||
)
|
||||
|
||||
// Use ~/.sendxmpprc if no config path is specified.
|
||||
if configPath == "" {
|
||||
// Get systems user config path.
|
||||
osConfigDir := os.Getenv("$XDG_CONFIG_HOME")
|
||||
if osConfigDir != "" {
|
||||
configPath = osConfigDir + "/.sendxmpprc"
|
||||
} else {
|
||||
// Get the current user.
|
||||
curUser, err := user.Current()
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
// Get home directory.
|
||||
home := curUser.HomeDir
|
||||
if home == "" {
|
||||
return output, errors.New("No home directory found.")
|
||||
}
|
||||
configPath = home + "/.sendxmpprc"
|
||||
}
|
||||
}
|
||||
|
||||
// Check that config file is existing.
|
||||
info, err := os.Stat(configPath)
|
||||
if os.IsNotExist(err) {
|
||||
return output, err
|
||||
}
|
||||
|
||||
// Check for file permissions. Must be 600.
|
||||
perm := info.Mode().Perm()
|
||||
if strconv.FormatInt(int64(perm), 8) != "600" {
|
||||
return output, errors.New("Wrong permissions for " + configPath + ": " +
|
||||
strconv.FormatInt(int64(perm), 8) + " instead of 600.")
|
||||
}
|
||||
|
||||
// Open config file.
|
||||
file, err := os.Open(configPath)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
|
||||
// Read config file per line.
|
||||
for scanner.Scan() {
|
||||
if strings.HasPrefix(scanner.Text(), "#") == true {
|
||||
continue
|
||||
}
|
||||
|
||||
row := strings.Split(scanner.Text(), " ")
|
||||
|
||||
switch row[0] {
|
||||
case "username:":
|
||||
output.username = row[1]
|
||||
case "jserver:":
|
||||
output.jserver = row[1]
|
||||
case "password:":
|
||||
output.password = row[1]
|
||||
case "port:":
|
||||
output.port = row[1]
|
||||
default:
|
||||
if len(row) >= 2 {
|
||||
if strings.Contains(scanner.Text(), ";") == true {
|
||||
output.username = strings.Split(row[0], ";")[0]
|
||||
output.jserver = strings.Split(row[0], ";")[1]
|
||||
output.password = row[1]
|
||||
} else {
|
||||
output.username = strings.Split(row[0], ":")[0]
|
||||
output.jserver = strings.Split(row[0], "@")[1]
|
||||
output.password = row[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output, err
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
var (
|
||||
err error
|
||||
server = flag.String("server", "example.com", "XMPP server address.")
|
||||
port = flag.String("port", "5222", "XMPP server port.")
|
||||
user = flag.String("user", "bob@example.com", "Username for XMPP account.")
|
||||
password = flag.String("pass", "ChangeThis!", "Password for XMPP account.")
|
||||
contact = flag.String("contact", "alice@example.com", "Recipient of the message.")
|
||||
muc = flag.String("muc", "offtopic@conference.example.com", "MUC to send the message to.")
|
||||
mucNick = flag.String("muc-nick", "go-sendxmpp", "The nickname the bot uses in the MUC.")
|
||||
messagePtr = flag.String("message", "Hello World!", "The message you want to send.")
|
||||
err error
|
||||
message string
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
// Define command line flags.
|
||||
flagHelp := getopt.BoolLong("help", 0, "Show help.")
|
||||
flagDebug := getopt.BoolLong("debug", 'd', "Show debugging info.")
|
||||
flagServer := getopt.StringLong("jserver", 'j', "", "XMPP server address.")
|
||||
flagUser := getopt.StringLong("username", 'u', "", "Username for XMPP account.")
|
||||
flagPassword := getopt.StringLong("password", 'p', "", "Password for XMPP account.")
|
||||
flagChatroom := getopt.BoolLong("chatroom", 'c', "Send message to a chatroom.")
|
||||
// flagMessage := getopt.StringLong("message", 'm', "", "The message you want to send.")
|
||||
flagTLS := getopt.BoolLong("tls", 't', "Use TLS.")
|
||||
flagStartTLS := getopt.BoolLong("start-tls", 'x', "Use StartTLS.")
|
||||
flagResource := getopt.StringLong("resource", 'r', "go-sendxmpp", "Set resource. "+
|
||||
"When sending to a chatroom this is used as 'alias'. (Default: go-sendxmpp)")
|
||||
flagFile := getopt.StringLong("file", 'f', "", "Set configuration file. (Default: ~/.sendxmppr)")
|
||||
|
||||
message := *messagePtr
|
||||
// Parse command line flags.
|
||||
getopt.Parse()
|
||||
|
||||
if *contact == "alice@example.com" && *muc == "offtopic@conference.example.com" {
|
||||
log.Fatal("No target specified.")
|
||||
// If requested, show help and quit.
|
||||
if *flagHelp {
|
||||
getopt.Usage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Read recipients from command line and quit if none are specified.
|
||||
recipients := getopt.Args()
|
||||
if len(recipients) == 0 {
|
||||
log.Fatal("No recipient specified.")
|
||||
}
|
||||
|
||||
// Quit if unreasonable TLS setting is set.
|
||||
if *flagStartTLS == true && *flagTLS == true {
|
||||
log.Fatal("Use either TLS or StartTLS.")
|
||||
}
|
||||
|
||||
// Check that all recipient JIDs are valid.
|
||||
for i, recipient := range recipients {
|
||||
validatedJid, err := marshalJID(recipient)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
recipients[i] = validatedJid
|
||||
}
|
||||
|
||||
// Read configuration from file.
|
||||
config, err := parseConfig(*flagFile)
|
||||
if err != nil {
|
||||
log.Println("Error parsing ", *flagFile, ": ", err)
|
||||
}
|
||||
|
||||
// Set connection options according to config.
|
||||
user := config.username
|
||||
server := config.jserver
|
||||
password := config.password
|
||||
if config.port != "" {
|
||||
server = server + ":" + config.port
|
||||
}
|
||||
|
||||
// Overwrite user if specified via command line flag.
|
||||
if *flagUser != "" {
|
||||
user = *flagUser
|
||||
}
|
||||
|
||||
// Overwrite server if specified via command line flag.
|
||||
if *flagServer != "" {
|
||||
server = *flagServer
|
||||
}
|
||||
|
||||
// Overwrite password if specified via command line flag.
|
||||
if *flagPassword != "" {
|
||||
password = *flagPassword
|
||||
}
|
||||
|
||||
// Set XMPP connection options.
|
||||
options := xmpp.Options{
|
||||
Host: *server + ":" + *port,
|
||||
User: *user,
|
||||
Password: *password,
|
||||
NoTLS: true,
|
||||
StartTLS: true,
|
||||
Debug: false,
|
||||
Host: server,
|
||||
User: user,
|
||||
Resource: *flagResource,
|
||||
Password: password,
|
||||
NoTLS: !*flagTLS,
|
||||
StartTLS: *flagStartTLS,
|
||||
Debug: *flagDebug,
|
||||
}
|
||||
|
||||
// Connect to server.
|
||||
@ -51,15 +225,15 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if message == "Hello World!" {
|
||||
if message == "" {
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
|
||||
if message == "Hello World!" {
|
||||
message = string(scanner.Text())
|
||||
if message == "" {
|
||||
message = scanner.Text()
|
||||
} else {
|
||||
message = message + "\n" + string(scanner.Text())
|
||||
message = message + "\n" + scanner.Text()
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,28 +244,43 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
if *muc != "offtopic@conference.example.com" {
|
||||
// Join the MUC
|
||||
mucStatus, err := client.JoinMUCNoHistory(*muc, *mucNick)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Send message to chatroom(s) if the flag is set.
|
||||
if *flagChatroom {
|
||||
|
||||
// Exit if Status is > 300, see https://xmpp.org/registrar/mucstatus.html
|
||||
if mucStatus > 300 {
|
||||
log.Fatal("Couldn't join MUC. Status:", mucStatus)
|
||||
}
|
||||
for _, recipient := range recipients {
|
||||
|
||||
_, err = client.Send(xmpp.Chat{Remote: *muc, Type: "groupchat", Text: message})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Join the MUC.
|
||||
mucStatus, err := client.JoinMUCNoHistory(recipient, *flagResource)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if *contact != "alice@example.com" {
|
||||
_, err = client.Send(xmpp.Chat{Remote: *contact, Type: "chat", Text: message})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
// Exit if Status is > 300, see https://xmpp.org/registrar/mucstatus.html
|
||||
if mucStatus > 300 {
|
||||
log.Fatal("Couldn't join MUC. Status:", mucStatus)
|
||||
}
|
||||
|
||||
// Send the message.
|
||||
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "groupchat", Text: message})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// After sending the message, leave the Muc
|
||||
_, err = client.LeaveMUC(recipient)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
for _, recipient := range recipients {
|
||||
|
||||
// If the chatroom flag is not set, send message to contact(s).
|
||||
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "chat", Text: message})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
|
Loading…
Reference in New Issue
Block a user