# Textpipe - SMS API Gateway An Android app that turns your phone into an SMS API gateway with a web interface. ## Features - **REST API** - Send and receive SMS via HTTP endpoints - **Dual SIM Support** - Each SIM gets its own API key - **Web UI** - Google Messages-like interface accessible from any browser - **Local Database** - All messages stored locally with delivery tracking - **Background Service** - Runs as a foreground service with persistent notification - **Auto-start** - Optionally start on device boot - **Root Port Redirect** - Use ports 80/443 with root access via iptables ## Requirements - Android 7.0+ (API 24+) - SMS permissions - Phone state permissions (for dual SIM) - (Optional) Root access for privileged ports ## Building ### Prerequisites - Android Studio or command line with Android SDK - JDK 11+ - Node.js 18+ (for web UI) ### Build Steps 1. **Clone the repository** ```bash git clone cd textpipe ``` 2. **Build the Web UI** ```bash cd webui npm install npm run build cd .. ``` This builds the Vue frontend to `app/src/main/assets/webui/` 3. **Build the Android App** ```bash ./gradlew assembleDebug ``` The APK will be at `app/build/outputs/apk/debug/app-debug.apk` 4. **Install on device** ```bash adb install app/build/outputs/apk/debug/app-debug.apk ``` ### Release Build ```bash ./gradlew assembleRelease ``` Note: You'll need to configure signing in `app/build.gradle.kts` for release builds. ## Usage ### Initial Setup 1. Install and open the app 2. Grant all requested permissions (SMS, Phone, Notifications) 3. Note the API key(s) shown for each SIM card 4. Configure the port (default: 8080) 5. Tap "Start Server" 6. (Optional) Disable battery optimization for reliable background operation ### API Endpoints Base URL: `http://:` #### Status (No auth required) ``` GET /api/status ``` Returns server status and SIM information. #### Send SMS ``` POST /api/sms/send Header: X-API-Key: Content-Type: application/json { "to": "+1234567890", "text": "Hello from Textpipe!" } ``` Response: ```json { "id": 1, "status": "pending", "simSlot": 0 } ``` #### List Messages ``` GET /api/sms/messages Header: X-API-Key: ``` Optional query parameter: `?type=sent` or `?type=received` Response: ```json { "messages": [ { "id": 1, "type": "sent", "address": "+1234567890", "text": "Hello!", "simSlot": 0, "status": "delivered", "timestamp": 1707148800000, "deliveryTimestamp": 1707148805000 } ], "total": 1 } ``` #### Get Message Status ``` GET /api/sms/status/{id} Header: X-API-Key: ``` ### Authentication Pass your API key in one of these ways: - Header: `Authorization: Bearer ` - Header: `X-API-Key: ` - Query param: `?api_key=` Each SIM card has its own unique API key. The API key determines which SIM sends the message. ### Web Interface Open `http://:/` in any browser to access the web UI. 1. Enter your API key to login 2. View conversations grouped by contact 3. Send new messages using the + button 4. Click on a conversation to view message thread ### cURL Examples **Send SMS:** ```bash curl -X POST http://10.0.1.12:8080/api/sms/send \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key-here" \ -d '{"to": "+1234567890", "text": "Hello!"}' ``` **Check status:** ```bash curl http://10.0.1.12:8080/api/status ``` **List messages:** ```bash curl -H "X-API-Key: your-api-key-here" \ http://10.0.1.12:8080/api/sms/messages ``` **Get specific message:** ```bash curl -H "X-API-Key: your-api-key-here" \ http://10.0.1.12:8080/api/sms/status/1 ``` ## Configuration ### Port Configuration - Default port: 8080 - Can be changed in the app UI - For ports below 1024 (like 80 or 443), root access is required - With root, the app uses iptables to redirect traffic from the privileged port to the actual server port ### Auto-start Enable "Auto-start on boot" in Settings to automatically start the server when the device boots. ### Battery Optimization For reliable background operation, disable battery optimization for Textpipe: 1. Go to Settings in the app 2. Tap "Disable" next to Battery Optimization 3. Confirm in the system dialog ## Project Structure ``` textpipe/ ├── app/ # Android app │ └── src/main/ │ ├── java/sh/sar/textpipe/ │ │ ├── MainActivity.kt │ │ ├── TextpipeApplication.kt │ │ ├── data/ │ │ │ ├── db/ # Room database │ │ │ ├── model/ # API models │ │ │ └── repository/ # Data repository │ │ ├── server/ # Ktor HTTP server │ │ │ ├── TextpipeServer.kt │ │ │ ├── auth/ # API key auth │ │ │ └── routes/ # API endpoints │ │ ├── service/ # Android services │ │ │ ├── TextpipeService.kt │ │ │ ├── SmsSender.kt │ │ │ ├── SmsReceiver.kt │ │ │ └── BootReceiver.kt │ │ ├── sim/ # SIM management │ │ ├── root/ # Root utilities │ │ └── ui/ # Compose UI │ ├── assets/webui/ # Built web UI │ └── AndroidManifest.xml ├── webui/ # Vue.js web interface │ ├── src/ │ │ ├── App.vue │ │ ├── api.js │ │ ├── style.css │ │ └── components/ │ ├── package.json │ └── vite.config.js ├── gradle/ │ └── libs.versions.toml # Dependency versions └── build.gradle.kts ``` ## Tech Stack ### Android App - Kotlin - Jetpack Compose (UI) - Ktor CIO (HTTP server) - Room (Database) - Kotlin Coroutines - kotlinx.serialization (JSON) ### Web UI - Vue 3 - Vite - Vanilla CSS ## Message Status Flow ``` pending → sent → delivered ↘ failed ``` - **pending** - Message queued, sending in progress - **sent** - Message sent successfully - **delivered** - Delivery confirmation received - **failed** - Send failed ## Troubleshooting ### "Address already in use" error The port is still bound from a previous instance. Either: - Wait a few seconds and try again - Change to a different port - Force stop the app and restart ### Server doesn't start - Check that no other app is using the port - Verify all permissions are granted - Check logcat for errors: `adb logcat -s TextpipeServer TextpipeService` ### Messages not sending - Verify SMS permission is granted - Check you have cellular signal - Ensure the API key matches an active SIM ### Web UI not loading - Verify the server is running (check app status) - Check you're using the correct IP and port - Try accessing `/api/status` directly ## License MIT