Skip to content

Commit

Permalink
1) The app now listens to the SMS in background.
Browse files Browse the repository at this point in the history
2) Renamed ForwarderObserver to ForwarderManager.
3) Renamed KeyValueSettgins.dart to key_value_settings.dart.
4) Abandoned sms_maintained in favor of telephony because the letter
supports backround execution.
  • Loading branch information
optimalstrategy committed Mar 9, 2021
1 parent a9da2a1 commit d4b4153
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 120 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
compileSdkVersion 28
compileSdkVersion 29

lintOptions {
disable 'InvalidPackage'
Expand All @@ -27,7 +27,7 @@ android {
defaultConfig {
applicationId "team.whatever.sms_forwarder_app"
minSdkVersion 21
targetSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand Down
7 changes: 7 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,12 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

<receiver android:name="com.shounakmulay.telephony.sms.IncomingSmsReceiver"
android:permission="android.permission.BROADCAST_SMS" android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
</manifest>
6 changes: 2 additions & 4 deletions ios/Flutter/flutter_export_environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ export "FLUTTER_APPLICATION_PATH=/home/george/projects/sms_forwarder_app"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=/opt/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "FLUTTER_BUILD_NAME=1.4.0"
export "FLUTTER_BUILD_NUMBER=1.4.0"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
Expand Down
67 changes: 67 additions & 0 deletions lib/background_forwarder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import 'package:telephony/telephony.dart';

import 'forwarding.dart';
import 'manager.dart';

/// A wrapper for [ForwarderManager] that registers a background message handler.
/// Resets the background forwarder every time a field is updated.
class BackgroundForwarder {
static ForwarderManager _backgroundManager;
final ForwarderManager mgr = new ForwarderManager();

BackgroundForwarder(Telephony telephony) {
telephony.listenIncomingSms(
onNewMessage: (msg) async => await mgr.forward(msg),
onBackgroundMessage: onBackgroundMessage
);
}

static void onBackgroundMessage(SmsMessage msg) async {
if (_backgroundManager == null) {
_backgroundManager = new ForwarderManager();
await _backgroundManager.loadFromPrefs();
}
await _backgroundManager.forward(msg);
}

HttpCallbackForwarder get httpCallbackForwarder => mgr.httpCallbackForwarder;

TelegramBotForwarder get telegramBotForwarder => mgr.telegramBotForwarder;

DeployedTelegramBotForwarder get deployedTelegramBotForwarder =>
mgr.deployedTelegramBotForwarder;

set httpCallbackForwarder(HttpCallbackForwarder fwd) {
mgr.httpCallbackForwarder = fwd;
invalidateBackgroundManager();
}

set telegramBotForwarder(TelegramBotForwarder fwd) {
mgr.telegramBotForwarder = fwd;
invalidateBackgroundManager();
}

set deployedTelegramBotForwarder(DeployedTelegramBotForwarder fwd) {
mgr.deployedTelegramBotForwarder = fwd;
invalidateBackgroundManager();
}

/// Loads the forwarders from a json.
Future<Map> loadFromPrefs() async {
var result = await mgr.loadFromPrefs();
return result;
}

/// Dumps the forwarders to shared preferences.
void dumpToPrefs() async => mgr.dumpToPrefs();

/// Returns the mapping (forwarder name -> not null)
Map reportReadiness() {
return mgr.reportReadiness();
}

/// Sets the background manager to `null`.
static void invalidateBackgroundManager() {
_backgroundManager = null;
}
}
54 changes: 37 additions & 17 deletions lib/forwarding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,28 @@ import 'dart:core';
import 'dart:convert';

import 'package:http/http.dart' as http;
import 'package:sms_maintained/sms.dart';
import 'package:telephony/telephony.dart';
import 'package:flutter/foundation.dart';

extension ToMap on SmsMessage {
Map get toMap {
return {
"id": this.id,
"address": this.address,
"body": this.body,
"date": this.date,
"dateSent": this.dateSent,
"read": this.read,
"seen": this.seen,
"subject": this.subject,
"subscriptionId": this.subscriptionId,
"threadId": this.threadId,
"type": this.type,
"status": this.status,
};
}
}

/// Defines the forwarder interface.
abstract class AbstractForwarder {
/// Should forward the given sms.
Expand Down Expand Up @@ -60,9 +79,9 @@ abstract class HttpForwarder implements AbstractForwarder {
static String mapToJson(Map map) => json.encode(_castMap(map));

/// Casts all keys and values in the map to String. Removes the entry with
/// the key thread_id.
/// the key threadId.
static Map<String, String> _castMap(Map map) {
map.remove('thread_id');
map.remove('threadId');
return Map.from(map.map(
// Cast each field to string
(k, v) => MapEntry(k.toString(), v.toString())));
Expand Down Expand Up @@ -176,20 +195,20 @@ class HttpCallbackForwarder extends AbstractForwarder with HttpForwarder {
switch (method) {
case HttpMethod.GET:
// Convert the sms to JSON and merge it with the uri payload
var smsData = sms.toMap;
final smsData = sms.toMap;
smsData.addAll(uriPayload);
// Then URI encode the map and perform the request
String uriParams = HttpForwarder.mapToUri(smsData);
final uriParams = HttpForwarder.mapToUri(smsData);
return http.get("$_callbackUrl$uriParams");

case HttpMethod.POST:
case HttpMethod.PUT:
// Convert the sms to json and merge it with the json payload
var payload = sms.toMap;
final payload = sms.toMap;
payload.addAll(jsonPayload);
// URI encode the uri payload and append it to the url
var uriParams = HttpForwarder.mapToUri(uriPayload);
var url = "$_callbackUrl$uriParams";
final uriParams = HttpForwarder.mapToUri(uriPayload);
final url = "$_callbackUrl$uriParams";
// Perform the request using the required method
return method == HttpMethod.POST
? http.post(url, body: HttpForwarder.mapToJson(payload))
Expand Down Expand Up @@ -240,13 +259,14 @@ class TelegramBotForwarder extends AbstractForwarder with HttpForwarder {
/// Sends the SMS data to the user with [_chatId].
@override
Future<http.Response> send(SmsMessage sms) {
final date = DateTime.fromMillisecondsSinceEpoch(sms.date);
// Encode message
String uriParams = HttpForwarder.mapToUri({
"chat_id": _chatId,
"text": "New SMS message from ${sms.address}:\n${sms.body}\n\n"
"Date: ${sms.date}."
"Date: $date."
});
String url = this.method("sendMessage");
final url = this.method("sendMessage");
return http.post("$url$uriParams");
}

Expand Down Expand Up @@ -305,34 +325,34 @@ class DeployedTelegramBotForwarder extends HttpCallbackForwarder {

/// Checks if the user with [_tgHandle] exists on the server.
Future<bool> checkSetupURL() async {
var params = {"username": _tgHandle, "code": _tgCode};
var r =
final params = {"username": _tgHandle, "code": _tgCode};
final r =
await http.get("$_baseUrl/check_user${HttpForwarder.mapToUri(params)}");
_isSetUp = r?.statusCode == 200;
return Future<bool>(() => isSetUp);
}

/// Sends the SMS data to the server via a POST request.
Future<http.Response> send(SmsMessage sms) {
var map = sms.toMap;
map['date'] =
sms.date.toString(); // the date field is in milliseconds by default
final map = sms.toMap;
final date = DateTime.fromMillisecondsSinceEpoch(sms.date);
map['date'] = date.toString();
String payload = HttpForwarder.mapToJson(map);
String url = "$_callbackUrl?code=$_tgCode&username=$_tgHandle";
return http.post(url, body: payload);
}

/// Generates a random 8-character code.
String _genCode() {
var rand = Random();
final rand = Random();
return String.fromCharCodes(
new List.generate(8, (_) => rand.nextInt(26) + 65));
}

/// Dumps the forwarder's settings to json.
@override
String toJson() {
var fields = {
final fields = {
"tgCode": _tgCode,
"baseUrl": _baseUrl,
"tgHandle": _tgHandle,
Expand Down
1 change: 0 additions & 1 deletion lib/KeyValueSettings.dart → lib/key_value_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ class _KeyValuePairWidgetState extends State<_KeyValuePairWidget> {

@override
Widget build(BuildContext context) {
var pairs = _parentState.pairs;
return Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Container(
width: 125,
Expand Down
Loading

0 comments on commit d4b4153

Please sign in to comment.