# How SmsForwarder Implements SMS Command Control with the smsf# Prefix

> Discover how SmsForwarder uses the smsf# prefix to implement SMS command control. Securely manage Wi-Fi, FRPC tunnels, and power remotely with this powerful tool.

- Repository: [pppscn/SmsForwarder](https://github.com/pppscn/SmsForwarder)
- Tags: internals
- Published: 2026-06-22

---

**SmsForwarder listens for incoming SMS messages prefixed with `smsf#`, validates the sender against a safe-phone list, parses the remaining text into function-action-parameter triples, and dispatches commands to control Wi-Fi, FRPC tunnels, system power, or relay outbound SMS.**

The SmsForwarder app ([pppscn/SmsForwarder](https://github.com/pppscn/SmsForwarder)) provides a lightweight remote-control interface that allows users to trigger actions on an Android device via specially formatted text messages. By implementing SMS command control with the `smsf#` prefix, the app transforms incoming texts into executable commands without requiring internet connectivity.

## Receiving and Validating SMS Commands

The entry point for all remote commands is the `SmsReceiver` broadcast receiver located in [`app/src/main/kotlin/cn/ppps/forwarder/receiver/SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/receiver/SmsReceiver.kt). When the device receives an SMS, the receiver first checks whether the command feature is enabled via `SettingUtils.enableSmsCommand` and then inspects the message body for the mandatory `smsf#` prefix.

```kotlin
if (SettingUtils.enableSmsCommand && msg.startsWith("smsf#")) { … }

```

*(see line 66 of [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt))*

Before processing, the receiver validates the sender's phone number against a user-defined safe-phone list stored in the app settings. Only messages from explicitly allowed numbers are accepted, preventing unauthorized remote access.

## Parsing the smsf# Syntax

Once validated, the prefix is stripped and the remainder is passed to `SmsCommandUtils.execute()` (lines 44-45 of [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt)). The core parsing logic resides in [`app/src/main/kotlin/cn/ppps/forwarder/utils/SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/utils/SmsCommandUtils.kt), where the command string is split into a maximum of three segments using the `#` delimiter.

```kotlin
val cmdList = smsCommand.split("#", limit = 3)
val function = cmdList[0]          // e.g., "wifi", "frpc", "system"
val action   = cmdList[1]          // e.g., "on", "start", "reboot"
val param    = if (cmdList.count() > 2) cmdList[2] else ""

```

*(see lines 37-44 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt))*

This structure creates a consistent grammar: `smsf#<function>#<action>#<optional_parameter>`.

## Command Dispatch and Implementation

A Kotlin `when` statement routes the parsed request to the appropriate handler. The following subsections detail the implementation for each supported command category.

### FRPC Tunnel Control

The `frpc` command manages Frp (Fast Reverse Proxy) tunnels via the native `Frpclib` library. When the function is `frpc`, the action (`start` or `stop`) and optional UID parameter determine which tunnels to control.

```kotlin
// Start all autorun configs or a specific UID
Frpclib.runContent(config.uid, config.file)

// Stop specific tunnel
Frpclib.close(uid)

```

*(see lines 45-78 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt))*

### HTTP Server Management

The `httpserver` command controls the built-in `HttpServerService`. Sending `smsf#httpserver#start` triggers an explicit Intent to launch the service, while `stop` terminates it.

```kotlin
val intent = Intent(context, HttpServerService::class.java)
context.startService(intent)

```

*(see lines 81-89 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt))*

### System Operations

The `system` function executes privileged device actions. Before invoking `reboot` or `shutdown`, the code verifies root access via `DeviceUtils.isDeviceRooted()`.

```kotlin
when (action) {
    "reboot" -> DeviceUtils.reboot()
    "shutdown" -> DeviceUtils.shutdown()
}

```

*(see lines 91-116 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt))*

### Wi-Fi Toggling

The `wifi` command uses the Android `WifiManager` to toggle the radio state. This requires no root access but does need the appropriate `CHANGE_WIFI_STATE` permission.

```kotlin
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
wifiManager.isWifiEnabled = (action == "on")

```

*(see lines 118-124 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt))*

### SMS Relay

The `sms` function parses a JSON payload to send an outbound message through a specific SIM slot. The JSON structure (`SmsSendData`) includes `phoneNumbers`, `msgContent`, and `simSlot`.

```kotlin
val data = Gson().fromJson(param, SmsSendData::class.java)
PhoneUtils.sendSms(data.phoneNumbers, data.msgContent, data.simSlot)

```

*(see lines 126-155 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt))*

## Security Mechanisms

SmsForwarder implements multiple safeguards to prevent malicious command execution:

- **Safe-Phone Validation**: Only numbers listed in `SettingUtils.smsCommandSafePhone` are permitted to send commands.
- **Root Verification**: System-level commands (`reboot`, `shutdown`) explicitly check `DeviceUtils.isDeviceRooted()` before execution.
- **Duplicate Protection**: For system commands, `HistoryUtils` maintains a cache to prevent rapid re-execution of identical commands (lines 96-108 of [`SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsCommandUtils.kt)).

## User Documentation

The exact syntax is documented in the user interface via [`res/values/strings.xml`](https://github.com/pppscn/SmsForwarder/blob/main/res/values/strings.xml) at line 373, which explains the command format to end users:

```xml
<string name="sms_command_tips">
    根据短信指令开关对应功能，指令格式：smsf#功能名#动作名
</string>

```

## Summary

- **Entry Point**: [`SmsReceiver.kt`](https://github.com/pppscn/SmsForwarder/blob/main/SmsReceiver.kt) filters messages for the `smsf#` prefix and validates senders against a safe-phone list.
- **Parser**: `SmsCommandUtils.execute()` splits commands into function-action-parameter triples using a limit of 3 splits on the `#` character.
- **Supported Commands**: FRPC tunnel control, HTTP server management, system reboot/shutdown (requires root), Wi-Fi toggling, and SMS relay.
- **Security Layers**: Safe-phone lists, root checks for privileged operations, and historical duplicate command prevention.

## Frequently Asked Questions

### What is the exact format for SMS commands in SmsForwarder?

The format is `smsf#<function>#<action>#<optional_parameter>`. The parser splits the string on `#` into a maximum of three parts, where the first part is the function name (e.g., `wifi`, `frpc`), the second is the action (e.g., `on`, `start`), and the third is an optional parameter used for specific FRPC UIDs or JSON SMS payloads.

### Which source file handles the parsing of smsf# commands?

The parsing logic is implemented in [`app/src/main/kotlin/cn/ppps/forwarder/utils/SmsCommandUtils.kt`](https://github.com/pppscn/SmsForwarder/blob/main/app/src/main/kotlin/cn/ppps/forwarder/utils/SmsCommandUtils.kt). The `execute()` method at line 37 performs the string splitting and dispatches to the appropriate handler via a `when` statement.

### Does SmsForwarder require root access for all SMS commands?

No, root access is required only for system-level commands such as `reboot` and `shutdown`. The code explicitly checks `DeviceUtils.isDeviceRooted()` before executing these operations. Commands for Wi-Fi, FRPC, HTTP server, and SMS relay operate without root privileges.

### How does SmsForwarder prevent unauthorized SMS command execution?

The app enforces authorization through a configurable safe-phone list stored in `SettingUtils`. Additionally, the entire command feature is gated by the boolean `enableSmsCommand` setting. Only messages from approved senders that begin with the `smsf#` prefix are processed; all others are ignored or forwarded through the normal pipeline.