mirror of
https://github.com/la5nta/pat
synced 2026-08-13 17:46:54 -04:00
This eliminates the need for Linux's AX25 stack when using Direwolf or AGWPE TNCs. It makes AGWPE the default AX.25 engine if the build does not include Linux AX.25 support. Direwolf >= v1.6 is recommended (< v1.2 is unsupported). Closes #367
173 lines
3.4 KiB
Go
173 lines
3.4 KiB
Go
// Copyright 2016 Martin Hebnes Pedersen (LA5NTA). All rights reserved.
|
|
// Use of this source code is governed by the MIT-license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/la5nta/wl2k-go/transport/ax25"
|
|
"github.com/peterh/liner"
|
|
)
|
|
|
|
func Interactive(ctx context.Context) {
|
|
line := liner.NewLiner()
|
|
defer line.Close()
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
defer close(done)
|
|
for {
|
|
str, _ := line.Prompt(getPrompt())
|
|
if str == "" {
|
|
continue
|
|
}
|
|
line.AppendHistory(str)
|
|
|
|
if str[0] == '#' {
|
|
continue
|
|
}
|
|
|
|
if quit := execCmd(str); quit {
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
select {
|
|
case <-ctx.Done():
|
|
case <-done:
|
|
}
|
|
}
|
|
|
|
func execCmd(line string) (quit bool) {
|
|
cmd, param := parseCommand(line)
|
|
switch cmd {
|
|
case "connect":
|
|
if param == "" {
|
|
printInteractiveUsage()
|
|
return
|
|
}
|
|
|
|
Connect(param)
|
|
case "listen":
|
|
Listen(param)
|
|
case "unlisten":
|
|
Unlisten(param)
|
|
case "heard":
|
|
PrintHeard()
|
|
case "freq":
|
|
freq(param)
|
|
case "qtc":
|
|
PrintQTC()
|
|
case "debug":
|
|
os.Setenv("ardop_debug", "1")
|
|
fmt.Println("Number of goroutines:", runtime.NumGoroutine())
|
|
case "q", "quit":
|
|
return true
|
|
case "":
|
|
return
|
|
default:
|
|
printInteractiveUsage()
|
|
}
|
|
return
|
|
}
|
|
|
|
func printInteractiveUsage() {
|
|
fmt.Println("Uri examples: 'LA3F@5350', 'LA1B-10 v LA5NTA-1', 'LA5NTA:secret@192.168.1.1:54321'")
|
|
|
|
methods := []string{
|
|
MethodArdop,
|
|
MethodAX25, MethodAX25AGWPE, MethodAX25Linux, MethodAX25SerialTNC,
|
|
MethodPactor,
|
|
MethodTelnet,
|
|
MethodVaraHF,
|
|
MethodVaraFM,
|
|
}
|
|
fmt.Println("Methods:", strings.Join(methods, ", "))
|
|
|
|
cmds := []string{
|
|
"connect METHOD:[URI] or alias Connect to a remote station.",
|
|
"listen METHOD Listen for incoming connections.",
|
|
"unlisten METHOD Unregister listener for incoming connections.",
|
|
"freq METHOD:FREQ Change rig frequency.",
|
|
"heard Display all stations heard over the air.",
|
|
"qtc Print pending outbound messages.",
|
|
}
|
|
fmt.Println("Commands: ")
|
|
for _, cmd := range cmds {
|
|
fmt.Printf(" %s\n", cmd)
|
|
}
|
|
}
|
|
|
|
func getPrompt() string {
|
|
var buf bytes.Buffer
|
|
|
|
status := getStatus()
|
|
|
|
if len(status.ActiveListeners) > 0 {
|
|
fmt.Fprintf(&buf, "L%v", status.ActiveListeners)
|
|
}
|
|
|
|
fmt.Fprint(&buf, "> ")
|
|
return buf.String()
|
|
}
|
|
|
|
func PrintHeard() {
|
|
pf := func(call string, t time.Time) {
|
|
fmt.Printf(" %-10s (%s)\n", call, t.Format(time.RFC1123))
|
|
}
|
|
|
|
fmt.Println("ardop:")
|
|
if adTNC == nil {
|
|
fmt.Println(" (not initialized)")
|
|
} else if heard := adTNC.Heard(); len(heard) == 0 {
|
|
fmt.Println(" (none)")
|
|
} else {
|
|
for call, t := range heard {
|
|
pf(call, t)
|
|
}
|
|
}
|
|
|
|
fmt.Println("ax25+linux:")
|
|
if heard, err := ax25.Heard(config.AX25Linux.Port); err != nil {
|
|
fmt.Printf(" (%s)\n", err)
|
|
} else if len(heard) == 0 {
|
|
fmt.Println(" (none)")
|
|
} else {
|
|
for call, t := range heard {
|
|
pf(call, t)
|
|
}
|
|
}
|
|
}
|
|
|
|
func PrintQTC() {
|
|
msgs, err := mbox.Outbox()
|
|
if err != nil {
|
|
log.Println(err)
|
|
return
|
|
}
|
|
fmt.Printf("QTC: %d.\n", len(msgs))
|
|
for _, msg := range msgs {
|
|
fmt.Printf(`%-12.12s (%s): %s`, msg.MID(), msg.Subject(), fmt.Sprint(msg.To()))
|
|
if msg.Header.Get("X-P2POnly") == "true" {
|
|
fmt.Printf(" (P2P only)")
|
|
}
|
|
fmt.Println("")
|
|
}
|
|
}
|
|
|
|
func parseCommand(str string) (mode, param string) {
|
|
parts := strings.SplitN(str, " ", 2)
|
|
if len(parts) == 1 {
|
|
return parts[0], ""
|
|
}
|
|
return parts[0], parts[1]
|
|
}
|