2021-03-03 10:48:27 +00:00
|
|
|
// Copyright 2018 - 2021 Martin Dosch.
|
2020-04-05 20:02:09 +00:00
|
|
|
// Use of this source code is governed by the BSD-2-clause
|
2020-04-04 07:42:09 +00:00
|
|
|
// license that can be found in the LICENSE file.
|
2018-08-04 10:19:32 +00:00
|
|
|
|
2018-08-04 10:16:28 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
2020-04-03 12:35:03 +00:00
|
|
|
"crypto/tls"
|
2018-08-10 10:14:21 +00:00
|
|
|
"errors"
|
2021-10-05 15:11:50 +00:00
|
|
|
"fmt"
|
2018-08-04 10:16:28 +00:00
|
|
|
"io"
|
|
|
|
"log"
|
2021-10-05 15:11:50 +00:00
|
|
|
"net"
|
2018-08-04 10:16:28 +00:00
|
|
|
"os"
|
2020-10-01 16:55:41 +00:00
|
|
|
"os/exec"
|
2018-08-10 10:14:21 +00:00
|
|
|
"os/user"
|
2019-02-21 17:20:54 +00:00
|
|
|
"runtime"
|
2018-08-10 10:14:21 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2019-02-20 20:22:31 +00:00
|
|
|
"time"
|
2018-08-04 10:16:28 +00:00
|
|
|
|
2020-01-22 18:31:31 +00:00
|
|
|
"github.com/mattn/go-xmpp" // BSD-3-Clause
|
|
|
|
"github.com/pborman/getopt/v2" // BSD-3-Clause
|
2018-08-04 10:16:28 +00:00
|
|
|
)
|
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
type configuration struct {
|
|
|
|
username string
|
|
|
|
jserver string
|
|
|
|
port string
|
|
|
|
password string
|
2021-06-26 07:59:08 +00:00
|
|
|
resource string
|
2018-08-10 10:14:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
)
|
|
|
|
|
2020-05-23 16:21:42 +00:00
|
|
|
// Use $XDG_CONFIG_HOME/.config/go-sendxmpp/sendxmpprc or
|
|
|
|
// ~/.sendxmpprc if no config path is specified.
|
2018-08-10 10:14:21 +00:00
|
|
|
if configPath == "" {
|
|
|
|
// Get systems user config path.
|
|
|
|
osConfigDir := os.Getenv("$XDG_CONFIG_HOME")
|
|
|
|
if osConfigDir != "" {
|
2020-05-23 16:21:42 +00:00
|
|
|
configPath = osConfigDir + "/go-sendxmpp/sendxmpprc"
|
|
|
|
// Check that the config file is existing.
|
|
|
|
_, err := os.Stat(configPath)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
// If the file is not existing at ~/.config/go-sendxmpp/sendxmpprc
|
|
|
|
// check at the perl sendxmpp legacy destination.
|
|
|
|
configPath = osConfigDir + "/.sendxmpprc"
|
|
|
|
_, err = os.Stat(configPath)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return output, errors.New("no configuration file found")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
} else {
|
|
|
|
// Get the current user.
|
|
|
|
curUser, err := user.Current()
|
|
|
|
if err != nil {
|
|
|
|
return output, err
|
|
|
|
}
|
|
|
|
// Get home directory.
|
|
|
|
home := curUser.HomeDir
|
|
|
|
if home == "" {
|
2019-02-13 17:31:58 +00:00
|
|
|
return output, errors.New("no home directory found")
|
2018-08-10 10:14:21 +00:00
|
|
|
}
|
2020-05-23 16:21:42 +00:00
|
|
|
configPath = home + "/.config/go-sendxmpp/sendxmpprc"
|
|
|
|
// Check that config file is existing.
|
|
|
|
_, err = os.Stat(configPath)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
// If the file is not existing at ~/.config/go-sendxmpp/sendxmpprc
|
|
|
|
// check at the perl sendxmpp legacy destination.
|
|
|
|
configPath = home + "/.sendxmpprc"
|
|
|
|
_, err = os.Stat(configPath)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return output, errors.New("no configuration file found")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 17:20:54 +00:00
|
|
|
// Only check file permissions if we are not running on windows.
|
|
|
|
if runtime.GOOS != "windows" {
|
2020-05-23 16:21:42 +00:00
|
|
|
info, _ := os.Stat(configPath)
|
2020-10-01 17:22:26 +00:00
|
|
|
// Check for file permissions. Must be 600, 640, 440 or 400.
|
2019-02-21 17:20:54 +00:00
|
|
|
perm := info.Mode().Perm()
|
|
|
|
permissions := strconv.FormatInt(int64(perm), 8)
|
2020-10-01 17:22:26 +00:00
|
|
|
if permissions != "600" && permissions != "640" && permissions != "440" && permissions != "400" {
|
2019-02-21 17:20:54 +00:00
|
|
|
return output, errors.New("Wrong permissions for " + configPath + ": " +
|
2020-10-01 17:22:26 +00:00
|
|
|
permissions + " instead of 400, 440, 600 or 640.")
|
2019-02-21 17:20:54 +00:00
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Open config file.
|
|
|
|
file, err := os.Open(configPath)
|
|
|
|
if err != nil {
|
|
|
|
return output, err
|
|
|
|
}
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
scanner.Split(bufio.ScanLines)
|
|
|
|
|
|
|
|
// Read config file per line.
|
|
|
|
for scanner.Scan() {
|
2020-04-02 17:35:12 +00:00
|
|
|
if strings.HasPrefix(scanner.Text(), "#") {
|
2018-08-10 10:14:21 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-10-01 16:55:41 +00:00
|
|
|
row := strings.SplitN(scanner.Text(), " ", 2)
|
2018-08-10 10:14:21 +00:00
|
|
|
|
|
|
|
switch row[0] {
|
|
|
|
case "username:":
|
|
|
|
output.username = row[1]
|
|
|
|
case "jserver:":
|
|
|
|
output.jserver = row[1]
|
|
|
|
case "password:":
|
|
|
|
output.password = row[1]
|
2020-10-01 16:55:41 +00:00
|
|
|
case "eval_password:":
|
|
|
|
shell := os.Getenv("SHELL")
|
|
|
|
if shell == "" {
|
|
|
|
shell = "/bin/sh"
|
|
|
|
}
|
|
|
|
out, err := exec.Command(shell, "-c", row[1]).Output()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
output.password = string(out)
|
|
|
|
if output.password[len(output.password)-1] == '\n' {
|
|
|
|
output.password = output.password[:len(output.password)-1]
|
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
case "port:":
|
|
|
|
output.port = row[1]
|
2021-06-26 07:59:08 +00:00
|
|
|
case "resource:":
|
|
|
|
output.resource = row[1]
|
2018-08-10 10:14:21 +00:00
|
|
|
default:
|
|
|
|
if len(row) >= 2 {
|
2020-04-02 17:35:12 +00:00
|
|
|
if strings.Contains(scanner.Text(), ";") {
|
2018-08-10 10:14:21 +00:00
|
|
|
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]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-21 17:15:46 +00:00
|
|
|
file.Close()
|
2018-08-10 10:14:21 +00:00
|
|
|
|
2020-06-06 10:06:55 +00:00
|
|
|
// Check if the username is a valid JID
|
|
|
|
output.username, err = MarshalJID(output.username)
|
|
|
|
if err != nil {
|
|
|
|
// Check whether only the local part was used by appending an @ and the
|
|
|
|
// server part.
|
|
|
|
output.username = output.username + "@" + output.jserver
|
|
|
|
// Check if the username is a valid JID now
|
|
|
|
output.username, err = MarshalJID(output.username)
|
|
|
|
if err != nil {
|
|
|
|
return output, errors.New("invalid username/JID: " + output.username)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
return output, err
|
|
|
|
}
|
|
|
|
|
2018-08-10 11:12:21 +00:00
|
|
|
func readMessage(messageFilePath string) (string, error) {
|
|
|
|
var (
|
|
|
|
output string
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
// Check that message file is existing.
|
|
|
|
_, err = os.Stat(messageFilePath)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return output, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Open message file.
|
|
|
|
file, err := os.Open(messageFilePath)
|
|
|
|
if err != nil {
|
|
|
|
return output, err
|
|
|
|
}
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
scanner.Split(bufio.ScanLines)
|
|
|
|
|
|
|
|
for scanner.Scan() {
|
|
|
|
|
|
|
|
if output == "" {
|
|
|
|
output = scanner.Text()
|
|
|
|
} else {
|
|
|
|
output = output + "\n" + scanner.Text()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
|
|
if err != io.EOF {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 17:15:46 +00:00
|
|
|
file.Close()
|
|
|
|
|
2018-08-10 11:12:21 +00:00
|
|
|
return output, err
|
|
|
|
}
|
|
|
|
|
2018-08-04 10:16:28 +00:00
|
|
|
func main() {
|
|
|
|
|
|
|
|
var (
|
2021-06-26 07:59:08 +00:00
|
|
|
err error
|
|
|
|
message, user, server, password, resource string
|
2018-08-04 10:16:28 +00:00
|
|
|
)
|
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
// Define command line flags.
|
|
|
|
flagHelp := getopt.BoolLong("help", 0, "Show help.")
|
2020-04-09 12:58:03 +00:00
|
|
|
flagHttpUpload := getopt.StringLong("http-upload", 0, "", "Send a file via http-upload.")
|
2018-08-10 10:14:21 +00:00
|
|
|
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.")
|
2022-02-12 08:06:52 +00:00
|
|
|
flagDirectTLS := getopt.BoolLong("tls", 't', "Use direct TLS.")
|
2021-06-26 07:59:08 +00:00
|
|
|
flagResource := getopt.StringLong("resource", 'r', "", "Set resource. "+
|
2021-07-02 08:55:03 +00:00
|
|
|
"When sending to a chatroom this is used as 'alias'.")
|
2021-02-28 16:58:32 +00:00
|
|
|
flagFile := getopt.StringLong("file", 'f', "", "Set configuration file. (Default: "+
|
|
|
|
"~/.config/go-sendxmpp/sendxmpprc)")
|
2018-08-10 11:12:21 +00:00
|
|
|
flagMessageFile := getopt.StringLong("message", 'm', "", "Set file including the message.")
|
2018-08-10 13:03:04 +00:00
|
|
|
flagInteractive := getopt.BoolLong("interactive", 'i', "Interactive mode (for use with e.g. 'tail -f').")
|
2020-04-05 19:49:17 +00:00
|
|
|
flagSkipVerify := getopt.BoolLong("no-tls-verify", 'n',
|
|
|
|
"Skip verification of TLS certificates (not recommended).")
|
2021-01-30 13:24:54 +00:00
|
|
|
flagRaw := getopt.BoolLong("raw", 0, "Send raw XML.")
|
2022-02-07 15:14:47 +00:00
|
|
|
flagListen := getopt.BoolLong("listen", 'l', "Listen for messages and print them to stdout.")
|
2022-02-12 08:18:02 +00:00
|
|
|
flagTimeout := getopt.IntLong("timeout", 0, 10, "Connection timeout in seconds.")
|
2022-02-12 08:36:12 +00:00
|
|
|
flagTLSMinVersion := getopt.IntLong("tls-version", 0, 12,
|
|
|
|
"Minimal TLS version. 10 (TSLv1.0), 11 (TLSv1.1), 12 (TLSv1.2) or 13 (TLSv1.3).")
|
2022-02-12 10:16:45 +00:00
|
|
|
flagVersion := getopt.BoolLong("version", 0, "Show version information.")
|
2022-02-19 07:30:35 +00:00
|
|
|
flagMUCPassword := getopt.StringLong("muc-password", 0, "", "Password for password protected MUCs.")
|
2018-08-10 10:14:21 +00:00
|
|
|
|
|
|
|
// Parse command line flags.
|
|
|
|
getopt.Parse()
|
|
|
|
|
|
|
|
// If requested, show help and quit.
|
|
|
|
if *flagHelp {
|
|
|
|
getopt.Usage()
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2022-02-12 10:16:45 +00:00
|
|
|
// If requested, show version and quit.
|
|
|
|
if *flagVersion {
|
2022-02-12 11:32:18 +00:00
|
|
|
fmt.Println("go-sendxmpp", "devel")
|
2022-02-12 10:16:45 +00:00
|
|
|
fmt.Println("License: BSD-2-clause")
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
// Read recipients from command line and quit if none are specified.
|
2022-02-06 22:25:00 +00:00
|
|
|
// For listening or sending raw XML it's not required to specify a recipient except
|
|
|
|
// when sending raw messages to MUCs (go-sendxmpp will join the MUC automatically).
|
2018-08-10 10:14:21 +00:00
|
|
|
recipients := getopt.Args()
|
2022-02-06 22:25:00 +00:00
|
|
|
if (len(recipients) == 0 && !*flagRaw && !*flagListen) ||
|
|
|
|
(len(recipients) == 0 && *flagChatroom) {
|
2018-08-10 10:14:21 +00:00
|
|
|
log.Fatal("No recipient specified.")
|
|
|
|
}
|
2018-08-04 10:16:28 +00:00
|
|
|
|
2020-04-04 07:40:24 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2021-01-21 09:42:07 +00:00
|
|
|
// Read configuration file if user or password is not specified.
|
|
|
|
if *flagUser == "" || *flagPassword == "" {
|
2019-02-20 21:23:29 +00:00
|
|
|
// Read configuration from file.
|
|
|
|
config, err := parseConfig(*flagFile)
|
|
|
|
if err != nil {
|
2020-04-03 12:28:08 +00:00
|
|
|
log.Fatal("Error parsing ", *flagFile, ": ", err)
|
2019-02-20 21:23:29 +00:00
|
|
|
}
|
|
|
|
// Set connection options according to config.
|
|
|
|
user = config.username
|
|
|
|
server = config.jserver
|
|
|
|
password = config.password
|
2021-06-26 07:59:08 +00:00
|
|
|
resource = config.resource
|
2019-02-20 21:23:29 +00:00
|
|
|
if config.port != "" {
|
2021-10-05 15:11:50 +00:00
|
|
|
server = net.JoinHostPort(server, fmt.Sprint(config.port))
|
2019-02-20 21:23:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-21 17:14:10 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2021-06-26 07:59:08 +00:00
|
|
|
// Overwrite resource if specified via command line flag
|
|
|
|
if *flagResource != "" {
|
|
|
|
resource = *flagResource
|
|
|
|
} else if resource == "" {
|
2021-07-02 08:55:03 +00:00
|
|
|
// Use "go-sendxmpp" plus a random string if no other resource is specified
|
|
|
|
resource = "go-sendxmpp." + getID()
|
2021-06-26 07:59:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-09 15:01:48 +00:00
|
|
|
if (*flagHttpUpload != "") && (*flagInteractive || (*flagMessageFile != "")) {
|
|
|
|
if *flagInteractive {
|
|
|
|
log.Fatal("Interactive mode and http upload can't" +
|
|
|
|
" be used at the same time.")
|
|
|
|
}
|
|
|
|
if *flagMessageFile != "" {
|
|
|
|
log.Fatal("You can't send a message while using" +
|
|
|
|
" http upload.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 08:18:02 +00:00
|
|
|
// Timeout
|
|
|
|
timeout := time.Duration(*flagTimeout * 1000000000)
|
|
|
|
|
2020-04-02 17:35:12 +00:00
|
|
|
// Use ALPN
|
2020-04-03 12:35:03 +00:00
|
|
|
var tlsConfig tls.Config
|
2021-03-03 21:10:45 +00:00
|
|
|
tlsConfig.ServerName = user[strings.Index(user, "@")+1:]
|
2020-04-02 17:35:12 +00:00
|
|
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "xmpp-client")
|
2020-04-05 19:49:17 +00:00
|
|
|
tlsConfig.InsecureSkipVerify = *flagSkipVerify
|
2022-02-12 08:36:12 +00:00
|
|
|
switch *flagTLSMinVersion {
|
|
|
|
case 10:
|
|
|
|
tlsConfig.MinVersion = tls.VersionTLS10
|
|
|
|
case 11:
|
|
|
|
tlsConfig.MinVersion = tls.VersionTLS11
|
|
|
|
case 12:
|
|
|
|
tlsConfig.MinVersion = tls.VersionTLS12
|
|
|
|
case 13:
|
|
|
|
tlsConfig.MinVersion = tls.VersionTLS13
|
|
|
|
default:
|
|
|
|
fmt.Println("Unknown TLS version.")
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
2020-04-02 17:35:12 +00:00
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
// Set XMPP connection options.
|
2018-08-04 10:16:28 +00:00
|
|
|
options := xmpp.Options{
|
2022-02-12 08:18:02 +00:00
|
|
|
Host: server,
|
|
|
|
User: user,
|
|
|
|
DialTimeout: timeout,
|
2021-06-26 07:59:08 +00:00
|
|
|
Resource: resource,
|
2021-02-28 12:57:06 +00:00
|
|
|
Password: password,
|
2022-02-12 08:11:03 +00:00
|
|
|
// NoTLS doesn't mean that no TLS is used at all but that instead
|
|
|
|
// of using an encrypted connection to the server (direct TLS)
|
|
|
|
// an unencrypted connection is established. As StartTLS is
|
|
|
|
// set when NoTLS is set go-sendxmpp won't use unencrypted
|
|
|
|
// client-to-server connections.
|
|
|
|
// See https://pkg.go.dev/github.com/mattn/go-xmpp#Options
|
|
|
|
NoTLS: !*flagDirectTLS,
|
|
|
|
StartTLS: !*flagDirectTLS,
|
|
|
|
Debug: *flagDebug,
|
|
|
|
TLSConfig: &tlsConfig,
|
2018-08-04 10:16:28 +00:00
|
|
|
}
|
|
|
|
|
2018-08-10 11:12:21 +00:00
|
|
|
// Read message from file.
|
|
|
|
if *flagMessageFile != "" {
|
|
|
|
message, err = readMessage(*flagMessageFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-04 10:16:28 +00:00
|
|
|
// Connect to server.
|
2022-02-12 08:06:52 +00:00
|
|
|
client, err := connect(options, *flagDirectTLS)
|
2018-08-04 10:16:28 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2020-04-09 12:58:03 +00:00
|
|
|
if *flagHttpUpload != "" {
|
2020-04-09 13:47:03 +00:00
|
|
|
message = httpUpload(client, tlsConfig.ServerName,
|
2020-04-09 12:58:03 +00:00
|
|
|
*flagHttpUpload)
|
|
|
|
}
|
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
// Skip reading message if '-i' or '--interactive' is set to work with e.g. 'tail -f'.
|
2022-02-06 22:25:00 +00:00
|
|
|
// Also for listening mode.
|
|
|
|
if !*flagInteractive && !*flagListen {
|
2018-08-10 13:03:04 +00:00
|
|
|
if message == "" {
|
2018-08-04 10:16:28 +00:00
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
for scanner.Scan() {
|
2018-08-04 10:16:28 +00:00
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
if message == "" {
|
|
|
|
message = scanner.Text()
|
|
|
|
} else {
|
|
|
|
message = message + "\n" + scanner.Text()
|
|
|
|
}
|
2018-08-04 10:16:28 +00:00
|
|
|
}
|
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
if err := scanner.Err(); err != nil {
|
|
|
|
if err != io.EOF {
|
2020-04-03 12:14:48 +00:00
|
|
|
// Close connection and quit.
|
|
|
|
_ = client.Close()
|
2018-08-10 13:03:04 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2018-08-04 10:16:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 13:24:54 +00:00
|
|
|
// Send raw XML to chatroom
|
|
|
|
if *flagChatroom && *flagRaw {
|
2022-02-19 07:30:35 +00:00
|
|
|
var err error
|
2021-01-31 11:35:24 +00:00
|
|
|
// Join the MUCs.
|
|
|
|
for _, recipient := range recipients {
|
2022-02-19 07:30:35 +00:00
|
|
|
if *flagMUCPassword != "" {
|
|
|
|
dummyTime := time.Now()
|
|
|
|
_, err = client.JoinProtectedMUC(recipient, *flagResource,
|
|
|
|
*flagMUCPassword, 0, 0, &dummyTime)
|
|
|
|
} else {
|
|
|
|
_, err = client.JoinMUCNoHistory(recipient, *flagResource)
|
|
|
|
}
|
2021-01-31 11:35:24 +00:00
|
|
|
if err != nil {
|
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error joining.
|
|
|
|
_ = client.Close()
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2021-01-30 13:24:54 +00:00
|
|
|
}
|
|
|
|
// Send raw XMP
|
|
|
|
_, err = client.SendOrg(message)
|
|
|
|
if err != nil {
|
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error sending.
|
|
|
|
_ = client.Close()
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2021-01-31 11:35:24 +00:00
|
|
|
// After sending the message, leave the MUCs
|
|
|
|
for _, recipient := range recipients {
|
2021-01-31 11:57:45 +00:00
|
|
|
_, err = client.LeaveMUC(recipient)
|
2021-01-31 11:35:24 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
2021-01-30 13:24:54 +00:00
|
|
|
}
|
|
|
|
// Wait for a short time as some messages are not delievered by the server
|
|
|
|
// if the connection is closed immediately after sending a message.
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-02-06 22:25:00 +00:00
|
|
|
if *flagListen {
|
|
|
|
for {
|
2022-02-07 15:13:45 +00:00
|
|
|
received, err := client.Recv()
|
2022-02-06 22:25:00 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
2022-02-07 15:17:59 +00:00
|
|
|
switch v := received.(type) {
|
2022-02-06 22:25:00 +00:00
|
|
|
case xmpp.Chat:
|
2022-02-07 15:17:59 +00:00
|
|
|
if v.Text == "" {
|
|
|
|
continue
|
|
|
|
}
|
2022-02-07 16:44:44 +00:00
|
|
|
t := time.Now()
|
|
|
|
bareFrom := strings.Split(v.Remote, "/")[0]
|
2022-02-07 15:17:59 +00:00
|
|
|
// Print any messages if no recipients are specified
|
|
|
|
if len(recipients) == 0 {
|
2022-02-07 16:44:44 +00:00
|
|
|
fmt.Println(t.Format(time.RFC3339), bareFrom+":", v.Text)
|
2022-02-07 15:17:59 +00:00
|
|
|
} else {
|
|
|
|
for _, recipient := range recipients {
|
|
|
|
if bareFrom == strings.ToLower(recipient) {
|
2022-02-07 16:44:44 +00:00
|
|
|
fmt.Println(t.Format(time.RFC3339), bareFrom+":", v.Text)
|
2022-02-07 15:17:59 +00:00
|
|
|
}
|
|
|
|
}
|
2022-02-06 22:25:00 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
// Send message to chatroom(s) if the flag is set.
|
|
|
|
if *flagChatroom {
|
2018-08-04 10:16:28 +00:00
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
for _, recipient := range recipients {
|
2018-08-04 10:16:28 +00:00
|
|
|
|
2018-08-10 10:14:21 +00:00
|
|
|
// Join the MUC.
|
2022-02-19 07:30:35 +00:00
|
|
|
if *flagMUCPassword != "" {
|
|
|
|
dummyTime := time.Now()
|
|
|
|
_, err = client.JoinProtectedMUC(recipient, *flagResource,
|
|
|
|
*flagMUCPassword, 0, 0, &dummyTime)
|
|
|
|
} else {
|
|
|
|
_, err = client.JoinMUCNoHistory(recipient, *flagResource)
|
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
if err != nil {
|
2020-04-03 12:14:48 +00:00
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error joining.
|
|
|
|
_ = client.Close()
|
2018-08-10 10:14:21 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2018-08-10 13:03:04 +00:00
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
// Send in endless loop (for usage with e.g. "tail -f").
|
2020-01-22 18:49:32 +00:00
|
|
|
if *flagInteractive {
|
2018-08-10 13:03:04 +00:00
|
|
|
for {
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
scanner.Scan()
|
|
|
|
message = scanner.Text()
|
|
|
|
for _, recipient := range recipients {
|
2018-08-20 11:24:48 +00:00
|
|
|
_, err = client.Send(xmpp.Chat{Remote: recipient,
|
|
|
|
Type: "groupchat", Text: message})
|
2018-08-10 13:03:04 +00:00
|
|
|
if err != nil {
|
2020-04-03 12:14:48 +00:00
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error sending.
|
|
|
|
_ = client.Close()
|
2018-08-10 13:03:04 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2018-08-10 10:14:21 +00:00
|
|
|
// Send the message.
|
2018-08-10 13:03:04 +00:00
|
|
|
for _, recipient := range recipients {
|
2020-04-09 14:49:27 +00:00
|
|
|
if *flagHttpUpload != "" {
|
2020-04-11 16:59:32 +00:00
|
|
|
_, err = client.Send(xmpp.Chat{Remote: recipient,
|
|
|
|
Type: "groupchat", Ooburl: message, Text: message})
|
2020-04-09 14:49:27 +00:00
|
|
|
} else {
|
|
|
|
_, err = client.Send(xmpp.Chat{Remote: recipient,
|
|
|
|
Type: "groupchat", Text: message})
|
|
|
|
}
|
2018-08-10 13:03:04 +00:00
|
|
|
if err != nil {
|
2020-04-03 12:14:48 +00:00
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error sending.
|
|
|
|
_ = client.Close()
|
2018-08-10 13:03:04 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
}
|
2018-08-10 13:03:04 +00:00
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
for _, recipient := range recipients {
|
2018-08-10 10:14:21 +00:00
|
|
|
// After sending the message, leave the Muc
|
|
|
|
_, err = client.LeaveMUC(recipient)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
2018-08-04 10:16:28 +00:00
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
} else {
|
2021-01-30 13:24:54 +00:00
|
|
|
// Send raw XML
|
|
|
|
if *flagRaw {
|
|
|
|
_, err = client.SendOrg(message)
|
|
|
|
if err != nil {
|
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error sending.
|
|
|
|
_ = client.Close()
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
// Wait for a short time as some messages are not delievered by the server
|
|
|
|
// if the connection is closed immediately after sending a message.
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-10 13:03:04 +00:00
|
|
|
// Send in endless loop (for usage with e.g. "tail -f").
|
2020-01-22 18:49:32 +00:00
|
|
|
if *flagInteractive {
|
2018-08-10 13:03:04 +00:00
|
|
|
for {
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
|
|
scanner.Scan()
|
|
|
|
message = scanner.Text()
|
|
|
|
for _, recipient := range recipients {
|
2018-08-20 11:24:48 +00:00
|
|
|
_, err = client.Send(xmpp.Chat{Remote: recipient,
|
|
|
|
Type: "chat", Text: message})
|
2018-08-10 13:03:04 +00:00
|
|
|
if err != nil {
|
2020-04-03 12:14:48 +00:00
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error sending.
|
|
|
|
_ = client.Close()
|
2018-08-10 13:03:04 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for _, recipient := range recipients {
|
2020-04-09 14:49:27 +00:00
|
|
|
if *flagHttpUpload != "" {
|
2020-04-11 16:59:32 +00:00
|
|
|
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "chat",
|
|
|
|
Ooburl: message, Text: message})
|
2020-04-09 14:49:27 +00:00
|
|
|
} else {
|
|
|
|
_, err = client.Send(xmpp.Chat{Remote: recipient, Type: "chat",
|
|
|
|
Text: message})
|
|
|
|
}
|
2018-08-10 13:03:04 +00:00
|
|
|
if err != nil {
|
2020-04-03 12:14:48 +00:00
|
|
|
// Try to nicely close connection,
|
|
|
|
// even if there was an error sending.
|
|
|
|
_ = client.Close()
|
2018-08-10 13:03:04 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2018-08-10 10:14:21 +00:00
|
|
|
}
|
2018-08-04 10:16:28 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-10 13:03:04 +00:00
|
|
|
|
2019-02-20 20:22:31 +00:00
|
|
|
// Wait for a short time as some messages are not delievered by the server
|
|
|
|
// if the connection is closed immediately after sending a message.
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
2019-02-13 17:31:14 +00:00
|
|
|
// Close XMPP connection
|
|
|
|
err = client.Close()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2018-08-04 10:16:28 +00:00
|
|
|
}
|