Added cgi-bin scripts

This commit is contained in:
Russel Yasol
2025-01-17 14:57:15 +08:00
parent 397e0de45a
commit b8f9feef20
46 changed files with 3603 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# Set content type for JSON response
echo "Content-Type: application/json"
echo ""
# Check if the file exists
if [ -f "/etc/config/atcommands.user" ]; then
# Start JSON object
printf "{\n"
awk -F';' '
BEGIN { first = 1 }
{
gsub(/\r/, "", $0)
if (!first) printf ",\n "
else printf " "
gsub(/"/, "\\\"", $1)
gsub(/"/, "\\\"", $2)
printf "\"%s\": \"%s\"", $1, $2
first = 0
}
' /etc/config/atcommands.user
printf "\n}"
else
echo '{"error": "No Data"}'
fi

View File

@@ -0,0 +1,49 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Create a temporary file to store the processed data
temp_file=$(mktemp)
# Process ARP entries and store in temporary file
arp -a | while IFS= read -r line; do
if [ -n "$line" ]; then
# Extract hostname (or IP if hostname is "?"), IP, and MAC
hostname=$(echo "$line" | awk '{print $1}')
ip=$(echo "$line" | awk -F '[()]' '{print $2}')
mac=$(echo "$line" | awk '{print $4}')
# Skip entries without valid MAC addresses
if [ "$mac" = "<incomplete>" ]; then
continue
fi
# If hostname is "?", use the IP address instead
if [ "$hostname" = "?" ]; then
hostname="$ip"
fi
# Store each entry in the temp file
echo "$hostname:$ip:$mac" >> "$temp_file"
fi
done
# Initialize JSON array
echo -n "["
# Process the temporary file to create JSON
first=true
while IFS=: read -r hostname ip mac; do
if [ "$first" = true ]; then
first=false
else
echo -n ","
fi
echo -n "{\"hostname\":\"$hostname\",\"ip\":\"$ip\",\"mac\":\"$mac\"}"
done < "$temp_file"
# Close the JSON array
echo "]"
# Clean up
rm -f "$temp_file"

View File

@@ -0,0 +1,90 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
mtu_firewall_file="/etc/firewall.user.mtu"
network_interface="rmnet_data0"
lan_utils_script="/etc/data/lanUtils.sh"
get_current_mtu() {
ip link show "$network_interface" | grep -o "mtu [0-9]*" | cut -d' ' -f2
}
update_lanutils_mtu_config() {
local action="$1"
if [ "$action" = "add" ]; then
# Add the MTU firewall file line if not already present
if ! grep -q "local mtu_firewall_file=/etc/firewall.user.mtu" "$lan_utils_script"; then
sed -i '/local ttl_firewall_file=\/etc\/firewall.user.ttl/a local mtu_firewall_file=/etc/firewall.user.mtu' "$lan_utils_script"
fi
elif [ "$action" = "remove" ]; then
# Remove the MTU firewall file line if present
sed -i '/local mtu_firewall_file=\/etc\/firewall.user.mtu/d' "$lan_utils_script"
fi
}
case "$REQUEST_METHOD" in
GET)
# Fetch current MTU
current_mtu=$(get_current_mtu)
current_mtu=${current_mtu:-1500}
# Check if custom MTU is configured
if [ -f "$mtu_firewall_file" ]; then
echo "{\"isEnabled\": true, \"currentValue\": $current_mtu}"
else
echo "{\"isEnabled\": false, \"currentValue\": $current_mtu}"
fi
;;
POST)
read -r post_data
mtu_value=$(echo "$post_data" | sed 's/mtu=//')
# Check for disable functionality
if [ "$mtu_value" = "disable" ]; then
# Remove the MTU configuration file
rm -f "$mtu_firewall_file"
# Remove the MTU configuration line from lanUtils.sh
update_lanutils_mtu_config "remove"
# Get the default MTU
default_mtu=$(get_current_mtu)
default_mtu=${default_mtu:-1500}
echo "{\"success\": true, \"message\": \"MTU configuration disabled\", \"currentValue\": $default_mtu}"
exit 0
fi
# Validate MTU input
if ! [[ "$mtu_value" =~ ^[0-9]+$ ]]; then
echo "{\"success\": false, \"error\": \"Invalid MTU value\"}"
exit 1
fi
# Create firewall MTU configuration file with individual interface commands
> "$mtu_firewall_file" # Clear the file
for iface in $(ls /sys/class/net | grep '^rmnet_data'); do
echo "ip link set $iface mtu $mtu_value" >> "$mtu_firewall_file"
done
# Immediately apply MTU change
for iface in $(ls /sys/class/net | grep '^rmnet_data'); do
ip link set "$iface" mtu "$mtu_value"
done
# Add the MTU configuration line to lanUtils.sh
update_lanutils_mtu_config "add"
# Run lanUtils.sh to update network configuration
if [ -f "$lan_utils_script" ]; then
. "$lan_utils_script"
fi
echo "{\"success\": true, \"message\": \"MTU configuration updated to $mtu_value\", \"currentValue\": $mtu_value}"
;;
*)
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
;;
esac

View File

@@ -0,0 +1,94 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
ttl_file="/etc/firewall.user.ttl"
lan_utils_script="/etc/data/lanUtils.sh"
setup_persistent_config() {
if [ ! -f "$lan_utils_script" ]; then
echo "{\"success\": false, \"error\": \"lanUtils.sh not found\"}"
return 1
fi
# Backup the original script if not already done
if [ ! -f "${lan_utils_script}.bak" ]; then
cp "$lan_utils_script" "${lan_utils_script}.bak"
fi
# Add the local ttl_firewall_file line if it's not already present
if ! grep -q "local ttl_firewall_file" "$lan_utils_script"; then
sed -i '/local tcpmss_firewall_filev6/a \ local ttl_firewall_file=/etc/firewall.user.ttl' "$lan_utils_script"
fi
# Add the condition to include the ttl_firewall_file if it's not already present
if ! grep -q "if \[ -f \"\$ttl_firewall_file\" \]; then" "$lan_utils_script"; then
sed -i '/if \[ -f "\$tcpmss_firewall_filev6" \]; then/i \ if [ -f "\$ttl_firewall_file" ]; then\n cat \$ttl_firewall_file >> \$firewall_file\n fi' "$lan_utils_script"
fi
}
clear_existing_rules() {
local current_ttl=$1
if [ -n "$current_ttl" ]; then
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set "$current_ttl" 2>/dev/null
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set "$current_ttl" 2>/dev/null
fi
}
case "$REQUEST_METHOD" in
GET)
# Ensure consistent JSON format for GET requests
if [ -s "$ttl_file" ]; then
ttl_value=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
# Ensure ttl_value is a number, default to 0 if not
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
ttl_value=0
fi
echo "{\"isEnabled\": true, \"currentValue\": $ttl_value}"
else
echo "{\"isEnabled\": false, \"currentValue\": 0}"
fi
;;
POST)
read -r post_data
ttl_value=$(echo "$post_data" | sed 's/ttl=//')
# Ensure ttl_file exists
touch "$ttl_file" 2>/dev/null
if [ ! -f "$ttl_file" ]; then
echo "{\"success\": false, \"error\": \"Cannot create TTL file\"}"
exit 1
fi
# Setup persistent configuration
setup_persistent_config
# Get current TTL value for cleanup
current_ttl=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
echo "{\"success\": false, \"error\": \"Invalid TTL value\"}"
elif [ "$ttl_value" = "0" ]; then
clear_existing_rules "$current_ttl"
> "$ttl_file"
echo "{\"success\": true}"
else
# Clear existing rules
clear_existing_rules "$current_ttl"
# Set new rules
echo "iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set $ttl_value" > "$ttl_file"
echo "ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set $ttl_value" >> "$ttl_file"
# Apply the rules
iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set "$ttl_value"
ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set "$ttl_value"
echo "{\"success\": true}"
fi
;;
*)
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
;;
esac

View File

@@ -0,0 +1,74 @@
#!/bin/sh
# CGI header
echo "Content-type: application/json"
echo ""
# Queue file
QUEUE_FILE="/tmp/at_pipe.txt"
RESULT_FILE="/tmp/at_results.json"
LOG_FILE="/var/log/at_commands.log"
# Create queue file if it doesn't exist
touch "${QUEUE_FILE}"
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG_FILE}"
}
# Function to generate random ID
generate_random_id() {
# Combine multiple sources of randomness
local timestamp=$(date +%s%N)
local random1=$(head -c 4 /dev/urandom | xxd -p)
local random2=$(echo $$ $RANDOM | md5sum | head -c 8)
echo "${timestamp}-${random1}-${random2}"
}
# Function to escape special characters for JSON
escape_json() {
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g'
}
# Function to decode URL
decode_url() {
local encoded="$1"
# First handle percent-encoded characters
printf '%b' "${encoded}" | sed -e 's/%\([0-9A-Fa-f][0-9A-Fa-f]\)/\\x\1/g' | xargs -0 echo -e |
# Then handle plus signs separately (preserve them for AT commands)
sed 's/[+]/%2B/g' | sed 's/%2B/+/g'
}
# Get command from query string
QUERY_STRING="${QUERY_STRING:-}"
RAW_COMMAND=$(echo "${QUERY_STRING}" | sed 's/^command=//')
if [ -n "${RAW_COMMAND}" ]; then
# Decode URL-encoded command with fixed plus sign handling
AT_COMMAND=$(decode_url "${RAW_COMMAND}")
# Generate unique random ID
CMD_ID=$(generate_random_id)
# Create timestamp
TIMESTAMP=$(date '+%H:%M:%S')
# Escape command for JSON
ESCAPED_COMMAND=$(escape_json "${AT_COMMAND}")
# Create JSON entry for queue (all in one line)
QUEUE_ENTRY=$(printf '{"id":"%s","timestamp":"%s","command":"%s","status":"pending"}\n' \
"${CMD_ID}" "${TIMESTAMP}" "${ESCAPED_COMMAND}")
# Add to queue file
echo "${QUEUE_ENTRY}" >> "${QUEUE_FILE}"
log_message "Queued command: ${AT_COMMAND} with ID: ${CMD_ID}"
# Return immediate response
printf '{"status":"queued","message":"Command has been queued","command":"%s","id":"%s","queued_at":"%s"}\n' \
"${ESCAPED_COMMAND}" "${CMD_ID}" "${TIMESTAMP}"
else
# Return error response
printf '{"status":"error","message":"No command provided","timestamp":"%s"}\n' "$(date '+%H:%M:%S')"
exit 1
fi

View File

@@ -0,0 +1,97 @@
#!/bin/sh
echo "Content-type: application/json"
echo "Access-Control-Allow-Origin: *"
echo "Access-Control-Allow-Methods: GET, POST, OPTIONS"
echo "Access-Control-Allow-Headers: Content-Type"
echo ""
# Configuration
RESULT_FILE="/tmp/at_results.json"
LOG_FILE="/var/log/at_commands.log"
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG_FILE}"
}
# Function to return error response
send_error() {
local message="$1"
jq -n \
--arg msg "${message}" \
--arg time "$(date '+%H:%M:%S')" \
'{
status: "error",
message: $msg,
timestamp: $time
}'
exit 1
}
# Parse query parameters
eval $(echo "${QUERY_STRING}" | tr '&' '\n' | sed 's/\([^=]*\)=\([^=]*\)/\1="\2"/')
# Check if results file exists
if [ ! -f "${RESULT_FILE}" ]; then
send_error "No results found"
fi
# Validate results file contains valid JSON
if ! cat "${RESULT_FILE}" | jq . >/dev/null 2>&1; then
log_message "Invalid JSON in results file"
send_error "Invalid results data"
fi
# Handle different query types
case "${action}" in
"get_by_id")
# Fetch specific result by ID
if [ -z "${id}" ]; then
send_error "No ID provided"
fi
result=$(cat "${RESULT_FILE}" | jq --arg id "${id}" '. | map(select(.id == $id)) | .[0]')
if [ "${result}" = "null" ]; then
send_error "No result found for ID: ${id}"
else
echo "${result}"
fi
;;
"get_latest")
# Fetch the most recent N results (default to 10)
limit=${limit:-10}
cat "${RESULT_FILE}" | jq --arg limit "${limit}" 'reverse | limit(($limit|tonumber); .)'
;;
"get_by_status")
# Fetch results by status
if [ -z "${status}" ]; then
send_error "No status provided"
fi
cat "${RESULT_FILE}" | jq --arg status "${status}" '. | map(select(.status == $status))'
;;
"clear")
# Clear all results (optional)
if [ "${confirm}" = "true" ]; then
echo "[]" > "${RESULT_FILE}"
jq -n \
--arg time "$(date '+%H:%M:%S')" \
'{
status: "success",
message: "Results cleared",
timestamp: $time
}'
else
send_error "Confirmation required to clear results"
fi
;;
*)
# Default: return all results
cat "${RESULT_FILE}"
;;
esac

View File

@@ -0,0 +1,78 @@
#!/bin/sh
# Function to URL-decode the input
urldecode() {
local data="$1"
echo -e "$(echo "$data" | sed 's/+/ /g;s/%\(..\)/\\x\1/g;')"
}
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Read the input from POST data
read INPUT_DATA
# Extract the command from the input data (format: command=AT+COMMAND)
RAW_COMMAND=$(echo "$INPUT_DATA" | sed 's/command=//g')
# URL-decode the command
COMMAND=$(urldecode "$RAW_COMMAND")
# Define unique input/output files and AT port
INPUT_FILE="/tmp/custom_input_$$.txt"
OUTPUT_FILE="/tmp/custom_output_$$.txt"
# Debug logging
DEBUG_LOG="/tmp/debug.log"
echo "Starting at_handler script at $(date)" > "$DEBUG_LOG"
CONFIG_FILE="/etc/quecManager.conf"
# Check config file
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file not found: $CONFIG_FILE" >> "$DEBUG_LOG"
echo '{"error": "Config file not found"}'
exit 1
fi
# Get AT_PORT with debug logging
AT_PORT=$(head -n 1 "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' \n\r' | sed 's|^dev/||')
echo "Raw config line: $(head -n 1 "$CONFIG_FILE")" >> "$DEBUG_LOG"
echo "Extracted AT_PORT: '$AT_PORT'" >> "$DEBUG_LOG"
if [ -z "$AT_PORT" ]; then
echo "AT_PORT is empty" >> "$DEBUG_LOG"
output_error "Failed to read AT_PORT from config"
fi
# Check if AT_PORT exists
if [ ! -c "/dev/$AT_PORT" ]; then
echo "AT_PORT device not found: /dev/$AT_PORT" >> "$DEBUG_LOG"
echo "Available smd devices:" >> "$DEBUG_LOG"
ls -l /dev/smd* >> "$DEBUG_LOG" 2>&1
output_error "AT_PORT device not found"
fi
# Write the command directly to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "/dev/$AT_PORT" "$OUTPUT_FILE"
# Read the output from output.txt
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters (like newlines and double quotes) for JSON compatibility
ESCAPED_OUTPUT=$(echo "$OUTPUT" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g')
# Escape double quotes in the command for JSON compatibility
ESCAPED_COMMAND=$(echo "$COMMAND" | sed 's/"/\\"/g')
# Create the JSON response
JSON_RESPONSE=$(printf "{\"command\":\"%s\",\"output\":\"%s\"}" "$ESCAPED_COMMAND" "$ESCAPED_OUTPUT")
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"

View File

@@ -0,0 +1,45 @@
#!/bin/sh
# Set Content-Type for CGI script
echo "Content-type: application/json"
echo ""
# Read POST data
read POST_DATA
# Debug log for generated hash
DEBUG_LOG = "/tmp/auth.log"
# Extract the password from POST data (URL encoded)
USER="root"
INPUT_PASSWORD=$(echo "$POST_DATA" | sed -n 's/^.*password=\([^&]*\).*$/\1/p')
# URL-decode the password (replace + with space and decode %XX)
INPUT_PASSWORD=$(echo "$INPUT_PASSWORD" | sed 's/+/ /g;s/%\(..\)/\\x\1/g' | xargs -0 printf "%b")
# Extract the hashed password from /etc/shadow for the specified user
USER_SHADOW_ENTRY=$(grep "^$USER:" /etc/shadow)
if [ -z "$USER_SHADOW_ENTRY" ]; then
echo '{"state":"failed", "message":"User not found"}'
exit 1
fi
# Extract the password hash (it's the second field, colon-separated)
USER_HASH=$(echo "$USER_SHADOW_ENTRY" | cut -d: -f2)
# Extract the salt (MD5 uses the $1$ prefix followed by the salt)
SALT=$(echo "$USER_HASH" | cut -d'$' -f3)
# Generate a hash from the input password using the same salt
GENERATED_HASH=$(echo "$INPUT_PASSWORD" | openssl passwd -1 -salt "$SALT" -stdin)
# Log generated hash for debugging
echo "Generated hash: $GENERATED_HASH" >> $DEBUG_LOG
# Compare the generated hash with the one in the shadow file
if [ "$GENERATED_HASH" = "$USER_HASH" ]; then
echo '{"state":"success"}'
else
echo '{"state":"failed"}'
fi

View File

@@ -0,0 +1,66 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error flag
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Remove the entire quecmanager directory
if [ -d "/etc/quecmanager/apn_profile/" ]; then
rm -rf /etc/quecmanager/apn_profile/
if [ $? -ne 0 ]; then
append_error "Failed to remove quecmanager directory"
fi
else
append_error "quecmanager directory not found"
fi
# Remove the line from rc.local
if [ -f "/etc/rc.local" ]; then
# Create a temporary file
temp_file=$(mktemp)
# Remove the apnProfiles.sh line and copy to temp file
sed '/\/etc\/quecmanager\/apnProfiles.sh/d' /etc/rc.local > "$temp_file"
# Check if sed command was successful
if [ $? -eq 0 ]; then
# Replace original file with modified version
mv "$temp_file" /etc/rc.local
if [ $? -ne 0 ]; then
append_error "Failed to update rc.local"
fi
else
append_error "Failed to modify rc.local"
rm -f "$temp_file"
fi
else
append_error "rc.local file not found"
fi
# Remove temporary files that might have been created
rm -f /tmp/apn_result.txt
rm -f /tmp/debug.log
rm -f /tmp/inputICCID.txt
rm -f /tmp/outputICCID.txt
rm -f /tmp/inputAPN.txt
rm -f /tmp/outputAPN.txt
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"APN profiles and configuration successfully removed\"}"
fi

View File

@@ -0,0 +1,45 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/apn_profile/apn_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo "{}"
exit 0
fi
# Read the configuration file
iccidProfile1=$(grep "^iccidProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
apnProfile1=$(grep "^apnProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
pdpType1=$(grep "^pdpType1=" "$CONFIG_FILE" | cut -d'=' -f2)
iccidProfile2=$(grep "^iccidProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
apnProfile2=$(grep "^apnProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
pdpType2=$(grep "^pdpType2=" "$CONFIG_FILE" | cut -d'=' -f2)
# Build the JSON response
echo "{"
# Add Profile 1 if it exists
if [ -n "$iccidProfile1" ]; then
echo " \"profile1\": {"
echo " \"iccid\": \"$iccidProfile1\","
echo " \"apn\": \"$apnProfile1\","
echo " \"pdpType\": \"$pdpType1\""
echo " }"
# Add comma if Profile 2 exists
[ -n "$iccidProfile2" ] && echo " ,"
fi
# Add Profile 2 if it exists
if [ -n "$iccidProfile2" ]; then
echo " \"profile2\": {"
echo " \"iccid\": \"$iccidProfile2\","
echo " \"apn\": \"$apnProfile2\","
echo " \"pdpType\": \"$pdpType2\""
echo " }"
fi
echo "}"

View File

@@ -0,0 +1,292 @@
#!/bin/sh
# Parse POST data (using busybox compatible method)
read -r QUERY_STRING
# Function to urldecode (busybox compatible version)
urldecode() {
local value="$1"
value="${value//+/ }"
value="${value//%/\\x}"
printf '%b' "$value"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
apnProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile1=\([^&]*\).*/\1/p' | tr -d "'")
pdpType1=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType1=\([^&]*\).*/\1/p' | tr -d "'")
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
apnProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile2=\([^&]*\).*/\1/p' | tr -d "'")
pdpType2=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType2=\([^&]*\).*/\1/p' | tr -d "'")
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
apnProfile1=$(urldecode "$apnProfile1")
pdpType1=$(urldecode "$pdpType1")
iccidProfile2=$(urldecode "$iccidProfile2")
apnProfile2=$(urldecode "$apnProfile2")
pdpType2=$(urldecode "$pdpType2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Create directory with proper permissions
mkdir -p /etc/quecmanager/apn_profile
chmod 755 /etc/quecmanager/apn_profile
# Create a configuration file to store APN profiles (with proper permissions)
cat > /etc/quecmanager/apn_profile/apn_config.txt <<EOF
iccidProfile1=${iccidProfile1}
apnProfile1=${apnProfile1}
pdpType1=${pdpType1}
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/apn_profile/apn_config.txt <<EOF
iccidProfile2=${iccidProfile2}
apnProfile2=${apnProfile2}
pdpType2=${pdpType2}
EOF
fi
chmod 644 /etc/quecmanager/apn_profile/apn_config.txt
# Create the apnProfiles.sh script with proper locking mechanism and logging
cat > /etc/quecmanager/apn_profile/apnProfiles.sh <<'EOF'
#!/bin/sh
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/tmp/apn_profiles.log"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Enhanced logging function with debug level
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t apn_profiles "${level}: ${message}"
}
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1"
local wait_count=0
while [ $wait_count -lt 6 ]; do
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
log_message "DEBUG" "Waiting for ${command_type} to clear (attempt ${wait_count})"
sleep 1
wait_count=$((wait_count + 1))
else
return 0
fi
done
log_message "WARN" "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Simplified lock handling with debug
handle_lock() {
log_message "DEBUG" "Checking queue file status before lock"
if [ -f "$QUEUE_FILE" ]; then
log_message "DEBUG" "Current queue content: $(cat $QUEUE_FILE)"
else
log_message "DEBUG" "Queue file does not exist, creating it"
touch "$QUEUE_FILE"
fi
check_and_clean_stale "FETCH_LOCK"
log_message "DEBUG" "Adding AT_COMMAND entry to queue"
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
check_and_clean_stale "AT_COMMAND"
}
# Execute AT command without timeout dependency
execute_at_command() {
local command="$1"
local result=""
log_message "DEBUG" "Executing AT command: ${command}"
handle_lock
# Execute command and capture all output
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
log_message "DEBUG" "Removing our entry from queue"
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -ne 0 ]; then
log_message "ERROR" "Command failed with status $status: $command"
log_message "ERROR" "Command output: $result"
return 1
fi
log_message "DEBUG" "Command successful. Output: $result"
echo "$result"
return 0
}
# Get current ICCID with enhanced debug
get_current_iccid() {
local result
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to get current ICCID"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "ICCID attempt ${retry_count}"
result=$(execute_at_command "AT+ICCID")
local cmd_status=$?
log_message "DEBUG" "AT+ICCID command returned status: ${cmd_status}"
log_message "DEBUG" "AT+ICCID raw output: ${result}"
if [ $cmd_status -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
local iccid=$(echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]')
log_message "INFO" "Retrieved current ICCID: ${iccid}"
echo "${iccid}"
return 0
else
log_message "WARN" "Attempt ${retry_count} failed to get valid ICCID"
log_message "WARN" "Result: ${result}"
fi
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
log_message "INFO" "Waiting 2 seconds before retry"
sleep 2
fi
done
log_message "ERROR" "Failed to get ICCID after $max_retries attempts"
return 1
}
# Set APN with modified error handling - removed strict OK check
set_apn() {
local pdp_type="$1"
local apn="$2"
local result
local retry_count=0
local max_retries=3
if [ -z "$pdp_type" ] || [ -z "$apn" ]; then
log_message "ERROR" "Invalid PDP type or APN"
return 1
fi
while [ $retry_count -lt $max_retries ]; do
result=$(execute_at_command "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0")
if [ $? -eq 0 ]; then
log_message "INFO" "Successfully set APN: $apn with PDP type: $pdp_type"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to set APN: $apn after $max_retries attempts"
return 1
}
# Load configuration
if [ -f /etc/quecmanager/apn_profile/apn_config.txt ]; then
. /etc/quecmanager/apn_profile/apn_config.txt
log_message "INFO" "Loaded configuration - Profile1 ICCID: ${iccidProfile1}, Profile2 ICCID: ${iccidProfile2:-none}"
else
log_message "ERROR" "Configuration file not found"
echo "Configuration file not found" > /tmp/apn_result.txt
exit 1
fi
# Get current ICCID and trim any whitespace
current_iccid=$(get_current_iccid | tr -d '[:space:]')
if [ $? -ne 0 ]; then
log_message "ERROR" "Failed to get current ICCID"
echo "Failed to get current ICCID" > /tmp/apn_result.txt
exit 1
fi
# Trim any whitespace from profile ICCIDs
iccidProfile1=$(echo "${iccidProfile1}" | tr -d '[:space:]')
[ -n "$iccidProfile2" ] && iccidProfile2=$(echo "${iccidProfile2}" | tr -d '[:space:]')
# Log the comparison values
log_message "INFO" "Comparing ICCIDs:"
log_message "INFO" "Current ICCID: ${current_iccid}"
log_message "INFO" "Profile1 ICCID: ${iccidProfile1}"
[ -n "$iccidProfile2" ] && log_message "INFO" "Profile2 ICCID: ${iccidProfile2}"
# Match ICCID and apply corresponding profile
if [ "${current_iccid}" = "${iccidProfile1}" ]; then
log_message "INFO" "Matched with Profile1, applying settings..."
if set_apn "$pdpType1" "$apnProfile1"; then
echo "APN set successfully" > /tmp/apn_result.txt
else
echo "Failed to set APN" > /tmp/apn_result.txt
fi
elif [ -n "$iccidProfile2" ] && [ "${current_iccid}" = "${iccidProfile2}" ]; then
log_message "INFO" "Matched with Profile2, applying settings..."
if set_apn "$pdpType2" "$apnProfile2"; then
echo "APN set successfully" > /tmp/apn_result.txt
else
echo "Failed to set APN" > /tmp/apn_result.txt
fi
else
log_message "WARN" "No matching ICCID profile found"
echo "No matching ICCID profile found" > /tmp/apn_result.txt
fi
EOF
# Make the script executable
chmod 755 /etc/quecmanager/apn_profile/apnProfiles.sh
# Add to rc.local if not already present
if ! grep -q "^[^#]*\/etc\/quecmanager\/apn_profile\/apnProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/apn_profile/apnProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/apn_profile/apnProfiles.sh
# Check the result
if [ -f /tmp/apn_result.txt ]; then
result=$(cat /tmp/apn_result.txt)
rm -f /tmp/apn_result.txt
case "$result" in
"APN set successfully")
echo '{"status": "success", "message": "APN profiles saved and applied successfully"}'
;;
"No matching ICCID profile found")
echo '{"status": "warning", "message": "APN profiles saved but no matching ICCID found"}'
;;
"Configuration file not found")
echo '{"status": "error", "message": "Configuration file not found"}'
;;
"Failed to get current ICCID")
echo '{"status": "error", "message": "Failed to get current ICCID"}'
;;
*)
echo '{"status": "error", "message": "APN profiles saved but failed to apply"}'
;;
esac
else
echo '{"status": "error", "message": "Something went wrong while processing APN profiles"}'
fi

View File

@@ -0,0 +1,38 @@
#!/bin/sh
# handle_sms.sh - CGI script to handle SMS web requests
# Content type declaration for CGI
echo "Content-type: application/json"
echo ""
# Check if atinout and jq are installed
if ! command -v atinout &> /dev/null || ! command -v jq &> /dev/null; then
echo '{"error": "Required tools (atinout or jq) are not installed"}'
exit 1
fi
# Check if the device exists
if [ ! -c "/dev/smd7" ]; then
echo '{"error": "Device /dev/smd7 not found"}'
exit 1
fi
# # Fetch all SMS messages and update the JSON file
# Disabled until the atinout bug is fixed
# if ! echo "AT+CMGL=\"ALL\"" | atinout - /dev/smd7 - | jq -R -s '
# split("\n") |
# map(select(length > 0)) |
# map(
# select(startswith("+CMGL:") or (. != "OK" and . != "ERROR"))
# ) |
# {messages: .}
# ' > /tmp/sms_inbox.json; then
# echo '{"error": "Failed to fetch SMS messages"}'
# exit 1
# fi
# Return the contents of the JSON file
if [ -f "/tmp/sms_inbox.json" ]; then
cat /tmp/sms_inbox.json
else
echo '{"error": "SMS inbox file not found"}'
fi

View File

@@ -0,0 +1,66 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error flag
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Remove the entire quecmanager directory
if [ -d "/etc/quecmanager/imei_profile/" ]; then
rm -rf /etc/quecmanager/imei_profile/
if [ $? -ne 0 ]; then
append_error "Failed to remove quecmanager directory"
fi
else
append_error "quecmanager directory not found"
fi
# Remove the line from rc.local
if [ -f "/etc/rc.local" ]; then
# Create a temporary file
temp_file=$(mktemp)
# Remove the imeiProfiles.sh line and copy to temp file
sed '/\/etc\/quecmanager\/imeiProfiles.sh/d' /etc/rc.local > "$temp_file"
# Check if sed command was successful
if [ $? -eq 0 ]; then
# Replace original file with modified version
mv "$temp_file" /etc/rc.local
if [ $? -ne 0 ]; then
append_error "Failed to update rc.local"
fi
else
append_error "Failed to modify rc.local"
rm -f "$temp_file"
fi
else
append_error "rc.local file not found"
fi
# Remove temporary files that might have been created
rm -f /tmp/imei_result.txt
rm -f /tmp/debug.log
rm -f /tmp/inputICCID.txt
rm -f /tmp/outputICCID.txt
rm -f /tmp/inputIMEI.txt
rm -f /tmp/outputIMEI.txt
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"IMEI profiles and configuration successfully removed\"}"
fi

View File

@@ -0,0 +1,39 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/imei_profile/imei_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo "{}"
exit 0
fi
# Read the configuration file
iccidProfile1=$(grep "^iccidProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
imeiProfile1=$(grep "^imeiProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
iccidProfile2=$(grep "^iccidProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
imeiProfile2=$(grep "^imeiProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
# Build the JSON response
echo "{"
# Add Profile 1 if it exists
if [ -n "$iccidProfile1" ]; then
echo " \"profile1\": {"
echo " \"iccid\": \"$iccidProfile1\","
echo " \"imei\": \"$imeiProfile1\""
echo " }"
# Add comma if Profile 2 exists
[ -n "$iccidProfile2" ] && echo " ,"
fi
# Add Profile 2 if it exists
if [ -n "$iccidProfile2" ]; then
echo " \"profile2\": {"
echo " \"iccid\": \"$iccidProfile2\","
echo " \"imei\": \"$imeiProfile2\""
echo " }"
fi
echo "}"

View File

@@ -0,0 +1,333 @@
#!/bin/sh
# Parse POST data (using busybox compatible method)
read -r QUERY_STRING
# Function to urldecode (busybox compatible version)
urldecode() {
local value="$1"
value="${value//+/ }"
value="${value//%/\\x}"
printf '%b' "$value"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
imeiProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile1=\([^&]*\).*/\1/p' | tr -d "'")
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
imeiProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile2=\([^&]*\).*/\1/p' | tr -d "'")
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
imeiProfile1=$(urldecode "$imeiProfile1")
iccidProfile2=$(urldecode "$iccidProfile2")
imeiProfile2=$(urldecode "$imeiProfile2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$imeiProfile1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Create directory with proper permissions
mkdir -p /etc/quecmanager/imei_profile
chmod 755 /etc/quecmanager/imei_profile
# Create a configuration file to store IMEI profiles
cat > /etc/quecmanager/imei_profile/imei_config.txt <<EOF
iccidProfile1=${iccidProfile1}
imeiProfile1=${imeiProfile1}
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/imei_profile/imei_config.txt <<EOF
iccidProfile2=${iccidProfile2}
imeiProfile2=${imeiProfile2}
EOF
fi
chmod 644 /etc/quecmanager/imei_profile/imei_config.txt
# Create the imeiProfiles.sh script with proper locking mechanism and logging
cat > /etc/quecmanager/imei_profile/imeiProfiles.sh <<'EOF'
#!/bin/sh
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/tmp/imei_profiles.log"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Enhanced logging function with debug level
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t imei_profiles "${level}: ${message}"
}
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1"
local wait_count=0
while [ $wait_count -lt 6 ]; do
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
log_message "DEBUG" "Waiting for ${command_type} to clear (attempt ${wait_count})"
sleep 1
wait_count=$((wait_count + 1))
else
return 0
fi
done
log_message "WARN" "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Simplified lock handling with debug
handle_lock() {
log_message "DEBUG" "Checking queue file status before lock"
if [ -f "$QUEUE_FILE" ]; then
log_message "DEBUG" "Current queue content: $(cat $QUEUE_FILE)"
else
log_message "DEBUG" "Queue file does not exist, creating it"
touch "$QUEUE_FILE"
fi
check_and_clean_stale "FETCH_LOCK"
log_message "DEBUG" "Adding AT_COMMAND entry to queue"
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
check_and_clean_stale "AT_COMMAND"
}
# Execute AT command without timeout dependency
execute_at_command() {
local command="$1"
local result=""
log_message "DEBUG" "Executing AT command: ${command}"
handle_lock
# Execute command and capture all output
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
log_message "DEBUG" "Removing our entry from queue"
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -ne 0 ]; then
log_message "ERROR" "Command failed with status $status: $command"
log_message "ERROR" "Command output: $result"
return 1
fi
log_message "DEBUG" "Command successful. Output: $result"
echo "$result"
return 0
}
# Get current ICCID with enhanced debug
get_current_iccid() {
local result
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to get current ICCID"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "ICCID attempt ${retry_count}"
result=$(execute_at_command "AT+ICCID")
local cmd_status=$?
log_message "DEBUG" "AT+ICCID command returned status: ${cmd_status}"
log_message "DEBUG" "AT+ICCID raw output: ${result}"
if [ $cmd_status -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
local iccid=$(echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]')
log_message "INFO" "Retrieved current ICCID: ${iccid}"
echo "${iccid}"
return 0
else
log_message "WARN" "Attempt ${retry_count} failed to get valid ICCID"
log_message "WARN" "Result: ${result}"
fi
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
log_message "INFO" "Waiting 2 seconds before retry"
sleep 2
fi
done
log_message "ERROR" "Failed to get ICCID after $max_retries attempts"
return 1
}
# Get current IMEI with enhanced debug
get_current_imei() {
local result
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to get current IMEI"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "IMEI attempt ${retry_count}"
result=$(execute_at_command "AT+CGSN")
local cmd_status=$?
log_message "DEBUG" "AT+CGSN command returned status: ${cmd_status}"
log_message "DEBUG" "AT+CGSN raw output: ${result}"
if [ $cmd_status -eq 0 ]; then
local imei=$(echo "$result" | grep -v "AT+CGSN" | grep -v "OK" | tr -d '\r\n[:space:]')
if [ -n "$imei" ]; then
log_message "INFO" "Retrieved current IMEI: ${imei}"
echo "${imei}"
return 0
fi
fi
log_message "WARN" "Attempt ${retry_count} failed to get valid IMEI"
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to get IMEI after $max_retries attempts"
return 1
}
# Set IMEI with enhanced debug
set_imei() {
local imei="$1"
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to set IMEI: ${imei}"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "IMEI set attempt ${retry_count}"
result=$(execute_at_command "AT+EGMR=1,7,\"$imei\";+QPOWD=1")
local cmd_status=$?
log_message "DEBUG" "AT+EGMR command returned status: ${cmd_status}"
log_message "DEBUG" "AT+EGMR raw output: ${result}"
if [ $cmd_status -eq 0 ] && echo "$result" | grep -q "OK"; then
log_message "INFO" "Successfully set IMEI: ${imei}"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to set IMEI after $max_retries attempts"
return 1
}
# Load configuration
if [ -f /etc/quecmanager/imei_profile/imei_config.txt ]; then
. /etc/quecmanager/imei_profile/imei_config.txt
log_message "INFO" "Loaded configuration - Profile1 ICCID: ${iccidProfile1}, IMEI: ${imeiProfile1}"
[ -n "$iccidProfile2" ] && log_message "INFO" "Profile2 ICCID: ${iccidProfile2}, IMEI: ${imeiProfile2}"
else
log_message "ERROR" "Configuration file not found"
echo "Configuration file not found" > /tmp/imei_result.txt
exit 1
fi
# Get current ICCID and IMEI
current_iccid=$(get_current_iccid)
current_imei=$(get_current_imei)
if [ $? -ne 0 ]; then
log_message "ERROR" "Failed to get current ICCID or IMEI"
echo "Failed to get current ICCID or IMEI" > /tmp/imei_result.txt
exit 1
fi
log_message "INFO" "Current ICCID: ${current_iccid}"
log_message "INFO" "Current IMEI: ${current_imei}"
# Match ICCID and apply corresponding profile
if [ "${current_iccid}" = "${iccidProfile1}" ]; then
log_message "INFO" "Matched with Profile1"
if [ "${current_imei}" != "${imeiProfile1}" ]; then
log_message "INFO" "IMEI needs updating for Profile1"
if set_imei "${imeiProfile1}"; then
echo "IMEI set successfully" > /tmp/imei_result.txt
else
echo "Failed to set IMEI" > /tmp/imei_result.txt
fi
else
log_message "INFO" "IMEI already matches Profile1"
echo "IMEI already correct" > /tmp/imei_result.txt
fi
elif [ -n "${iccidProfile2}" ] && [ "${current_iccid}" = "${iccidProfile2}" ]; then
log_message "INFO" "Matched with Profile2"
if [ "${current_imei}" != "${imeiProfile2}" ]; then
log_message "INFO" "IMEI needs updating for Profile2"
if set_imei "${imeiProfile2}"; then
echo "IMEI set successfully" > /tmp/imei_result.txt
else
echo "Failed to set IMEI" > /tmp/imei_result.txt
fi
else
log_message "INFO" "IMEI already matches Profile2"
echo "IMEI already correct" > /tmp/imei_result.txt
fi
else
log_message "WARN" "No matching ICCID profile found"
echo "No matching ICCID profile found" > /tmp/imei_result.txt
fi
EOF
# Make the script executable
chmod 755 /etc/quecmanager/imei_profile/imeiProfiles.sh
# Add to rc.local if not already present
if ! grep -q "^[^#]*\/etc\/quecmanager\/imei_profile\/imeiProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/imei_profile/imeiProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/imei_profile/imeiProfiles.sh
# Check the result
if [ -f /tmp/imei_result.txt ]; then
result=$(cat /tmp/imei_result.txt)
rm -f /tmp/imei_result.txt
case "$result" in
"IMEI set successfully")
echo '{"status": "success", "message": "IMEI profiles saved and applied successfully"}'
;;
"IMEI already correct")
echo '{"status": "success", "message": "IMEI profiles saved, no changes needed"}'
;;
"No matching ICCID profile found")
echo '{"status": "warning", "message": "IMEI profiles saved but no matching ICCID found"}'
;;
"Configuration file not found")
echo '{"status": "error", "message": "Configuration file not found"}'
;;
"Failed to get current ICCID or IMEI")
echo '{"status": "error", "message": "Failed to get current ICCID or IMEI"}'
;;
*)
echo '{"status": "error", "message": "IMEI profiles saved but failed to apply"}'
;;
esac
else
echo '{"status": "error", "message": "Something went wrong while processing IMEI profiles"}'
fi

View File

@@ -0,0 +1,201 @@
#!/bin/sh
# Configuration
CONFIG_FILE="/etc/cell_lock_schedule.conf"
STATUS_FILE="/tmp/cell_lock_status"
CELL_LOCK_SCRIPT="/usr/bin/set_cell_lock.sh"
# Function to create set_cell_lock.sh script
create_cell_lock_script() {
# Only create the script if it doesn't exist
if [ ! -f "$CELL_LOCK_SCRIPT" ]; then
cat >"$CELL_LOCK_SCRIPT" <<'EOL'
#!/bin/sh
ACTION=$1
LTE_PARAMS=$2
NR5G_PARAMS=$3
case "$ACTION" in
enable)
# Enable LTE lock if parameters exist
if [ -n "$LTE_PARAMS" ]; then
echo "AT+QNWLOCK=\"common/4g\",$LTE_PARAMS" | atinout - /dev/smd11 -
fi
# Enable NR5G lock if parameters exist
if [ -n "$NR5G_PARAMS" ]; then
echo "AT+QNWLOCK=\"common/5g\",$NR5G_PARAMS" | atinout - /dev/smd11 -
fi
;;
disable)
# Disable LTE lock
echo 'AT+QNWLOCK="common/4g",0' | atinout - /dev/smd11 -
# Disable NR5G lock
echo 'AT+QNWLOCK="common/5g",0' | atinout - /dev/smd11 -
;;
*)
echo "Invalid action"
exit 1
;;
esac
# Restart network registration to apply changes
echo "AT+COPS=2" | atinout - /dev/smd11 -
sleep 2
echo "AT+COPS=0" | atinout - /dev/smd11 -
exit 0
EOL
# Make the script executable
chmod +x "$CELL_LOCK_SCRIPT"
fi
}
# Function to remove set_cell_lock.sh script
remove_cell_lock_script() {
if [ -f "$CELL_LOCK_SCRIPT" ]; then
rm "$CELL_LOCK_SCRIPT"
fi
}
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Function to convert HH:MM to cron format
convert_to_cron_time() {
echo "$1" | awk -F: '{print $2, $1}'
}
# Function to save configuration
save_config() {
echo "START_TIME=$1" >"$CONFIG_FILE"
echo "END_TIME=$2" >>"$CONFIG_FILE"
echo "ENABLED=1" >>"$CONFIG_FILE"
}
# Function to disable scheduling
disable_scheduling() {
if [ -f "$CONFIG_FILE" ]; then
sed -i 's/ENABLED=1/ENABLED=0/' "$CONFIG_FILE"
fi
# Remove any existing cron jobs
crontab -l | grep -v "set_cell_lock.sh" | crontab -
# Remove the set_cell_lock.sh script
remove_cell_lock_script
}
# Function to get current status
get_status() {
if [ -f "$CONFIG_FILE" ]; then
ENABLED=$(grep "ENABLED=" "$CONFIG_FILE" | cut -d'=' -f2)
START_TIME=$(grep "START_TIME=" "$CONFIG_FILE" | cut -d'=' -f2)
END_TIME=$(grep "END_TIME=" "$CONFIG_FILE" | cut -d'=' -f2)
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"enabled\":$ENABLED,\"start_time\":\"$START_TIME\",\"end_time\":\"$END_TIME\"}"
else
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"enabled\":0,\"start_time\":\"\",\"end_time\":\"\"}"
fi
}
# Handle POST requests
if [ "$REQUEST_METHOD" = "POST" ]; then
# Read POST data
read -r POST_DATA
# Check if disabling is requested
echo "$POST_DATA" | grep -q "disable=true"
if [ $? -eq 0 ]; then
disable_scheduling
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"status\":\"success\",\"message\":\"Scheduling disabled\"}"
exit 0
fi
# Extract start and end times
START_TIME=$(echo "$POST_DATA" | grep -o 'start_time=[^&]*' | cut -d'=' -f2)
END_TIME=$(echo "$POST_DATA" | grep -o 'end_time=[^&]*' | cut -d'=' -f2)
# Decode times
START_TIME=$(urldecode "$START_TIME")
END_TIME=$(urldecode "$END_TIME")
# Validate times
if [ -z "$START_TIME" ] || [ -z "$END_TIME" ]; then
echo "Status: 400 Bad Request"
echo "Content-Type: application/json"
echo ""
echo "{\"error\":\"Missing start or end time\"}"
exit 1
fi
# Create set_cell_lock.sh script
create_cell_lock_script
# Convert times to cron format
CRON_START=$(convert_to_cron_time "$START_TIME")
CRON_END=$(convert_to_cron_time "$END_TIME")
# Save configuration
save_config "$START_TIME" "$END_TIME"
# Check current cell lock status and get parameters
LTE_STATUS=$(echo 'AT+QNWLOCK="common/4g"' | atinout - /dev/smd11 -)
NR5G_STATUS=$(echo 'AT+QNWLOCK="common/5g"' | atinout - /dev/smd11 -)
# Extract LTE parameters if locked
LTE_PARAMS=$(echo "$LTE_STATUS" | grep -o '"common/4g",[^[:space:]]*' | cut -d',' -f2-)
NR5G_PARAMS=$(echo "$NR5G_STATUS" | grep -o '"common/5g",[^[:space:]]*' | cut -d',' -f2-)
# Create temporary file for new crontab
TEMP_CRON=$(mktemp)
# Get existing crontab entries (excluding our script)
crontab -l 2>/dev/null | grep -v "set_cell_lock.sh" >"$TEMP_CRON"
# Add new entries
echo "$CRON_START * * * $CELL_LOCK_SCRIPT enable \"$LTE_PARAMS\" \"$NR5G_PARAMS\"" >>"$TEMP_CRON"
echo "$CRON_END * * * $CELL_LOCK_SCRIPT disable" >>"$TEMP_CRON"
# Install new crontab
crontab "$TEMP_CRON"
rm "$TEMP_CRON"
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"status\":\"success\",\"message\":\"Scheduling enabled\"}"
exit 0
fi
# Parse query string for GET requests
if [ "$REQUEST_METHOD" = "GET" ]; then
QUERY_STRING=$(echo "$QUERY_STRING" | sed 's/&/\n/g')
for param in $QUERY_STRING; do
case "$param" in
status=*)
get_status
exit 0
;;
esac
done
fi
# If no valid request is made
echo "Status: 400 Bad Request"
echo "Content-Type: application/json"
echo ""
echo "{\"error\":\"Invalid request\"}"
exit 1

View File

@@ -0,0 +1,50 @@
#!/bin/sh
# Set content type
printf "Content-Type: application/json\n\n"
# URL decode function
urldecode() {
echo "$*" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\\\x\1/g' | xargs -0 printf '%b'
}
# Extract indexes from query string
query=$(echo "$QUERY_STRING" | grep -o 'indexes=[^&]*' | cut -d= -f2)
indexes=$(urldecode "$query")
# Function to output JSON response
send_json() {
printf '{"status":"%s","message":"%s"}\n' "$1" "$2"
}
# Validate input
if [ -z "$indexes" ]; then
send_json "error" "No indexes provided"
exit 0
fi
# Initialize counters
success=0
failure=0
# Process each index
echo "$indexes" | tr ',' '\n' | while read -r index; do
if [ -n "$index" ] && [ "$index" -eq "$index" ] 2>/dev/null; then
if sms_tool delete "$index" 2>/dev/null; then
success=$((success + 1))
else
failure=$((failure + 1))
fi
fi
done
# Send response
if [ $success -gt 0 ]; then
if [ $failure -eq 0 ]; then
send_json "success" "Successfully deleted $success message(s)"
else
send_json "partial" "Deleted $success message(s), failed to delete $failure message(s)"
fi
else
send_json "error" "Failed to delete messages"
fi

View File

@@ -0,0 +1,10 @@
#!/bin/sh
printf "Content-type: application/json\r\n\r\n"
# Execute the command and return the JSON response
if command -v sms_tool > /dev/null 2>&1; then
sms_tool -j recv
else
printf '{"error": "sms_tool not found"}\n'
fi

View File

@@ -0,0 +1,57 @@
#!/bin/sh
echo "Content-Type: application/json"
echo "Cache-Control: no-cache"
echo ""
# Function to URL decode the string
urldecode() {
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}
# Function to escape JSON string
escape_json() {
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\n/\\n/g; s/\r/\\r/g; s/\t/\\t/g'
}
# Read POST data
read -r QUERY_STRING
# Extract phone and message from POST data
phone=$(echo "$QUERY_STRING" | grep -o 'phone=[^&]*' | cut -d= -f2)
message=$(echo "$QUERY_STRING" | grep -o 'message=[^&]*' | cut -d= -f2)
# URL decode the message
decoded_message=$(urldecode "$message")
# Validate inputs
if [ -z "$phone" ] || [ -z "$message" ]; then
echo '{"success":false,"error":"Phone number and message are required"}'
exit 0
fi
# Validate phone number (only numbers allowed)
if ! echo "$phone" | grep -q '^[0-9]\+$'; then
echo '{"success":false,"error":"Invalid phone number format"}'
exit 0
fi
# Try to send SMS and capture output
result=$(sms_tool send "$phone" "$decoded_message" 2>&1)
escaped_result=$(escape_json "$result")
# Check if SMS was sent successfully by looking for "sms sent sucessfully"
if echo "$result" | grep -q "sms sent sucessfully"; then
# Extract the message ID if present
message_id=$(echo "$result" | grep -o '[0-9]*$')
echo "{\"success\":true,\"message\":\"SMS sent successfully\",\"messageId\":\"$message_id\",\"raw\":\"$escaped_result\"}"
elif echo "$result" | grep -q "sms not sent, code 350"; then
# Kill any hanging sms_tool process
pkill -f "sms_tool send"
echo '{"success":false,"error":"No prepaid credit available"}'
else
# Kill any hanging sms_tool process
pkill -f "sms_tool send"
echo "{\"success\":false,\"error\":\"Failed to send SMS\",\"raw\":\"$escaped_result\"}"
fi

View File

@@ -0,0 +1,195 @@
#!/bin/sh
# Configuration
CONFIG_FILE="/etc/keep_alive_schedule.conf"
STATUS_FILE="/tmp/keep_alive_status"
SPEEDTEST_SCRIPT="/www/cgi-bin/home/speedtest/speedtest.sh"
# Function to convert HH:MM to minutes since midnight
time_to_minutes() {
echo "$1" | awk -F: '{print $1 * 60 + $2}'
}
# Function to validate time interval
validate_interval() {
START_TIME=$1
END_TIME=$2
INTERVAL_MINUTES=$3
# Convert times to minutes
START_MINUTES=$(time_to_minutes "$START_TIME")
END_MINUTES=$(time_to_minutes "$END_TIME")
# Calculate duration between start and end time
if [ $END_MINUTES -lt $START_MINUTES ]; then
# Handle case where end time is on the next day
DURATION=$((1440 - START_MINUTES + END_MINUTES))
else
DURATION=$((END_MINUTES - START_MINUTES))
fi
# Check if interval is longer than duration
if [ $INTERVAL_MINUTES -gt $DURATION ]; then
return 1
fi
return 0
}
# Function to generate cron time expression
generate_cron_time() {
START_TIME=$1
END_TIME=$2
INTERVAL=$3
START_HOUR=$(echo "$START_TIME" | cut -d: -f1 | sed 's/^0//')
START_MIN=$(echo "$START_TIME" | cut -d: -f2)
END_HOUR=$(echo "$END_TIME" | cut -d: -f1 | sed 's/^0//')
END_MIN=$(echo "$END_TIME" | cut -d: -f2)
# If end time is less than start time, it means we cross midnight
if [ $(time_to_minutes "$END_TIME") -lt $(time_to_minutes "$START_TIME") ]; then
# Create two cron entries for before and after midnight
echo "*/$INTERVAL $START_HOUR-23 * * * $SPEEDTEST_SCRIPT"
echo "*/$INTERVAL 0-$((END_HOUR - 1)) * * * $SPEEDTEST_SCRIPT"
else
echo "*/$INTERVAL $START_HOUR-$((END_HOUR - 1)) * * * $SPEEDTEST_SCRIPT"
fi
}
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Function to save configuration
save_config() {
echo "START_TIME=$1" >"$CONFIG_FILE"
echo "END_TIME=$2" >>"$CONFIG_FILE"
echo "INTERVAL=$3" >>"$CONFIG_FILE"
echo "ENABLED=1" >>"$CONFIG_FILE"
}
# Function to disable scheduling
disable_scheduling() {
if [ -f "$CONFIG_FILE" ]; then
sed -i 's/ENABLED=1/ENABLED=0/' "$CONFIG_FILE"
fi
# Remove any existing cron jobs
crontab -l | grep -v "$SPEEDTEST_SCRIPT" | crontab -
}
# Function to get current status
get_status() {
if [ -f "$CONFIG_FILE" ]; then
ENABLED=$(grep "ENABLED=" "$CONFIG_FILE" | cut -d'=' -f2)
START_TIME=$(grep "START_TIME=" "$CONFIG_FILE" | cut -d'=' -f2)
END_TIME=$(grep "END_TIME=" "$CONFIG_FILE" | cut -d'=' -f2)
INTERVAL=$(grep "INTERVAL=" "$CONFIG_FILE" | cut -d'=' -f2)
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"enabled\":$ENABLED,\"start_time\":\"$START_TIME\",\"end_time\":\"$END_TIME\",\"interval\":$INTERVAL}"
else
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"enabled\":0,\"start_time\":\"\",\"end_time\":\"\",\"interval\":0}"
fi
}
# Handle POST requests
if [ "$REQUEST_METHOD" = "POST" ]; then
# Read POST data
read -r POST_DATA
# Check if disabling is requested
echo "$POST_DATA" | grep -q "disable=true"
if [ $? -eq 0 ]; then
disable_scheduling
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"status\":\"success\",\"message\":\"Scheduling disabled\"}"
exit 0
fi
# Extract times and interval
START_TIME=$(echo "$POST_DATA" | grep -o 'start_time=[^&]*' | cut -d'=' -f2)
END_TIME=$(echo "$POST_DATA" | grep -o 'end_time=[^&]*' | cut -d'=' -f2)
INTERVAL=$(echo "$POST_DATA" | grep -o 'interval=[^&]*' | cut -d'=' -f2)
# Decode times
START_TIME=$(urldecode "$START_TIME")
END_TIME=$(urldecode "$END_TIME")
INTERVAL=$(urldecode "$INTERVAL")
# Validate times
if [ -z "$START_TIME" ] || [ -z "$END_TIME" ] || [ -z "$INTERVAL" ]; then
echo "Status: 400 Bad Request"
echo "Content-Type: application/json"
echo ""
echo "{\"error\":\"Missing start time, end time, or interval\"}"
exit 1
fi
# Validate interval is a number
if ! echo "$INTERVAL" | grep -q '^[0-9]\+$'; then
echo "Status: 400 Bad Request"
echo "Content-Type: application/json"
echo ""
echo "{\"error\":\"Interval must be a number in minutes\"}"
exit 1
fi
# Validate interval
if ! validate_interval "$START_TIME" "$END_TIME" "$INTERVAL"; then
echo "Status: 400 Bad Request"
echo "Content-Type: application/json"
echo ""
echo "{\"error\":\"Interval is longer than the time between start and end time\"}"
exit 1
fi
# Create temporary file for new crontab
TEMP_CRON=$(mktemp)
# Get existing crontab entries (excluding our script)
crontab -l 2>/dev/null | grep -v "$SPEEDTEST_SCRIPT" >"$TEMP_CRON"
# Generate and add cron entries
generate_cron_time "$START_TIME" "$END_TIME" "$INTERVAL" >>"$TEMP_CRON"
# Install new crontab
crontab "$TEMP_CRON"
rm "$TEMP_CRON"
# Save configuration
save_config "$START_TIME" "$END_TIME" "$INTERVAL"
echo "Status: 200 OK"
echo "Content-Type: application/json"
echo ""
echo "{\"status\":\"success\",\"message\":\"Keep-alive scheduling enabled\"}"
exit 0
fi
# Parse query string for GET requests
if [ "$REQUEST_METHOD" = "GET" ]; then
QUERY_STRING=$(echo "$QUERY_STRING" | sed 's/&/\n/g')
for param in $QUERY_STRING; do
case "$param" in
status=*)
get_status
exit 0
;;
esac
done
fi
# If no valid request is made
echo "Status: 400 Bad Request"
echo "Content-Type: application/json"
echo ""
echo "{\"error\":\"Invalid request\"}"
exit 1

View File

@@ -0,0 +1,61 @@
#!/bin/sh
# Configuration and log directories
CONFIG_DIR="/etc/quecmanager/quecwatch"
QUECWATCH_SCRIPT="${CONFIG_DIR}/quecwatch.sh"
RCLOCAL="/etc/rc.local"
LOG_DIR="/tmp/log/quecwatch"
DEBUG_LOG_FILE="${LOG_DIR}/debug.log"
# Log directory for cleaning process
CLEANUP_LOG_FILE="${LOG_DIR}/cleanup.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
# Function to log cleanup events
log_cleanup() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${CLEANUP_LOG_FILE}"
}
# Default response headers
echo "Content-type: application/json"
echo ""
# Cleanup function
cleanup_quecwatch() {
# Start logging cleanup process
log_cleanup "Starting QuecWatch cleanup process"
# Stop any running QuecWatch processes
log_cleanup "Stopping QuecWatch processes"
pkill -f "${QUECWATCH_SCRIPT}" >> "${CLEANUP_LOG_FILE}" 2>&1
# Remove QuecWatch script from rc.local
if [ -f "${RCLOCAL}" ]; then
log_cleanup "Removing QuecWatch entries from rc.local"
sed -i '\|/etc/quecmanager/quecwatch/quecwatch.sh|d' "${RCLOCAL}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
# Remove configuration directory
if [ -d "${CONFIG_DIR}" ]; then
log_cleanup "Removing configuration directory: ${CONFIG_DIR}"
rm -rf "${CONFIG_DIR}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
# Remove log directory
if [ -d "${LOG_DIR}" ]; then
log_cleanup "Removing log directory: ${LOG_DIR}"
rm -rf "${LOG_DIR}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
log_cleanup "QuecWatch cleanup completed successfully"
# Optional: Output JSON response
echo '{"status": "success", "message": "QuecWatch disabled and removed"}'
}
# Execute cleanup
cleanup_quecwatch
exit 0

View File

@@ -0,0 +1,411 @@
#!/bin/sh
# Read POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Configuration directory
CONFIG_DIR="/etc/quecmanager/quecwatch"
QUECWATCH_CONFIG="${CONFIG_DIR}/quecwatch.conf"
QUECWATCH_SCRIPT="${CONFIG_DIR}/quecwatch.sh"
RCLOCAL="/etc/rc.local"
LOG_DIR="/tmp/log/quecwatch"
DEBUG_LOG_FILE="${LOG_DIR}/debug.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
# Extract values from POST data
action=$(echo "$QUERY_STRING" | grep -o 'action=[^&]*' | cut -d= -f2)
ping_target=$(echo "$QUERY_STRING" | grep -o 'ping_target=[^&]*' | cut -d= -f2)
ping_interval=$(echo "$QUERY_STRING" | grep -o 'ping_interval=[^&]*' | cut -d= -f2)
ping_failures=$(echo "$QUERY_STRING" | grep -o 'ping_failures=[^&]*' | cut -d= -f2)
max_retries=$(echo "$QUERY_STRING" | grep -o 'max_retries=[^&]*' | cut -d= -f2)
connection_refresh=$(echo "$QUERY_STRING" | grep -o 'connection_refresh=[^&]*' | cut -d= -f2)
auto_sim_failover=$(echo "$QUERY_STRING" | grep -o 'auto_sim_failover=[^&]*' | cut -d= -f2)
sim_failover_schedule=$(echo "$QUERY_STRING" | grep -o 'sim_failover_schedule=[^&]*' | cut -d= -f2)
# URL decode the values
action=$(urldecode "$action")
ping_target=$(urldecode "$ping_target")
ping_interval=$(urldecode "$ping_interval")
ping_failures=$(urldecode "$ping_failures")
max_retries=$(urldecode "$max_retries")
connection_refresh=$(urldecode "$connection_refresh")
auto_sim_failover=$(urldecode "$auto_sim_failover")
sim_failover_schedule=$(urldecode "$sim_failover_schedule")
# Default response headers
echo "Content-type: application/json"
echo ""
# Validate inputs
if [ -z "$ping_target" ]; then
echo '{"status": "error", "message": "Ping target is required"}'
exit 1
fi
# Initialize configuration function
initialize_config() {
# Create config directory if not exists
mkdir -p "${CONFIG_DIR}"
# Write configuration with defaults and user-provided values
cat >"${QUECWATCH_CONFIG}" <<EOL
# QuecWatch Configuration File
# Ping Target (IP or domain to ping)
PING_TARGET=${ping_target}
# Interval between ping checks (in seconds)
PING_INTERVAL=${ping_interval:-30}
# Number of consecutive ping failures before taking action
PING_FAILURES=${ping_failures:-3}
# Maximum number of retry attempts
MAX_RETRIES=${max_retries:-5}
# Current retry count (should start at 0)
CURRENT_RETRIES=0
# Enable/Disable Connection Refresh
CONNECTION_REFRESH=${connection_refresh:-false}
# Number of connection refresh attempts
REFRESH_COUNT=${connection_refresh:+3}
# Enable/Disable Auto SIM Failover
AUTO_SIM_FAILOVER=${auto_sim_failover:-false}
# Schedule for checking initial SIM (in minutes)
# 0 means no scheduled check
SIM_FAILOVER_SCHEDULE=${sim_failover_schedule:-0}
# Indicate that QuecWatch is enabled
ENABLED=true
EOL
chmod 644 "${QUECWATCH_CONFIG}"
}
# Generate monitoring script function
generate_monitoring_script() {
cat >"${QUECWATCH_SCRIPT}" <<'EOL'
#!/bin/sh
# Load configuration
. /etc/quecmanager/quecwatch/quecwatch.conf
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/tmp/log/quecwatch/quecwatch.log"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Enhanced logging function with debug level
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t quecwatch "${level}: ${message}"
}
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1"
local wait_count=0
while [ $wait_count -lt 6 ]; do
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
log_message "DEBUG" "Waiting for ${command_type} to clear (attempt ${wait_count})"
sleep 1
wait_count=$((wait_count + 1))
else
return 0
fi
done
log_message "WARN" "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Handle lock with debug logging
handle_lock() {
log_message "DEBUG" "Checking queue file status before lock"
if [ -f "$QUEUE_FILE" ]; then
log_message "DEBUG" "Current queue content: $(cat $QUEUE_FILE)"
else
log_message "DEBUG" "Queue file does not exist, creating it"
touch "$QUEUE_FILE"
fi
check_and_clean_stale "FETCH_LOCK"
log_message "DEBUG" "Adding AT_COMMAND entry to queue"
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
check_and_clean_stale "AT_COMMAND"
}
# Execute AT command with enhanced error handling
execute_at_command() {
local command="$1"
local result=""
local retry_count=0
local max_retries=3
log_message "DEBUG" "Executing AT command: ${command}"
while [ $retry_count -lt $max_retries ]; do
handle_lock
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
log_message "DEBUG" "Removing our entry from queue"
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -eq 0 ] && [ -n "$result" ]; then
log_message "DEBUG" "Command successful. Output: $result"
echo "$result"
return 0
fi
log_message "WARN" "Command failed (attempt $((retry_count + 1))): $result"
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Command failed after $max_retries attempts: $command"
return 1
}
# Function to update retry count in config
update_retry_count() {
local new_retry_count=$1
sed -i "s/CURRENT_RETRIES=[0-9]*/CURRENT_RETRIES=${new_retry_count}/" /etc/quecmanager/quecwatch/quecwatch.conf
# Reload config to ensure latest values
. /etc/quecmanager/quecwatch/quecwatch.conf
}
# Function to get current SIM slot with enhanced error handling
get_current_sim() {
local output
local retry_count=0
local max_retries=3
while [ $retry_count -lt $max_retries ]; do
output=$(execute_at_command "AT+QUIMSLOT?")
if [ $? -eq 0 ] && echo "$output" | grep -q "+QUIMSLOT:"; then
echo "$output" | grep "+QUIMSLOT:" | awk '{print $2}'
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to get current SIM slot after $max_retries attempts"
return 1
}
# Function to switch SIM card with enhanced error handling
switch_sim_card() {
log_message "INFO" "Attempting to switch SIM card"
# Get current SIM slot
current_sim_slot=$(get_current_sim)
if [ $? -ne 0 ]; then
log_message "ERROR" "Failed to get current SIM slot"
return 1
fi # Changed from } to fi
# Toggle between SIM slots
new_sim_slot=$((current_sim_slot % 2 + 1))
log_message "INFO" "Switching from SIM slot ${current_sim_slot} to SIM slot ${new_sim_slot}"
if ! execute_at_command "AT+QUIMSLOT=${new_sim_slot}"; then
log_message "ERROR" "Failed to switch to SIM slot ${new_sim_slot}"
return 1
fi
sleep 10 # Allow time for SIM switch and network registration
return 0
}
# Function to check internet connectivity
check_internet() {
ping -c 3 ${PING_TARGET} > /dev/null 2>&1
return $?
}
# Function to perform connection recovery
perform_connection_recovery() {
local recovery_attempted=0
local recovery_successful=0
if [ "${CONNECTION_REFRESH}" = "true" ] && [ "${retry_trigger}" -eq 1 ] && [ "${REFRESH_COUNT}" -gt 0 ]; then
log_message "INFO" "Attempting connection refresh"
if ! execute_at_command "AT+COPS=2"; then
log_message "ERROR" "Failed to detach from network"
return 1
fi
sleep 2
if ! execute_at_command "AT+COPS=0"; then
log_message "ERROR" "Failed to reattach to network"
return 1
fi # <-- Changed from } to fi
sleep 5
if check_internet; then
log_message "INFO" "Connection refresh successful"
recovery_successful=1
return 0
fi
REFRESH_COUNT=$((REFRESH_COUNT - 1))
sed -i "s/REFRESH_COUNT=.*/REFRESH_COUNT=${REFRESH_COUNT}/" /etc/quecmanager/quecwatch/quecwatch.conf
recovery_attempted=1
fi
[ ${recovery_successful} -eq 1 ] && return 0 || return 1
}
# Store initial SIM slot
initial_sim_slot=""
if [ "${AUTO_SIM_FAILOVER}" = "true" ]; then
initial_sim_slot=$(get_current_sim)
if [ $? -eq 0 ]; then
log_message "INFO" "Auto SIM failover enabled. Initial SIM slot: ${initial_sim_slot}"
else
log_message "ERROR" "Failed to get initial SIM slot"
fi
fi
# Main monitoring loop
failure_count=0
retry_trigger=0
sim_failover_interval=0
while true; do
if ! check_internet; then
failure_count=$((failure_count + 1))
log_message "INFO" "Ping failed. Failure count: ${failure_count}"
if [ ${failure_count} -ge ${PING_FAILURES} ]; then
failure_count=0
retry_trigger=$((retry_trigger + 1))
update_retry_count ${retry_trigger}
log_message "INFO" "Failure threshold reached. Retry trigger: ${retry_trigger}"
if [ ${retry_trigger} -ge ${MAX_RETRIES} ]; then
if [ "${AUTO_SIM_FAILOVER}" = "true" ]; then
log_message "INFO" "Max retries exhausted. Attempting SIM failover."
if switch_sim_card && check_internet; then
log_message "INFO" "SIM failover successful"
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_message "ERROR" "SIM failover failed. Performing system reboot."
reboot
fi
else
log_message "INFO" "Max retries exhausted. Auto SIM failover disabled. Removing QuecWatch."
sed -i '\|/etc/quecmanager/quecwatch/quecwatch.sh|d' /etc/rc.local
reboot
exit 0
fi
else
if perform_connection_recovery; then
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_message "ERROR" "Recovery failed. Performing system reboot."
reboot
fi
fi
fi
else
failure_count=0
retry_trigger=0
update_retry_count 0
log_message "INFO" "Modem is connected to the internet"
if [ "${AUTO_SIM_FAILOVER}" = "true" ] && [ "${SIM_FAILOVER_SCHEDULE}" -gt 0 ]; then
current_sim_slot=$(get_current_sim)
if [ -n "${initial_sim_slot}" ] && [ "${current_sim_slot}" != "${initial_sim_slot}" ]; then
sim_failover_interval=$((sim_failover_interval + 1))
if [ $((sim_failover_interval * PING_INTERVAL)) -ge $((SIM_FAILOVER_SCHEDULE * 60)) ]; then
log_message "INFO" "Scheduled check: Attempting to switch back to initial SIM ${initial_sim_slot}"
if execute_at_command "AT+QUIMSLOT=${initial_sim_slot}"; then
sleep 10
if check_internet; then
log_message "INFO" "Initial SIM restored successfully"
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_message "WARN" "Initial SIM still not working. Switching back to backup SIM."
execute_at_command "AT+QUIMSLOT=${current_sim_slot}"
sleep 10
fi
else
log_message "ERROR" "Failed to switch to initial SIM"
fi
sim_failover_interval=0
fi
fi
fi
fi
sleep ${PING_INTERVAL}
done
EOL
chmod +x "${QUECWATCH_SCRIPT}"
# Run the script
"${QUECWATCH_SCRIPT}" &
}
# Enable QuecWatch
enable_quecwatch() {
initialize_config
generate_monitoring_script
if ! grep -q "${QUECWATCH_SCRIPT}" "${RCLOCAL}"; then
[ -f "${RCLOCAL}" ] || touch "${RCLOCAL}"
chmod +x "${RCLOCAL}"
sed -i '$i'"${QUECWATCH_SCRIPT} &" "${RCLOCAL}"
fi
# Output success JSON
echo '{"status": "success", "message": "QuecWatch enabled", "config": "'${QUECWATCH_CONFIG}'"}'
}
# Log debug information
{
echo "Timestamp: $(date)"
echo "Script Path: $0"
echo "Ping Target: $ping_target"
echo "Ping Interval: $ping_interval"
echo "Ping Failures: $ping_failures"
echo "Max Retries: $max_retries"
echo "Connection Refresh: $connection_refresh"
echo "Auto SIM Failover: $auto_sim_failover"
echo "SIM Failover Schedule: $sim_failover_schedule"
} >>"$DEBUG_LOG_FILE" 2>&1
# Enable QuecWatch
enable_quecwatch
exit 0

View File

@@ -0,0 +1,79 @@
#!/bin/sh
# Set headers for JSON response
echo "Content-type: application/json"
echo ""
# Configuration file path
CONFIG_FILE="/etc/quecmanager/quecwatch/quecwatch.conf"
# Check if configuration file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "inactive", "message": "QuecWatch is not configured"}'
exit 0
fi
# Function to safely get config value
get_config_value() {
grep "^$1=" "$CONFIG_FILE" | cut -d'=' -f2
}
# Check if QuecWatch is enabled
enabled=$(get_config_value "ENABLED")
if [ "$enabled" != "true" ]; then
echo '{"status": "inactive", "message": "QuecWatch is disabled"}'
exit 0
fi
# Fetch configuration values
ping_target=$(get_config_value "PING_TARGET")
ping_interval=$(get_config_value "PING_INTERVAL")
ping_failures=$(get_config_value "PING_FAILURES")
max_retries=$(get_config_value "MAX_RETRIES")
current_retries=$(get_config_value "CURRENT_RETRIES")
connection_refresh=$(get_config_value "CONNECTION_REFRESH")
refresh_count=$(get_config_value "REFRESH_COUNT")
# New configuration options
mobile_data_reconnect=$(get_config_value "MOBILE_DATA_RECONNECT")
auto_sim_failover=$(get_config_value "AUTO_SIM_FAILOVER")
sim_failover_schedule=$(get_config_value "SIM_FAILOVER_SCHEDULE")
# Default values if not set
mobile_data_reconnect=${mobile_data_reconnect:-false}
auto_sim_failover=${auto_sim_failover:-false}
sim_failover_schedule=${sim_failover_schedule:-30}
# Check monitoring script existence
QUECWATCH_SCRIPT="/etc/quecmanager/quecwatch/quecwatch.sh"
if [ ! -f "$QUECWATCH_SCRIPT" ]; then
echo '{"status": "error", "message": "Monitoring script is missing"}'
exit 0
fi
# Check log file for recent activity
LOG_FILE="/tmp/log/quecwatch/quecwatch.log"
last_log=""
if [ -f "$LOG_FILE" ]; then
last_log=$(tail -n 1 "$LOG_FILE")
fi
# Prepare JSON response
cat <<EOF
{
"status": "active",
"config": {
"pingTarget": "${ping_target}",
"pingInterval": ${ping_interval},
"pingFailures": ${ping_failures},
"maxRetries": ${max_retries},
"currentRetries": ${current_retries},
"connectionRefresh": ${connection_refresh},
"refreshCount": ${refresh_count:-0},
"mobileDataReconnect": ${mobile_data_reconnect},
"autoSimFailover": ${auto_sim_failover},
"simFailoverSchedule": ${sim_failover_schedule}
},
"lastActivity": "${last_log}"
}
EOF

View File

@@ -0,0 +1,195 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define file paths and configuration
QUEUE_FILE="/tmp/at_pipe.txt"
LOCK_KEYWORD="FETCH_DATA_LOCK"
MAX_WAIT=6 # Maximum seconds to wait for lock
# Function to output error in JSON format
output_error() {
printf '{"error": "%s"}\n' "$1"
exit 1
}
# Function to clean and add lock with simplified timeout logic
add_clean_lock() {
local TIMESTAMP=$(date +%s)
local WAIT_START=$(date +%s)
while true; do
local CURRENT_TIME=$(date +%s)
# After MAX_WAIT seconds, forcibly remove any existing lock
if [ $((CURRENT_TIME - WAIT_START)) -ge $MAX_WAIT ]; then
# Remove any existing lock entries regardless of owner
sed -i "/${LOCK_KEYWORD}/d" "$QUEUE_FILE"
logger -t at_commands "Removed existing lock after $MAX_WAIT seconds timeout"
fi
# Add our lock entry
printf '{"id":"%s","timestamp":"%s","command":"%s","status":"lock","pid":"%s","start_time":"%s"}\n' \
"${LOCK_KEYWORD}" \
"$(date '+%H:%M:%S')" \
"${LOCK_KEYWORD}" \
"$$" \
"$TIMESTAMP" >> "$QUEUE_FILE"
# Verify our lock was written
if grep -q "\"pid\":\"$$\".*\"start_time\":\"$TIMESTAMP\"" "$QUEUE_FILE"; then
logger -t at_commands "Lock created by PID $$ at $TIMESTAMP"
# Register cleanup handler
trap 'remove_lock; exit' INT TERM EXIT
return 0
fi
# If we haven't exceeded MAX_WAIT, sleep and try again
if [ $((CURRENT_TIME - WAIT_START)) -lt $MAX_WAIT ]; then
sleep 1
else
logger -t at_commands "Failed to acquire lock after $MAX_WAIT seconds"
return 1
fi
done
}
# Simple remove lock function that only removes our entry
remove_lock() {
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
logger -t at_commands "Lock removed by PID $$"
}
# Improved JSON string escaping function
escape_json() {
printf '%s' "$1" | awk '
BEGIN { RS="\n"; ORS="\\n" }
{
gsub(/\\/, "\\\\")
gsub(/"/, "\\\"")
gsub(/\r/, "")
gsub(/\t/, "\\t")
gsub(/\f/, "\\f")
gsub(/\b/, "\\b")
print
}
' | sed 's/\\n$//'
}
# Enhanced AT command execution with retries
execute_at_command() {
local CMD="$1"
local RETRY_COUNT=0
local MAX_RETRIES=3
local OUTPUT=""
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
OUTPUT=$(sms_tool at "$CMD" -t 4 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$OUTPUT" ]; then
echo "$OUTPUT"
return 0
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
[ $RETRY_COUNT -lt $MAX_RETRIES ] && sleep 1
done
logger -t at_commands "Command failed after $MAX_RETRIES attempts: $CMD"
return 1
}
# Enhanced command processing function
process_commands() {
local commands="$1"
local first=1
# Start JSON array
printf '['
# Process each command
for cmd in $commands; do
# Add comma separator if not first item
[ $first -eq 0 ] && printf ','
first=0
# Execute command with retries
OUTPUT=$(execute_at_command "$cmd")
local CMD_STATUS=$?
# Properly escape both command and output for JSON
ESCAPED_CMD=$(escape_json "$cmd")
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Format JSON object with proper escaping
if [ $CMD_STATUS -eq 0 ]; then
printf '{"command":"%s","response":"%s","status":"success"}' \
"${ESCAPED_CMD}" \
"${ESCAPED_OUTPUT}"
else
printf '{"command":"%s","response":"Command failed","status":"error"}' \
"${ESCAPED_CMD}"
fi
sleep 0.1
done
# Close JSON array
printf ']\n'
}
# Main process wrapper with automatic lock handling
main_with_clean_lock() {
# Set timeout for the entire script
( sleep 60; kill -TERM $$ 2>/dev/null ) &
TIMEOUT_PID=$!
if ! add_clean_lock; then
output_error "Failed to acquire lock for command processing"
kill $TIMEOUT_PID 2>/dev/null
exit 1
fi
# Process commands
process_commands "$COMMANDS"
# Clean up
remove_lock
kill $TIMEOUT_PID 2>/dev/null
}
# Define command sets
define_command_sets() {
COMMAND_SET_1='AT+QUIMSLOT? AT+CNUM AT+COPS? AT+CIMI AT+ICCID AT+CGSN AT+CPIN? AT+CGDCONT? AT+CREG? AT+CFUN? AT+QENG="servingcell" AT+QTEMP AT+CGCONTRDP AT+QCAINFO AT+QRSRP AT+QMAP="WWAN" AT+C5GREG=2;+C5GREG? AT+CGREG=2;+CGREG? AT+QRSRQ AT+QSINR'
COMMAND_SET_2='AT+CGDCONT? AT+CGCONTRDP AT+QNWPREFCFG="mode_pref" AT+QNWPREFCFG="nr5g_disable_mode" AT+QUIMSLOT?'
COMMAND_SET_3='AT+CGMI AT+CGMM AT+QGMR AT+CNUM AT+CIMI AT+ICCID AT+CGSN AT+QMAP="LANIP" AT+QMAP="WWAN" AT+QGETCAPABILITY'
COMMAND_SET_4='AT+QMAP="MPDN_RULE" AT+QMAP="DHCPV4DNS" AT+QCFG="usbnet"'
COMMAND_SET_5='AT+QRSRP AT+QRSRQ AT+QSINR AT+QCAINFO AT+QSPN'
COMMAND_SET_6='AT+CEREG=2;+CEREG? AT+C5GREG=2;+C5GREG? AT+CPIN? AT+CGDCONT? AT+CGCONTRDP AT+QMAP="WWAN" AT+QRSRP AT+QTEMP AT+QNETRC?'
COMMAND_SET_7='AT+QNWPREFCFG="policy_band" AT+QNWPREFCFG="lte_band";+QNWPREFCFG="nsa_nr5g_band";+QNWPREFCFG="nr5g_band"'
COMMAND_SET_8='AT+QNWLOCK="common/4g" AT+QNWLOCK="common/5g" AT+QNWLOCK="save_ctrl"'
}
# Main execution
define_command_sets
# Get command set from query string with validation
COMMAND_SET=$(echo "$QUERY_STRING" | grep -o 'set=[1-8]' | cut -d'=' -f2 | tr -cd '0-9')
if [ -z "$COMMAND_SET" ] || [ "$COMMAND_SET" -lt 1 ] || [ "$COMMAND_SET" -gt 8 ]; then
COMMAND_SET=1 # Default to set 1 if invalid or no set specified
fi
# Select the appropriate command set
case "$COMMAND_SET" in
1) COMMANDS="$COMMAND_SET_1";;
2) COMMANDS="$COMMAND_SET_2";;
3) COMMANDS="$COMMAND_SET_3";;
4) COMMANDS="$COMMAND_SET_4";;
5) COMMANDS="$COMMAND_SET_5";;
6) COMMANDS="$COMMAND_SET_6";;
7) COMMANDS="$COMMAND_SET_7";;
8) COMMANDS="$COMMAND_SET_8";;
esac
# Execute main process with clean lock handling
main_with_clean_lock

View File

@@ -0,0 +1,10 @@
#!/bin/sh
echo "Content-Type: application/json"
echo "Cache-Control: no-cache, no-store, must-revalidate"
echo "Pragma: no-cache"
echo "Expires: 0"
echo ""
# Basic response indicating the server is up
echo '{"alive": true}'

View File

@@ -0,0 +1,14 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Ping 8.8.8.8 with 2 packets and capture the result
if ping -c 2 8.8.8.8 > /dev/null 2>&1; then
# Ping was successful
echo '{"connection": "ACTIVE"}'
else
# Ping failed
echo '{"connection": "INACTIVE"}'
fi

View File

@@ -0,0 +1,20 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Run ethtool on eth0 and capture the output
ethtool_output=$(ethtool eth0)
# Extract Link Speed
speed=$(echo "$ethtool_output" | grep "Speed:" | awk '{print $2}')
# Extract Link Status
link_status=$(echo "$ethtool_output" | grep "Link detected:" | awk '{print $3}')
# Extract Auto-negotiation status
auto_negotiation=$(echo "$ethtool_output" | grep "Auto-negotiation:" | awk '{print $2}')
# Create JSON output
echo "{\"link_speed\": \"$speed\", \"link_status\": \"$link_status\", \"auto_negotiation\": \"$auto_negotiation\"}"

View File

@@ -0,0 +1,8 @@
#!/bin/sh
# Set content type to JSON
echo "Content-Type: application/json"
echo
# Read the JSON file and get only the last entry using jq
jq 'last' /www/signal_graphs/data_usage.json

View File

@@ -0,0 +1,119 @@
#!/bin/sh
# Set common headers
echo "Content-Type: application/json"
echo "Access-Control-Allow-Origin: *"
echo "Cache-Control: no-cache, no-store, must-revalidate"
echo ""
# Lock file path
LOCK_FILE="/tmp/hw_details.lock"
LOCK_TIMEOUT=10 # Maximum wait time in seconds
# Function to acquire lock
acquire_lock() {
local start_time=$(date +%s)
while [ -e "$LOCK_FILE" ]; do
# Check if lock is stale (older than LOCK_TIMEOUT seconds)
if [ -f "$LOCK_FILE" ]; then
local lock_time=$(stat -c %Y "$LOCK_FILE" 2>/dev/null)
local current_time=$(date +%s)
if [ $((current_time - lock_time)) -gt $LOCK_TIMEOUT ]; then
rm -f "$LOCK_FILE"
break
fi
fi
# Check if we've waited too long
if [ $(($(date +%s) - start_time)) -gt $LOCK_TIMEOUT ]; then
error_response "Timeout waiting for lock"
exit 1
fi
sleep 0.1
done
# Create lock file with current PID
echo $$ > "$LOCK_FILE"
}
# Function to release lock
release_lock() {
rm -f "$LOCK_FILE"
}
# Function to handle errors and return JSON
error_response() {
echo "{\"error\": \"$1\"}"
exit 1
}
# Function to cleanup on exit
cleanup() {
release_lock
exit $?
}
# Set trap for cleanup
trap cleanup EXIT INT TERM
# Function to get memory information
get_memory_info() {
free_output=$(free -b)
memory_info=$(echo "$free_output" | awk '/Mem:/ {print "{\"total\": " $2 ", \"used\": " $3 ", \"available\": " $7 "}"}')
echo "$memory_info"
}
# Function to get ethernet information
get_ethernet_info() {
interface=${1:-eth0}
# Check if ethtool is installed
if ! which ethtool >/dev/null 2>&1; then
error_response "ethtool not found"
fi
# Check if interface exists
if ! ip link show "$interface" >/dev/null 2>&1; then
error_response "Interface $interface not found"
fi
# Run ethtool and capture output
ethtool_output=$(ethtool "$interface" 2>/dev/null) || error_response "Failed to get ethernet information"
# Extract values using sed instead of grep -P
speed=$(echo "$ethtool_output" | sed -n 's/.*Speed: \([^[:space:]]*\).*/\1/p' || echo "Unknown")
link_status=$(echo "$ethtool_output" | sed -n 's/.*Link detected: \(yes\|no\).*/\1/p' || echo "unknown")
auto_negotiation=$(echo "$ethtool_output" | sed -n 's/.*Auto-negotiation: \(on\|off\).*/\1/p' || echo "unknown")
# Output JSON
echo "{\"link_speed\":\"$speed\",\"link_status\":\"$link_status\",\"auto_negotiation\":\"$auto_negotiation\"}"
}
# Main execution
# Acquire lock before proceeding
acquire_lock
# Parse query string for type and interface
type=$(echo "$QUERY_STRING" | sed -n 's/.*type=\([^&]*\).*/\1/p')
interface=$(echo "$QUERY_STRING" | sed -n 's/.*interface=\([^&]*\).*/\1/p')
# Default interface if not specified
[ -z "$interface" ] && interface="eth0"
# Convert type to lowercase using tr
type=$(echo "$type" | tr '[:upper:]' '[:lower:]')
# Check type parameter and call appropriate function
case "$type" in
"memory")
get_memory_info
;;
"eth")
get_ethernet_info "$interface"
;;
*)
error_response "Invalid type. Use 'memory' or 'eth'"
;;
esac
# Lock will be automatically released by the cleanup trap

View File

@@ -0,0 +1,30 @@
#!/bin/sh
# Ensure the script outputs proper CGI headers
echo "Content-Type: application/json"
echo ""
# Directory where JSON files are stored (adjust as needed)
JSON_DIR="/www/signal_graphs/"
# Function to safely read JSON file
read_json_file() {
local file="$1"
if [ -f "$file" ]; then
cat "$file"
else
echo "[]" # Return empty array if file doesn't exist
fi
}
# Collect signal metrics from JSON files
RSRP=$(read_json_file "${JSON_DIR}/rsrp.json")
RSRQ=$(read_json_file "${JSON_DIR}/rsrq.json")
SINR=$(read_json_file "${JSON_DIR}/sinr.json")
# Combine metrics into a single JSON object
printf '{
"rsrp": %s,
"rsrq": %s,
"sinr": %s
}' "$RSRP" "$RSRQ" "$SINR"

View File

@@ -0,0 +1,15 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Run free command and capture the output, using -b for bytes
free_output=$(free -b)
# Extract memory information using awk
# Skip the header, take the Mem: line, and extract total, used, and available
memory_info=$(echo "$free_output" | awk '/Mem:/ {print "{\"total\": " $2 ", \"used\": " $3 ", \"available\": " $7 "}"}')
# Output the JSON
echo "$memory_info"

View File

@@ -0,0 +1,24 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Ping 8.8.8.8 with 5 packets and capture the full output
ping_result=$(ping -c 5 8.8.8.8)
# Check if ping was successful
if [ $? -eq 0 ]; then
# Extract the average latency using awk
avg_latency=$(echo "$ping_result" | awk '/avg/ {split($4, a, "/"); print int(a[2])}')
# If average latency was extracted, return it
if [ ! -z "$avg_latency" ]; then
echo "{\"connection\": \"ACTIVE\", \"latency\": $avg_latency}"
else
echo '{"connection": "ACTIVE", "latency": 0}'
fi
else
# Ping failed
echo '{"connection": "INACTIVE", "latency": 0}'
fi

View File

@@ -0,0 +1,11 @@
#!/bin/sh
export HOME=/tmp/home
# Create named pipe for speedtest output if it doesn't exist
[ ! -p /tmp/realtime_spd.json ] && mkfifo /tmp/realtime_spd.json
# Run speedtest in background
/usr/bin/speedtest --accept-license -f json -p yes --progress-update-interval=100 > /tmp/realtime_spd.json
# Remove named pipe
rm /tmp/realtime_spd.json

View File

@@ -0,0 +1,13 @@
#!/bin/sh
echo "Content-Type: text/event-stream"
echo "Cache-Control: no-cache"
echo "Connection: keep-alive"
echo ""
# Use cat to read from the FIFO
cat /tmp/realtime_spd.json | while read line; do
echo "data: $line"
echo
sleep 0.1
done

View File

@@ -0,0 +1,10 @@
#!/bin/sh
# /www/cgi-bin/start_speedtest.sh
echo "Content-Type: application/json"
echo ""
# Run speedtest in background
/www/cgi-bin/home/speedtest/speedtest.sh
# Immediately return a success response
echo '{"status":"started"}'

View File

@@ -0,0 +1,37 @@
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
start_service() {
# echo "Starting QuecManager services"
procd_open_instance
procd_set_param command /www/cgi-bin/services/log_signal_metrics.sh
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
procd_open_instance
procd_set_param command /www/cgi-bin/services/at_queue_processor.sh
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
procd_open_instance
procd_set_param command /www/cgi-bin/services/clear_logs.sh
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
echo "Signal Metrics Logger Running"
echo "All QuecManager services Running"
}
stop_service() {
# procd will handle stopping all instances automatically
echo "Stopping QuecManager services."
}

View File

@@ -0,0 +1,169 @@
#!/bin/sh
QUEUE_FILE="/tmp/at_pipe.txt"
RESULT_FILE="/tmp/at_results.json"
LOG_FILE="/var/log/at_commands.log"
# Define all lock keywords
FETCH_LOCK_KEYWORD="FETCH_DATA_LOCK"
SIGNAL_LOCK_KEYWORD="SIGNAL_METRICS_LOCK"
# Combine keywords for pattern matching
ALL_LOCK_KEYWORDS="${FETCH_LOCK_KEYWORD}\\|${SIGNAL_LOCK_KEYWORD}"
# Create or clear necessary files
touch "${QUEUE_FILE}"
[ ! -f "${RESULT_FILE}" ] && echo '[]' > "${RESULT_FILE}"
# Log messages to the log file
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG_FILE}"
}
# Escape special characters for JSON
escape_json() {
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g'
}
# Function to check if any lock is present
is_system_locked() {
grep -q "\"command\":\"\\(${ALL_LOCK_KEYWORDS}\\)\"" "${QUEUE_FILE}"
return $?
}
# Process a single command
process_command() {
local command="$1"
local timestamp="$2"
local cmd_id="$3"
log_message "Processing command: ${command} (ID: ${cmd_id})"
# Check if sms_tool exists and is executable
if ! which sms_tool >/dev/null 2>&1; then
log_message "Error: sms_tool not found in PATH"
result="sms_tool not found"
exit_code=1
else
# Execute the AT command using sms_tool
result=$(sms_tool at "${command}" 2>&1)
exit_code=$?
log_message "Command output: ${result}"
log_message "Exit code: ${exit_code}"
fi
# Escape the command and result for JSON
escaped_command=$(escape_json "${command}")
escaped_result=$(echo "${result}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g' | tr -d '\r')
# Generate the result JSON
if [ ${exit_code} -eq 0 ]; then
log_message "Command successful: ${command}"
RESULT_JSON=$(printf '{"id":"%s","status":"success","command":"%s","response":"%s","queued_at":"%s","executed_at":"%s"}' \
"${cmd_id}" "${escaped_command}" "${escaped_result}" "${timestamp}" "$(date '+%H:%M:%S')")
else
log_message "Command failed: ${command}"
RESULT_JSON=$(printf '{"id":"%s","status":"error","command":"%s","error":"%s","queued_at":"%s","executed_at":"%s"}' \
"${cmd_id}" "${escaped_command}" "${escaped_result}" "${timestamp}" "$(date '+%H:%M:%S')")
fi
# Update the results file safely
if ! current_results=$(cat "${RESULT_FILE}" 2>/dev/null); then
log_message "Error reading results file, initializing new one"
echo '[]' > "${RESULT_FILE}"
current_results='[]'
fi
# Append the result JSON to the results file
if ! echo "${current_results}" | jq --argjson new "${RESULT_JSON}" '. + [$new]' > "${RESULT_FILE}.tmp"; then
log_message "Error updating results file"
return 1
fi
mv "${RESULT_FILE}.tmp" "${RESULT_FILE}"
log_message "Successfully updated results file"
return ${exit_code}
}
# Check if an entry is a lock entry
is_lock_entry() {
local line="$1"
echo "${line}" | grep -q "\"command\":\"\\(${ALL_LOCK_KEYWORDS}\\)\""
return $?
}
# Process pending commands in the queue
process_pending_commands() {
while true; do
# Check if any lock is present
if is_system_locked; then
local lock_type=$(grep -o "\"command\":\"[^\"]*\"" "${QUEUE_FILE}" | grep "${ALL_LOCK_KEYWORDS}")
log_message "System is locked: ${lock_type}, waiting..."
sleep 0.5
continue
fi
# Read the first line from the queue
line=$(head -n 1 "${QUEUE_FILE}" 2>/dev/null)
if [ -n "${line}" ]; then
log_message "Processing queue entry: ${line}"
# Skip processing if it's a lock entry
if is_lock_entry "${line}"; then
log_message "Found lock entry, skipping"
sed -i '1d' "${QUEUE_FILE}"
continue
fi
# Validate JSON before processing
if ! echo "${line}" | jq empty 2>/dev/null; then
log_message "Invalid JSON in queue, skipping line"
sed -i '1d' "${QUEUE_FILE}"
continue
fi
# Parse the command, timestamp, and ID from the JSON entry
command=$(echo "${line}" | jq -r '.command // empty')
timestamp=$(echo "${line}" | jq -r '.timestamp // empty')
cmd_id=$(echo "${line}" | jq -r '.id // empty')
if [ -z "${command}" ] || [ -z "${timestamp}" ] || [ -z "${cmd_id}" ]; then
log_message "Missing required fields in JSON, skipping"
sed -i '1d' "${QUEUE_FILE}"
continue
fi
# Process the command
process_command "${command}" "${timestamp}" "${cmd_id}"
# Remove the processed line from the queue
sed -i '1d' "${QUEUE_FILE}"
# Add a small delay between commands
sleep 0.1
else
# No commands in queue, wait briefly before checking again
sleep 0.5
break
fi
done
}
# Main queue monitoring loop
process_queue() {
log_message "Starting queue processor with multiple lock support"
while true; do
# Process any pending commands
process_pending_commands
# Wait for changes to the queue file
inotifywait -q -e modify,create "${QUEUE_FILE}" >/dev/null 2>&1
# Small delay to allow file to stabilize
sleep 0.1
done
}
# Start processing the queue
log_message "Queue processor started with file monitoring and multiple lock support"
process_queue

View File

@@ -0,0 +1,38 @@
#!/bin/sh
# Script for SMS initialization and initial fetch
# Check if atinout and jq are installed
if ! command -v atinout &> /dev/null || ! command -v jq &> /dev/null; then
echo "Error: Required tools (atinout or jq) are not installed"
exit 1
fi
# Check if the device exists
if [ ! -c "/dev/smd7" ]; then
echo "Error: Device /dev/smd7 not found"
exit 1
fi
# Set SMS text mode
if ! echo "AT+CMGF=1" | atinout - /dev/smd7 -; then
echo "Error: Failed to set SMS text mode"
exit 1
fi
# Wait for 2 seconds
sleep 2
# Fetch initial SMS messages
if ! echo "AT+CMGL=\"ALL\"" | atinout - /dev/smd7 - | jq -R -s '
split("\n") |
map(select(length > 0)) |
map(
select(startswith("+CMGL:") or (. != "OK" and . != "ERROR"))
) |
{messages: .}
' > /tmp/sms_inbox.json; then
echo "Error: Failed to fetch SMS messages"
exit 1
fi
# Exit successfully
exit 0

View File

@@ -0,0 +1,32 @@
#!/bin/sh
# Script path
SCRIPT_PATH=$(readlink -f "$0")
# Fix the spacing in the cron line to ensure exactly 5 fields
CRON_LINE="0 0 * * * $SCRIPT_PATH"
# Install crontab if not already present
if ! crontab -l | grep -Fq "$SCRIPT_PATH"; then
# Get existing crontab - ensuring clean formatting
(crontab -l 2>/dev/null | grep -v "$SCRIPT_PATH" || true; echo "$CRON_LINE") | crontab -
if [ $? -eq 0 ]; then
logger -t log_cleanup "Successfully installed crontab job"
else
logger -t log_cleanup "Failed to install crontab job"
exit 1
fi
fi
# Clean specified log files using echo redirection
echo "" > /tmp/apn_profiles.log
echo "" > /tmp/imei_profiles.log
echo "" > /var/log/at_commands.log
# Add error handling
if [ $? -ne 0 ]; then
logger -t log_cleanup "Failed to clean one or more log files"
exit 1
fi
logger -t log_cleanup "Successfully cleaned log files"

View File

@@ -0,0 +1,130 @@
#!/bin/sh
# Configuration
LOGDIR="/www/signal_graphs"
MAX_ENTRIES=10
INTERVAL=60
QUEUE_FILE="/tmp/at_pipe.txt"
FETCH_LOCK_KEYWORD="FETCH_LOCK"
PAUSE_FILE="/tmp/signal_logging.pause"
# Ensure the directory exists
mkdir -p "$LOGDIR"
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1" # Either "FETCH_LOCK" or "AT_COMMAND"
local wait_count=0
while [ $wait_count -lt 6 ]; do
# Check if our type of entry exists
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
sleep 1
wait_count=$((wait_count + 1))
else
# Entry is gone, we can proceed
return 0
fi
done
# If we get here, entry is stale - remove it
logger -t signal_metrics "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Simplified lock handling
handle_lock() {
# First check and clean any FETCH_LOCK entries
check_and_clean_stale "FETCH_LOCK"
# Add our own entry
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >>"$QUEUE_FILE"
# Then check and clean our own entry if it gets stuck
check_and_clean_stale "AT_COMMAND"
}
# Clean output function
clean_output() {
local output=""
read -r line
while read -r line; do
case "$line" in
"OK" | "")
continue
;;
*)
if [ -n "$output" ]; then
output="$output\\n$line"
else
output="$line"
fi
;;
esac
done
echo "$output"
}
# Execute AT command
execute_at_command() {
local COMMAND="$1"
handle_lock
local OUTPUT=$(sms_tool at "$COMMAND" -t 4 2>/dev/null | clean_output)
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE" # Remove our entry
echo "$OUTPUT"
}
# Log signal metric
log_signal_metric() {
[ -f "$PAUSE_FILE" ] && return
local COMMAND="$1"
local FILENAME="$2"
local LOGFILE="$LOGDIR/$FILENAME"
mkdir -p "$(dirname "$LOGFILE")"
local TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
local SIGNAL_OUTPUT=$(execute_at_command "$COMMAND")
[ ! -s "$LOGFILE" ] && echo "[]" >"$LOGFILE"
if [ -n "$SIGNAL_OUTPUT" ]; then
local TEMP_FILE="${LOGFILE}.tmp.$$"
if jq --arg dt "$TIMESTAMP" \
--arg out "$SIGNAL_OUTPUT" \
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
"$LOGFILE" >"$TEMP_FILE"; then
mv "$TEMP_FILE" "$LOGFILE"
else
rm -f "$TEMP_FILE"
return 1
fi
fi
}
# Main continuous logging function
start_continuous_logging() {
sleep 20
logger -t signal_metrics "Starting continuous signal metrics logging (PID: $$)"
trap 'logger -t signal_metrics "Stopping signal metrics logging"; exit 0' INT TERM
while true; do
if [ ! -f "$PAUSE_FILE" ]; then
log_signal_metric "AT+QRSRP" "rsrp.json"
log_signal_metric "AT+QRSRQ" "rsrq.json"
log_signal_metric "AT+QSINR" "sinr.json"
log_signal_metric "AT+QGDCNT?;+QGDNRCNT?" "data_usage.json"
fi
sleep "$INTERVAL"
done
}
# Start the continuous logging
start_continuous_logging

View File

@@ -0,0 +1,52 @@
#!/bin/sh
# Set Content-Type for CGI script
echo "Content-type: application/json"
echo ""
# Read POST data
read POST_DATA
# Debug log
DEBUG_LOG="/tmp/password_change.log"
# Extract the passwords from POST data
OLD_PASSWORD=$(echo "$POST_DATA" | sed -n 's/^.*oldPassword=\([^&]*\).*$/\1/p')
NEW_PASSWORD=$(echo "$POST_DATA" | sed -n 's/^.*newPassword=\([^&]*\).*$/\1/p')
# URL-decode the passwords
OLD_PASSWORD=$(echo "$OLD_PASSWORD" | sed 's/+/ /g;s/%\(..\)/\\x\1/g' | xargs -0 printf "%b")
NEW_PASSWORD=$(echo "$NEW_PASSWORD" | sed 's/+/ /g;s/%\(..\)/\\x\1/g' | xargs -0 printf "%b")
# User to change password for
USER="root"
# Verify old password first
USER_SHADOW_ENTRY=$(grep "^$USER:" /etc/shadow)
if [ -z "$USER_SHADOW_ENTRY" ]; then
echo '{"state":"failed", "message":"User not found"}'
exit 1
fi
# Extract current password hash and salt
USER_HASH=$(echo "$USER_SHADOW_ENTRY" | cut -d: -f2)
SALT=$(echo "$USER_HASH" | cut -d'$' -f3)
# Generate hash from old password
OLD_GENERATED_HASH=$(echo "$OLD_PASSWORD" | openssl passwd -1 -salt "$SALT" -stdin)
# Verify old password
if [ "$OLD_GENERATED_HASH" != "$USER_HASH" ]; then
echo '{"state":"failed", "message":"Current password is incorrect"}'
exit 1
fi
# Change password using passwd command
# We need to pass both the new password and its confirmation
(echo "$NEW_PASSWORD"; echo "$NEW_PASSWORD") | passwd $USER 2>> $DEBUG_LOG
if [ $? -eq 0 ]; then
echo '{"state":"success", "message":"Password changed successfully"}'
else
echo '{"state":"failed", "message":"Failed to change password"}'
fi

View File

@@ -0,0 +1,38 @@
#!/bin/sh
# Script for SMS initialization and initial fetch
# Check if atinout and jq are installed
if ! command -v atinout &> /dev/null || ! command -v jq &> /dev/null; then
echo "Error: Required tools (atinout or jq) are not installed"
exit 1
fi
# Check if the device exists
if [ ! -c "/dev/smd7" ]; then
echo "Error: Device /dev/smd7 not found"
exit 1
fi
# Set SMS text mode
if ! echo "AT+CMGF=1" | atinout - /dev/smd7 -; then
echo "Error: Failed to set SMS text mode"
exit 1
fi
# Wait for 2 seconds
sleep 2
# Fetch initial SMS messages
if ! echo "AT+CMGL=\"ALL\"" | atinout - /dev/smd7 - | jq -R -s '
split("\n") |
map(select(length > 0)) |
map(
select(startswith("+CMGL:") or (. != "OK" and . != "ERROR"))
) |
{messages: .}
' > /tmp/sms_inbox.json; then
echo "Error: Failed to fetch SMS messages"
exit 1
fi
# Exit successfully
exit 0

View File

@@ -0,0 +1,38 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Configuration file path
CONFIG_FILE="/etc/quecManager.conf"
# Check if the config file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"error": "Configuration file not found"}'
exit 1
fi
# Initialize variables
AT_PORT=""
AT_PORT_CUSTOM=""
DATA_REFRESH_RATE=""
# Read the config file line by line and extract values
while IFS='=' read -r key value; do
# Remove leading/trailing whitespace
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
case "$key" in
"AT_port") AT_PORT="$value" ;;
"AT_port_custom") AT_PORT_CUSTOM="$value" ;;
"data_refresh_rate") DATA_REFRESH_RATE="$value" ;;
esac
done <"$CONFIG_FILE"
# Output JSON
echo "{"
echo " \"AT_port\": \"$AT_PORT\","
echo " \"AT_port_custom\": \"$AT_PORT_CUSTOM\","
echo " \"data_refresh_rate\": $DATA_REFRESH_RATE"
echo "}"

View File

@@ -0,0 +1,64 @@
#!/bin/sh
# Send CGI headers first
echo "Content-Type: application/json"
echo "Cache-Control: no-cache"
echo
# Initialize variables for file paths
APN_SCRIPT="/etc/quecmanager/apn_profile/apnProfiles.sh"
IMEI_SCRIPT="/etc/quecmanager/imei_profile/imeiProfiles.sh"
# Function to output JSON
output_json() {
local status="$1"
local message="$2"
echo "{\"status\": \"$status\", \"message\": \"$message\"}"
}
# Function to execute script if it exists
execute_if_exists() {
local script_path="$1"
if [ -f "$script_path" ] && [ -x "$script_path" ]; then
$script_path >/dev/null 2>&1
return $?
fi
return 2
}
# Main execution
main() {
scripts_executed=0
has_error=0
# Try to execute APN script
execute_if_exists "$APN_SCRIPT"
apn_result=$?
if [ $apn_result -eq 0 ]; then
scripts_executed=$(($scripts_executed + 1))
elif [ $apn_result -eq 1 ]; then
has_error=1
fi
# Try to execute IMEI script
execute_if_exists "$IMEI_SCRIPT"
imei_result=$?
if [ $imei_result -eq 0 ]; then
scripts_executed=$(($scripts_executed + 1))
elif [ $imei_result -eq 1 ]; then
has_error=1
fi
# Output appropriate message based on results
if [ $scripts_executed -eq 0 ]; then
output_json "info" "No scripts to restart"
elif [ $has_error -eq 1 ]; then
output_json "error" "Error executing one or more scripts"
else
output_json "success" "Scripts restarted successfully"
fi
}
# Run main function
main

View File

@@ -0,0 +1,11 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Get the IP address of the br-lan interface
brlan_ip=$(ip route | grep 'dev br-lan proto kernel scope link' | awk '{print $9}')
# Output the IP in JSON format
echo "{\"br_lan_ip\": \"$brlan_ip\"}"

View File

@@ -0,0 +1,29 @@
#!/bin/sh
# save-config.sh
echo "Content-Type: application/json"
echo ""
# Read POST data
read -n $CONTENT_LENGTH POST_DATA
# Configuration file path
CONFIG_FILE="/etc/quecManager.conf"
# Parse JSON input and update config file
AT_PORT=$(echo "$POST_DATA" | grep -o '"AT_port":"[^"]*"' | cut -d'"' -f4)
AT_PORT_CUSTOM=$(echo "$POST_DATA" | grep -o '"AT_port_custom":"[^"]*"' | cut -d'"' -f4)
DATA_REFRESH_RATE=$(echo "$POST_DATA" | grep -o '"data_refresh_rate":"[^"]*"' | cut -d'"' -f4)
# Create new config content
cat > "$CONFIG_FILE" << EOF
AT_port = $AT_PORT
AT_port_custom = $AT_PORT_CUSTOM
data_refresh_rate = $DATA_REFRESH_RATE
EOF
# Check if write was successful
if [ $? -eq 0 ]; then
echo '{"success": true, "message": "Configuration saved successfully"}'
else
echo '{"success": false, "error": "Failed to save configuration"}'
fi