QuecManager non-beta

Its about time I did this!
This commit is contained in:
Cameron Thompson
2025-04-02 23:09:08 -04:00
parent c4a340bd36
commit c42907e346
482 changed files with 47267 additions and 109914 deletions

View File

@@ -0,0 +1,95 @@
#!/bin/sh
# Location: /www/cgi-bin/quecmanager/profiles/check_status.cgi
# Set content type to JSON
echo "Content-type: application/json"
echo ""
# Configuration
STATUS_FILE="/tmp/quecprofiles_status.json"
TRACK_FILE="/tmp/quecprofiles_active"
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t quecprofiles -p "daemon.$level" "status_check: $1"
}
# Function to output default "idle" JSON
output_idle_json() {
cat <<EOF
{
"status": "idle",
"message": "No active profile operations",
"profile": "unknown",
"progress": 0,
"timestamp": $(date +%s)
}
EOF
exit 0
}
# Check if status file exists
if [ -f "$STATUS_FILE" ]; then
# Check if file is not empty
if [ -s "$STATUS_FILE" ]; then
# Cat the entire file content (more reliable than grep)
status_content=$(cat "$STATUS_FILE")
# Log content for debugging
log_message "Status file content: $status_content" "debug"
# Check if it looks like valid JSON
if echo "$status_content" | grep -q "status"; then
# Output the status file content
cat "$STATUS_FILE"
# Extract status for logging only
status=$(echo "$status_content" | sed -n 's/.*"status":"\([^"]*\)".*/\1/p')
log_message "Status from file: $status" "info"
exit 0
else
log_message "Status file exists but not valid JSON" "warn"
fi
else
log_message "Status file exists but empty" "warn"
fi
fi
# If we get here, either no file exists or it's invalid/old
# Check if track file exists (as a fallback)
if [ -f "$TRACK_FILE" ]; then
status_info=$(cat "$TRACK_FILE")
status=$(echo "$status_info" | cut -d':' -f1)
profile=$(echo "$status_info" | cut -d':' -f2)
progress=$(echo "$status_info" | cut -d':' -f3)
# Make sure the message reflects the actual status
if [ "$status" = "success" ]; then
message="Profile successfully applied"
elif [ "$status" = "applying" ]; then
message="Profile operation in progress"
elif [ "$status" = "error" ]; then
message="Profile operation failed"
elif [ "$status" = "rebooting" ]; then
message="Device is rebooting to apply changes"
else
message="Profile operation status: $status"
fi
# Output JSON based on track file
cat <<EOF
{
"status": "$status",
"message": "$message",
"profile": "$profile",
"progress": $progress,
"timestamp": $(date +%s)
}
EOF
log_message "Retrieved status from track file: $status" "info"
exit 0
fi
# If no valid files found, output idle state
output_idle_json

View File

@@ -0,0 +1,157 @@
#!/bin/sh
# Location: /www/cgi-bin/quecmanager/profiles/list_profiles.sh
# Set content type to JSON and ensure blank line is output
echo "Content-type: application/json"
echo ""
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t quecprofiles -p "daemon.$level" "list_profiles: $1"
# Also log to our error file
echo "[$(date)] $level: $1" >>/tmp/list_profiles_error.log
}
# Function to output JSON error response
output_error() {
local message="$1"
echo "{\"status\":\"error\",\"message\":\"$message\",\"profiles\":[]}"
log_message "$message" "error"
exit 1
}
# Function to sanitize string for JSON
sanitize_for_json() {
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | sed 's/\t/\\t/g' | tr -d '\r\n'
}
# Check if UCI command exists
if ! which uci >/dev/null 2>&1; then
output_error "UCI command not found"
fi
# Function to extract profiles from UCI config
get_profiles() {
log_message "Fetching profiles from UCI config"
# Check if UCI config exists
if [ ! -f /etc/config/quecprofiles ]; then
log_message "No profiles config found" "warn"
echo "{\"status\":\"success\",\"profiles\":[]}"
return 0
fi
# Start JSON output
local json_output=""
local first=1
local count=0
# Get all profile indices - make sure this succeeds
local indices=$(uci -q show quecprofiles | grep -o '@profile\[[0-9]*\]' | sort -u)
# Debug output
echo "Found indices: $indices" >>/tmp/list_profiles_error.log
if [ -z "$indices" ]; then
log_message "No profile indices found" "warn"
echo "{\"status\":\"success\",\"profiles\":[]}"
return 0
fi
# Process each profile
for idx in $indices; do
log_message "Processing profile index: $idx"
# Try different UCI get approaches
local name
name=$(uci -q get "quecprofiles.$idx.name" 2>/dev/null)
if [ -z "$name" ]; then
log_message "Failed to get name for $idx, trying alternative method" "warn"
local section=${idx#@profile[}
section=${section%]}
name=$(uci -q get "quecprofiles.@profile[$section].name" 2>/dev/null)
fi
# Get profile details
local iccid=$(uci -q get "quecprofiles.$idx.iccid" 2>/dev/null)
local imei=$(uci -q get "quecprofiles.$idx.imei" 2>/dev/null)
local apn=$(uci -q get "quecprofiles.$idx.apn" 2>/dev/null)
local pdp_type=$(uci -q get "quecprofiles.$idx.pdp_type" 2>/dev/null)
local lte_bands=$(uci -q get "quecprofiles.$idx.lte_bands" 2>/dev/null)
local sa_nr5g_bands=$(uci -q get "quecprofiles.$idx.sa_nr5g_bands" 2>/dev/null)
local nsa_nr5g_bands=$(uci -q get "quecprofiles.$idx.nsa_nr5g_bands" 2>/dev/null)
local network_type=$(uci -q get "quecprofiles.$idx.network_type" 2>/dev/null)
local ttl=$(uci -q get "quecprofiles.$idx.ttl" 2>/dev/null)
local paused=$(uci -q get "quecprofiles.$idx.paused" 2>/dev/null)
# Debug output
log_message "Retrieved for $idx: name=$name, iccid=$iccid, apn=$apn, paused=$paused"
# Skip if missing required fields
if [ -z "$name" ] || [ -z "$iccid" ] || [ -z "$apn" ]; then
log_message "Skipping invalid profile: $idx (missing required fields)" "warn"
continue
fi
# Sanitize all values to ensure valid JSON
name=$(sanitize_for_json "$name")
iccid=$(sanitize_for_json "$iccid")
imei=$(sanitize_for_json "${imei:-""}")
apn=$(sanitize_for_json "$apn")
pdp_type=$(sanitize_for_json "${pdp_type:-"IPV4V6"}")
lte_bands=$(sanitize_for_json "${lte_bands:-""}")
sa_nr5g_bands=$(sanitize_for_json "${sa_nr5g_bands:-""}")
nsa_nr5g_bands=$(sanitize_for_json "${nsa_nr5g_bands:-""}")
network_type=$(sanitize_for_json "${network_type:-"LTE"}")
ttl=$(sanitize_for_json "${ttl:-0}")
paused=$(sanitize_for_json "${paused:-0}")
# Create profile JSON
local profile_json="{"
profile_json="${profile_json}\"name\":\"${name}\","
profile_json="${profile_json}\"iccid\":\"${iccid}\","
profile_json="${profile_json}\"imei\":\"${imei}\","
profile_json="${profile_json}\"apn\":\"${apn}\","
profile_json="${profile_json}\"pdp_type\":\"${pdp_type}\","
profile_json="${profile_json}\"lte_bands\":\"${lte_bands}\","
profile_json="${profile_json}\"sa_nr5g_bands\":\"${sa_nr5g_bands}\","
profile_json="${profile_json}\"nsa_nr5g_bands\":\"${nsa_nr5g_bands}\","
profile_json="${profile_json}\"network_type\":\"${network_type}\","
profile_json="${profile_json}\"ttl\":\"${ttl}\","
profile_json="${profile_json}\"paused\":\"${paused}\""
profile_json="${profile_json}}"
# Add comma if not first
if [ $first -eq 0 ]; then
json_output="${json_output},"
else
first=0
fi
# Add profile to output
json_output="${json_output}${profile_json}"
count=$((count+1))
done
# Complete the JSON response
local response="{\"status\":\"success\",\"profiles\":[${json_output}]}"
# Save the response for debugging
echo "$response" > /tmp/list_profiles_response.json
echo "$response"
log_message "Found and returned $count profiles"
return 0
}
# Start fresh error log
echo "=== List Profiles Run $(date) ===" > /tmp/list_profiles_error.log
# Main execution
{
get_profiles
} || {
# Error handler
output_error "Failed to retrieve profiles"
}

View File

@@ -0,0 +1,356 @@
#!/bin/sh
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_create.sh
# Set content type to JSON
echo -n ""
echo "Content-type: application/json"
echo ""
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t quecprofiles -p "daemon.$level" "create: $1"
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
local data="${3:-{}}"
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
exit 0
}
# Function to sanitize input
sanitize() {
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
}
# Function to validate ICCID (simple check)
validate_iccid() {
local iccid="$1"
if [ -z "$iccid" ] || [ ${#iccid} -lt 10 ] || [ ${#iccid} -gt 20 ]; then
return 1
fi
# Check that it's only digits
if ! echo "$iccid" | grep -q '^[0-9]\+$'; then
return 1
fi
return 0
}
# Function to validate IMEI (simple check)
validate_imei() {
local imei="$1"
if [ -z "$imei" ]; then
return 0 # IMEI is optional
fi
if [ ${#imei} -ne 15 ] || ! echo "$imei" | grep -q '^[0-9]\+$'; then
return 1
fi
return 0
}
# Function to validate band list
validate_bands() {
local bands="$1"
if [ -z "$bands" ]; then
return 0 # Empty is valid
fi
# Check format (comma-separated numbers)
if ! echo "$bands" | grep -q '^[0-9]\+\(,[0-9]\+\)*$'; then
return 1
fi
return 0
}
# Function to validate network type
validate_network_type() {
local net_type="$1"
case "$net_type" in
"LTE" | "NR5G" | "LTE:NR5G")
return 0
;;
*)
return 1
;;
esac
}
# Function to validate PDP type
validate_pdp_type() {
local pdp_type="$1"
case "$pdp_type" in
"IP" | "IPV6" | "IPV4V6")
return 0
;;
*)
return 1
;;
esac
}
# Add function to validate TTL
validate_ttl() {
local ttl="$1"
if [ -z "$ttl" ]; then
return 0 # Empty is valid (will be treated as 0/disabled)
fi
# Check that TTL is a number between 0 and 255
if ! echo "$ttl" | grep -q '^[0-9]\+$' || [ "$ttl" -gt 255 ]; then
return 1
fi
return 0
}
# Function to check if a profile with the same name or ICCID already exists
check_duplicate_profile() {
local name="$1"
local iccid="$2"
# Check for duplicate name
local existing_name=$(uci -q show quecprofiles | grep ".name='$name'" | head -n 1)
if [ -n "$existing_name" ]; then
return 1
fi
# Check for duplicate ICCID
local existing_iccid=$(uci -q show quecprofiles | grep ".iccid='$iccid'" | head -n 1)
if [ -n "$existing_iccid" ]; then
return 2
fi
return 0
}
# Function to create new profile
create_profile() {
local name="$1"
local iccid="$2"
local imei="$3"
local apn="$4"
local pdp_type="$5"
local lte_bands="$6"
local sa_nr5g_bands="$7"
local nsa_nr5g_bands="$8"
local network_type="$9"
local ttl="${10}"
# Generate a unique ID for the profile
local profile_id="profile_$(date +%s)_$(head -c 4 /dev/urandom | hexdump -e '"%x"')"
# Add to UCI config
uci -q batch <<EOF
add quecprofiles profile
set quecprofiles.@profile[-1].name='$name'
set quecprofiles.@profile[-1].iccid='$iccid'
set quecprofiles.@profile[-1].imei='$imei'
set quecprofiles.@profile[-1].apn='$apn'
set quecprofiles.@profile[-1].pdp_type='$pdp_type'
set quecprofiles.@profile[-1].lte_bands='$lte_bands'
set quecprofiles.@profile[-1].sa_nr5g_bands='$sa_nr5g_bands'
set quecprofiles.@profile[-1].nsa_nr5g_bands='$nsa_nr5g_bands'
set quecprofiles.@profile[-1].network_type='$network_type'
set quecprofiles.@profile[-1].ttl='$ttl'
set quecprofiles.@profile[-1].paused='0'
commit quecprofiles
EOF
# Check if the operation was successful
if [ $? -eq 0 ]; then
log_message "Successfully created profile '$name' for ICCID $iccid"
return 0
else
log_message "Failed to create profile '$name'" "error"
return 1
fi
}
# Output debug info
log_message "Received create profile request" "debug"
# Ensure UCI config exists
if [ ! -f /etc/config/quecprofiles ]; then
# Create initial config file
cat >/etc/config/quecprofiles <<EOF
config quecprofiles 'settings'
option check_interval '60'
option enable_autoswitch '1'
option apply_priority '20'
EOF
log_message "Created initial quecprofiles config file"
fi
# Get POST data
if [ "$REQUEST_METHOD" = "POST" ]; then
# Get content length
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
if [ -n "$CONTENT_LENGTH" ]; then
# Read POST data
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
# Debug log
log_message "Received POST data: $POST_DATA" "debug"
# Parse JSON with jsonfilter if available
if command -v jsonfilter >/dev/null 2>&1; then
name=$(echo "$POST_DATA" | jsonfilter -e '@.name' 2>/dev/null)
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
imei=$(echo "$POST_DATA" | jsonfilter -e '@.imei' 2>/dev/null)
apn=$(echo "$POST_DATA" | jsonfilter -e '@.apn' 2>/dev/null)
pdp_type=$(echo "$POST_DATA" | jsonfilter -e '@.pdp_type' 2>/dev/null)
lte_bands=$(echo "$POST_DATA" | jsonfilter -e '@.lte_bands' 2>/dev/null)
sa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.sa_nr5g_bands' 2>/dev/null)
nsa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.nsa_nr5g_bands' 2>/dev/null)
network_type=$(echo "$POST_DATA" | jsonfilter -e '@.network_type' 2>/dev/null)
ttl=$(echo "$POST_DATA" | jsonfilter -e '@.ttl' 2>/dev/null)
log_message "Parsed JSON data for profile: $name" "debug"
else
# If jsonfilter is not available, try basic parsing
# This is less reliable but might work for simple cases
name=$(echo "$POST_DATA" | grep -o '"name":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
imei=$(echo "$POST_DATA" | grep -o '"imei":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
apn=$(echo "$POST_DATA" | grep -o '"apn":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
pdp_type=$(echo "$POST_DATA" | grep -o '"pdp_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
lte_bands=$(echo "$POST_DATA" | grep -o '"lte_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
sa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"sa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
nsa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"nsa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
network_type=$(echo "$POST_DATA" | grep -o '"network_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
ttl=$(echo "$POST_DATA" | grep -o '"ttl":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
log_message "Basic parsing for profile: $name" "warn"
fi
else
log_message "No content length specified" "error"
output_json "error" "No data received"
fi
else
# URL parameters for GET requests (less secure, but supported for testing)
name=$(echo "$QUERY_STRING" | grep -o 'name=[^&]*' | cut -d'=' -f2)
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
imei=$(echo "$QUERY_STRING" | grep -o 'imei=[^&]*' | cut -d'=' -f2)
apn=$(echo "$QUERY_STRING" | grep -o 'apn=[^&]*' | cut -d'=' -f2)
pdp_type=$(echo "$QUERY_STRING" | grep -o 'pdp_type=[^&]*' | cut -d'=' -f2)
lte_bands=$(echo "$QUERY_STRING" | grep -o 'lte_bands=[^&]*' | cut -d'=' -f2)
sa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'sa_nr5g_bands=[^&]*' | cut -d'=' -f2)
nsa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'nsa_nr5g_bands=[^&]*' | cut -d'=' -f2)
network_type=$(echo "$QUERY_STRING" | grep -o 'network_type=[^&]*' | cut -d'=' -f2)
ttl=$(echo "$QUERY_STRING" | grep -o 'ttl=[^&]*' | cut -d'=' -f2)
# URL decode values
name=$(echo "$name" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
imei=$(echo "$imei" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
apn=$(echo "$apn" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
pdp_type=$(echo "$pdp_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
lte_bands=$(echo "$lte_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
sa_nr5g_bands=$(echo "$sa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
nsa_nr5g_bands=$(echo "$nsa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
network_type=$(echo "$network_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
ttl=$(echo "$ttl" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
log_message "Using URL parameters" "warn"
fi
# Sanitize inputs
name=$(sanitize "${name:-}")
iccid=$(sanitize "${iccid:-}")
imei=$(sanitize "${imei:-}")
apn=$(sanitize "${apn:-}")
pdp_type=$(sanitize "${pdp_type:-IP}")
lte_bands=$(sanitize "${lte_bands:-}")
sa_nr5g_bands=$(sanitize "${sa_nr5g_bands:-}")
nsa_nr5g_bands=$(sanitize "${nsa_nr5g_bands:-}")
network_type=$(sanitize "${network_type:-LTE}")
ttl=$(sanitize "${ttl:-0}") # Default to 0 (disabled)
# Output debug info
log_message "Creating profile: $name, ICCID: $iccid, IMEI: $imei, APN: $apn" "debug"
# Validate required inputs
if [ -z "$name" ]; then
log_message "Profile name is missing" "error"
output_json "error" "Profile name is required"
fi
if [ -z "$iccid" ]; then
log_message "ICCID is missing" "error"
output_json "error" "ICCID is required"
fi
if [ -z "$apn" ]; then
log_message "APN is missing" "error"
output_json "error" "APN is required"
fi
# Validate input formats
if ! validate_iccid "$iccid"; then
log_message "Invalid ICCID format: $iccid" "error"
output_json "error" "Invalid ICCID format. It should be 10-20 digits."
fi
if ! validate_imei "$imei"; then
log_message "Invalid IMEI format: $imei" "error"
output_json "error" "Invalid IMEI format. It should be exactly 15 digits."
fi
if ! validate_bands "$lte_bands"; then
log_message "Invalid LTE bands format: $lte_bands" "error"
output_json "error" "Invalid LTE bands format. Use comma-separated numbers (e.g., 1,3,7)"
fi
if ! validate_bands "$sa_nr5g_bands"; then
log_message "Invalid SA NR5G bands format: $sa_nr5g_bands" "error"
output_json "error" "Invalid SA NR5G bands format. Use comma-separated numbers (e.g., 41,78)"
fi
if ! validate_bands "$nsa_nr5g_bands"; then
log_message "Invalid NSA NR5G bands format: $nsa_nr5g_bands" "error"
output_json "error" "Invalid NSA NR5G bands format. Use comma-separated numbers (e.g., 1,79)"
fi
if ! validate_network_type "$network_type"; then
log_message "Invalid network type: $network_type" "error"
output_json "error" "Invalid network type. Use 'LTE', 'NR5G', or 'LTE:NR5G'"
fi
if ! validate_pdp_type "$pdp_type"; then
log_message "Invalid PDP type: $pdp_type" "error"
output_json "error" "Invalid PDP type. Use 'IP', 'IPV6', or 'IPV4V6'"
fi
if ! validate_ttl "$ttl"; then
log_message "Invalid TTL value: $ttl" "error"
output_json "error" "Invalid TTL value. It should be a number between 0 and 255."
fi
# Check for duplicates
check_duplicate_profile "$name" "$iccid"
dup_status=$?
if [ $dup_status -eq 1 ]; then
log_message "Duplicate profile name: $name" "error"
output_json "error" "A profile with this name already exists"
elif [ $dup_status -eq 2 ]; then
log_message "Duplicate ICCID: $iccid" "error"
output_json "error" "A profile with this ICCID already exists"
fi
# Create the profile
if create_profile "$name" "$iccid" "$imei" "$apn" "$pdp_type" "$lte_bands" "$sa_nr5g_bands" "$nsa_nr5g_bands" "$network_type" "$ttl"; then
# Trigger immediate profile application
touch "/tmp/quecprofiles_check"
chmod 644 "/tmp/quecprofiles_check"
log_message "Triggered immediate profile check after creation" "info"
# Create profile data JSON for return - WITHOUT outer curly braces
profile_data="\"name\":\"$name\",\"iccid\":\"$iccid\",\"imei\":\"$imei\",\"apn\":\"$apn\",\"pdp_type\":\"$pdp_type\",\"lte_bands\":\"$lte_bands\",\"sa_nr5g_bands\":\"$sa_nr5g_bands\",\"nsa_nr5g_bands\":\"$nsa_nr5g_bands\",\"network_type\":\"$network_type\",\"ttl\":\"$ttl\""
# Wrap the data field in curly braces inside output_json
output_json "success" "Profile created successfully" "{$profile_data}"
else
output_json "error" "Failed to create profile. Please check system logs."
fi

View File

@@ -0,0 +1,138 @@
#!/bin/sh
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_delete.sh
# Set content type to JSON
echo -n ""
echo "Content-type: application/json"
echo ""
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t quecprofiles -p "daemon.$level" "delete: $1"
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
local data="${3:-{}}"
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
exit 0
}
# Function to sanitize input
sanitize() {
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
}
# Function to find profile by ICCID
find_profile_by_iccid() {
local iccid="$1"
# Get all profile indices
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
for profile_index in $profile_indices; do
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
if [ "$current_iccid" = "$iccid" ]; then
echo "$profile_index"
return 0
fi
done
return 1
}
# Function to delete a profile
delete_profile() {
local profile_index="$1"
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
# Delete the profile from UCI config
uci -q batch <<EOF
delete quecprofiles.$profile_index
commit quecprofiles
EOF
# Check if the operation was successful
if [ $? -eq 0 ]; then
log_message "Successfully deleted profile '$profile_name'" "info"
return 0
else
log_message "Failed to delete profile '$profile_name'" "error"
return 1
fi
}
# Output debug info
log_message "Received delete profile request" "debug"
# Ensure UCI config exists
if [ ! -f /etc/config/quecprofiles ]; then
log_message "quecprofiles config does not exist" "error"
output_json "error" "Configuration file not found"
fi
# Get ICCID from request
iccid=""
if [ "$REQUEST_METHOD" = "POST" ]; then
# Get content length
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
if [ -n "$CONTENT_LENGTH" ]; then
# Read POST data
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
# Debug log
log_message "Received POST data: $POST_DATA" "debug"
# Parse JSON with jsonfilter if available
if command -v jsonfilter >/dev/null 2>&1; then
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
else
# If jsonfilter is not available, try basic parsing
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
fi
else
log_message "No content length specified" "error"
output_json "error" "No data received"
fi
elif [ -n "$QUERY_STRING" ]; then
# URL parameters for GET or DELETE requests
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
# URL decode value
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
log_message "Using URL parameter: iccid=$iccid" "debug"
fi
# Sanitize input
iccid=$(sanitize "${iccid:-}")
# Validate ICCID
if [ -z "$iccid" ]; then
log_message "ICCID is missing" "error"
output_json "error" "ICCID is required to identify the profile"
fi
# Find profile to delete
profile_index=$(find_profile_by_iccid "$iccid")
if [ $? -ne 0 ]; then
log_message "Profile with ICCID $iccid not found" "error"
output_json "error" "Profile not found"
fi
# Get profile info for response
profile_name=$(uci -q get quecprofiles.$profile_index.name)
# Delete the profile
if delete_profile "$profile_index"; then
log_message "Profile deleted successfully: $profile_name" "info"
output_json "success" "Profile deleted successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\"}"
else
log_message "Failed to delete profile: $profile_name" "error"
output_json "error" "Failed to delete profile. Please check system logs."
fi

View File

@@ -0,0 +1,392 @@
#!/bin/sh
# Location: /www/cgi-bin/quecmanager/profiles/quec_profile_edit.sh
# Set content type to JSON
echo -n ""
echo "Content-type: application/json"
echo ""
# Configuration
CHECK_TRIGGER="/tmp/quecprofiles_check"
APPLIED_FLAG="/tmp/quecprofiles_applied"
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t quecprofiles -p "daemon.$level" "edit: $1"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] edit: $1" >>/tmp/quec_profile_edit.log
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
local data="${3:-{}}"
# Debug log to file only
echo "Generating JSON response: status=$status, message=$message" >>/tmp/quec_profile_debug.log
echo "Data payload: $data" >>/tmp/quec_profile_debug.log
# Use printf for consistent output without newlines or extra characters
printf '{"status":"%s","message":"%s","data":%s}' "$status" "$message" "$data"
# Add debug marker at end of JSON
echo "" >>/tmp/quec_profile_debug.log
echo "JSON response generated at $(date)" >>/tmp/quec_profile_debug.log
exit 0
}
# Function to sanitize input
sanitize() {
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
}
# Function to validate ICCID (simple check)
validate_iccid() {
local iccid="$1"
if [ -z "$iccid" ] || [ ${#iccid} -lt 10 ] || [ ${#iccid} -gt 20 ]; then
return 1
fi
# Check that it's only digits
if ! echo "$iccid" | grep -q '^[0-9]\+$'; then
return 1
fi
return 0
}
# Function to validate IMEI (simple check)
validate_imei() {
local imei="$1"
if [ -z "$imei" ]; then
return 0 # IMEI is optional
fi
if [ ${#imei} -ne 15 ] || ! echo "$imei" | grep -q '^[0-9]\+$'; then
return 1
fi
return 0
}
# Function to validate band list
validate_bands() {
local bands="$1"
if [ -z "$bands" ]; then
return 0 # Empty is valid
fi
# Check format (comma-separated numbers)
if ! echo "$bands" | grep -q '^[0-9]\+\(,[0-9]\+\)*$'; then
return 1
fi
return 0
}
# Function to validate network type
validate_network_type() {
local net_type="$1"
case "$net_type" in
"LTE" | "NR5G" | "LTE:NR5G")
return 0
;;
*)
return 1
;;
esac
}
# Function to validate PDP type
validate_pdp_type() {
local pdp_type="$1"
case "$pdp_type" in
"IP" | "IPV6" | "IPV4V6")
return 0
;;
*)
return 1
;;
esac
}
validate_ttl() {
local ttl="$1"
if [ -z "$ttl" ]; then
return 0 # Empty is valid (will be treated as 0/disabled)
fi
# Check that TTL is a number between 0 and 255
if ! echo "$ttl" | grep -q '^[0-9]\+$' || [ "$ttl" -gt 255 ]; then
return 1
fi
return 0
}
# Function to check if a profile with given ICCID exists
find_profile_by_iccid() {
local iccid="$1"
# Get all profile indices
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
for profile_index in $profile_indices; do
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
if [ "$current_iccid" = "$iccid" ]; then
echo "$profile_index"
return 0
fi
done
return 1
}
# Function to check for duplicate name (excluding current profile)
check_duplicate_name() {
local name="$1"
local current_iccid="$2"
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
for profile_index in $profile_indices; do
local iccid=$(uci -q get quecprofiles.$profile_index.iccid)
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
# Skip the current profile we're editing
if [ "$iccid" = "$current_iccid" ]; then
continue
fi
if [ "$profile_name" = "$name" ]; then
return 0 # Found duplicate
fi
done
return 1 # No duplicate
}
# Function to update an existing profile
update_profile() {
local profile_index="$1"
local name="$2"
local imei="$3"
local apn="$4"
local pdp_type="$5"
local lte_bands="$6"
local sa_nr5g_bands="$7"
local nsa_nr5g_bands="$8"
local network_type="$9"
local ttl="${10}"
# Update the profile in UCI config
uci -q batch <<EOF
set quecprofiles.$profile_index.name='$name'
set quecprofiles.$profile_index.imei='$imei'
set quecprofiles.$profile_index.apn='$apn'
set quecprofiles.$profile_index.pdp_type='$pdp_type'
set quecprofiles.$profile_index.lte_bands='$lte_bands'
set quecprofiles.$profile_index.sa_nr5g_bands='$sa_nr5g_bands'
set quecprofiles.$profile_index.nsa_nr5g_bands='$nsa_nr5g_bands'
set quecprofiles.$profile_index.network_type='$network_type'
set quecprofiles.$profile_index.ttl='$ttl'
commit quecprofiles
EOF
# Check if the operation was successful
if [ $? -eq 0 ]; then
log_message "Successfully updated profile '$name'" "info"
# Remove the applied flag file to force reapplication on next check
rm -f "$APPLIED_FLAG"
# Touch the check trigger file to force daemon to check ASAP
touch "$CHECK_TRIGGER"
log_message "Triggered profile check for updated profile '$name'" "info"
return 0
else
log_message "Failed to update profile '$name'" "error"
return 1
fi
}
# Output debug info
log_message "Received edit profile request" "debug"
# Ensure UCI config exists
if [ ! -f /etc/config/quecprofiles ]; then
log_message "quecprofiles config does not exist" "error"
output_json "error" "Configuration file not found"
fi
# Get POST data
if [ "$REQUEST_METHOD" = "POST" ]; then
# Get content length
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
if [ -n "$CONTENT_LENGTH" ]; then
# Read POST data
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
# Debug log
log_message "Received POST data: $POST_DATA" "debug"
# Parse JSON with jsonfilter if available
if command -v jsonfilter >/dev/null 2>&1; then
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
name=$(echo "$POST_DATA" | jsonfilter -e '@.name' 2>/dev/null)
imei=$(echo "$POST_DATA" | jsonfilter -e '@.imei' 2>/dev/null)
apn=$(echo "$POST_DATA" | jsonfilter -e '@.apn' 2>/dev/null)
pdp_type=$(echo "$POST_DATA" | jsonfilter -e '@.pdp_type' 2>/dev/null)
lte_bands=$(echo "$POST_DATA" | jsonfilter -e '@.lte_bands' 2>/dev/null)
sa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.sa_nr5g_bands' 2>/dev/null)
nsa_nr5g_bands=$(echo "$POST_DATA" | jsonfilter -e '@.nsa_nr5g_bands' 2>/dev/null)
network_type=$(echo "$POST_DATA" | jsonfilter -e '@.network_type' 2>/dev/null)
ttl=$(echo "$POST_DATA" | jsonfilter -e '@.ttl' 2>/dev/null)
log_message "Parsed JSON data for profile: $name" "debug"
else
# If jsonfilter is not available, try basic parsing
# This is less reliable but might work for simple cases
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
name=$(echo "$POST_DATA" | grep -o '"name":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
imei=$(echo "$POST_DATA" | grep -o '"imei":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
apn=$(echo "$POST_DATA" | grep -o '"apn":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
pdp_type=$(echo "$POST_DATA" | grep -o '"pdp_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
lte_bands=$(echo "$POST_DATA" | grep -o '"lte_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
sa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"sa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
nsa_nr5g_bands=$(echo "$POST_DATA" | grep -o '"nsa_nr5g_bands":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
network_type=$(echo "$POST_DATA" | grep -o '"network_type":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
ttl=$(echo "$POST_DATA" | grep -o '"ttl":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
log_message "Basic parsing for profile: $name" "warn"
fi
else
log_message "No content length specified" "error"
output_json "error" "No data received"
fi
else
# URL parameters for GET requests (less secure, but supported for testing)
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
name=$(echo "$QUERY_STRING" | grep -o 'name=[^&]*' | cut -d'=' -f2)
imei=$(echo "$QUERY_STRING" | grep -o 'imei=[^&]*' | cut -d'=' -f2)
apn=$(echo "$QUERY_STRING" | grep -o 'apn=[^&]*' | cut -d'=' -f2)
pdp_type=$(echo "$QUERY_STRING" | grep -o 'pdp_type=[^&]*' | cut -d'=' -f2)
lte_bands=$(echo "$QUERY_STRING" | grep -o 'lte_bands=[^&]*' | cut -d'=' -f2)
sa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'sa_nr5g_bands=[^&]*' | cut -d'=' -f2)
nsa_nr5g_bands=$(echo "$QUERY_STRING" | grep -o 'nsa_nr5g_bands=[^&]*' | cut -d'=' -f2)
network_type=$(echo "$QUERY_STRING" | grep -o 'network_type=[^&]*' | cut -d'=' -f2)
ttl=$(echo "$QUERY_STRING" | grep -o 'ttl=[^&]*' | cut -d'=' -f2)
# URL decode values
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
name=$(echo "$name" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
imei=$(echo "$imei" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
apn=$(echo "$apn" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
pdp_type=$(echo "$pdp_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
lte_bands=$(echo "$lte_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
sa_nr5g_bands=$(echo "$sa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
nsa_nr5g_bands=$(echo "$nsa_nr5g_bands" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
network_type=$(echo "$network_type" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
ttl=$(echo "$ttl" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
log_message "Using URL parameters" "warn"
fi
# Sanitize inputs
iccid=$(sanitize "${iccid:-}")
name=$(sanitize "${name:-}")
imei=$(sanitize "${imei:-}")
apn=$(sanitize "${apn:-}")
pdp_type=$(sanitize "${pdp_type:-IP}")
lte_bands=$(sanitize "${lte_bands:-}")
sa_nr5g_bands=$(sanitize "${sa_nr5g_bands:-}")
nsa_nr5g_bands=$(sanitize "${nsa_nr5g_bands:-}")
network_type=$(sanitize "${network_type:-LTE}")
ttl=$(sanitize "${ttl:-0}") # Default to 0 (disabled)
# Output debug info
log_message "Editing profile: $name, ICCID: $iccid, IMEI: $imei, APN: $apn" "debug"
# Validate required inputs
if [ -z "$iccid" ]; then
log_message "ICCID is missing" "error"
output_json "error" "ICCID is required to identify the profile"
fi
if [ -z "$name" ]; then
log_message "Profile name is missing" "error"
output_json "error" "Profile name is required"
fi
if [ -z "$apn" ]; then
log_message "APN is missing" "error"
output_json "error" "APN is required"
fi
# Validate input formats
if ! validate_iccid "$iccid"; then
log_message "Invalid ICCID format: $iccid" "error"
output_json "error" "Invalid ICCID format. It should be 10-20 digits."
fi
if ! validate_imei "$imei"; then
log_message "Invalid IMEI format: $imei" "error"
output_json "error" "Invalid IMEI format. It should be exactly 15 digits."
fi
if ! validate_bands "$lte_bands"; then
log_message "Invalid LTE bands format: $lte_bands" "error"
output_json "error" "Invalid LTE bands format. Use comma-separated numbers (e.g., 1,3,7)"
fi
if ! validate_bands "$sa_nr5g_bands"; then
log_message "Invalid SA NR5G bands format: $sa_nr5g_bands" "error"
output_json "error" "Invalid SA NR5G bands format. Use comma-separated numbers (e.g., 41,78)"
fi
if ! validate_bands "$nsa_nr5g_bands"; then
log_message "Invalid NSA NR5G bands format: $nsa_nr5g_bands" "error"
output_json "error" "Invalid NSA NR5G bands format. Use comma-separated numbers (e.g., 1,79)"
fi
if ! validate_network_type "$network_type"; then
log_message "Invalid network type: $network_type" "error"
output_json "error" "Invalid network type. Use 'LTE', 'NR5G', or 'LTE:NR5G'"
fi
if ! validate_pdp_type "$pdp_type"; then
log_message "Invalid PDP type: $pdp_type" "error"
output_json "error" "Invalid PDP type. Use 'IP', 'IPV6', or 'IPV4V6'"
fi
if ! validate_ttl "$ttl"; then
log_message "Invalid TTL value: $ttl" "error"
output_json "error" "Invalid TTL value. It should be a number between 0 and 255."
fi
# Find profile to edit
profile_index=$(find_profile_by_iccid "$iccid")
if [ $? -ne 0 ]; then
log_message "Profile with ICCID $iccid not found" "error"
output_json "error" "Profile not found"
fi
# Check for duplicate name
if check_duplicate_name "$name" "$iccid"; then
log_message "Duplicate profile name: $name" "error"
output_json "error" "A profile with this name already exists"
fi
# Update profile
if update_profile "$profile_index" "$name" "$imei" "$apn" "$pdp_type" "$lte_bands" "$nr5g_bands" "$network_type"; then
# Trigger immediate profile application
touch "/tmp/quecprofiles_check"
chmod 644 "/tmp/quecprofiles_check"
log_message "Triggered immediate profile check after update" "info"
# Create a clean JSON response with properly escaped quotes
printf '{"status":"success","message":"Profile updated successfully","data":{"name":"%s","iccid":"%s","imei":"%s","apn":"%s","pdp_type":"%s","lte_bands":"%s","nr5g_bands":"%s","network_type":"%s"}}' \
"$name" "$iccid" "$imei" "$apn" "$pdp_type" "$lte_bands" "$nr5g_bands" "$network_type"
log_message "Profile updated successfully: $name" "info"
# Note: The conditional trigger is replaced with the direct trigger above
else
printf '{"status":"error","message":"Failed to update profile. Please check system logs."}'
log_message "Failed to update profile: $name" "error"
fi

View File

@@ -0,0 +1,193 @@
#!/bin/sh
# Location: /www/cgi-bin/quecmanager/profiles/toggle_pause.sh
# Set content type to JSON
echo -n ""
echo "Content-type: application/json"
echo ""
# Configuration
CHECK_TRIGGER="/tmp/quecprofiles_check"
STATUS_FILE="/tmp/quecprofiles_status.json"
TRACK_FILE="/tmp/quecprofiles_active"
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t quecprofiles -p "daemon.$level" "toggle_pause: $1"
}
# Function to update status file directly - used when pausing a profile
update_status_to_paused() {
local profile_name="$1"
# Create JSON status for paused profile
cat > "$STATUS_FILE" <<EOF
{
"status": "paused",
"message": "Profile is paused. Resume the profile to apply settings.",
"profile": "$profile_name",
"progress": 0,
"timestamp": $(date +%s)
}
EOF
# Create simple track file for easy checking
echo "paused:$profile_name:0" > "$TRACK_FILE"
chmod 644 "$TRACK_FILE" "$STATUS_FILE"
log_message "Status updated: paused - Profile is paused ($profile_name)" "info"
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
local data="${3:-{}}"
printf '{"status":"%s","message":"%s","data":%s}\n' "$status" "$message" "$data"
exit 0
}
# Function to sanitize input
sanitize() {
echo "$1" | tr -d '\r\n' | sed 's/[^a-zA-Z0-9,.:_-]//g'
}
# Function to find profile by ICCID
find_profile_by_iccid() {
local iccid="$1"
# Get all profile indices
local profile_indices=$(uci show quecprofiles | grep -o '@profile\[[0-9]\+\]' | sort -u)
for profile_index in $profile_indices; do
local current_iccid=$(uci -q get quecprofiles.$profile_index.iccid)
if [ "$current_iccid" = "$iccid" ]; then
echo "$profile_index"
return 0
fi
done
return 1
}
# Function to toggle pause state
toggle_pause_state() {
local profile_index="$1"
local paused="$2" # 0 or 1
local profile_name=$(uci -q get quecprofiles.$profile_index.name)
# Update the profile in UCI config
uci -q batch <<EOF
set quecprofiles.$profile_index.paused='$paused'
commit quecprofiles
EOF
# Check if the operation was successful
if [ $? -eq 0 ]; then
if [ "$paused" = "1" ]; then
log_message "Successfully paused profile '$profile_name'" "info"
# Immediately update status to paused without waiting for daemon
update_status_to_paused "$profile_name"
return 0
else
log_message "Successfully resumed profile '$profile_name'" "info"
# Touch the check trigger file to force daemon to check ASAP
touch "$CHECK_TRIGGER"
chmod 644 "$CHECK_TRIGGER"
log_message "Triggered profile check for resumed profile '$profile_name'" "info"
return 0
fi
else
log_message "Failed to update pause state for profile '$profile_name'" "error"
return 1
fi
}
# Output debug info
log_message "Received toggle pause request" "debug"
# Ensure UCI config exists
if [ ! -f /etc/config/quecprofiles ]; then
log_message "quecprofiles config does not exist" "error"
output_json "error" "Configuration file not found"
fi
# Get POST data
iccid=""
paused=""
if [ "$REQUEST_METHOD" = "POST" ]; then
# Get content length
CONTENT_LENGTH=$(echo "$CONTENT_LENGTH" | tr -cd '0-9')
if [ -n "$CONTENT_LENGTH" ]; then
# Read POST data
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
# Debug log
log_message "Received POST data: $POST_DATA" "debug"
# Parse JSON with jsonfilter if available
if command -v jsonfilter >/dev/null 2>&1; then
iccid=$(echo "$POST_DATA" | jsonfilter -e '@.iccid' 2>/dev/null)
paused=$(echo "$POST_DATA" | jsonfilter -e '@.paused' 2>/dev/null)
else
# If jsonfilter is not available, try basic parsing
iccid=$(echo "$POST_DATA" | grep -o '"iccid":"[^"]*"' | head -1 | cut -d':' -f2 | tr -d '"')
paused=$(echo "$POST_DATA" | grep -o '"paused":[0-1]' | head -1 | cut -d':' -f2)
fi
else
log_message "No content length specified" "error"
output_json "error" "No data received"
fi
elif [ -n "$QUERY_STRING" ]; then
# URL parameters for GET requests (for testing)
iccid=$(echo "$QUERY_STRING" | grep -o 'iccid=[^&]*' | cut -d'=' -f2)
paused=$(echo "$QUERY_STRING" | grep -o 'paused=[^&]*' | cut -d'=' -f2)
# URL decode values
iccid=$(echo "$iccid" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;' | xargs -0 printf "%b")
log_message "Using URL parameters: iccid=$iccid, paused=$paused" "debug"
fi
# Sanitize inputs
iccid=$(sanitize "${iccid:-}")
paused=$(sanitize "${paused:-}")
# Validate required inputs
if [ -z "$iccid" ]; then
log_message "ICCID is missing" "error"
output_json "error" "ICCID is required to identify the profile"
fi
# Validate pause state (must be 0 or 1)
if [ "$paused" != "0" ] && [ "$paused" != "1" ]; then
log_message "Invalid paused state: $paused" "error"
output_json "error" "Paused state must be 0 (resumed) or 1 (paused)"
fi
# Find profile to toggle
profile_index=$(find_profile_by_iccid "$iccid")
if [ $? -ne 0 ]; then
log_message "Profile with ICCID $iccid not found" "error"
output_json "error" "Profile not found"
fi
# Get profile info for response
profile_name=$(uci -q get quecprofiles.$profile_index.name)
# Toggle pause state
if toggle_pause_state "$profile_index" "$paused"; then
if [ "$paused" = "1" ]; then
log_message "Profile paused successfully: $profile_name" "info"
output_json "success" "Profile paused successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\",\"paused\":true}"
else
log_message "Profile resumed successfully: $profile_name" "info"
output_json "success" "Profile resumed successfully" "{\"iccid\":\"$iccid\",\"name\":\"$profile_name\",\"paused\":false}"
fi
else
log_message "Failed to update pause state for profile: $profile_name" "error"
output_json "error" "Failed to update profile status. Please check system logs."
fi