Files
ubuntu-based-kiosk/setup_intercom.sh
T
Claude 5efc4a6e91 Fix talkkonnect uninstall in setup_intercom.sh
The uninstall function was only removing old installation paths, causing
talkkonnect to appear as "still installed" after uninstalling.

Fixed both check_talkkonnect_status() and uninstall_talkkonnect():

check_talkkonnect_status():
- Now checks for both old and new installation locations
- Old: ~/go/bin/talkkonnect and ~/talkkonnect.xml
- New: /usr/local/bin/talkkonnect and ~/.config/talkkonnect/
- Checks all locations to accurately determine if installed

uninstall_talkkonnect():
- Removes binaries from BOTH /usr/local/bin and ~/go/bin
- Removes config from BOTH ~/.config/talkkonnect and ~/talkkonnect.xml
- Properly stops and disables service before removing
- Shows progress with descriptive messages
- Optionally removes source directory ~/talkkonnect
- Only performs actions if files/directories actually exist

Now uninstall properly removes everything and status correctly shows
"Not installed" after uninstalling.
2025-11-23 18:28:56 +00:00

1208 lines
40 KiB
Bash
Executable File

#!/bin/bash
################################################################################
### UBK Mumble/Talkkonnect Intercom Setup ###
### Standalone Installation and Management Script ###
################################################################################
#
# This script provides a complete push-to-talk (PTT) intercom solution using:
# - Murmur: The Mumble server (can run on one kiosk)
# - talkkonnect: A headless Mumble client for push-to-talk communication
#
# Use Cases:
# 1. Server + Client (All-in-one): One kiosk acts as both server and client
# 2. Client Only: Connect to an existing Mumble server
# 3. Server Only: Set up a kiosk as the intercom server
#
# Other kiosks or devices can connect using:
# - talkkonnect (Linux)
# - Mumble desktop client (Windows/Mac/Linux)
# - Mumble mobile app (iOS/Android)
#
################################################################################
VERSION="1.0.0"
KIOSK_USER="${KIOSK_USER:-kiosk}"
################################################################################
### HELPER FUNCTIONS
################################################################################
log_error() {
echo "[ERROR] $*" >&2
}
log_success() {
echo "✓ $*"
}
log_warning() {
echo "⚠ $*"
}
pause() {
read -r -p "Press Enter to continue..."
}
get_ip_address() {
hostname -I | awk '{print $1}' || echo "No IP"
}
################################################################################
### STATUS CHECK FUNCTIONS
################################################################################
check_murmur_status() {
local installed=false
local running=false
if systemctl list-unit-files | grep -q "mumble-server.service"; then
installed=true
if systemctl is-active --quiet mumble-server; then
running=true
fi
fi
echo "$installed:$running"
}
check_talkkonnect_status() {
local installed=false
local running=false
# Check multiple possible installation locations
# New installation: /usr/local/bin/talkkonnect and ~/.config/talkkonnect/
# Old installation: ~/go/bin/talkkonnect and ~/talkkonnect.xml
if [[ -f /etc/systemd/system/talkkonnect.service ]] || \
[[ -f /usr/local/bin/talkkonnect ]] || \
[[ -f "/home/$KIOSK_USER/go/bin/talkkonnect" ]] || \
[[ -d "/home/$KIOSK_USER/.config/talkkonnect" ]] || \
[[ -f "/home/$KIOSK_USER/talkkonnect.xml" ]]; then
installed=true
if systemctl is-active --quiet talkkonnect; then
running=true
fi
fi
echo "$installed:$running"
}
################################################################################
### MURMUR SERVER INSTALLATION
################################################################################
install_murmur_server() {
echo
echo "═══════════════════════════════════════════════════════════════"
echo " INSTALLING MURMUR SERVER"
echo "═══════════════════════════════════════════════════════════════"
echo
echo "[1/5] Installing mumble-server package..."
sudo apt update
sudo apt install -y mumble-server
echo "[2/5] Getting configuration details..."
read -r -s -p "SuperUser password: " superuser_pass
echo
read -r -s -p "Server password (clients need this): " server_pass
echo
read -r -p "Welcome text [Welcome to Kiosk Intercom]: " welcome_text
welcome_text="${welcome_text:-Welcome to Kiosk Intercom}"
echo "[3/5] Creating configuration..."
local config_file="/etc/mumble-server.ini"
# Create config if it doesn't exist
if [[ ! -f "$config_file" ]]; then
sudo tee "$config_file" > /dev/null <<'MURMURCONF'
# Murmur configuration file
# Database location
database=/var/lib/mumble-server/mumble-server.sqlite
# Network settings
port=64738
host=0.0.0.0
# Logging
logfile=/var/log/mumble-server/mumble-server.log
# Limits
users=10
bandwidth=72000
# Welcome message
welcometext=Welcome
# Server password
serverpassword=
# Allow pings
allowping=true
# Enable HTML
allowhtml=true
MURMURCONF
log_success "Config file created"
fi
# Update configuration
sudo sed -i "s|^welcometext=.*|welcometext=$welcome_text|" "$config_file"
sudo sed -i "s|^port=.*|port=64738|" "$config_file"
sudo sed -i "s|^users=.*|users=10|" "$config_file"
sudo sed -i "s|^bandwidth=.*|bandwidth=72000|" "$config_file"
if [[ -n "$server_pass" ]]; then
sudo sed -i "s|^serverpassword=.*|serverpassword=$server_pass|" "$config_file"
fi
echo "[4/5] Setting SuperUser password..."
# Stop service before setting password
sudo systemctl stop mumble-server 2>/dev/null || true
sleep 2
# Set SuperUser password
echo "$superuser_pass" | sudo murmurd -ini "$config_file" -supw - 2>/dev/null || {
log_warning "Could not set SuperUser password via murmurd command"
echo "You can set it later with: sudo murmurd -ini $config_file -supw YOUR_PASSWORD"
}
echo "[5/5] Starting service..."
sudo systemctl enable mumble-server
sudo systemctl start mumble-server
# Configure firewall
sudo ufw allow 64738/tcp comment 'Mumble/Murmur' 2>/dev/null || true
sudo ufw allow 64738/udp comment 'Mumble/Murmur' 2>/dev/null || true
sleep 3
local server_ip=$(get_ip_address)
log_success "Murmur server installed"
echo
echo "═══════════════════════════════════════════════════════════════"
echo " Server: $server_ip:64738"
echo " SuperUser: SuperUser / $superuser_pass"
[[ -n "$server_pass" ]] && echo " Password: $server_pass"
echo
echo "Connect with Mumble app:"
echo " Server: $server_ip"
echo " Port: 64738"
[[ -n "$server_pass" ]] && echo " Password: $server_pass"
echo "═══════════════════════════════════════════════════════════════"
pause
}
################################################################################
### TALKKONNECT CLIENT INSTALLATION
################################################################################
# This is the replacement install_talkkonnect_with_config() function
# Copy this into setup_intercom.sh starting at line 197
install_talkkonnect_with_config() {
local server_addr="$1"
local server_port="$2"
local tk_user="$3"
local tk_pass="$4"
local tk_channel="$5"
echo
echo "═══════════════════════════════════════════════════════════════"
echo " INSTALLING TALKKONNECT CLIENT"
echo "═══════════════════════════════════════════════════════════════"
echo
echo "Using proven installation method (same as talkkonnect_complete_install.sh)..."
echo
# Get target user info
local TARGET_USER="$KIOSK_USER"
local TARGET_UID=$(id -u "$TARGET_USER")
local TARGET_HOME="/home/$TARGET_USER"
local CONFIG_DIR="$TARGET_HOME/.config/talkkonnect"
# Verify home directory exists
if [ ! -d "$TARGET_HOME" ]; then
log_error "Home directory does not exist: $TARGET_HOME"
pause
return 1
fi
# --- System Prep ------------------------------------------------------
echo "[1/7] Installing system dependencies..."
sudo apt update
sudo apt install -y wget git build-essential pkg-config \
libasound2-dev libopus-dev libopus0 libopusfile-dev \
libpipewire-0.3-dev libevdev-dev libopenal-dev alsa-utils
# --- Go Installation --------------------------------------------------
echo "[2/7] Installing Go 1.24.1..."
if ! command -v go &>/dev/null || ! go version | grep -q "go1.24"; then
sudo rm -rf /usr/local/go
wget -q https://go.dev/dl/go1.24.1.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.24.1.linux-amd64.tar.gz
rm -f go1.24.1.linux-amd64.tar.gz
sudo ln -sf /usr/local/go/bin/go /usr/bin/go
export PATH="/usr/local/go/bin:$PATH"
log_success "Go 1.24.1 installed"
else
log_success "Go already installed"
fi
# --- Clone TalkKonnect ------------------------------------------------
echo "[3/7] Cloning talkkonnect repository..."
cd ~
if [ -d "talkkonnect" ]; then
rm -rf talkkonnect
fi
git clone https://github.com/talkkonnect/talkkonnect.git
cd talkkonnect
# --- Patch gopus for x86_64 -------------------------------------------
echo "[4/7] Applying x86_64 Opus patch..."
go mod vendor
if [ -d "vendor/github.com/talkkonnect/gopus" ]; then
cat > vendor/github.com/talkkonnect/gopus/opus_nonshared.go << 'EOFOPUS'
// +build amd64,cgo 386,cgo
package gopus
// #cgo pkg-config: opus
// #cgo LDFLAGS: -lm
//
// #include <stdio.h>
// #include <stdlib.h>
// #include <opus.h>
//
// enum {
// gopus_ok = OPUS_OK,
// gopus_bad_arg = OPUS_BAD_ARG,
// gopus_small_buffer = OPUS_BUFFER_TOO_SMALL,
// gopus_internal = OPUS_INTERNAL_ERROR,
// gopus_invalid_packet = OPUS_INVALID_PACKET,
// gopus_unimplemented = OPUS_UNIMPLEMENTED,
// gopus_invalid_state = OPUS_INVALID_STATE,
// gopus_alloc_fail = OPUS_ALLOC_FAIL,
// };
//
// enum {
// gopus_application_voip = OPUS_APPLICATION_VOIP,
// gopus_application_audio = OPUS_APPLICATION_AUDIO,
// gopus_restricted_lowdelay = OPUS_APPLICATION_RESTRICTED_LOWDELAY,
// gopus_bitrate_max = OPUS_BITRATE_MAX,
// };
//
// void gopus_setvbr(OpusEncoder *encoder, int vbr) {
// opus_encoder_ctl(encoder, OPUS_SET_VBR(vbr));
// }
//
// void gopus_setbitrate(OpusEncoder *encoder, int bitrate) {
// opus_encoder_ctl(encoder, OPUS_SET_BITRATE(bitrate));
// }
//
// opus_int32 gopus_bitrate(OpusEncoder *encoder) {
// opus_int32 bitrate;
// opus_encoder_ctl(encoder, OPUS_GET_BITRATE(&bitrate));
// return bitrate;
// }
//
// void gopus_setapplication(OpusEncoder *encoder, int application) {
// opus_encoder_ctl(encoder, OPUS_SET_APPLICATION(application));
// }
//
// opus_int32 gopus_application(OpusEncoder *encoder) {
// opus_int32 application;
// opus_encoder_ctl(encoder, OPUS_GET_APPLICATION(&application));
// return application;
// }
//
// void gopus_encoder_resetstate(OpusEncoder *encoder) {
// opus_encoder_ctl(encoder, OPUS_RESET_STATE);
// }
//
// void gopus_decoder_resetstate(OpusDecoder *decoder) {
// opus_decoder_ctl(decoder, OPUS_RESET_STATE);
// }
import "C"
import (
"errors"
"unsafe"
)
type Application int
const (
Voip Application = C.gopus_application_voip
Audio Application = C.gopus_application_audio
RestrictedLowDelay Application = C.gopus_restricted_lowdelay
)
const (
BitrateMaximum = C.gopus_bitrate_max
)
type Encoder struct {
data []byte
cEncoder *C.struct_OpusEncoder
}
func NewEncoder(sampleRate, channels int, application Application) (*Encoder, error) {
encoder := &Encoder{}
encoder.data = make([]byte, int(C.opus_encoder_get_size(C.int(channels))))
encoder.cEncoder = (*C.struct_OpusEncoder)(unsafe.Pointer(&encoder.data[0]))
ret := C.opus_encoder_init(encoder.cEncoder, C.opus_int32(sampleRate), C.int(channels), C.int(application))
if err := getErr(ret); err != nil {
return nil, err
}
return encoder, nil
}
func (e *Encoder) Encode(pcm []int16, frameSize, maxDataBytes int) ([]byte, error) {
pcmPtr := (*C.opus_int16)(unsafe.Pointer(&pcm[0]))
data := make([]byte, maxDataBytes)
dataPtr := (*C.uchar)(unsafe.Pointer(&data[0]))
encodedC := C.opus_encode(e.cEncoder, pcmPtr, C.int(frameSize), dataPtr, C.opus_int32(len(data)))
encoded := int(encodedC)
if encoded < 0 {
return nil, getErr(C.int(encodedC))
}
return data[0:encoded], nil
}
func (e *Encoder) SetVbr(vbr bool) {
var cVbr C.int
if vbr {
cVbr = 1
} else {
cVbr = 0
}
C.gopus_setvbr(e.cEncoder, cVbr)
}
func (e *Encoder) SetBitrate(bitrate int) {
C.gopus_setbitrate(e.cEncoder, C.int(bitrate))
}
func (e *Encoder) Bitrate() int {
return int(C.gopus_bitrate(e.cEncoder))
}
func (e *Encoder) SetApplication(application Application) {
C.gopus_setapplication(e.cEncoder, C.int(application))
}
func (e *Encoder) Application() Application {
return Application(C.gopus_application(e.cEncoder))
}
func (e *Encoder) ResetState() {
C.gopus_encoder_resetstate(e.cEncoder)
}
type Decoder struct {
data []byte
cDecoder *C.struct_OpusDecoder
channels int
}
func NewDecoder(sampleRate, channels int) (*Decoder, error) {
decoder := &Decoder{}
decoder.data = make([]byte, int(C.opus_decoder_get_size(C.int(channels))))
decoder.cDecoder = (*C.struct_OpusDecoder)(unsafe.Pointer(&decoder.data[0]))
ret := C.opus_decoder_init(decoder.cDecoder, C.opus_int32(sampleRate), C.int(channels))
if err := getErr(ret); err != nil {
return nil, err
}
decoder.channels = channels
return decoder, nil
}
func (d *Decoder) Decode(data []byte, frameSize int, fec bool) ([]int16, error) {
var dataPtr *C.uchar
if len(data) > 0 {
dataPtr = (*C.uchar)(unsafe.Pointer(&data[0]))
}
dataLen := C.opus_int32(len(data))
output := make([]int16, d.channels*frameSize)
outputPtr := (*C.opus_int16)(unsafe.Pointer(&output[0]))
var cFec C.int
if fec {
cFec = 1
} else {
cFec = 0
}
cRet := C.opus_decode(d.cDecoder, dataPtr, dataLen, outputPtr, C.int(frameSize), cFec)
ret := int(cRet)
if ret < 0 {
return nil, getErr(cRet)
}
return output[:ret*d.channels], nil
}
func (d *Decoder) ResetState() {
C.gopus_decoder_resetstate(d.cDecoder)
}
func GetSamplesPerFrame(data []byte, samplingRate int) (int, error) {
dataPtr := (*C.uchar)(unsafe.Pointer(&data[0]))
cSamplingRate := C.opus_int32(samplingRate)
cRet := C.opus_packet_get_samples_per_frame(dataPtr, cSamplingRate)
return int(cRet), nil
}
func CountFrames(data []byte) (int, error) {
dataPtr := (*C.uchar)(unsafe.Pointer(&data[0]))
cLen := C.opus_int32(len(data))
cRet := C.opus_packet_get_nb_frames(dataPtr, cLen)
if err := getErr(cRet); err != nil {
return 0, err
}
return int(cRet), nil
}
var (
ErrBadArgument = errors.New("bad argument")
ErrSmallBuffer = errors.New("buffer is too small")
ErrInternal = errors.New("internal error")
ErrInvalidPacket = errors.New("invalid packet")
ErrUnimplemented = errors.New("unimplemented")
ErrInvalidState = errors.New("invalid state")
ErrAllocFail = errors.New("allocation failed")
ErrUnknown = errors.New("unknown error")
)
func getErr(code C.int) error {
switch code {
case C.gopus_ok:
return nil
case C.gopus_bad_arg:
return ErrBadArgument
case C.gopus_small_buffer:
return ErrSmallBuffer
case C.gopus_internal:
return ErrInternal
case C.gopus_invalid_packet:
return ErrInvalidPacket
case C.gopus_unimplemented:
return ErrUnimplemented
case C.gopus_invalid_state:
return ErrInvalidState
case C.gopus_alloc_fail:
return ErrAllocFail
default:
return ErrUnknown
}
}
EOFOPUS
log_success "Opus patch applied"
fi
# --- Build TalkKonnect ------------------------------------------------
echo "[5/7] Building talkkonnect (this may take a few minutes)..."
cd ~/talkkonnect/cmd/talkkonnect
export CGO_ENABLED=1
export CGO_CFLAGS="$(pkg-config --cflags opus)"
export CGO_LDFLAGS="$(pkg-config --libs opus) -lm"
go build -mod=vendor -v -o ~/talkkonnect-binary . 2>&1 | tail -20
if [ ! -f ~/talkkonnect-binary ]; then
log_error "Build failed!"
pause
return 1
fi
# Stop any running instances
if systemctl is-active --quiet talkkonnect 2>/dev/null; then
sudo systemctl stop talkkonnect
fi
if pgrep -x talkkonnect > /dev/null; then
sudo pkill -9 talkkonnect
sleep 1
fi
# Install binary
sudo cp ~/talkkonnect-binary /usr/local/bin/talkkonnect
sudo chmod +x /usr/local/bin/talkkonnect
rm ~/talkkonnect-binary
log_success "Binary installed to /usr/local/bin/talkkonnect"
# --- User Permissions -------------------------------------------------
echo "[6/7] Setting up permissions..."
if ! groups "$TARGET_USER" | grep -q input; then
sudo usermod -a -G input "$TARGET_USER"
log_success "Added $TARGET_USER to 'input' group"
fi
if ! groups "$TARGET_USER" | grep -q audio; then
sudo usermod -a -G audio "$TARGET_USER"
log_success "Added $TARGET_USER to 'audio' group"
fi
# --- Configuration ----------------------------------------------------
echo "[7/7] Creating configuration..."
# Create config directory as target user
if [ "$TARGET_USER" != "$USER" ]; then
sudo -u "$TARGET_USER" mkdir -p "$CONFIG_DIR"
else
mkdir -p "$CONFIG_DIR"
fi
# Create config file with provided settings
sudo tee "$CONFIG_DIR/talkkonnect.xml" > /dev/null <<EOFXML
<?xml version="1.0" encoding="UTF-8"?>
<document type="talkkonnect/xml">
<global>
<software>
<settings outputdevice="default"
logfilenameandpath="$CONFIG_DIR/talkkonnect.log"
logging="both"
daemonize="false"
cancelconnect="false"
simplexwithvox="false"
nextserverindex="0"/>
<autoprovisioning enabled="false"/>
</software>
<hardware>
<settings targetboard="pc" voiceactivitytimersecs="200"/>
<io>
<pins enabled="false"/>
</io>
</hardware>
</global>
<accounts>
<account name="default" default="true">
<serverandport>$server_addr:$server_port</serverandport>
<username>$tk_user</username>
<password>$tk_pass</password>
<insecure>true</insecure>
<register>false</register>
<certificate></certificate>
<channel>$tk_channel</channel>
<ident></ident>
<tokens enabled="false"></tokens>
<voicetargets enabled="false">
<id id="1" iscurrent="false" name="default">
<channels></channels>
<users></users>
</id>
</voicetargets>
</account>
</accounts>
<beacon enabled="false"/>
<audio>
<input>
<settings enabled="true" device="default" samplerate="48000"
channels="1" codec="opus" framespersecond="50"/>
</input>
<output>
<settings enabled="true" device="default" samplerate="48000" channels="1"/>
</output>
</audio>
<ptt enabled="false">
<usbkeyboard enabled="false"/>
</ptt>
<voiceactivity enabled="true">
<settings threshold="0.3" holdtimems="1000" holdtimeoutms="2000"/>
</voiceactivity>
<sounds enabled="false"/>
<txtts enabled="false"/>
<smtp enabled="false"/>
<api enabled="false"/>
<printxml enabled="false"/>
</document>
EOFXML
# Set ownership
sudo chown -R "$TARGET_USER:$TARGET_USER" "$CONFIG_DIR"
sudo chmod 755 "$CONFIG_DIR"
sudo chmod 644 "$CONFIG_DIR/talkkonnect.xml"
# Create systemd service
sudo tee /etc/systemd/system/talkkonnect.service > /dev/null <<EOFSVC
[Unit]
Description=TalkKonnect Headless Mumble Transceiver
After=network-online.target sound.target
Wants=network-online.target
[Service]
Type=simple
User=$TARGET_USER
Group=$TARGET_USER
WorkingDirectory=$TARGET_HOME
ExecStart=/usr/local/bin/talkkonnect -config $CONFIG_DIR/talkkonnect.xml
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment="XDG_RUNTIME_DIR=/run/user/$TARGET_UID"
[Install]
WantedBy=multi-user.target
EOFSVC
sudo systemctl daemon-reload
sudo systemctl enable talkkonnect
sudo systemctl start talkkonnect
sleep 3
log_success "talkkonnect installed successfully!"
echo "═══════════════════════════════════════════════════════════════"
echo " Server: $server_addr:$server_port"
echo " Username: $tk_user"
echo " Channel: $tk_channel"
echo " Config: $CONFIG_DIR/talkkonnect.xml"
echo " Binary: /usr/local/bin/talkkonnect"
echo "═══════════════════════════════════════════════════════════════"
echo
# Show status
if systemctl is-active --quiet talkkonnect; then
log_success "Service is running"
echo "View logs: sudo journalctl -u talkkonnect -f"
else
log_warning "Service may have issues"
echo "Check logs: sudo journalctl -u talkkonnect -n 50"
fi
pause
}
install_talkkonnect_only() {
echo
echo "═══════════════════════════════════════════════════════════════"
echo " TALKKONNECT - CONNECT TO EXISTING SERVER"
echo "═══════════════════════════════════════════════════════════════"
echo
echo "Enter Murmur/Mumble server details:"
read -r -p "Server address (IP or domain): " server_addr
read -r -p "Port [64738]: " server_port
server_port="${server_port:-64738}"
read -r -p "Username: " tk_user
read -r -s -p "Password: " tk_pass
echo
read -r -p "Channel [Root]: " tk_channel
tk_channel="${tk_channel:-Root}"
install_talkkonnect_with_config "$server_addr" "$server_port" "$tk_user" "$tk_pass" "$tk_channel"
}
install_murmur_and_talkkonnect() {
echo
echo "═══════════════════════════════════════════════════════════════"
echo " ALL-IN-ONE: SERVER + CLIENT"
echo "═══════════════════════════════════════════════════════════════"
echo
echo "Installing Murmur server..."
install_murmur_server
echo
echo "Now installing talkkonnect client..."
echo "Configuring to connect to local server..."
# Auto-configure for local server
AUTO_SERVER="127.0.0.1"
AUTO_PORT="64738"
read -r -p "Username for talkkonnect [kiosk]: " tk_user
tk_user="${tk_user:-kiosk}"
read -r -s -p "Server password: " tk_pass
echo
install_talkkonnect_with_config "$AUTO_SERVER" "$AUTO_PORT" "$tk_user" "$tk_pass" "Root"
}
################################################################################
### SERVICE MANAGEMENT
################################################################################
toggle_murmur_service() {
echo
if systemctl is-active --quiet mumble-server; then
echo "Stopping Murmur server..."
sudo systemctl stop mumble-server
log_success "Murmur stopped"
else
echo "Starting Murmur server..."
sudo systemctl start mumble-server
sleep 2
if systemctl is-active --quiet mumble-server; then
log_success "Murmur started"
else
log_error "Failed to start - check logs: sudo journalctl -u mumble-server"
fi
fi
pause
}
toggle_talkkonnect_service() {
echo
if systemctl is-active --quiet talkkonnect; then
echo "Stopping talkkonnect..."
sudo systemctl stop talkkonnect
log_success "talkkonnect stopped"
else
echo "Starting talkkonnect..."
sudo systemctl start talkkonnect
sleep 2
if systemctl is-active --quiet talkkonnect; then
log_success "talkkonnect started"
else
log_error "Failed to start - check logs: sudo journalctl -u talkkonnect"
fi
fi
pause
}
################################################################################
### RECONFIGURATION
################################################################################
reconfigure_murmur() {
echo
echo "Reconfigure Murmur Server:"
echo " 1. Change welcome text"
echo " 2. Change server password"
echo " 3. Change SuperUser password"
echo " 4. Change port"
echo " 0. Cancel"
read -r -p "Choose: " reconfig_choice
local config_file="/etc/mumble-server.ini"
case "$reconfig_choice" in
1)
read -r -p "New welcome text: " new_welcome
sudo sed -i "s|^welcometext=.*|welcometext=$new_welcome|" "$config_file"
sudo systemctl restart mumble-server
log_success "Welcome text updated"
;;
2)
read -r -s -p "New server password (blank=none): " new_pass
echo
sudo sed -i "s|^serverpassword=.*|serverpassword=$new_pass|" "$config_file"
sudo systemctl restart mumble-server
log_success "Server password updated"
;;
3)
read -r -s -p "New SuperUser password: " su_pass
echo
sudo systemctl stop mumble-server
echo "$su_pass" | sudo murmurd -ini "$config_file" -supw - 2>/dev/null
sudo systemctl start mumble-server
log_success "SuperUser password updated"
;;
4)
read -r -p "New port [64738]: " new_port
new_port="${new_port:-64738}"
sudo sed -i "s|^port=.*|port=$new_port|" "$config_file"
sudo systemctl restart mumble-server
log_success "Port updated to $new_port"
;;
esac
pause
}
reconfigure_talkkonnect() {
echo
echo "Reconfigure talkkonnect:"
echo " 1. Change server"
echo " 2. Change credentials"
echo " 3. Change channel"
echo " 0. Cancel"
read -r -p "Choose: " reconfig_choice
case "$reconfig_choice" in
1)
read -r -p "Server address: " new_server
read -r -p "Port [64738]: " new_port
new_port="${new_port:-64738}"
sudo -u "$KIOSK_USER" sed -i "s|<server>.*</server>|<server>$new_server</server>|" /home/$KIOSK_USER/talkkonnect.xml
sudo -u "$KIOSK_USER" sed -i "s|<port>.*</port>|<port>$new_port</port>|" /home/$KIOSK_USER/talkkonnect.xml
sudo systemctl restart talkkonnect
log_success "Server updated"
;;
2)
read -r -p "Username: " new_user
read -r -s -p "Password: " new_pass
echo
sudo -u "$KIOSK_USER" sed -i "s|<username>.*</username>|<username>$new_user</username>|" /home/$KIOSK_USER/talkkonnect.xml
sudo -u "$KIOSK_USER" sed -i "s|<password>.*</password>|<password>$new_pass</password>|" /home/$KIOSK_USER/talkkonnect.xml
sudo systemctl restart talkkonnect
log_success "Credentials updated"
;;
3)
read -r -p "Channel: " new_channel
sudo -u "$KIOSK_USER" sed -i "s|<channel>.*</channel>|<channel>$new_channel</channel>|" /home/$KIOSK_USER/talkkonnect.xml
sudo systemctl restart talkkonnect
log_success "Channel updated"
;;
esac
pause
}
################################################################################
### LOGS AND DIAGNOSTICS
################################################################################
view_talkkonnect_logs() {
echo
echo "Recent talkkonnect logs:"
echo "═══════════════════════════════════════════════════════════════"
sudo journalctl -u talkkonnect -n 50 --no-pager
echo
pause
}
view_murmur_logs() {
echo
echo "Recent Murmur server logs:"
echo "═══════════════════════════════════════════════════════════════"
sudo journalctl -u mumble-server -n 50 --no-pager
echo
pause
}
################################################################################
### UNINSTALLATION
################################################################################
uninstall_murmur() {
echo
read -r -p "Uninstall Murmur server? (yes/no): " confirm
[[ "$confirm" != "yes" ]] && return
echo "Uninstalling..."
sudo systemctl stop mumble-server 2>/dev/null || true
sudo systemctl disable mumble-server 2>/dev/null || true
sudo apt remove -y mumble-server 2>/dev/null || true
read -r -p "Remove configuration and database? (y/n): " remove_data
if [[ "$remove_data" =~ ^[Yy]$ ]]; then
sudo rm -rf /var/lib/mumble-server
sudo rm -f /etc/mumble-server.ini
log_success "Murmur and data removed"
else
log_success "Murmur removed (data preserved)"
fi
pause
}
uninstall_talkkonnect() {
echo
read -r -p "Uninstall talkkonnect? (yes/no): " confirm
[[ "$confirm" != "yes" ]] && return
echo "Uninstalling talkkonnect..."
# Stop and disable service
if systemctl is-active --quiet talkkonnect 2>/dev/null; then
echo "[+] Stopping talkkonnect service..."
sudo systemctl stop talkkonnect
fi
if systemctl is-enabled --quiet talkkonnect 2>/dev/null; then
echo "[+] Disabling talkkonnect service..."
sudo systemctl disable talkkonnect
fi
# Remove systemd service file
if [[ -f /etc/systemd/system/talkkonnect.service ]]; then
echo "[+] Removing service file..."
sudo rm -f /etc/systemd/system/talkkonnect.service
sudo systemctl daemon-reload
fi
# Remove binaries (both old and new locations)
if [[ -f /usr/local/bin/talkkonnect ]]; then
echo "[+] Removing binary from /usr/local/bin..."
sudo rm -f /usr/local/bin/talkkonnect
fi
if [[ -f "/home/$KIOSK_USER/go/bin/talkkonnect" ]]; then
echo "[+] Removing binary from ~/go/bin..."
sudo rm -f "/home/$KIOSK_USER/go/bin/talkkonnect"
fi
# Remove config files (both old and new locations)
if [[ -d "/home/$KIOSK_USER/.config/talkkonnect" ]]; then
echo "[+] Removing config directory ~/.config/talkkonnect..."
sudo rm -rf "/home/$KIOSK_USER/.config/talkkonnect"
fi
if [[ -f "/home/$KIOSK_USER/talkkonnect.xml" ]]; then
echo "[+] Removing old config file ~/talkkonnect.xml..."
sudo rm -f "/home/$KIOSK_USER/talkkonnect.xml"
fi
# Remove source directory if it exists
read -r -p "Also remove source directory ~/talkkonnect? (y/n): " remove_source
if [[ "$remove_source" =~ ^[Yy]$ ]] && [[ -d "/home/$KIOSK_USER/talkkonnect" ]]; then
echo "[+] Removing source directory..."
sudo rm -rf "/home/$KIOSK_USER/talkkonnect"
fi
log_success "talkkonnect uninstalled"
pause
}
################################################################################
### MAIN MENU
################################################################################
show_status() {
local murmur_status=$(check_murmur_status)
local murmur_installed=$(echo "$murmur_status" | cut -d: -f1)
local murmur_running=$(echo "$murmur_status" | cut -d: -f2)
local tk_status=$(check_talkkonnect_status)
local tk_installed=$(echo "$tk_status" | cut -d: -f1)
local tk_running=$(echo "$tk_status" | cut -d: -f2)
echo
echo "═══════════════════════════════════════════════════════════════"
echo " INTERCOM STATUS"
echo "═══════════════════════════════════════════════════════════════"
echo
# Murmur status
if [[ "$murmur_installed" == "true" ]]; then
echo "Murmur Server: ✓ Installed"
if [[ "$murmur_running" == "true" ]]; then
echo " Status: Running"
local server_ip=$(get_ip_address)
echo " Address: $server_ip:64738"
else
echo " Status: Stopped"
fi
echo
else
echo "Murmur Server: Not installed"
echo
fi
# talkkonnect status
if [[ "$tk_installed" == "true" ]]; then
echo "talkkonnect Client: ✓ Installed"
if [[ "$tk_running" == "true" ]]; then
echo " Status: Running"
if [[ -f /home/$KIOSK_USER/talkkonnect.xml ]]; then
local server=$(grep "serveraddress" /home/$KIOSK_USER/talkkonnect.xml 2>/dev/null | sed 's/.*<server>\(.*\)<\/server>/\1/' || echo "Unknown")
echo " Server: $server"
fi
else
echo " Status: Stopped"
fi
echo
else
echo "talkkonnect Client: Not installed"
echo
fi
}
main_menu() {
while true; do
clear
echo "═══════════════════════════════════════════════════════════════"
echo " UBK INTERCOM SETUP v${VERSION}"
echo " Mumble/Talkkonnect Push-to-Talk System"
echo "═══════════════════════════════════════════════════════════════"
show_status
local murmur_status=$(check_murmur_status)
local murmur_installed=$(echo "$murmur_status" | cut -d: -f1)
local murmur_running=$(echo "$murmur_status" | cut -d: -f2)
local tk_status=$(check_talkkonnect_status)
local tk_installed=$(echo "$tk_status" | cut -d: -f1)
local tk_running=$(echo "$tk_status" | cut -d: -f2)
echo "═══════════════════════════════════════════════════════════════"
echo " INSTALLATION OPTIONS"
echo "═══════════════════════════════════════════════════════════════"
local menu_num=1
# Installation options (shown when nothing installed)
if [[ "$murmur_installed" == "false" && "$tk_installed" == "false" ]]; then
echo " $menu_num. Install All-in-One (Server + Client)"
local opt_all_in_one=$menu_num
((menu_num++))
echo " $menu_num. Install Murmur Server Only"
local opt_server_only=$menu_num
((menu_num++))
echo " $menu_num. Install talkkonnect Client Only"
local opt_client_only=$menu_num
((menu_num++))
else
# Murmur management options
if [[ "$murmur_installed" == "true" ]]; then
echo
echo "Murmur Server:"
if [[ "$murmur_running" == "true" ]]; then
echo " $menu_num. Stop Murmur"
else
echo " $menu_num. Start Murmur"
fi
local opt_murmur_toggle=$menu_num
((menu_num++))
echo " $menu_num. Reconfigure Murmur"
local opt_murmur_reconfig=$menu_num
((menu_num++))
echo " $menu_num. View Murmur Logs"
local opt_murmur_logs=$menu_num
((menu_num++))
echo " $menu_num. Uninstall Murmur"
local opt_murmur_uninstall=$menu_num
((menu_num++))
else
echo
echo " $menu_num. Install Murmur Server"
local opt_install_murmur=$menu_num
((menu_num++))
fi
# talkkonnect management options
if [[ "$tk_installed" == "true" ]]; then
echo
echo "talkkonnect Client:"
if [[ "$tk_running" == "true" ]]; then
echo " $menu_num. Stop talkkonnect"
else
echo " $menu_num. Start talkkonnect"
fi
local opt_tk_toggle=$menu_num
((menu_num++))
echo " $menu_num. Reconfigure talkkonnect"
local opt_tk_reconfig=$menu_num
((menu_num++))
echo " $menu_num. View talkkonnect Logs"
local opt_tk_logs=$menu_num
((menu_num++))
echo " $menu_num. Uninstall talkkonnect"
local opt_tk_uninstall=$menu_num
((menu_num++))
else
echo
echo " $menu_num. Install talkkonnect Client"
local opt_install_tk=$menu_num
((menu_num++))
fi
fi
echo
echo "═══════════════════════════════════════════════════════════════"
echo " 0. Exit"
echo "═══════════════════════════════════════════════════════════════"
echo
read -r -p "Choose [0-$((menu_num-1))]: " choice
# Handle menu selection
case "$choice" in
0)
echo "Exiting..."
exit 0
;;
${opt_all_in_one:-})
install_murmur_and_talkkonnect
;;
${opt_server_only:-})
install_murmur_server
;;
${opt_client_only:-})
install_talkkonnect_only
;;
${opt_install_murmur:-})
install_murmur_server
;;
${opt_install_tk:-})
install_talkkonnect_only
;;
${opt_murmur_toggle:-})
toggle_murmur_service
;;
${opt_murmur_reconfig:-})
reconfigure_murmur
;;
${opt_murmur_logs:-})
view_murmur_logs
;;
${opt_murmur_uninstall:-})
uninstall_murmur
;;
${opt_tk_toggle:-})
toggle_talkkonnect_service
;;
${opt_tk_reconfig:-})
reconfigure_talkkonnect
;;
${opt_tk_logs:-})
view_talkkonnect_logs
;;
${opt_tk_uninstall:-})
uninstall_talkkonnect
;;
*)
echo "Invalid choice"
sleep 1
;;
esac
done
}
################################################################################
### ENTRY POINT
################################################################################
# Check if running as root
if [[ $EUID -eq 0 ]]; then
log_error "This script should not be run as root"
echo "Please run as: ./setup_intercom.sh"
exit 1
fi
# Check if kiosk user exists
if ! id "$KIOSK_USER" &>/dev/null; then
log_warning "User '$KIOSK_USER' does not exist"
read -r -p "Enter the username to use for installation: " KIOSK_USER
if ! id "$KIOSK_USER" &>/dev/null; then
log_error "User '$KIOSK_USER' not found"
exit 1
fi
fi
# Run main menu
main_menu