Browse Source

Pass command arguments in environment variables

tags/v0.2.2
Russ Garrett 7 years ago
parent
commit
7c33366a0c
No account linked to committer's email address
5 changed files with 63 additions and 26 deletions
  1. 18
    6
      README.md
  2. 22
    5
      command.go
  3. 21
    13
      examples/command_runner.py
  4. 1
    1
      main.go
  5. 1
    1
      tcplistener/tcplistener.go

+ 18
- 6
README.md View File

@@ -60,10 +60,22 @@ You can use irccat to execute commands from IRC:
60 60
 
61 61
     ?commandname string of arguments
62 62
 
63
-This will call your `commands.handler` script with the command-line
64
-arguments:
65
-
66
-    nickname [channel] respond_to commandname [string of arguments]
63
+This will call your `commands.handler` script, with the following
64
+environment variables:
65
+
66
+* `IRCCAT_COMMAND`: The name of the command, without the preceding `?`
67
+* `IRCCAT_ARGS`: The arguments provided ("string of arguments" in this
68
+  example)
69
+* `IRCCAT_NICK`: Nickname of the calling user
70
+* `IRCCAT_USER`: Username of the calling user
71
+* `IRCCAT_HOST`: Hostname of the calling user
72
+* `IRCCAT_CHANNEL`: Channel the command was issued in (may be blank if
73
+  issued in PM)
74
+* `IRCCAT_RESPOND_TO`: The nick or channel that the STDOUT of the
75
+  command will be sent to
76
+
77
+The command handler's STDOUT will be sent back to the nick or channel
78
+where the command was issued.
67 79
 
68 80
 irccat will only recognise commands from users in private message if
69 81
 the user is joined to `commands.auth_channel` defined in the config.
@@ -73,5 +85,5 @@ the user is joined to `commands.auth_channel` defined in the config.
73 85
 * HTTP endpoint handlers.
74 86
 * Doesn't support !join, !part commands, but does automatically reload
75 87
   the config and join new channels.
76
-* Arguments are passed individually to the command handler script,
77
-  rather than in one string as a single argument.
88
+* Arguments are passed as environment variables to the command handler
89
+  script, rather than as a single argument.

+ 22
- 5
command.go View File

@@ -2,10 +2,13 @@ package main
2 2
 
3 3
 import (
4 4
 	"bytes"
5
+	"fmt"
5 6
 	"github.com/spf13/viper"
6 7
 	"github.com/thoj/go-ircevent"
8
+	"os"
7 9
 	"os/exec"
8 10
 	"strings"
11
+	"time"
9 12
 )
10 13
 
11 14
 func (i *IRCCat) handleCommand(event *irc.Event) {
@@ -27,12 +30,20 @@ func (i *IRCCat) handleCommand(event *irc.Event) {
27 30
 
28 31
 	parts := strings.SplitN(msg, " ", 1)
29 32
 
30
-	var cmd *exec.Cmd
31
-	if len(parts) == 1 {
32
-		cmd = exec.Command(viper.GetString("commands.handler"), event.Nick, channel, respond_to, parts[0][1:])
33
-	} else {
34
-		cmd = exec.Command(viper.GetString("commands.handler"), event.Nick, channel, respond_to, parts[0][1:], parts[1])
33
+	args := ""
34
+	if len(parts) > 1 {
35
+		args = parts[1]
35 36
 	}
37
+
38
+	cmd := exec.Command(viper.GetString("commands.handler"))
39
+	cmd.Env = append(os.Environ(), fmt.Sprintf("IRCCAT_NICK=%s", event.Nick),
40
+		fmt.Sprintf("IRCCAT_USER=%s", event.User),
41
+		fmt.Sprintf("IRCCAT_HOST=%s", event.Host),
42
+		fmt.Sprintf("IRCCAT_CHANNEL=%s", channel),
43
+		fmt.Sprintf("IRCCAT_RESPOND_TO=%s", respond_to),
44
+		fmt.Sprintf("IRCCAT_COMMAND=%s", parts[0][1:]),
45
+		fmt.Sprintf("IRCCAT_ARGS=%s", args))
46
+
36 47
 	i.runCommand(cmd, respond_to)
37 48
 }
38 49
 
@@ -55,7 +66,13 @@ func (i *IRCCat) runCommand(cmd *exec.Cmd, respond_to string) {
55 66
 
56 67
 	for _, line := range lines[0:line_count] {
57 68
 		if line != "" {
69
+			// 360 bytes is the worst-case maximum size for PRIVMSG lines. Truncate the lines at that length.
70
+			if len(line) > 360 {
71
+				line = line[:360]
72
+			}
58 73
 			i.irc.Privmsg(respond_to, line)
59 74
 		}
75
+		// Pause between lines to avoid being flooded out
76
+		time.Sleep(250)
60 77
 	}
61 78
 }

+ 21
- 13
examples/command_runner.py View File

@@ -1,5 +1,8 @@
1 1
 #!/usr/bin/python
2
-import os, sys, re, subprocess
2
+import os
3
+import sys
4
+import re
5
+import subprocess
3 6
 
4 7
 # If this script is set as your command handler, when any ?command is run in IRC it will
5 8
 # look in the path defined below for a script matching that command name and run it.
@@ -10,28 +13,33 @@ import os, sys, re, subprocess
10 13
 
11 14
 path = '/usr/share/irccat/'
12 15
 
13
-bits = sys.argv[1:]
14
-command = bits[3].lower()
16
+# Example of retrieving all the environment variables.
17
+# We only need command here as all the others will be available in the script's environment.
18
+nick = os.environ.get('IRCCAT_NICK')
19
+user = os.environ.get('IRCCAT_USER')
20
+host = os.environ.get('IRCCAT_HOST')
21
+channel = os.environ.get('IRCCAT_CHANNEL')
22
+respond_to = os.environ.get('IRCCAT_RESPOND_TO')
23
+command = os.environ.get('IRCCAT_COMMAND')
24
+args = os.environ.get('IRCCAT_ARGS')
15 25
 
16 26
 found = False
17 27
 if re.match('^[a-z0-9]+$', command):
18
-    for file in os.listdir(path):
28
+    for filename in os.listdir(path):
19 29
 
20
-        if re.match('^%s\.[a-z]+$' % command, file):
30
+        if re.match('^%s\.[a-z]+$' % command, filename):
21 31
             found = True
22
-            
23
-            procArgs = [path + file]
24
-            procArgs.extend(bits)
25
-            proc = subprocess.Popen(procArgs, stdout=subprocess.PIPE)
32
+
33
+            proc = subprocess.Popen(os.path.join(path, filename), stdout=subprocess.PIPE)
26 34
             stdout = proc.stdout
27 35
 
28 36
             while True:
29 37
                 # We do this to avoid buffering from the subprocess stdout
30
-                print os.read(stdout.fileno(), 65536),
38
+                print(os.read(stdout.fileno(), 65536))
31 39
                 sys.stdout.flush()
32 40
 
33
-                if proc.poll() != None:
41
+                if proc.poll() is not None:
34 42
                     break
35 43
 
36
-if found == False:
37
-    print "Unknown command '%s'" % command
44
+if not found:
45
+    print("Unknown command '%s'" % command)

+ 1
- 1
main.go View File

@@ -30,7 +30,7 @@ type IRCCat struct {
30 30
 }
31 31
 
32 32
 func main() {
33
-	loggo.ConfigureLoggers("<root>=DEBUG")
33
+	loggo.ConfigureLoggers("<root>=INFO")
34 34
 	log.Infof("IRCCat %s (%s) starting...", branch, revision)
35 35
 	viper.SetConfigName("irccat")
36 36
 	viper.AddConfigPath("/etc")

+ 1
- 1
tcplistener/tcplistener.go View File

@@ -29,7 +29,7 @@ func New() (*TCPListener, error) {
29 29
 }
30 30
 
31 31
 func (l *TCPListener) Run(irccon *irc.Connection) {
32
-	log.Infof("Listening for TCP requests on %s", viper.GetString("tcp_listen"))
32
+	log.Infof("Listening for TCP requests on %s", viper.GetString("tcp.listen"))
33 33
 	l.irc = irccon
34 34
 	go l.acceptConnections()
35 35
 }

Loading…
Cancel
Save