├── android-studio-project
├── settings.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── SMS-Forwarding
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── drawable
│ │ │ │ │ ├── launcher.png
│ │ │ │ │ └── menu_add.png
│ │ │ │ ├── drawable-hdpi
│ │ │ │ │ └── menu_add.png
│ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ └── menu_add.png
│ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ └── menu_add.png
│ │ │ │ ├── drawable-xxxhdpi
│ │ │ │ │ └── menu_add.png
│ │ │ │ ├── values
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── themes.xml
│ │ │ │ │ └── strings.xml
│ │ │ │ ├── menu
│ │ │ │ │ └── activity_recipient_list.xml
│ │ │ │ └── layout
│ │ │ │ │ ├── activity_recipient_list.xml
│ │ │ │ │ └── dialog_recipient_listitem.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── github
│ │ │ │ │ └── warren_bank
│ │ │ │ │ └── sms_automatic_forwarding
│ │ │ │ │ ├── event
│ │ │ │ │ ├── SMSSender.java
│ │ │ │ │ └── SMSReceiver.java
│ │ │ │ │ ├── security_model
│ │ │ │ │ └── RuntimePermissions.java
│ │ │ │ │ ├── data_model
│ │ │ │ │ ├── Preferences.java
│ │ │ │ │ └── RecipientListItem.java
│ │ │ │ │ └── ui
│ │ │ │ │ └── RecipientListActivity.java
│ │ │ └── AndroidManifest.xml
│ │ ├── withContactName
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── warren_bank
│ │ │ │ └── sms_automatic_forwarding
│ │ │ │ ├── security_model
│ │ │ │ └── OptionalRuntimePermissions.java
│ │ │ │ └── data_model
│ │ │ │ └── Contacts.java
│ │ ├── noContactName
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── warren_bank
│ │ │ │ └── sms_automatic_forwarding
│ │ │ │ ├── security_model
│ │ │ │ └── OptionalRuntimePermissions.java
│ │ │ │ └── data_model
│ │ │ │ └── Contacts.java
│ │ └── withAllLanguageTranslations
│ │ │ └── res
│ │ │ ├── values-zh-rTW
│ │ │ └── strings.xml
│ │ │ ├── values-zh
│ │ │ └── strings.xml
│ │ │ ├── values-ko
│ │ │ └── strings.xml
│ │ │ ├── values-ja
│ │ │ └── strings.xml
│ │ │ ├── values-az
│ │ │ └── strings.xml
│ │ │ ├── values-he
│ │ │ └── strings.xml
│ │ │ ├── values-ar
│ │ │ └── strings.xml
│ │ │ ├── values-sq
│ │ │ └── strings.xml
│ │ │ ├── values-fa
│ │ │ └── strings.xml
│ │ │ ├── values-bn
│ │ │ └── strings.xml
│ │ │ ├── values-tr
│ │ │ └── strings.xml
│ │ │ ├── values-hi
│ │ │ └── strings.xml
│ │ │ ├── values-ur
│ │ │ └── strings.xml
│ │ │ ├── values-fi
│ │ │ └── strings.xml
│ │ │ ├── values-sv
│ │ │ └── strings.xml
│ │ │ ├── values-th
│ │ │ └── strings.xml
│ │ │ ├── values-et
│ │ │ └── strings.xml
│ │ │ ├── values-gl
│ │ │ └── strings.xml
│ │ │ ├── values-nb
│ │ │ └── strings.xml
│ │ │ ├── values-pl
│ │ │ └── strings.xml
│ │ │ ├── values-sk
│ │ │ └── strings.xml
│ │ │ ├── values-cs
│ │ │ └── strings.xml
│ │ │ ├── values-de
│ │ │ └── strings.xml
│ │ │ ├── values-eo
│ │ │ └── strings.xml
│ │ │ ├── values-da
│ │ │ └── strings.xml
│ │ │ ├── values-lv
│ │ │ └── strings.xml
│ │ │ ├── values-hu
│ │ │ └── strings.xml
│ │ │ ├── values-id
│ │ │ └── strings.xml
│ │ │ ├── values-eu
│ │ │ └── strings.xml
│ │ │ ├── values-lt
│ │ │ └── strings.xml
│ │ │ ├── values-nl
│ │ │ └── strings.xml
│ │ │ ├── values-ru
│ │ │ └── strings.xml
│ │ │ ├── values-sl
│ │ │ └── strings.xml
│ │ │ ├── values-es
│ │ │ └── strings.xml
│ │ │ ├── values-pb
│ │ │ └── strings.xml
│ │ │ ├── values-ro
│ │ │ └── strings.xml
│ │ │ ├── values-uk
│ │ │ └── strings.xml
│ │ │ ├── values-ky
│ │ │ └── strings.xml
│ │ │ ├── values-ms
│ │ │ └── strings.xml
│ │ │ ├── values-pt
│ │ │ └── strings.xml
│ │ │ ├── values-bg
│ │ │ └── strings.xml
│ │ │ ├── values-el
│ │ │ └── strings.xml
│ │ │ ├── values-it
│ │ │ └── strings.xml
│ │ │ ├── values-tl
│ │ │ └── strings.xml
│ │ │ ├── values-fr
│ │ │ └── strings.xml
│ │ │ ├── values-ca
│ │ │ └── strings.xml
│ │ │ └── values-ga
│ │ │ └── strings.xml
│ ├── proguard-rules.txt
│ └── build.gradle
├── constants.gradle
├── gradle.properties
├── build.gradle
├── gradlew.bat
└── gradlew
├── screenshots
├── 2-prefs-add-new-entry-dialog.png
├── 3-prefs-one-entry-in-whitelist.png
└── 1-prefs-no-entries-in-whitelist.png
├── .gitignore
├── package.json
├── README.md
└── LICENSE.txt
/android-studio-project/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':SMS-Forwarding'
2 |
--------------------------------------------------------------------------------
/screenshots/2-prefs-add-new-entry-dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/screenshots/2-prefs-add-new-entry-dialog.png
--------------------------------------------------------------------------------
/screenshots/3-prefs-one-entry-in-whitelist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/screenshots/3-prefs-one-entry-in-whitelist.png
--------------------------------------------------------------------------------
/screenshots/1-prefs-no-entries-in-whitelist.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/screenshots/1-prefs-no-entries-in-whitelist.png
--------------------------------------------------------------------------------
/android-studio-project/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/drawable/launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/SMS-Forwarding/src/main/res/drawable/launcher.png
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/drawable/menu_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/SMS-Forwarding/src/main/res/drawable/menu_add.png
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/drawable-hdpi/menu_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/SMS-Forwarding/src/main/res/drawable-hdpi/menu_add.png
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/drawable-xhdpi/menu_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/SMS-Forwarding/src/main/res/drawable-xhdpi/menu_add.png
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/drawable-xxhdpi/menu_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/SMS-Forwarding/src/main/res/drawable-xxhdpi/menu_add.png
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/drawable-xxxhdpi/menu_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/warren-bank/Android-SMS-Automatic-Forwarding/HEAD/android-studio-project/SMS-Forwarding/src/main/res/drawable-xxxhdpi/menu_add.png
--------------------------------------------------------------------------------
/android-studio-project/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withContactName/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node.js dev-dependencies
2 | node_modules/
3 |
4 | # Android generated
5 | bin
6 | gen
7 | obj
8 | lint.xml
9 |
10 | # IntelliJ IDEA
11 | .idea
12 | *.iml
13 | *.ipr
14 | *.iws
15 | classes
16 | gen-external-apklibs
17 |
18 | # Gradle
19 | .gradle
20 | build
21 | buildout
22 | out
23 |
24 | # Other
25 | .DS_Store
26 | local.properties
27 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #999999
5 |
6 | #999999
7 | #FFFFFF
8 |
9 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/menu/activity_recipient_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/noContactName/java/com/github/warren_bank/sms_automatic_forwarding/security_model/OptionalRuntimePermissions.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.security_model;
2 |
3 | import android.app.Activity;
4 |
5 | public final class OptionalRuntimePermissions {
6 | public static void requestPermissions(Activity activity) {}
7 | }
8 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/noContactName/java/com/github/warren_bank/sms_automatic_forwarding/data_model/Contacts.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.data_model;
2 |
3 | import android.content.Context;
4 |
5 | public final class Contacts {
6 | public static String getContactName(Context context, String phoneNumber) {
7 | return null;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/android-studio-project/constants.gradle:
--------------------------------------------------------------------------------
1 | project.ext {
2 | applicationId = 'com.github.warren_bank.sms_automatic_forwarding'
3 | releaseVersionCode = Integer.parseInt("002030111", 10) //Integer.MAX_VALUE == 2147483647
4 | releaseVersion = '002.03.01-11API'
5 | javaVersion = JavaVersion.VERSION_1_8
6 | minSdkVersion = 11
7 | targetSdkVersion = 35
8 | compileSdkVersion = 35
9 | buildToolsVersion = '34.0.0'
10 | }
11 |
--------------------------------------------------------------------------------
/android-studio-project/gradle.properties:
--------------------------------------------------------------------------------
1 | android.nonFinalResIds=false
2 |
3 | # ----------------------------------------------------------
4 | # increase RAM allocation in 2x places:
5 | #
6 | # 1) in file:
7 | # C:\Android\android-studio\bin\studio64.exe.vmoptions
8 | # by changing value from:
9 | # -Xmx768m
10 | # to:
11 | # -Xmx2048m
12 | #
13 | # 2) here:
14 | org.gradle.jvmargs=-Xmx2048M
15 | # ----------------------------------------------------------
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@warren-bank/Android-SMS-Automatic-Forwarding",
3 | "private": true,
4 | "license": "GPL-2.0",
5 | "devDependencies": {
6 | "@warren-bank/translate-android-strings": "^2.0.0"
7 | },
8 | "scripts": {
9 | "translate": "translate-android-strings -i \"en\" -f \"android-studio-project/SMS-Forwarding/src/main/res/values/strings.xml\" -d \"android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res\" -m --na --nc --nw -b \"SMS\"",
10 | "translate:debug": "npm run translate -- -o \"en\" --debug"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-zh-rTW/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS 转发中
4 | 開啟服務
5 | 转发接收者:
6 | 發件人必須以:
7 | 反恐
8 | 迪勒特
9 | 拯救
10 | ADD
11 | 錯誤: 缺少必要值
12 | 錯誤: 無法新增項目到清單
13 | 從:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS 转发
4 | 启用服务
5 | 转发收件人:
6 | 发件人必须结束于:
7 | 比利时
8 | 迪莱特
9 | 拯救
10 | 异常值
11 | 错误: 缺少必需值
12 | 错误: 无法将新项目添加到列表
13 | 转自:
14 |
--------------------------------------------------------------------------------
/android-studio-project/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:8.7.2' // https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
8 | // https://developer.android.com/build/releases/gradle-plugin#updating-gradle
9 | // https://developer.android.com/build/releases/gradle-plugin#api-level-support
10 | }
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | mavenCentral()
17 | }
18 | }
19 |
20 | task clean(type: Delete) {
21 | delete rootProject.buildDir
22 | }
23 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ko/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS 회사연혁
4 | 회사 소개
5 | 고객 지원:
6 | Sender는 끝이어야 합니다:
7 | CANCEL 소개
8 | 계정 만들기
9 | 제품 정보
10 | 사이트맵
11 | 오류: 필수 값
12 | 오류 : 목록에 새 항목을 추가 할 수 없습니다
13 | 거래 시작:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ja/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS フォワーディング
4 | サービスを有効にする
5 | 転送受信者:
6 | Sender は終了しなければなりません:
7 | ログイン
8 | ディレテ
9 | スエイブ
10 | 追加情報
11 | エラー: 必須値の欠如
12 | エラー:リストに新しい項目を追加できません
13 | から転送:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-az/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Uşaq
4 | Xidmət
5 | Uşaq alıcı:
6 | E-poçt ünvanı:
7 | C
8 | E-POÇT
9 | SAVE
10 | E-POÇT
11 | Yadda saxla
12 | Fayl: siyahısı yeni maddə əlavə etməyə bilər
13 | Daxil ol:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-he/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS קדימה
4 | שירות אמין
5 | קידום נמען:
6 | שלח חייב להסתיים עם:
7 | הזדמנות
8 | DELETE
9 | SAVE
10 | ADD
11 | טעות: חסר ערך
12 | טעות: לא ניתן להוסיף פריט חדש לרשימה
13 | קדימה:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ar/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS المستقبل
4 | الخدمة التمكينية
5 | المتلقي المباشر:
6 | يجب أن ينتهي الجنس:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | خسارة القيمة المطلوبة
12 | لا يمكن إضافة بند جديد للقائمة
13 | مقدم من:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-sq/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Vazhdo
4 | Aktivo shërbimin
5 | Vazhdo:
6 | Dërguesi me:
7 | KANCEL
8 | DELTË
9 | SAVE
10 | ADD
11 | Gabim: Mungon vlera
12 | Gabim: I pamundur shtimi i elementit të ri në listë
13 | Vazhdo:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-fa/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS پیشبرد
4 | خدمات
5 | بازگشت گیرنده:
6 | ارسال کننده باید با:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | خطای: از دست رفته ارزش
12 | خطا: نمی تواند آیتم جدید را به لیست اضافه کند
13 | برگرفته از::
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-bn/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS কল অনুবর্তন
4 | সার্ভিস সক্রিয় করো
5 | প্রাপক:
6 | প্রেরকের শেষে হওয়া আবশ্যক:
7 | ক্লীব
8 | লাভা
9 | সেভ
10 | ADD
11 | ত্রুটি: ভুল মান
12 | ত্রুটি: নতুন তালিকা যোগ করতে ব্যর্থ
13 | ফরওয়ার্ড করা হয়েছে:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Forwarding
4 | Enable Servis
5 | Forwarding alıcı:
6 | Sender ile bitmelidir:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Hata: Eksik Gerekli Değer
12 | Hata: Listeye yeni öğe ekleyebilir
13 | İleriden:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-hi/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS फॉरवर्डिंग
4 | सेवा
5 | फॉरवर्डिंग प्राप्तकर्ता:
6 | प्रेषक के साथ समाप्त होना चाहिए:
7 | CANCEL
8 | दिल्ली
9 | सेव
10 | ADD
11 | त्रुटि: मिसिंग आवश्यक मान
12 | त्रुटि: सूची में नया आइटम नहीं मिला
13 | अग्रेषित:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ur/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS ترقی
4 | سروس فعال کریں
5 | نجات پانے کیلئے:
6 | نئے سرے سے ختم ہونا ضروری ہے:
7 | رنگ
8 | آسٹریلیا
9 | یونان
10 | داؤد
11 | غلطی: مفقود درکار
12 | خامی: فہرست میں نئی آئٹم شامل نہیں کیا جاسکتا
13 | انعام کے لیے:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-fi/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Lähetys
4 | Käytä palvelua
5 | Vastaanottaja:
6 | Lähettäjän on päätyttävä:
7 | CANCEL
8 | POISTA
9 | SAVE
10 | ADD
11 | Virhe: puuttuva vaadittu arvo
12 | Virhe: Uutta kohdetta ei voitu lisätä luetteloon
13 | Eteenpäin:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-sv/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Framåt
4 | Aktivera service
5 | Framåt mottagare:
6 | Sender måste sluta med:
7 | CANCEL
8 | DELETE
9 | SPARA
10 | ADD
11 | Fel: Missing krävs värde
12 | Fel: Kunde inte lägga till nytt objekt i listan
13 | Framåt från:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-th/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS ส่งต่อ
4 | เปิดใช้งานบริการ
5 | กําลังส่งต่อผู้รับ:
6 | ผู้ส่งต้องสิ้นสุดด้วย:
7 | ซิงเกิล
8 | เดเลต
9 | ป้องกัน
10 | ADD
11 | ผิดพลาด: ค่าที่ไม่ต้องการ
12 | ผิดพลาด: ไม่สามารถเพิ่มรายการใหม่ไปยังรายการได้
13 | ส่งต่อจาก:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Forwarding
4 |
5 | Enable Service
6 | Forwarding recipient:
7 | Sender must end with:
8 | CANCEL
9 | DELETE
10 | SAVE
11 |
12 | ADD
13 |
14 | Error: Missing Required Value
15 | Error: Could not add new item to list
16 |
17 | Forwarded from:
18 |
19 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-et/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Edastamine
4 | Teenuse lubamine
5 | Saaja edastamine:
6 | Saatja peab lõpetama:
7 | TÜHISTADA
8 | DELETE
9 | PÄÄSTA
10 | LISA
11 | Viga: puudub nõutav väärtus
12 | Viga: uue elemendi lisamine nimekirja nurjus
13 | Edastatud:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-gl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Adiante
4 | Servicioable
5 | Reenviar destinatarios:
6 | Sender debe rematar con:
7 | ANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Erro: falta de valor
12 | Erro: Non se pode engadir un novo elemento á lista
13 | Enviado desde:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-nb/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Forwarding
4 | Aktiver tjeneste
5 | Sender mottaker:
6 | Sender må slutte med:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Feil: mangler nødvendig verdi
12 | Feil: Kunne ikke legge til nytt element i listen
13 | Forward fra:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-pl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Przekazywanie
4 | Włącz usługę
5 | Przekazywanie odbiorcy:
6 | Nadawca musi zakończyć:
7 | CANCEL
8 | DELETA
9 | SAVE
10 | ADD
11 | Błąd: brak wymaganej wartości
12 | Błąd: Nie można dodać nowego elementu do listy
13 | Przekazane:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-sk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Zasielanie
4 | Povoliť službu
5 | Zasielateľ:
6 | Odosielateľ musí skončiť:
7 | KANÁL
8 | DELTE
9 | SAVE
10 | ADD
11 | Chyba: Chýbajúca požadovaná hodnota
12 | Chyba: Nepodarilo sa pridať novú položku do zoznamu
13 | Zaslané z:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Předání
4 | Povolit službu
5 | Předání příjemce:
6 | Odesílatel musí skončit:
7 | KANCEL
8 | DELET
9 | BEZPEČNOST
10 | ADD
11 | Chyba: Chybějící požadovaná hodnota
12 | Chyba: Nelze přidat novou položku do seznamu
13 | Vypuštěno od:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Weiterleitung
4 | Service aktivieren
5 | Empfänger weitergeben:
6 | Absender muss enden:
7 | CANCEL
8 | DELE
9 | SAVE
10 | ADD
11 | Fehler: Fehlen erforderlicher Wert
12 | Fehler: Konnte keine neue Liste hinzufügen
13 | Vorwärts von:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-eo/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Antaŭite
4 | Enebla servo
5 | Antaŭite fare de ricevanto:
6 | Sendanto devas finiĝi kun:
7 | CANCEL
8 | DELIKTO
9 | SA
10 | ADD
11 | Eraro: Missing Required Value
12 | Eraro: ne povas aldoni novan objekton al listo
13 | Antaŭite de:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-da/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Fremsendelse
4 | Aktivér tjeneste
5 | Fremsendelse af modtager:
6 | Afsenderen skal slutte med:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Fejl: Manglende krævet værdi
12 | Fejl: Kunne ikke tilføje nyt punkt til listen
13 | Fremsendt fra:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-lv/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Pārsūtīšana
4 | Ieslēgt servisu
5 | Saņēmēja pārsūtīšana:
6 | Sūtītājam jābeidzas ar:
7 | CANEL
8 | DELETE
9 | SAVE
10 | PIEVIENOT
11 | Kļūda: Trūkst vajadzīgās vērtības
12 | Kļūda: Nevar pievienot jaunu ierakstu sarakstam
13 | Pārsūtīts no:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-hu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Továbbítás
4 | Szolgáltatás engedélyezése
5 | A kedvezményezett továbbítása:
6 | A feladónak:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Hiba: hiányzó szükséges érték
12 | Hiba: nem sikerült új elemet felvenni a listába
13 | Származási hely:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-id/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Meneruskan
4 | Aktifkan Layanan
5 | Penerima Penerusan:
6 | Pengirim harus diakhiri dengan:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Galat: Nilai yang Diperlukan Hilang
12 | Galat: Tak bisa menambah butir baru ke daftar
13 | Dicegah dari:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-eu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Aurreratzea
4 | Gaitu zerbitzua
5 | Birbidalitako hartzailea:
6 | Bidaltzaileak amaitu behar du:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Errorea: beharrezko balioa falta da
12 | Errorea: ezin izan da elementu berria gehitu zerrendan
13 | Aurrera:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-lt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Perdavimas
4 | Įjungti paslaugą
5 | Siunčiamas gavėjas:
6 | Siuntėjas turi baigti:
7 | CANCEL
8 | CONSTELLATION NAME (OPTIONAL)
9 | SAVE
10 | ADD
11 | Klaida: trūksta reikalaujamos vertės
12 | Klaida: į sąrašą nepavyko įtraukti naujo elemento
13 | Iš:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Doorsturen
4 | Dienst inschakelen
5 | Doorsturende ontvanger:
6 | Afzender moet eindigen met:
7 | ANNULEREN
8 | DELETE
9 | SAVE
10 | ADD
11 | Fout: ontbrekende vereiste waarde
12 | Fout: kon geen nieuw item aan lijst toevoegen
13 | Doorgestuurd van:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Вперед
4 | Включить сервис
5 | Направляющий получатель:
6 | Отправитель должен закончить:
7 | КАНЦЕЛЯРИЯ
8 | УДАЛИТЬ
9 | СПАСАТЬ
10 | СДВГ
11 | Ошибка: недостающая ценность
12 | Ошибка: нельзя добавлять новый элемент в список
13 | Перенесенный из:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-sl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Posredovanje
4 | Omogoči storitev
5 | Pošiljanje prejemnika:
6 | Pošiljatelj mora končati s:
7 | CANCEL
8 | DELETE
9 | REŠEVANJE
10 | ADD
11 | Napaka: manjka zahtevana vrednost
12 | Napaka: Ni moč dodati novega predmeta na seznam
13 | Posredovano iz:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Adelante
4 | Servicio de habilitación
5 | Recibido ascendente:
6 | El remitente debe terminar con:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Error: falta de valor requerido
12 | Error: No se puede añadir nuevo elemento a la lista
13 | Avanzado desde:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-pb/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Encaminhando
4 | Activar o Serviço
5 | Encaminhando destinatário:
6 | O remetente deve terminar com:
7 | CANCEL
8 | DELETE
9 | SAVE
10 | ADD
11 | Erro: Falta o valor necessário
12 | Erro: Não foi possível adicionar novo item à lista
13 | Encaminhado de:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ro/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Se transmite
4 | Activează serviciul
5 | Destinatar de expediere:
6 | Sender trebuie să se termine cu:
7 | CANCEL
8 | DELETE
9 | SALVARE
10 | ADD
11 | Eroare: Lipsește valoarea necesară
12 | Eroare: Nu s-a putut adăuga un nou element în listă
13 | De la:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-uk/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Переадресація
4 | Увімкнути послугу
5 | Переадресація одержувача:
6 | Відправник повинен закінчитися:
7 | КАНСЛ
8 | ДЕЛЕТЕК
9 | САВИ
10 | АДД
11 | Помилка: Обов\'язкове значення
12 | Помилка: Не можна додати новий елемент до списку
13 | Переадресований з:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withContactName/java/com/github/warren_bank/sms_automatic_forwarding/security_model/OptionalRuntimePermissions.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.security_model;
2 |
3 | import android.app.Activity;
4 | import android.os.Build;
5 |
6 | public final class OptionalRuntimePermissions {
7 | private static final int REQUEST_CODE = 1;
8 |
9 | public static void requestPermissions(Activity activity) {
10 | if (Build.VERSION.SDK_INT < 23)
11 | return;
12 |
13 | final String[] permissions_all = new String[]{ "android.permission.READ_CONTACTS" };
14 | final String[] permissions_req = RuntimePermissions.getMissingPermissions(activity, permissions_all);
15 |
16 | if (permissions_req == null)
17 | return;
18 |
19 | activity.requestPermissions(permissions_req, REQUEST_CODE);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ky/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Алдыга жылдыруу
4 | Кызмат көрсөтүү
5 | Алуучуну жөнөтүү:
6 | Сунуш берүүчү менен аяктоо керек:
7 | КАНЦЛЕР
8 | АЧЫК-АЙКЫН
9 | SAVE
10 | КОШУМЧА КОШУМЧА
11 | Ката: Керектүү баалуулуктун жоктугу
12 | Ката: Тизмеге жаңы пунктту кошууга болбойт
13 | Алдыга карай:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ms/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Pemajuan
4 | Memungkinkan Layanan
5 | Penerima Pemajuan Yesus:
6 | Pengirim harus diakhiri dengan:
7 | CANCEL HARUS
8 | ADUHAI
9 | SAVE
10 | ADD SDD
11 | Galat: Nilai Diperlukan Hilang
12 | Ralat: Tak dapat menambah item baru ke daftar
13 | Diteruskan dari:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Encaminhamento
4 | Habilitar o Serviço
5 | Encaminhamento do destinatário:
6 | O remetente deve terminar com:
7 | CANCELAMENTO
8 | DELETE
9 | SAVE
10 | ADD
11 | Erro: Falta de valor exigido
12 | Erro: Não poderia adicionar novo item à lista
13 | Forwarded de:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-bg/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Прехвърляне
4 | Включване на услугата
5 | Предаващ получател:
6 | Подателят трябва да завърши с:
7 | CANCEL
8 | ПОЛУЧЕТЕ
9 | SAVE
10 | ADD
11 | Грешка: Липсваща задължителна стойност
12 | Грешка: Грешка при добавяне на нов елемент към списъка
13 | Препратени от:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Προώθηση
4 | Ενεργοποίηση υπηρεσίας
5 | Παραλήπτης προώθησης:
6 | Ο αποστολέας πρέπει να τελειώσει με:
7 | ΑΚΥΡΩΣΗ
8 | ΔΕΛΕΤΗ
9 | ΣΩΛΗΝΑ
10 | ADD
11 | Σφάλμα: Λείπει η απαιτούμενη τιμή
12 | Σφάλμα: Αδυναμία προσθήκης νέου αντικειμένου στη λίστα
13 | Προωθημένο από:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Inoltro
4 | Servizio abilitato
5 | Inoltro del destinatario:
6 | Sender deve finire con:
7 | CANCELLAZIONE
8 | DELETE
9 | SAVE
10 | ADDETTI
11 | Errore: Valore richiesto mancante
12 | Errore: Non potrebbe aggiungere nuovo elemento all\'elenco
13 | Trasferito da:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-tl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Pagsulong
4 | Kaaya - ayang Paglilingkod
5 | Pagsulong sa tumanggap:
6 | Dapat magwakas ang nagpadala:
7 | SELERO
8 | DELETE
9 | KALIGAYAHAN
10 | ADD
11 | Error: Kulang sa Kailangang Halaga
12 | Error: hindi makapagdagdag ng bagong bagay sa listahan
13 | Mula sa unahan:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Transmission
4 | Activer le service
5 | Récipiendaire de transmission:
6 | L\'expéditeur doit terminer avec:
7 | ANNULATION
8 | DELETE
9 | SAUVER
10 | ADD
11 | Erreur : Valeur requise manquante
12 | Erreur : Impossible d\'ajouter un nouvel élément à la liste
13 | Transmis depuis:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ca/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Reenviament
4 | Habilita el servei
5 | S\' està reenviar el destinatari:
6 | El remitent ha d\' acabar amb:
7 | CLLACONSTELLATION NAME (OPTIONAL)
8 | DEVE
9 | SALVAR
10 | ADD
11 | Error: Falta valor requerit
12 | Error: no s\' ha pogut afegir un element nou a la llista
13 | Reenviat des de:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withAllLanguageTranslations/res/values-ga/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SMS Forwarding
4 | Seirbhís Cumasaithe
5 | Faighteoir ar aghaidh:
6 | Ní mór do Cender deireadh a chur leis:
7 | IRL - LIBRARY SERVICE
8 | ROLETE
9 | CAITHEAMH AIMSIRE
10 | ADD
11 | Earráid: Missing Luach Riachtanach
12 | Earráid: Níorbh fhéidir mír nua a chur leis an liosta
13 | Ar aghaidh ó:
14 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/layout/activity_recipient_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/withContactName/java/com/github/warren_bank/sms_automatic_forwarding/data_model/Contacts.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.data_model;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.net.Uri;
6 | import android.provider.ContactsContract;
7 |
8 | public final class Contacts {
9 | public static String getContactName(Context context, String phoneNumber) {
10 | String contactName = null;
11 |
12 | try {
13 | Uri uri = Uri.withAppendedPath(
14 | ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
15 | Uri.encode(phoneNumber)
16 | );
17 | String[] projection = new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME};
18 | Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
19 |
20 | if (cursor != null) {
21 | if(cursor.moveToFirst()) {
22 | contactName = cursor.getString(0);
23 | }
24 | cursor.close();
25 | }
26 | }
27 | catch(Exception e) {}
28 |
29 | return contactName;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/java/com/github/warren_bank/sms_automatic_forwarding/event/SMSSender.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.event;
2 |
3 | import com.github.warren_bank.sms_automatic_forwarding.R;
4 |
5 | import android.content.Context;
6 | import android.telephony.SmsManager;
7 | import java.util.ArrayList;
8 |
9 | public final class SMSSender {
10 |
11 | public static void forward(Context context, ArrayList recipients, String sender, String sender_contact_name, String body) {
12 | SmsManager sms = SmsManager.getDefault();
13 | String recipient;
14 |
15 | String preface = context.getString(R.string.sms_preface_heading);
16 | if ((sender_contact_name != null) && !sender_contact_name.isEmpty()) {
17 | preface += "\n " + sender_contact_name;
18 | }
19 | preface += "\n " + sender;
20 |
21 | ArrayList parts = sms.divideMessage(preface + "\n\n" + body);
22 |
23 | for (int i=0; i < recipients.size(); i++) {
24 | try {
25 | recipient = recipients.get(i);
26 | sms.sendMultipartTextMessage(recipient, null, parts, null, null);
27 | }
28 | catch(Exception e) { continue; }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/proguard-rules.txt:
--------------------------------------------------------------------------------
1 | ##---------- Begin: proguard configuration for Gson ----------
2 | # https://github.com/google/gson/blob/main/examples/android-proguard-example/proguard.cfg
3 |
4 | # Gson uses generic type information stored in a class file when working with fields.
5 | # Proguard removes such information by default, so configure it to keep all of it.
6 | -keepattributes Signature
7 |
8 | # For using GSON @Expose annotation
9 | -keepattributes *Annotation*
10 |
11 | # Gson specific classes
12 | -dontwarn sun.misc.**
13 | #-keep class com.google.gson.stream.** { *; }
14 |
15 | # Application classes that will be serialized/deserialized over Gson
16 | -keep class com.github.warren_bank.sms_automatic_forwarding.data_model.RecipientListItem { ; }
17 |
18 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
19 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
20 | -keep class * extends com.google.gson.TypeAdapter
21 | -keep class * implements com.google.gson.TypeAdapterFactory
22 | -keep class * implements com.google.gson.JsonSerializer
23 | -keep class * implements com.google.gson.JsonDeserializer
24 |
25 | # Prevent R8 from leaving Data object members always null
26 | -keepclassmembers,allowobfuscation class * {
27 | @com.google.gson.annotations.SerializedName ;
28 | }
29 |
30 | # Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
31 | -keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
32 | -keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
33 |
34 | ##---------- End: proguard configuration for Gson ----------
35 |
36 | -keeppackagenames com.github.warren_bank.sms_automatic_forwarding.**
37 |
38 | -keep class com.github.warren_bank.sms_automatic_forwarding.** { *; }
39 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/java/com/github/warren_bank/sms_automatic_forwarding/security_model/RuntimePermissions.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.security_model;
2 |
3 | import android.app.Activity;
4 | import android.content.pm.PackageManager;
5 | import android.os.Build;
6 | import java.util.ArrayList;
7 |
8 | public final class RuntimePermissions {
9 | private static final int REQUEST_CODE = 0;
10 |
11 | protected static String[] getMissingPermissions(Activity activity, String[] permissions_all) {
12 | ArrayList permissions_req = new ArrayList();
13 |
14 | for (String permission_name : permissions_all) {
15 | if (activity.checkSelfPermission(permission_name) != PackageManager.PERMISSION_GRANTED) {
16 | permissions_req.add(permission_name);
17 | }
18 | }
19 |
20 | return permissions_req.isEmpty()
21 | ? null
22 | : permissions_req.toArray(new String[0]);
23 | }
24 |
25 | public static boolean isEnabled(Activity activity) {
26 | if (Build.VERSION.SDK_INT < 23)
27 | return true;
28 |
29 | final String[] permissions_all = new String[]{ "android.permission.RECEIVE_SMS", "android.permission.SEND_SMS" };
30 | final String[] permissions_req = RuntimePermissions.getMissingPermissions(activity, permissions_all);
31 |
32 | if (permissions_req == null)
33 | return true;
34 |
35 | activity.requestPermissions(permissions_req, REQUEST_CODE);
36 | return false;
37 | }
38 |
39 | public static void onRequestPermissionsResult (Activity activity, int requestCode, String[] permissions, int[] grantResults) {
40 | if (requestCode != REQUEST_CODE)
41 | return;
42 |
43 | if (grantResults.length == 0)
44 | return;
45 |
46 | for (int result : grantResults) {
47 | if (result != PackageManager.PERMISSION_GRANTED) return;
48 | }
49 |
50 | activity.recreate();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/java/com/github/warren_bank/sms_automatic_forwarding/data_model/Preferences.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.data_model;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import java.util.ArrayList;
6 |
7 | public final class Preferences {
8 | private static final String PREFS_FILENAME = "PREFS";
9 | private static final String PREF_ENABLED = "ENABLED";
10 | private static final String PREF_LISTITEMS = "LISTITEMS";
11 |
12 | public static boolean isEnabled(Context context) {
13 | SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE);
14 | return sharedPreferences.getBoolean(PREF_ENABLED, true);
15 | }
16 |
17 | public static void setEnabled(Context context, boolean enabled) {
18 | SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE);
19 | SharedPreferences.Editor prefs_editor = sharedPreferences.edit();
20 | prefs_editor.putBoolean(PREF_ENABLED, enabled);
21 | prefs_editor.apply();
22 | }
23 |
24 | public static ArrayList getRecipientListItems(Context context) {
25 | SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE);
26 | String json = sharedPreferences.getString(PREF_LISTITEMS, null);
27 |
28 | return (json == null)
29 | ? new ArrayList()
30 | : RecipientListItem.fromJson(json)
31 | ;
32 | }
33 |
34 | public static void setRecipientListItems(Context context, ArrayList listItems) {
35 | String json = RecipientListItem.toJson(listItems);
36 |
37 | SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_FILENAME, Context.MODE_PRIVATE);
38 | SharedPreferences.Editor prefs_editor = sharedPreferences.edit();
39 | prefs_editor.putString(PREF_LISTITEMS, json);
40 | prefs_editor.apply();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: '../constants.gradle'
2 | apply plugin: 'com.android.application'
3 |
4 | android {
5 | namespace project.ext.applicationId
6 |
7 | compileSdkVersion project.ext.compileSdkVersion
8 | buildToolsVersion project.ext.buildToolsVersion
9 |
10 | compileOptions {
11 | sourceCompatibility project.ext.javaVersion
12 | targetCompatibility project.ext.javaVersion
13 | }
14 |
15 | defaultConfig {
16 | minSdkVersion project.ext.minSdkVersion
17 | targetSdkVersion project.ext.targetSdkVersion
18 |
19 | applicationId project.ext.applicationId
20 | versionName project.ext.releaseVersion
21 | versionCode project.ext.releaseVersionCode
22 |
23 | archivesBaseName += "-$versionName"
24 | }
25 |
26 | flavorDimensions "languageResources", "contactName"
27 |
28 | productFlavors {
29 | withAllLanguageTranslations {
30 | dimension "languageResources"
31 | }
32 | english {
33 | dimension "languageResources"
34 | }
35 | withContactName {
36 | dimension "contactName"
37 | }
38 | noContactName {
39 | dimension "contactName"
40 | }
41 | }
42 |
43 | buildTypes {
44 | release {
45 | debuggable false
46 | jniDebuggable false
47 | shrinkResources true
48 | minifyEnabled true
49 | proguardFiles = [
50 | "proguard-rules.txt",
51 | getDefaultProguardFile('proguard-android.txt')
52 | ]
53 | }
54 | debug {
55 | debuggable true
56 | jniDebuggable true
57 | shrinkResources false
58 | minifyEnabled false
59 | }
60 | }
61 |
62 | dependenciesInfo {
63 | includeInApk = false // Disables dependency metadata when building APKs.
64 | includeInBundle = false // Disables dependency metadata when building Android App Bundles.
65 | }
66 |
67 | lintOptions {
68 | disable 'MissingTranslation'
69 | abortOnError true
70 | }
71 | }
72 |
73 | dependencies {
74 | implementation 'com.google.code.gson:gson:2.8.5' // https://mvnrepository.com/artifact/com.google.code.gson/gson
75 | }
76 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/res/layout/dialog_recipient_listitem.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
17 |
18 |
23 |
24 |
30 |
31 |
37 |
38 |
44 |
45 |
52 |
53 |
59 |
60 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/android-studio-project/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/java/com/github/warren_bank/sms_automatic_forwarding/event/SMSReceiver.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.event;
2 |
3 | import com.github.warren_bank.sms_automatic_forwarding.R;
4 | import com.github.warren_bank.sms_automatic_forwarding.data_model.Contacts;
5 | import com.github.warren_bank.sms_automatic_forwarding.data_model.Preferences;
6 | import com.github.warren_bank.sms_automatic_forwarding.data_model.RecipientListItem;
7 |
8 | import android.content.BroadcastReceiver;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.os.Build;
12 | import android.os.Bundle;
13 | import android.telephony.SmsMessage;
14 | import android.util.Log;
15 | import java.util.ArrayList;
16 |
17 | public class SMSReceiver extends BroadcastReceiver {
18 | private static final String TAG = "SMSReceiver";
19 | private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
20 |
21 | public void onReceive(Context context, Intent intent) {
22 | if (!Preferences.isEnabled(context))
23 | return;
24 |
25 | final String action = intent.getAction();
26 | final Bundle extras = intent.getExtras();
27 |
28 | if (extras == null)
29 | return;
30 |
31 | final ArrayList listItems = Preferences.getRecipientListItems(context);
32 |
33 | if (listItems.isEmpty())
34 | return;
35 |
36 | if (action.equals(SMS_RECEIVED)) {
37 | final SmsMessage[] messages = get_SmsMessages(extras);
38 |
39 | String sender = null;
40 | ArrayList recipients = null;
41 | String body = null;
42 | String sender_contact_name = null;
43 |
44 | for (SmsMessage message : messages) {
45 | if (message == null)
46 | continue;
47 |
48 | try {
49 | sender = message.getOriginatingAddress().trim();
50 | recipients = RecipientListItem.match(listItems, sender);
51 |
52 | if (!recipients.isEmpty()) {
53 | body = message.getMessageBody();
54 |
55 | if (body != null) {
56 | body = body.trim();
57 |
58 | if (!body.isEmpty()) {
59 | Log.i(TAG, "SMS received.\nfrom: " + sender + "\nmessage: " + body);
60 |
61 | sender_contact_name = Contacts.getContactName(context, sender);
62 |
63 | SMSSender.forward(context, recipients, sender, sender_contact_name, body);
64 | }
65 | }
66 | }
67 | }
68 | catch (Exception e) { continue; }
69 | }
70 | }
71 | }
72 |
73 | private final static SmsMessage[] get_SmsMessages(Bundle extras) {
74 | final Object[] pdus = (Object[])extras.get("pdus");
75 | final String format = extras.getString("format", "3gpp");
76 | final SmsMessage[] messages = new SmsMessage[pdus.length];
77 |
78 | for (int i = 0; i < pdus.length; i++) {
79 | try {
80 | messages[i] = (Build.VERSION.SDK_INT >= 23)
81 | ? SmsMessage.createFromPdu((byte[])pdus[i], format)
82 | : SmsMessage.createFromPdu((byte[])pdus[i]);
83 | }
84 | catch (Exception e) {}
85 | }
86 | return messages;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### [SMS Forwarding](https://github.com/warren-bank/Android-SMS-Automatic-Forwarding)
2 |
3 | Android app that listens for incoming SMS text messages and conditionally forwards them to other numbers.
4 |
5 | #### Notes:
6 |
7 | * minimum supported version of Android:
8 | - Android 3.0 (API level 11)
9 |
10 | #### Screenshots:
11 |
12 | 
13 | 
14 | 
15 |
16 | - - - -
17 |
18 | ### Configuration
19 |
20 | #### Forwarding Rules:
21 |
22 | * `Enable Service` checkbox:
23 | - used to enable/disable this service
24 | * `ADD` ActionBar menu item:
25 | - adds new forwarding rule
26 | * forwarding rule entries are defined as follows:
27 | - `Forwarding recipient`:
28 | * a valid phone number (without any punctuation)
29 | - `Sender must end with`:
30 | * this value specifies a phone number (without any punctuation)
31 | - a match occurs when the _sender_ of an incoming SMS message ends with this exact value
32 | - a special match-all glob pattern `*` is supported,
which can either be manually entered into the field
or automatically set when the field is left empty
33 | * this value acts as a filter
34 | - `Forwarding recipient` will only receive copies of incoming SMS messages that match this value
35 | * forwarding rule entries can be modified
36 | - clicking on an existing recipient opens a dialog with options to:
37 | * edit field values, and save changes
38 | * delete
39 |
40 | #### Forwarding Rules (Advanced Usage):
41 |
42 | * `Forwarding recipient` field:
43 | - supports: comma-separated list of values
44 | - example:
45 | * `8001190000,8002290000,8003390000`
46 | * `Sender must end with` field:
47 | - supports: ``
48 | - where:
49 | * both `` and `` are a comma-separated list of values
50 | * `` is required
51 | * `` is optional
52 | * `` is a single character that denotes the start of ``
53 | - any of the following characters are allowed: `!/#`
54 | - special case:
55 | * `` is `*`
…all other values in its comma-separated list are ignored
56 | - examples:
57 | * `8001190000,8002290000,8003390000`
58 | * `*/8001190000,8002290000,8003390000`
59 | * `0000/8001190000,8002290000,8003390000`
60 | * `0000/90000`
61 |
62 | - - - -
63 |
64 | #### Build Flavors:
65 |
66 | * `english`
67 | - includes string resources for only the English language
68 | * `withAllLanguageTranslations`
69 | - includes string resources for additional languages
70 | * `noContactName`
71 | - "Forwarded from: <sender_phone>"
72 | * `withContactName`
73 | - "Forwarded from: <sender_name> <sender_phone>"
74 | * if `sender_phone` is found in the local contacts list,
and the contact has a name associated with it
75 | - "Forwarded from: <sender_phone>"
76 | * otherwise
77 |
78 | - - - -
79 |
80 | #### Caveats:
81 |
82 | * _Google Voice_:
83 | - when an SMS is sent from a _Google Voice_ number to the SIM card number
84 | * everything works as expected
85 | - when an SMS is sent to a _Google Voice_ number
86 | * the sender of the SMS message will always be a number belonging to the _Google Voice_ backend infrastructure
87 | * keep this in mind when setting forwarding filters
88 |
89 | #### Legal:
90 |
91 | * copyright: [Warren Bank](https://github.com/warren-bank)
92 | * license: [GPL-2.0](https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt)
93 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/java/com/github/warren_bank/sms_automatic_forwarding/data_model/RecipientListItem.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.data_model;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.reflect.TypeToken;
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.HashSet;
8 |
9 | public final class RecipientListItem {
10 | public String recipient;
11 | public String sender;
12 |
13 | public RecipientListItem() {
14 | this.recipient = "";
15 | this.sender = "";
16 | }
17 |
18 | public RecipientListItem(String recipient, String sender) {
19 | this.recipient = recipient;
20 | this.sender = sender;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return recipient;
26 | }
27 |
28 | // helpers
29 |
30 | public static ArrayList fromJson(String json) {
31 | ArrayList arrayList;
32 | Gson gson = new Gson();
33 | arrayList = gson.fromJson(json, new TypeToken>(){}.getType());
34 | return arrayList;
35 | }
36 |
37 | public static String toJson(ArrayList arrayList) {
38 | String json = new Gson().toJson(arrayList);
39 | return json;
40 | }
41 |
42 | public static ArrayList match(ArrayList arrayList, String sender) {
43 | ArrayList allRecipients = new ArrayList();
44 | RecipientListItem item;
45 | RecipientListItemCriteria criteria;
46 |
47 | for (int i=0; i < arrayList.size(); i++) {
48 | try {
49 | item = arrayList.get(i);
50 | criteria = new RecipientListItemCriteria(item);
51 |
52 | criteria.match(sender, allRecipients);
53 | }
54 | catch(Exception e) { continue; }
55 | }
56 |
57 | allRecipients = sanitizeMatches(sender, allRecipients);
58 | return allRecipients;
59 | }
60 |
61 | private static ArrayList sanitizeMatches(String sender, ArrayList allRecipients) {
62 | // remove duplicates from recipients list:
63 | HashSet uniqueRecipients = new HashSet(allRecipients);
64 | allRecipients = new ArrayList(uniqueRecipients);
65 |
66 | // remove sender from recipients list:
67 | allRecipients.remove(sender);
68 |
69 | return allRecipients;
70 | }
71 |
72 | /*
73 | * ---------------------------------------------------------------------------
74 | * Parser that supports more advanced values in 'recipient' and 'sender' fields.
75 | * Fully backwards compatible with older single-value field values.
76 | *
77 | * 'recipient' field:
78 | * - supports: comma-separated list of values
79 | * - example:
80 | * 8001190000,8002290000,8003390000
81 | *
82 | * 'sender' field:
83 | * - supports: !
84 | * - where:
85 | * * both and are a comma-separated list of values
86 | * * is required
87 | * * is optional
88 | * * the character '!' denotes the start of
89 | * - special case:
90 | * * is '*'
91 | * ..all other values in its comma-separated list are ignored
92 | * - examples:
93 | * 8001190000,8002290000,8003390000
94 | * *!8001190000,8002290000,8003390000
95 | * 0000!8001190000,8002290000,8003390000
96 | * 0000!90000
97 | * ---------------------------------------------------------------------------
98 | */
99 |
100 | private static class RecipientListItemCriteria {
101 | private String[] recipients;
102 | private String[] sender_whitelist;
103 | private String[] sender_blacklist;
104 |
105 | private static String[] splitCSV(String list) {
106 | return splitCSV(list, ',');
107 | }
108 |
109 | private static String[] splitCSV(String list, char delimiter) {
110 | return splitCSV(list, String.valueOf(delimiter));
111 | }
112 |
113 | private static String[] splitCSV(String list, String delimiter) {
114 | if (list == null) return null;
115 |
116 | String regex = "\\s*" + delimiter + "\\s*";
117 | return list.trim().split(regex);
118 | }
119 |
120 | private static void sanitizeInput(String[] input, boolean allowGlobPattern) {
121 | if ((input == null) || (input.length == 0)) return;
122 |
123 | if (allowGlobPattern && (input.length == 1) && ("*".equals(input[0]))) return;
124 |
125 | for (int i=0; i < input.length; i++) {
126 | input[i] = sanitizeInput(input[i]);
127 | }
128 | }
129 |
130 | private static String sanitizeInput(String input) {
131 | if ((input == null) || input.isEmpty()) return "";
132 |
133 | String prefix = (input.charAt(0) == '+')
134 | ? "+"
135 | : "";
136 |
137 | String numeric = input.replaceAll("[^0-9]", "");
138 |
139 | return prefix + numeric;
140 | }
141 |
142 | public RecipientListItemCriteria(RecipientListItem item) {
143 | parseRecipient(item.recipient);
144 | parseSender(item.sender);
145 |
146 | sanitizeInput(this.recipients, false);
147 | sanitizeInput(this.sender_whitelist, true);
148 | sanitizeInput(this.sender_blacklist, false);
149 | }
150 |
151 | private void parseRecipient(String recipient) {
152 | this.recipients = splitCSV(recipient);
153 | }
154 |
155 | private void parseSender(String sender) {
156 | String[] parts = splitCSV(sender, "[!/#]");
157 |
158 | if (parts == null)
159 | return;
160 | if (parts.length > 0) {
161 | String whitelist = parts[0];
162 | if (!whitelist.isEmpty()) {
163 | ArrayList wl_list = new ArrayList();
164 | String[] wl_array = splitCSV(whitelist);
165 | for (String wl_value : wl_array) {
166 | if (wl_value.isEmpty())
167 | continue;
168 | if (wl_value.equals("*")) {
169 | wl_list.clear();
170 | wl_list.add(wl_value);
171 | break;
172 | }
173 | wl_value = wl_value.replace("*", "");
174 | wl_list.add(wl_value);
175 | }
176 | this.sender_whitelist = wl_list.toArray(new String[0]);
177 | }
178 | }
179 | if (parts.length > 1) {
180 | String blacklist = parts[1];
181 | if (!blacklist.isEmpty()) {
182 | this.sender_blacklist = splitCSV(blacklist);
183 | }
184 | }
185 | }
186 |
187 | // mutates 'allRecipients' list
188 | private void match(String sender, ArrayList allRecipients) {
189 | if ((this.recipients == null) || (this.sender_whitelist == null)) return;
190 |
191 | // is sender in blacklist?
192 | if (this.sender_blacklist != null) {
193 | for (String bl_value : this.sender_blacklist) {
194 | if (sender.endsWith(bl_value)) {
195 | return;
196 | }
197 | }
198 | }
199 |
200 | // is sender in whitelist?
201 | for (String wl_value : this.sender_whitelist) {
202 | if (wl_value.equals("*") || sender.endsWith(wl_value)) {
203 | allRecipients.addAll(
204 | Arrays.asList(this.recipients)
205 | );
206 | return;
207 | }
208 | }
209 | }
210 | }
211 |
212 | }
213 |
--------------------------------------------------------------------------------
/android-studio-project/SMS-Forwarding/src/main/java/com/github/warren_bank/sms_automatic_forwarding/ui/RecipientListActivity.java:
--------------------------------------------------------------------------------
1 | package com.github.warren_bank.sms_automatic_forwarding.ui;
2 |
3 | import com.github.warren_bank.sms_automatic_forwarding.R;
4 | import com.github.warren_bank.sms_automatic_forwarding.data_model.Preferences;
5 | import com.github.warren_bank.sms_automatic_forwarding.data_model.RecipientListItem;
6 | import com.github.warren_bank.sms_automatic_forwarding.security_model.OptionalRuntimePermissions;
7 | import com.github.warren_bank.sms_automatic_forwarding.security_model.RuntimePermissions;
8 |
9 | import android.app.Activity;
10 | import android.app.Dialog;
11 | import android.os.Bundle;
12 | import android.view.Menu;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.view.Window;
16 | import android.widget.AdapterView;
17 | import android.widget.ArrayAdapter;
18 | import android.widget.Button;
19 | import android.widget.CheckBox;
20 | import android.widget.EditText;
21 | import android.widget.ListView;
22 | import android.widget.Toast;
23 | import java.util.ArrayList;
24 |
25 | public class RecipientListActivity extends Activity {
26 | private CheckBox inputEnable;
27 | private ListView listView;
28 |
29 | private ArrayList listItems;
30 | private ArrayAdapter listAdapter;
31 |
32 | // ---------------------------------------------------------------------------------------------
33 | // Lifecycle Events:
34 | // ---------------------------------------------------------------------------------------------
35 |
36 | @Override
37 | protected void onCreate(Bundle savedInstanceState) {
38 | super.onCreate(savedInstanceState);
39 | setContentView(R.layout.activity_recipient_list);
40 |
41 | inputEnable = (CheckBox) findViewById(R.id.input_enable);
42 | listView = (ListView) findViewById(R.id.listview);
43 |
44 | listItems = Preferences.getRecipientListItems(RecipientListActivity.this);
45 | listAdapter = new ArrayAdapter(RecipientListActivity.this, android.R.layout.simple_list_item_1, listItems);
46 | listView.setAdapter(listAdapter);
47 |
48 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
49 | @Override
50 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
51 | showEditDialog(position);
52 | return;
53 | }
54 | });
55 |
56 | if (RuntimePermissions.isEnabled(RecipientListActivity.this)) {
57 | OptionalRuntimePermissions.requestPermissions(RecipientListActivity.this);
58 |
59 | inputEnable.setChecked(Preferences.isEnabled(RecipientListActivity.this));
60 | inputEnable.setEnabled(true);
61 | inputEnable.setClickable(true);
62 |
63 | inputEnable.setOnClickListener(new View.OnClickListener() {
64 | @Override
65 | public void onClick(View v) {
66 | Preferences.setEnabled(RecipientListActivity.this, inputEnable.isChecked());
67 | }
68 | });
69 | }
70 | else {
71 | inputEnable.setChecked(false);
72 | inputEnable.setEnabled(false);
73 | inputEnable.setClickable(false);
74 |
75 | if (Preferences.isEnabled(RecipientListActivity.this)) {
76 | Preferences.setEnabled(RecipientListActivity.this, false);
77 | }
78 | }
79 | }
80 |
81 | @Override
82 | public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
83 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
84 |
85 | RuntimePermissions.onRequestPermissionsResult(RecipientListActivity.this, requestCode, permissions, grantResults);
86 | }
87 |
88 | // ---------------------------------------------------------------------------------------------
89 | // ActionBar:
90 | // ---------------------------------------------------------------------------------------------
91 |
92 | @Override
93 | public boolean onCreateOptionsMenu(Menu menu) {
94 | getActionBar().setDisplayShowHomeEnabled(false);
95 | getMenuInflater().inflate(R.menu.activity_recipient_list, menu);
96 | return true;
97 | }
98 |
99 | @Override
100 | public boolean onOptionsItemSelected(MenuItem menuItem) {
101 | switch(menuItem.getItemId()) {
102 | case R.id.menu_add: {
103 | showEditDialog(-1);
104 | return true;
105 | }
106 | default: {
107 | return super.onOptionsItemSelected(menuItem);
108 | }
109 | }
110 | }
111 |
112 | // ---------------------------------------------------------------------------------------------
113 | // Add/Edit Dialog:
114 | // ---------------------------------------------------------------------------------------------
115 |
116 | private void showEditDialog(final int position) {
117 | final boolean isAdd = (position < 0);
118 |
119 | final RecipientListItem listItem = (isAdd)
120 | ? new RecipientListItem()
121 | : listItems.get(position)
122 | ;
123 |
124 | final Dialog dialog = new Dialog(RecipientListActivity.this, R.style.app_theme);
125 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
126 | dialog.setContentView(R.layout.dialog_recipient_listitem);
127 |
128 | final EditText inputRecipient = (EditText) dialog.findViewById(R.id.input_recipient);
129 | final EditText inputSender = (EditText) dialog.findViewById(R.id.input_sender);
130 |
131 | final Button buttonDelete = (Button) dialog.findViewById(R.id.button_delete);
132 | final Button buttonSave = (Button) dialog.findViewById(R.id.button_save);
133 |
134 | inputRecipient.setText(listItem.recipient);
135 | inputSender.setText(
136 | listItem.sender.isEmpty() ? "*" : listItem.sender
137 | );
138 |
139 | if (isAdd) {
140 | buttonDelete.setText(R.string.label_button_cancel);
141 | }
142 |
143 | buttonDelete.setOnClickListener(new View.OnClickListener() {
144 | @Override
145 | public void onClick(View v) {
146 | if (!isAdd) {
147 | listItems.remove(position);
148 | listAdapter.notifyDataSetChanged();
149 | }
150 | dialog.dismiss();
151 | }
152 | });
153 |
154 | buttonSave.setOnClickListener(new View.OnClickListener() {
155 | @Override
156 | public void onClick(View v) {
157 | final String new_recipient = inputRecipient.getText().toString().trim();
158 |
159 | String new_sender = inputSender.getText().toString().trim();
160 | if (new_sender.equals("")) {
161 | new_sender = "*";
162 | }
163 |
164 | final boolean same_recipient = new_recipient.equals(listItem.recipient);
165 | final boolean same_sender = new_sender.equals(listItem.sender);
166 |
167 | if (new_recipient.equals("")) {
168 | Toast.makeText(RecipientListActivity.this, getResources().getString(R.string.error_missing_required_value), Toast.LENGTH_SHORT).show();
169 | return;
170 | }
171 |
172 | if (same_recipient && same_sender) {
173 | // no change
174 | dialog.dismiss();
175 | return;
176 | }
177 |
178 | if (!same_recipient) {
179 | listItem.recipient = new_recipient;
180 | }
181 | if (!same_sender) {
182 | listItem.sender = new_sender;
183 | }
184 |
185 | if (isAdd) {
186 | if (!listItems.add(listItem)) {
187 | Toast.makeText(RecipientListActivity.this, getResources().getString(R.string.error_add_listitem), Toast.LENGTH_SHORT).show();
188 | return;
189 | }
190 | }
191 |
192 | listAdapter.notifyDataSetChanged();
193 | dialog.dismiss();
194 |
195 | Preferences.setRecipientListItems(RecipientListActivity.this, listItems);
196 | }
197 | });
198 |
199 | dialog.show();
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/android-studio-project/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------