6 |
7 | 
8 | [](https://github.com/telegram-sms/telegram-sms/blob/master/LICENSE)
9 | [](https://github.com/telegram-sms/telegram-sms/releases/latest)
10 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fqwe7002%2Ftelegram-sms?ref=badge_shield)
11 |
12 | ## We're in this together
13 |
14 | > Fight COVID-19. Stay at home. Save lives.
15 |
16 | ## News, Questions and Contributions
17 |
18 | **Because the XDA updates itself to XDA2021, XDA Labs has been closed. I am sorry for this and I can no longer provide the XDA Lab version of Telegram SMS. You can still use the GitHub version to update your Telegram SMS. If you request a refund, please contact me via qwe7002@hotmail.com**
19 |
20 | You can follow the Telegram channel Telegram SMS Change Log for the latest news. [English](https://t.me/tg_sms_changelog_eng), [简体中文](https://t.me/tg_sms_changelog)
21 |
22 | **Please visit [https://reall.uk](https://reall.uk) to submit and discuss issues regarding this project.**
23 |
24 | **请访问 [https://reall.uk](https://reall.uk) 提交并讨论有关此项目的问题。**
25 |
26 | The primary language used for commit messages is Simplified Chinese. However, you're welcome to use English in commit messages when making contributions.
27 |
28 | If you want to generate the configuration QR code in a fast way, please visit [qrcode.telegram-sms.com](https://qrcode.telegram-sms.com).
29 |
30 | ## Get the Right Version
31 |
32 | **Warning**: All versions are not compatible (not signed by the same key)! You have to uninstall one first to install another, which will delete all your data.
33 |
34 | [Latest Release Download](https://github.com/telegram-sms/telegram-sms/releases/latest)
35 |
36 | [Pre-release Verison](https://github.com/qwe7002/telegram-sms) [Download](https://github.com/qwe7002/telegram-sms/actions?query=actor%3Areall-network+branch%3Anightly+is%3Asuccess+event%3Apush)
37 |
38 | **NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK!**
39 |
40 | [Telegram SMS compat](https://github.com/telegram-sms/telegram-sms-compat)
41 |
42 | Android 5.0 or lower? Click [](https://github.com/telegram-sms/telegram-sms-compat/releases/latest) to download the latest and greatest.
43 |
44 |
45 | ## Features
46 |
47 | - Forward SMS text messages to Telegram as a bot;
48 | - Notification regarding missed calls;
49 | - Notification regarding device battery power changes;
50 | - Remote control via chat command or SMS.
51 |
52 | ## Permission
53 |
54 | This app requires following permissions to work properly:
55 |
56 | - SMS: To read and send text messages.
57 | - Phone: Check whether it is a dual SIM-Card phone, the SIM status and its identification digits.
58 | - Call phone: Execute the USSD code.
59 | - Call log: Read incoming numbers.
60 | - Camera: Scan the QR code and quickly enter the Bot Token.
61 | - Notification access: Listen for notification messages.
62 |
63 | You can set this APP as the default SMS APP, which will stop popping up SMS notifications and set all received SMS as "read" on the phone.
64 |
65 | ## User Manual
66 |
67 | - [English](https://get.telegram-sms.com/wiki/User_manual)
68 | - [简体中文](https://get.telegram-sms.com/wiki/用户手册)
69 | - [繁體中文](https://get.telegram-sms.com/wiki/用戶手冊)
70 | - [日本語](https://get.telegram-sms.com/wiki/マニュアル)
71 |
72 | ## Licenses
73 |
74 | Telegram-SMS is licensed under [BSD 3-Clause License](https://get.telegram-sms.com/license).
75 |
76 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fqwe7002%2Ftelegram-sms?ref=badge_large)
77 |
78 | CodeauxLib is licensed under [BSD 3-Clause License](https://github.com/telegram-sms/telegram-sms/blob/master/codeauxlib-license/LICENSE).
79 |
80 | Artwork Use free fonts licensed by the whole society: [站酷庆科黄油体](https://www.zcool.com.cn/work/ZMTg5MDEyMDQ=.html)
81 |
82 | Copyright of the artwork belongs to [@walliant](https://www.pixiv.net/member.php?id=5600144). Licensed under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
83 |
84 | Cover Author: [@YJBeetle](https://github.com/yjbeetle)
85 |
86 | Download resource file of the artwork: [mega.nz](https://mega.nz/#F!TmwQSYjD!XN-uVfciajwy3okjIdpCAQ)
87 |
88 | Character set:
89 |
90 | - Name: Fay (菲, フェイ)
91 | - Birthday: 1st October, 2018
92 | - Place of birth: Fujian, China
93 | - Zodiac sign: Libra
94 | - Habits: Eat sweets, Maid dress, Listen Heavy metal music
95 |
96 | Designed by Reall with love in Fujian, China
97 |
98 | ## Acknowledgements
99 |
100 | This APP uses the following open source libraries:
101 |
102 | - [okhttp](https://github.com/square/okhttp)
103 | - [Gson](https://github.com/google/gson)
104 | - [CodeauxLib](https://github.com/telegram-sms/CodeauxLibPortable)
105 | - [Paper](https://github.com/pilgr/Paper)
106 | - [AwesomeQRCode](https://github.com/SumiMakito/AwesomeQRCode)
107 |
108 | The creation of this APP would not be possible without the help from the following people:
109 |
110 | - [@SumiMakito](https://github.com/SumiMakito) ([Donate](https://paypal.me/makito))
111 | - [@zsxsoft](https://github.com/zsxsoft)
112 | - [@walliant](https://www.pixiv.net/member.php?id=5600144) ([weibo](https://www.weibo.com/p/1005053186671274))
113 |
114 | I would also like to thank the following people for their hard work to localise this project:
115 |
116 | - English
117 | - [@tangbao](https://github.com/tangbao)
118 | - [@jixunmoe](https://github.com/jixunmoe) ([Donate](https://paypal.me/jixun))
119 | - Japanese
120 | - [@Lollycc](https://github.com/lollycc)
121 | - [@AisakaMk2](https://github.com/AisakaMk2)
122 | - [@Qiaogun](https://github.com/Qiaogun)
123 | - Spanish
124 | - [@David Alonso](https://github.com/lpdavidgc)
125 | - Chinese(Traditional)
126 | - [@lm902](https://github.com/lm902)
127 | - [@孟武尼德霍格龍](https://github.com/tony8077616)
128 |
129 | This APP uses the following public DNS service:
130 |
131 | - [1.1.1.1](https://1.1.1.1/)
132 |
133 | And finally, [sm.ms](https://sm.ms) for hosting images used in this page.
134 |
135 | ## Buy me a cup of coffee to help maintain this project further?
136 |
137 | - [via Github](https://get.telegram-sms.com/donate/github)
138 | - [via Paypal](https://get.telegram-sms.com/donate/paypal)
139 | - [via Bitcoin](bitcoin:17wmCCzy7hSSENnRBfUBMUSi7kdHYePrae) (**17wmCCzy7hSSENnRBfUBMUSi7kdHYePrae**)
140 | - [via UnionPay (中国银联云闪付)](https://get.telegram-sms.com/donate/unionpay)
141 |
142 | Your donation will make me work better for this project.
143 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
97 |
98 |
99 |
100 |
101 |
102 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
123 |
124 |
125 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
20 |
28 |
31 |
32 |
42 |
43 |
44 |
45 |
48 |
58 |
59 |
60 |
63 |
73 |
74 |
75 |
82 |
83 |
90 |
91 |
98 |
99 |
106 |
107 |
114 |
115 |
122 |
123 |
130 |
131 |
138 |
139 |
145 |
146 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/app/src/main/java/com/qwe7002/telegram_sms/static_class/other_func.java:
--------------------------------------------------------------------------------
1 | package com.qwe7002.telegram_sms.static_class;
2 |
3 | import android.Manifest;
4 | import android.app.Notification;
5 | import android.app.NotificationChannel;
6 | import android.app.NotificationManager;
7 | import android.content.Context;
8 | import android.content.pm.PackageManager;
9 | import android.os.Build;
10 | import android.telephony.SubscriptionInfo;
11 | import android.telephony.SubscriptionManager;
12 | import android.util.Log;
13 |
14 | import androidx.core.app.ActivityCompat;
15 |
16 | import com.google.gson.JsonObject;
17 | import com.google.gson.JsonParser;
18 | import com.qwe7002.telegram_sms.R;
19 | import com.qwe7002.telegram_sms.data_structure.sms_request_info;
20 |
21 | import org.jetbrains.annotations.NotNull;
22 |
23 | import java.util.HashMap;
24 | import java.util.Map;
25 |
26 | import io.paperdb.Paper;
27 |
28 |
29 | public class other_func {
30 |
31 | public static String get_nine_key_map_convert(String input) {
32 | final Map nine_key_map = new HashMap() {
33 | {
34 | put('A', 2);
35 | put('B', 2);
36 | put('C', 2);
37 | put('D', 3);
38 | put('E', 3);
39 | put('F', 3);
40 | put('G', 4);
41 | put('H', 4);
42 | put('I', 4);
43 | put('J', 5);
44 | put('K', 5);
45 | put('L', 5);
46 | put('M', 6);
47 | put('N', 6);
48 | put('O', 6);
49 | put('P', 7);
50 | put('Q', 7);
51 | put('R', 7);
52 | put('S', 7);
53 | put('T', 8);
54 | put('U', 8);
55 | put('V', 8);
56 | put('W', 9);
57 | put('X', 9);
58 | put('Y', 9);
59 | put('Z', 9);
60 | }
61 | };
62 | StringBuilder result_stringbuilder = new StringBuilder();
63 | char[] phone_number_char_array = input.toUpperCase().toCharArray();
64 | for (char c : phone_number_char_array) {
65 | if (Character.isUpperCase(c)) {
66 | result_stringbuilder.append(nine_key_map.get(c));
67 | } else {
68 | result_stringbuilder.append(c);
69 | }
70 | }
71 | return result_stringbuilder.toString();
72 | }
73 |
74 | public static long parse_string_to_long(String content) {
75 | long result = 0;
76 | try {
77 | result = Long.parseLong(content);
78 | } catch (NumberFormatException e) {
79 | e.printStackTrace();
80 | }
81 | return result;
82 | }
83 |
84 | @NotNull
85 | public static String get_send_phone_number(@NotNull String phone_number) {
86 | phone_number = get_nine_key_map_convert(phone_number);
87 | StringBuilder result = new StringBuilder();
88 | for (int i = 0; i < phone_number.length(); ++i) {
89 | char c = phone_number.charAt(i);
90 | if (c == '+' || Character.isDigit(c)) {
91 | result.append(c);
92 | }
93 | }
94 | return result.toString();
95 | }
96 |
97 | public static String get_dual_sim_card_display(Context context, int slot, boolean show_name) {
98 | String dual_sim = "";
99 | if (slot == -1) {
100 | return dual_sim;
101 | }
102 | if (other_func.get_active_card(context) >= 2) {
103 | String result = "";
104 | if (show_name) {
105 | result = "(" + get_sim_display_name(context, slot) + ")";
106 | }
107 | dual_sim = "SIM" + (slot + 1) + result + " ";
108 | }
109 | return dual_sim;
110 | }
111 |
112 | public static boolean is_phone_number(@NotNull String str) {
113 | for (int i = str.length(); --i >= 0; ) {
114 | char c = str.charAt(i);
115 | if (c == '+') {
116 | Log.d("is_phone_number", "is_phone_number: found +.");
117 | continue;
118 | }
119 | if (!Character.isDigit(c)) {
120 | return false;
121 | }
122 | }
123 | return true;
124 | }
125 |
126 |
127 | public static long get_message_id(String result) {
128 | JsonObject result_obj = JsonParser.parseString(result).getAsJsonObject().get("result").getAsJsonObject();
129 | return result_obj.get("message_id").getAsLong();
130 | }
131 |
132 | @NotNull
133 | public static Notification get_notification_obj(Context context, String notification_name) {
134 | Notification.Builder notification;
135 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
136 | NotificationChannel channel = new NotificationChannel(notification_name, notification_name,
137 | NotificationManager.IMPORTANCE_MIN);
138 | NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
139 | assert manager != null;
140 | manager.createNotificationChannel(channel);
141 | notification = new Notification.Builder(context, notification_name);
142 | } else {//Notification generation method after O
143 | notification = new Notification.Builder(context).setPriority(Notification.PRIORITY_MIN);
144 | }
145 | notification.setAutoCancel(false)
146 | .setSmallIcon(R.drawable.ic_stat)
147 | .setOngoing(true)
148 | .setTicker(context.getString(R.string.app_name))
149 | .setContentTitle(context.getString(R.string.app_name))
150 | .setContentText(notification_name + context.getString(R.string.service_is_running));
151 | return notification.build();
152 | }
153 |
154 | public static int get_sub_id(Context context, int slot) {
155 | int active_card = other_func.get_active_card(context);
156 | if (active_card >= 2) {
157 | if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
158 | return -1;
159 | }
160 | SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
161 | assert subscriptionManager != null;
162 | return subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slot).getSubscriptionId();
163 | }
164 | return -1;
165 | }
166 |
167 | public static int get_active_card(Context context) {
168 | if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
169 | Log.d("get_active_card", "No permission.");
170 | return -1;
171 | }
172 | SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
173 | assert subscriptionManager != null;
174 | return subscriptionManager.getActiveSubscriptionInfoCount();
175 | }
176 |
177 |
178 | public static String get_sim_display_name(Context context, int slot) {
179 | final String TAG = "get_sim_display_name";
180 | String result = "Unknown";
181 | if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
182 | Log.d(TAG, "No permission.");
183 | return result;
184 | }
185 | SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
186 | assert subscriptionManager != null;
187 | SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(slot);
188 | if (info == null) {
189 | Log.d(TAG, "The active card is in the second card slot.");
190 | if (get_active_card(context) == 1 && slot == 0) {
191 | info = subscriptionManager.getActiveSubscriptionInfoForSimSlotIndex(1);
192 | }
193 | if (info == null) {
194 | return result;
195 | }
196 | return result;
197 | }
198 | result = info.getDisplayName().toString();
199 | if (info.getDisplayName().toString().contains("CARD") || info.getDisplayName().toString().contains("SUB")) {
200 | result = info.getCarrierName().toString();
201 | }
202 | return result;
203 | }
204 |
205 |
206 | public static void add_message_list(long message_id, String phone, int slot) {
207 | sms_request_info item = new sms_request_info();
208 | item.phone = phone;
209 | item.card = slot;
210 | Paper.book().write(String.valueOf(message_id), item);
211 | Log.d("add_message_list", "add_message_list: " + message_id);
212 | }
213 |
214 | }
215 |
--------------------------------------------------------------------------------
/app/src/main/java/com/qwe7002/telegram_sms/battery_service.java:
--------------------------------------------------------------------------------
1 | package com.qwe7002.telegram_sms;
2 |
3 | import android.app.Notification;
4 | import android.app.Service;
5 | import android.content.BroadcastReceiver;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.IntentFilter;
9 | import android.content.SharedPreferences;
10 | import android.os.BatteryManager;
11 | import android.os.IBinder;
12 | import android.util.Log;
13 |
14 | import com.google.gson.Gson;
15 | import com.qwe7002.telegram_sms.config.proxy;
16 | import com.qwe7002.telegram_sms.data_structure.request_message;
17 | import com.qwe7002.telegram_sms.static_class.log_func;
18 | import com.qwe7002.telegram_sms.static_class.network_func;
19 | import com.qwe7002.telegram_sms.static_class.other_func;
20 | import com.qwe7002.telegram_sms.static_class.sms_func;
21 | import com.qwe7002.telegram_sms.value.const_value;
22 | import com.qwe7002.telegram_sms.value.notify_id;
23 |
24 | import org.jetbrains.annotations.NotNull;
25 |
26 | import java.io.IOException;
27 | import java.util.ArrayList;
28 | import java.util.Objects;
29 |
30 | import io.paperdb.Paper;
31 | import okhttp3.Call;
32 | import okhttp3.OkHttpClient;
33 | import okhttp3.Request;
34 | import okhttp3.RequestBody;
35 | import okhttp3.Response;
36 |
37 | public class battery_service extends Service {
38 | static String bot_token;
39 | static String chat_id;
40 | static boolean doh_switch;
41 | private Context context;
42 | private battery_receiver battery_receiver = null;
43 | static long last_receive_time = 0;
44 | static long last_receive_message_id = -1;
45 |
46 | private static ArrayList send_loop_list;
47 | @Override
48 | public int onStartCommand(Intent intent, int flags, int startId) {
49 | Notification notification = other_func.get_notification_obj(context, getString(R.string.battery_monitoring_notify));
50 | startForeground(notify_id.BATTERY, notification);
51 | return START_STICKY;
52 | }
53 |
54 | @Override
55 | public void onCreate() {
56 | super.onCreate();
57 | context = getApplicationContext();
58 | Paper.init(context);
59 | SharedPreferences sharedPreferences = context.getSharedPreferences("data", MODE_PRIVATE);
60 | chat_id = sharedPreferences.getString("chat_id", "");
61 | bot_token = sharedPreferences.getString("bot_token", "");
62 | doh_switch = sharedPreferences.getBoolean("doh_switch", true);
63 | boolean charger_status = sharedPreferences.getBoolean("charger_status", false);
64 | battery_receiver = new battery_receiver();
65 | IntentFilter filter = new IntentFilter();
66 | filter.addAction(Intent.ACTION_BATTERY_OKAY);
67 | filter.addAction(Intent.ACTION_BATTERY_LOW);
68 | if (charger_status) {
69 | filter.addAction(Intent.ACTION_POWER_CONNECTED);
70 | filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
71 | }
72 | filter.addAction(const_value.BROADCAST_STOP_SERVICE);
73 | registerReceiver(battery_receiver, filter);
74 | send_loop_list = new ArrayList<>();
75 | new Thread(() -> {
76 | ArrayList need_remove = new ArrayList<>();
77 | while (true) {
78 | for (send_obj item : send_loop_list) {
79 | network_handle(item);
80 | need_remove.add(item);
81 | }
82 | send_loop_list.removeAll(need_remove);
83 | need_remove.clear();
84 | if (send_loop_list.size() == 0) {
85 | //Only enter sleep mode when there are no messages
86 | try {
87 | //noinspection BusyWait
88 | Thread.sleep(1000);
89 | } catch (InterruptedException e) {
90 | e.printStackTrace();
91 | }
92 | }
93 | }
94 | }).start();
95 | }
96 |
97 | private void network_handle(send_obj obj) {
98 | String TAG = "network_handle";
99 | final request_message request_body = new request_message();
100 | request_body.chat_id = battery_service.chat_id;
101 | request_body.text = obj.content;
102 | String request_uri = network_func.get_url(battery_service.bot_token, "sendMessage");
103 | if ((System.currentTimeMillis() - last_receive_time) <= 5000L && last_receive_message_id != -1) {
104 | request_uri = network_func.get_url(bot_token, "editMessageText");
105 | request_body.message_id = last_receive_message_id;
106 | Log.d(TAG, "onReceive: edit_mode");
107 | }
108 | last_receive_time = System.currentTimeMillis();
109 | OkHttpClient okhttp_client = network_func.get_okhttp_obj(battery_service.doh_switch, Paper.book("system_config").read("proxy_config", new proxy()));
110 | String request_body_raw = new Gson().toJson(request_body);
111 | RequestBody body = RequestBody.create(request_body_raw, const_value.JSON);
112 | Request request = new Request.Builder().url(request_uri).method("POST", body).build();
113 | Call call = okhttp_client.newCall(request);
114 | final String error_head = "Send battery info failed:";
115 | try {
116 | Response response = call.execute();
117 | if (response.code() == 200) {
118 | last_receive_message_id = other_func.get_message_id(Objects.requireNonNull(response.body()).string());
119 | } else {
120 | assert response.body() != null;
121 | last_receive_message_id = -1;
122 | if (obj.action.equals(Intent.ACTION_BATTERY_LOW)) {
123 | sms_func.send_fallback_sms(context, request_body.text, -1);
124 | }
125 | }
126 | } catch (IOException e) {
127 | e.printStackTrace();
128 | log_func.write_log(context, error_head + e.getMessage());
129 | if (obj.action.equals(Intent.ACTION_BATTERY_LOW)) {
130 | sms_func.send_fallback_sms(context, request_body.text, -1);
131 | }
132 | }
133 | }
134 |
135 | @Override
136 | public void onDestroy() {
137 | unregisterReceiver(battery_receiver);
138 | stopForeground(true);
139 | super.onDestroy();
140 | }
141 |
142 | @Override
143 | public IBinder onBind(Intent intent) {
144 | return null;
145 | }
146 |
147 | private static class send_obj {
148 | public String content;
149 | public String action;
150 | }
151 |
152 | class battery_receiver extends BroadcastReceiver {
153 | @Override
154 | public void onReceive(final Context context, @NotNull final Intent intent) {
155 |
156 | String TAG = "battery_receiver";
157 | assert intent.getAction() != null;
158 | Log.d(TAG, "Receive action: " + intent.getAction());
159 | if (intent.getAction().equals(const_value.BROADCAST_STOP_SERVICE)) {
160 | Log.i(TAG, "Received stop signal, quitting now...");
161 | stopSelf();
162 | android.os.Process.killProcess(android.os.Process.myPid());
163 | return;
164 | }
165 | StringBuilder prebody = new StringBuilder(context.getString(R.string.system_message_head) + "\n");
166 | final String action = intent.getAction();
167 | BatteryManager batteryManager = (BatteryManager) context.getSystemService(BATTERY_SERVICE);
168 | switch (Objects.requireNonNull(action)) {
169 | case Intent.ACTION_BATTERY_OKAY:
170 | prebody.append(context.getString(R.string.low_battery_status_end));
171 | break;
172 | case Intent.ACTION_BATTERY_LOW:
173 | prebody.append(context.getString(R.string.battery_low));
174 | break;
175 | case Intent.ACTION_POWER_CONNECTED:
176 | prebody.append(context.getString(R.string.charger_connect));
177 | break;
178 | case Intent.ACTION_POWER_DISCONNECTED:
179 | prebody.append(context.getString(R.string.charger_disconnect));
180 | break;
181 | }
182 | assert batteryManager != null;
183 | int battery_level = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
184 | if (battery_level > 100) {
185 | Log.d(TAG, "The previous battery is over 100%, and the correction is 100%.");
186 | battery_level = 100;
187 | }
188 | String result = prebody.append("\n").append(context.getString(R.string.current_battery_level)).append(battery_level).append("%").toString();
189 | send_obj obj = new send_obj();
190 | obj.action = action;
191 | obj.content = result;
192 | send_loop_list.add(obj);
193 |
194 | }
195 | }
196 | }
197 |
198 |
--------------------------------------------------------------------------------
/app/src/main/java/com/qwe7002/telegram_sms/notify_apps_list_activity.java:
--------------------------------------------------------------------------------
1 |
2 | package com.qwe7002.telegram_sms;
3 |
4 | import android.content.Context;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 | import android.graphics.drawable.Drawable;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.BaseAdapter;
14 | import android.widget.CheckBox;
15 | import android.widget.Filter;
16 | import android.widget.Filterable;
17 | import android.widget.ImageView;
18 | import android.widget.ListView;
19 | import android.widget.ProgressBar;
20 | import android.widget.SearchView;
21 | import android.widget.TextView;
22 |
23 | import androidx.appcompat.app.AppCompatActivity;
24 |
25 | import org.jetbrains.annotations.NotNull;
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | import io.paperdb.Paper;
31 |
32 | public class notify_apps_list_activity extends AppCompatActivity {
33 | private app_adapter app_adapter;
34 | private Context context;
35 |
36 | @NotNull
37 | private List scan_app_list(PackageManager packageManager) {
38 | List app_info_list = new ArrayList<>();
39 | try {
40 | List package_info_list = packageManager.getInstalledPackages(0);
41 | for (int i = 0; i < package_info_list.size(); i++) {
42 | PackageInfo package_info = package_info_list.get(i);
43 | if (package_info.packageName.equals(context.getPackageName())) {
44 | continue;
45 | }
46 | app_info app_info = new app_info();
47 | app_info.package_name = package_info.packageName;
48 | app_info.app_name = package_info.applicationInfo.loadLabel(packageManager).toString();
49 | if (package_info.applicationInfo.loadIcon(packageManager) == null) {
50 | continue;
51 | }
52 | app_info.app_icon = package_info.applicationInfo.loadIcon(packageManager);
53 | app_info_list.add(app_info);
54 | }
55 | } catch (Exception e) {
56 | e.printStackTrace();
57 | }
58 | return app_info_list;
59 | }
60 |
61 | @Override
62 | protected void onCreate(Bundle savedInstanceState) {
63 | super.onCreate(savedInstanceState);
64 | context = getApplicationContext();
65 | Paper.init(context);
66 | this.setTitle(getString(R.string.app_list));
67 | setContentView(R.layout.activity_notify_apps_list);
68 | final ListView app_list = findViewById(R.id.app_listview);
69 | final SearchView filter_edit = findViewById(R.id.filter_searchview);
70 | filter_edit.setIconifiedByDefault(false);
71 | app_list.setTextFilterEnabled(true);
72 | app_adapter = new app_adapter(context);
73 | filter_edit.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
74 | @Override
75 | public boolean onQueryTextSubmit(String query) {
76 | return true;
77 | }
78 |
79 | @Override
80 | public boolean onQueryTextChange(String newText) {
81 | app_adapter.getFilter().filter(newText);
82 | return false;
83 | }
84 | });
85 |
86 | app_list.setAdapter(app_adapter);
87 | new Thread(() -> {
88 | final List app_info_list = scan_app_list(notify_apps_list_activity.this.getPackageManager());
89 | runOnUiThread(() -> {
90 | ProgressBar scan_label = findViewById(R.id.progress_view);
91 | scan_label.setVisibility(View.GONE);
92 | app_adapter.setData(app_info_list);
93 | });
94 | }).start();
95 | }
96 |
97 | static class app_adapter extends BaseAdapter implements Filterable {
98 | final String TAG = "notify_activity";
99 | List listen_list;
100 | List app_info_list = new ArrayList<>();
101 | List view_app_info_list = new ArrayList<>();
102 | private final Context context;
103 | private final Filter filter = new Filter() {
104 | @NotNull
105 | @Override
106 | protected FilterResults performFiltering(CharSequence constraint) {
107 | FilterResults results = new FilterResults();
108 | List list = new ArrayList<>();
109 | for (app_info app_info_item : app_info_list) {
110 | if (app_info_item.app_name.toLowerCase().contains(constraint.toString().toLowerCase())) {
111 | list.add(app_info_item);
112 | }
113 | }
114 | results.values = list;
115 | results.count = list.size();
116 | return results;
117 | }
118 |
119 | @SuppressWarnings("unchecked")
120 | @Override
121 | protected void publishResults(CharSequence constraint, @NotNull FilterResults results) {
122 | view_app_info_list = (ArrayList) results.values;
123 | notifyDataSetChanged();
124 | }
125 | };
126 |
127 | app_adapter(Context context) {
128 | this.context = context;
129 | this.listen_list = Paper.book("system_config").read("notify_listen_list", new ArrayList<>());
130 | }
131 |
132 | public List getData() {
133 | return app_info_list;
134 | }
135 |
136 | public void setData(List apps_info_list) {
137 | this.app_info_list = apps_info_list;
138 | this.view_app_info_list = app_info_list;
139 | notifyDataSetChanged();
140 | }
141 |
142 | @Override
143 | public int getCount() {
144 | if (view_app_info_list != null && view_app_info_list.size() > 0) {
145 | return view_app_info_list.size();
146 | }
147 | return 0;
148 | }
149 |
150 | @Override
151 | public Object getItem(int position) {
152 | if (view_app_info_list != null && view_app_info_list.size() > 0) {
153 | return view_app_info_list.get(position);
154 | }
155 | return null;
156 | }
157 |
158 | @Override
159 | public long getItemId(int position) {
160 | return 0;
161 | }
162 |
163 | @Override
164 | public View getView(int position, View convert_view, ViewGroup parent) {
165 | view_holder view_holder_object;
166 | app_info app_info = view_app_info_list.get(position);
167 | if (convert_view == null) {
168 | view_holder_object = new view_holder();
169 | convert_view = LayoutInflater.from(context).inflate(R.layout.item_app_info, parent, false);
170 | view_holder_object.app_icon = convert_view.findViewById(R.id.app_icon_imageview);
171 | view_holder_object.package_name = convert_view.findViewById(R.id.package_name_textview);
172 | view_holder_object.app_name = convert_view.findViewById(R.id.app_name_textview);
173 | view_holder_object.app_checkbox = convert_view.findViewById(R.id.select_checkbox);
174 | convert_view.setTag(view_holder_object);
175 | } else {
176 | view_holder_object = (notify_apps_list_activity.app_adapter.view_holder) convert_view.getTag();
177 | }
178 | view_holder_object.app_icon.setImageDrawable(app_info.app_icon);
179 | view_holder_object.app_name.setText(app_info.app_name);
180 | view_holder_object.package_name.setText(app_info.package_name);
181 | view_holder_object.app_checkbox.setChecked(listen_list.contains(app_info.package_name));
182 | view_holder_object.app_checkbox.setOnClickListener(v -> {
183 | app_info item_info = (app_info) getItem(position);
184 | String package_name = item_info.package_name;
185 | List listen_list_temp = Paper.book("system_config").read("notify_listen_list", new ArrayList<>());
186 | if (view_holder_object.app_checkbox.isChecked()) {
187 | if (!listen_list_temp.contains(package_name)) {
188 | listen_list_temp.add(package_name);
189 | }
190 | } else {
191 | listen_list_temp.remove(package_name);
192 | }
193 | Log.d(TAG, "notify_listen_list: " + listen_list_temp);
194 | Paper.book("system_config").write("notify_listen_list", listen_list_temp);
195 | listen_list = listen_list_temp;
196 | });
197 | return convert_view;
198 | }
199 |
200 | @Override
201 | public Filter getFilter() {
202 | return filter;
203 | }
204 |
205 | static class view_holder {
206 | ImageView app_icon;
207 | TextView app_name;
208 | TextView package_name;
209 | CheckBox app_checkbox;
210 | }
211 |
212 | }
213 |
214 | static class app_info {
215 | Drawable app_icon;
216 | String package_name;
217 | String app_name;
218 | }
219 | }
220 |
--------------------------------------------------------------------------------
/app/src/main/java/com/qwe7002/telegram_sms/sms_receiver.java:
--------------------------------------------------------------------------------
1 | package com.qwe7002.telegram_sms;
2 |
3 | import android.Manifest;
4 | import android.content.BroadcastReceiver;
5 | import android.content.ContentValues;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.content.SharedPreferences;
9 | import android.content.pm.PackageManager;
10 | import android.os.Build;
11 | import android.os.Bundle;
12 | import android.provider.Telephony;
13 | import android.telephony.SmsMessage;
14 | import android.telephony.SubscriptionInfo;
15 | import android.telephony.SubscriptionManager;
16 | import android.util.Log;
17 |
18 | import androidx.annotation.NonNull;
19 | import androidx.core.app.ActivityCompat;
20 |
21 | import com.github.sumimakito.codeauxlib.CodeauxLibPortable;
22 | import com.google.gson.Gson;
23 | import com.qwe7002.telegram_sms.config.proxy;
24 | import com.qwe7002.telegram_sms.data_structure.request_message;
25 | import com.qwe7002.telegram_sms.static_class.log_func;
26 | import com.qwe7002.telegram_sms.static_class.network_func;
27 | import com.qwe7002.telegram_sms.static_class.other_func;
28 | import com.qwe7002.telegram_sms.static_class.resend_func;
29 | import com.qwe7002.telegram_sms.static_class.service_func;
30 | import com.qwe7002.telegram_sms.static_class.sms_func;
31 | import com.qwe7002.telegram_sms.static_class.ussd_func;
32 | import com.qwe7002.telegram_sms.value.const_value;
33 |
34 | import java.io.IOException;
35 | import java.text.SimpleDateFormat;
36 | import java.util.ArrayList;
37 | import java.util.Date;
38 | import java.util.Locale;
39 | import java.util.Objects;
40 |
41 | import io.paperdb.Paper;
42 | import okhttp3.Call;
43 | import okhttp3.Callback;
44 | import okhttp3.OkHttpClient;
45 | import okhttp3.Request;
46 | import okhttp3.RequestBody;
47 | import okhttp3.Response;
48 |
49 |
50 | public class sms_receiver extends BroadcastReceiver {
51 | final static CodeauxLibPortable code_aux_lib = new CodeauxLibPortable();
52 | public void onReceive(final Context context, Intent intent) {
53 | Paper.init(context);
54 | final String TAG = "sms_receiver";
55 | Log.d(TAG, "Receive action: " + intent.getAction());
56 | Bundle extras = intent.getExtras();
57 | assert extras != null;
58 | final SharedPreferences sharedPreferences = context.getSharedPreferences("data", Context.MODE_PRIVATE);
59 | if (!sharedPreferences.getBoolean("initialized", false)) {
60 | Log.i(TAG, "Uninitialized, SMS receiver is deactivated.");
61 | return;
62 | }
63 | final boolean is_default_sms_app = Telephony.Sms.getDefaultSmsPackage(context).equals(context.getPackageName());
64 | assert intent.getAction() != null;
65 | if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED") && is_default_sms_app) {
66 | //When it is the default application, it will receive two broadcasts.
67 | Log.i(TAG, "reject: android.provider.Telephony.SMS_RECEIVED.");
68 | return;
69 | }
70 | String bot_token = sharedPreferences.getString("bot_token", "");
71 | String chat_id = sharedPreferences.getString("chat_id", "");
72 | String request_uri = network_func.get_url(bot_token, "sendMessage");
73 |
74 | int intent_slot = extras.getInt("slot", -1);
75 | final int sub_id = extras.getInt("subscription", -1);
76 | if (other_func.get_active_card(context) >= 2 && intent_slot == -1) {
77 | SubscriptionManager manager = SubscriptionManager.from(context);
78 | if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
79 | SubscriptionInfo info = manager.getActiveSubscriptionInfo(sub_id);
80 | intent_slot = info.getSimSlotIndex();
81 | }
82 | }
83 | final int slot = intent_slot;
84 | String dual_sim = other_func.get_dual_sim_card_display(context, intent_slot, sharedPreferences.getBoolean("display_dual_sim_display_name", false));
85 |
86 | Object[] pdus = (Object[]) extras.get("pdus");
87 | assert pdus != null;
88 | final SmsMessage[] messages = new SmsMessage[pdus.length];
89 | for (int i = 0; i < pdus.length; ++i) {
90 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
91 | messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i], extras.getString("format"));
92 | } else {
93 | messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
94 | }
95 | }
96 | if (messages.length == 0) {
97 | log_func.write_log(context, "Message length is equal to 0.");
98 | return;
99 | }
100 |
101 | StringBuilder message_body_builder = new StringBuilder();
102 | for (SmsMessage item : messages) {
103 | message_body_builder.append(item.getMessageBody());
104 | }
105 | final String message_body = message_body_builder.toString();
106 |
107 | final String message_address = messages[0].getOriginatingAddress();
108 | assert message_address != null;
109 |
110 | if (is_default_sms_app) {
111 | Log.i(TAG, "onReceive: Write to the system database.");
112 | new Thread(() -> {
113 | ContentValues values = new ContentValues();
114 | values.put(Telephony.Sms.ADDRESS, message_body);
115 | values.put(Telephony.Sms.BODY, message_address);
116 | values.put(Telephony.Sms.SUBSCRIPTION_ID, String.valueOf(sub_id));
117 | values.put(Telephony.Sms.READ, "1");
118 | context.getContentResolver().insert(Telephony.Sms.CONTENT_URI, values);
119 | }).start();
120 | }
121 |
122 | String trusted_phone_number = sharedPreferences.getString("trusted_phone_number", null);
123 | boolean is_trusted_phone = false;
124 | if (trusted_phone_number != null && trusted_phone_number.length() != 0) {
125 | is_trusted_phone = message_address.contains(trusted_phone_number);
126 | }
127 | final request_message request_body = new request_message();
128 | request_body.chat_id = chat_id;
129 |
130 | String message_body_html = message_body;
131 | final String message_head = "[" + dual_sim + context.getString(R.string.receive_sms_head) + "]" + "\n" + context.getString(R.string.from) + message_address + "\n" + context.getString(R.string.content);
132 | String raw_request_body_text = message_head + message_body;
133 | boolean is_verification_code = false;
134 | if (sharedPreferences.getBoolean("verification_code", false) && !is_trusted_phone) {
135 | if (message_body.length() <= 140) {
136 | String verification = code_aux_lib.find(message_body);
137 | if (verification != null) {
138 | request_body.parse_mode = "html";
139 | message_body_html = message_body
140 | .replace("<", "<")
141 | .replace(">", ">")
142 | .replace("&", "&")
143 | .replace(verification, "" + verification + "");
144 | is_verification_code = true;
145 | }
146 | } else {
147 | log_func.write_log(context, "SMS exceeds 140 characters, no verification code is recognized.");
148 | }
149 | }
150 | request_body.text = message_head + message_body_html;
151 | if (is_trusted_phone) {
152 | log_func.write_log(context, "SMS from trusted mobile phone detected");
153 | String message_command = message_body.toLowerCase().replace("_", "").replace("-", "");
154 | String[] command_list = message_command.split("\n");
155 | if (command_list.length > 0) {
156 | String[] message_list = message_body.split("\n");
157 | switch (command_list[0].trim()) {
158 | case "/restartservice":
159 | new Thread(() -> {
160 | service_func.stop_all_service(context);
161 | service_func.start_service(context, sharedPreferences.getBoolean("battery_monitoring_switch", false), sharedPreferences.getBoolean("chat_command", false));
162 | }).start();
163 | raw_request_body_text = context.getString(R.string.system_message_head) + "\n" + context.getString(R.string.restart_service);
164 | request_body.text = raw_request_body_text;
165 | break;
166 | case "/sendsms":
167 | case "/sendsms1":
168 | case "/sendsms2":
169 | if (androidx.core.content.ContextCompat.checkSelfPermission(context, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
170 | Log.i(TAG, "No SMS permission.");
171 | break;
172 | }
173 | String msg_send_to = other_func.get_send_phone_number(message_list[1]);
174 | if (other_func.is_phone_number(msg_send_to) && message_list.length > 2) {
175 | StringBuilder msg_send_content = new StringBuilder();
176 | for (int i = 2; i < message_list.length; ++i) {
177 | if (i != 2) {
178 | msg_send_content.append("\n");
179 | }
180 | msg_send_content.append(message_list[i]);
181 | }
182 | int send_slot = slot;
183 | if (other_func.get_active_card(context) > 1) {
184 | switch (command_list[0].trim()) {
185 | case "/sendsms1":
186 | send_slot = 0;
187 | break;
188 | case "/sendsms2":
189 | send_slot = 1;
190 | break;
191 | }
192 | }
193 | final int final_send_slot = send_slot;
194 | final int final_send_sub_id = other_func.get_sub_id(context, final_send_slot);
195 | new Thread(() -> sms_func.send_sms(context, msg_send_to, msg_send_content.toString(), final_send_slot, final_send_sub_id)).start();
196 | return;
197 | }
198 | break;
199 | case "/sendussd":
200 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
201 | if (androidx.core.content.ContextCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
202 | if (message_list.length == 2) {
203 | ussd_func.send_ussd(context, message_list[1], sub_id);
204 | return;
205 | }
206 | }
207 | } else {
208 | Log.i(TAG, "send_ussd: No permission.");
209 | return;
210 | }
211 | break;
212 | }
213 | }
214 | }
215 |
216 | if (!is_verification_code && !is_trusted_phone) {
217 | ArrayList black_list_array = Paper.book("system_config").read("block_keyword_list", new ArrayList<>());
218 | for (String black_list_item : black_list_array) {
219 | if (black_list_item.isEmpty()) {
220 | continue;
221 | }
222 |
223 | if (message_body.contains(black_list_item)) {
224 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(context.getString(R.string.time_format), Locale.UK);
225 | String write_message = request_body.text + "\n" + context.getString(R.string.time) + simpleDateFormat.format(new Date(System.currentTimeMillis()));
226 | ArrayList spam_sms_list;
227 | Paper.init(context);
228 | spam_sms_list = Paper.book().read("spam_sms_list", new ArrayList<>());
229 | if (spam_sms_list.size() >= 5) {
230 | spam_sms_list.remove(0);
231 | }
232 | spam_sms_list.add(write_message);
233 | Paper.book().write("spam_sms_list", spam_sms_list);
234 | Log.i(TAG, "Detected message contains blacklist keywords, add spam list");
235 | return;
236 | }
237 | }
238 | }
239 |
240 |
241 | RequestBody body = RequestBody.create(new Gson().toJson(request_body), const_value.JSON);
242 | OkHttpClient okhttp_client = network_func.get_okhttp_obj(sharedPreferences.getBoolean("doh_switch", true), Paper.book("system_config").read("proxy_config", new proxy()));
243 | Request request = new Request.Builder().url(request_uri).method("POST", body).build();
244 | Call call = okhttp_client.newCall(request);
245 | final String error_head = "Send SMS forward failed:";
246 | final String final_raw_request_body_text = raw_request_body_text;
247 | call.enqueue(new Callback() {
248 | @Override
249 | public void onFailure(@NonNull Call call, @NonNull IOException e) {
250 | e.printStackTrace();
251 | log_func.write_log(context, error_head + e.getMessage());
252 | sms_func.send_fallback_sms(context, final_raw_request_body_text, sub_id);
253 | resend_func.add_resend_loop(context, request_body.text);
254 | }
255 |
256 | @Override
257 | public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
258 | assert response.body() != null;
259 | String result = Objects.requireNonNull(response.body()).string();
260 | if (response.code() != 200) {
261 | log_func.write_log(context, error_head + response.code() + " " + result);
262 | sms_func.send_fallback_sms(context, final_raw_request_body_text, sub_id);
263 | resend_func.add_resend_loop(context, request_body.text);
264 | } else {
265 | if (!other_func.is_phone_number(message_address)) {
266 | log_func.write_log(context, "[" + message_address + "] Not a regular phone number.");
267 | return;
268 | }
269 | other_func.add_message_list(other_func.get_message_id(result), message_address, slot);
270 | }
271 | }
272 | });
273 | }
274 | }
275 |
276 |
277 |
--------------------------------------------------------------------------------
/externals_license/artworks/ic_stat:
--------------------------------------------------------------------------------
1 | Attribution-NonCommercial-ShareAlike 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
58 | Public License
59 |
60 | By exercising the Licensed Rights (defined below), You accept and agree
61 | to be bound by the terms and conditions of this Creative Commons
62 | Attribution-NonCommercial-ShareAlike 4.0 International Public License
63 | ("Public License"). To the extent this Public License may be
64 | interpreted as a contract, You are granted the Licensed Rights in
65 | consideration of Your acceptance of these terms and conditions, and the
66 | Licensor grants You such rights in consideration of benefits the
67 | Licensor receives from making the Licensed Material available under
68 | these terms and conditions.
69 |
70 |
71 | Section 1 -- Definitions.
72 |
73 | a. Adapted Material means material subject to Copyright and Similar
74 | Rights that is derived from or based upon the Licensed Material
75 | and in which the Licensed Material is translated, altered,
76 | arranged, transformed, or otherwise modified in a manner requiring
77 | permission under the Copyright and Similar Rights held by the
78 | Licensor. For purposes of this Public License, where the Licensed
79 | Material is a musical work, performance, or sound recording,
80 | Adapted Material is always produced where the Licensed Material is
81 | synched in timed relation with a moving image.
82 |
83 | b. Adapter's License means the license You apply to Your Copyright
84 | and Similar Rights in Your contributions to Adapted Material in
85 | accordance with the terms and conditions of this Public License.
86 |
87 | c. BY-NC-SA Compatible License means a license listed at
88 | creativecommons.org/compatiblelicenses, approved by Creative
89 | Commons as essentially the equivalent of this Public License.
90 |
91 | d. Copyright and Similar Rights means copyright and/or similar rights
92 | closely related to copyright including, without limitation,
93 | performance, broadcast, sound recording, and Sui Generis Database
94 | Rights, without regard to how the rights are labeled or
95 | categorized. For purposes of this Public License, the rights
96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
97 | Rights.
98 |
99 | e. Effective Technological Measures means those measures that, in the
100 | absence of proper authority, may not be circumvented under laws
101 | fulfilling obligations under Article 11 of the WIPO Copyright
102 | Treaty adopted on December 20, 1996, and/or similar international
103 | agreements.
104 |
105 | f. Exceptions and Limitations means fair use, fair dealing, and/or
106 | any other exception or limitation to Copyright and Similar Rights
107 | that applies to Your use of the Licensed Material.
108 |
109 | g. License Elements means the license attributes listed in the name
110 | of a Creative Commons Public License. The License Elements of this
111 | Public License are Attribution, NonCommercial, and ShareAlike.
112 |
113 | h. Licensed Material means the artistic or literary work, database,
114 | or other material to which the Licensor applied this Public
115 | License.
116 |
117 | i. Licensed Rights means the rights granted to You subject to the
118 | terms and conditions of this Public License, which are limited to
119 | all Copyright and Similar Rights that apply to Your use of the
120 | Licensed Material and that the Licensor has authority to license.
121 |
122 | j. Licensor means the individual(s) or entity(ies) granting rights
123 | under this Public License.
124 |
125 | k. NonCommercial means not primarily intended for or directed towards
126 | commercial advantage or monetary compensation. For purposes of
127 | this Public License, the exchange of the Licensed Material for
128 | other material subject to Copyright and Similar Rights by digital
129 | file-sharing or similar means is NonCommercial provided there is
130 | no payment of monetary compensation in connection with the
131 | exchange.
132 |
133 | l. Share means to provide material to the public by any means or
134 | process that requires permission under the Licensed Rights, such
135 | as reproduction, public display, public performance, distribution,
136 | dissemination, communication, or importation, and to make material
137 | available to the public including in ways that members of the
138 | public may access the material from a place and at a time
139 | individually chosen by them.
140 |
141 | m. Sui Generis Database Rights means rights other than copyright
142 | resulting from Directive 96/9/EC of the European Parliament and of
143 | the Council of 11 March 1996 on the legal protection of databases,
144 | as amended and/or succeeded, as well as other essentially
145 | equivalent rights anywhere in the world.
146 |
147 | n. You means the individual or entity exercising the Licensed Rights
148 | under this Public License. Your has a corresponding meaning.
149 |
150 |
151 | Section 2 -- Scope.
152 |
153 | a. License grant.
154 |
155 | 1. Subject to the terms and conditions of this Public License,
156 | the Licensor hereby grants You a worldwide, royalty-free,
157 | non-sublicensable, non-exclusive, irrevocable license to
158 | exercise the Licensed Rights in the Licensed Material to:
159 |
160 | a. reproduce and Share the Licensed Material, in whole or
161 | in part, for NonCommercial purposes only; and
162 |
163 | b. produce, reproduce, and Share Adapted Material for
164 | NonCommercial purposes only.
165 |
166 | 2. Exceptions and Limitations. For the avoidance of doubt, where
167 | Exceptions and Limitations apply to Your use, this Public
168 | License does not apply, and You do not need to comply with
169 | its terms and conditions.
170 |
171 | 3. Term. The term of this Public License is specified in Section
172 | 6(a).
173 |
174 | 4. Media and formats; technical modifications allowed. The
175 | Licensor authorizes You to exercise the Licensed Rights in
176 | all media and formats whether now known or hereafter created,
177 | and to make technical modifications necessary to do so. The
178 | Licensor waives and/or agrees not to assert any right or
179 | authority to forbid You from making technical modifications
180 | necessary to exercise the Licensed Rights, including
181 | technical modifications necessary to circumvent Effective
182 | Technological Measures. For purposes of this Public License,
183 | simply making modifications authorized by this Section 2(a)
184 | (4) never produces Adapted Material.
185 |
186 | 5. Downstream recipients.
187 |
188 | a. Offer from the Licensor -- Licensed Material. Every
189 | recipient of the Licensed Material automatically
190 | receives an offer from the Licensor to exercise the
191 | Licensed Rights under the terms and conditions of this
192 | Public License.
193 |
194 | b. Additional offer from the Licensor -- Adapted Material.
195 | Every recipient of Adapted Material from You
196 | automatically receives an offer from the Licensor to
197 | exercise the Licensed Rights in the Adapted Material
198 | under the conditions of the Adapter's License You apply.
199 |
200 | c. No downstream restrictions. You may not offer or impose
201 | any additional or different terms or conditions on, or
202 | apply any Effective Technological Measures to, the
203 | Licensed Material if doing so restricts exercise of the
204 | Licensed Rights by any recipient of the Licensed
205 | Material.
206 |
207 | 6. No endorsement. Nothing in this Public License constitutes or
208 | may be construed as permission to assert or imply that You
209 | are, or that Your use of the Licensed Material is, connected
210 | with, or sponsored, endorsed, or granted official status by,
211 | the Licensor or others designated to receive attribution as
212 | provided in Section 3(a)(1)(A)(i).
213 |
214 | b. Other rights.
215 |
216 | 1. Moral rights, such as the right of integrity, are not
217 | licensed under this Public License, nor are publicity,
218 | privacy, and/or other similar personality rights; however, to
219 | the extent possible, the Licensor waives and/or agrees not to
220 | assert any such rights held by the Licensor to the limited
221 | extent necessary to allow You to exercise the Licensed
222 | Rights, but not otherwise.
223 |
224 | 2. Patent and trademark rights are not licensed under this
225 | Public License.
226 |
227 | 3. To the extent possible, the Licensor waives any right to
228 | collect royalties from You for the exercise of the Licensed
229 | Rights, whether directly or through a collecting society
230 | under any voluntary or waivable statutory or compulsory
231 | licensing scheme. In all other cases the Licensor expressly
232 | reserves any right to collect such royalties, including when
233 | the Licensed Material is used other than for NonCommercial
234 | purposes.
235 |
236 |
237 | Section 3 -- License Conditions.
238 |
239 | Your exercise of the Licensed Rights is expressly made subject to the
240 | following conditions.
241 |
242 | a. Attribution.
243 |
244 | 1. If You Share the Licensed Material (including in modified
245 | form), You must:
246 |
247 | a. retain the following if it is supplied by the Licensor
248 | with the Licensed Material:
249 |
250 | i. identification of the creator(s) of the Licensed
251 | Material and any others designated to receive
252 | attribution, in any reasonable manner requested by
253 | the Licensor (including by pseudonym if
254 | designated);
255 |
256 | ii. a copyright notice;
257 |
258 | iii. a notice that refers to this Public License;
259 |
260 | iv. a notice that refers to the disclaimer of
261 | warranties;
262 |
263 | v. a URI or hyperlink to the Licensed Material to the
264 | extent reasonably practicable;
265 |
266 | b. indicate if You modified the Licensed Material and
267 | retain an indication of any previous modifications; and
268 |
269 | c. indicate the Licensed Material is licensed under this
270 | Public License, and include the text of, or the URI or
271 | hyperlink to, this Public License.
272 |
273 | 2. You may satisfy the conditions in Section 3(a)(1) in any
274 | reasonable manner based on the medium, means, and context in
275 | which You Share the Licensed Material. For example, it may be
276 | reasonable to satisfy the conditions by providing a URI or
277 | hyperlink to a resource that includes the required
278 | information.
279 | 3. If requested by the Licensor, You must remove any of the
280 | information required by Section 3(a)(1)(A) to the extent
281 | reasonably practicable.
282 |
283 | b. ShareAlike.
284 |
285 | In addition to the conditions in Section 3(a), if You Share
286 | Adapted Material You produce, the following conditions also apply.
287 |
288 | 1. The Adapter's License You apply must be a Creative Commons
289 | license with the same License Elements, this version or
290 | later, or a BY-NC-SA Compatible License.
291 |
292 | 2. You must include the text of, or the URI or hyperlink to, the
293 | Adapter's License You apply. You may satisfy this condition
294 | in any reasonable manner based on the medium, means, and
295 | context in which You Share Adapted Material.
296 |
297 | 3. You may not offer or impose any additional or different terms
298 | or conditions on, or apply any Effective Technological
299 | Measures to, Adapted Material that restrict exercise of the
300 | rights granted under the Adapter's License You apply.
301 |
302 |
303 | Section 4 -- Sui Generis Database Rights.
304 |
305 | Where the Licensed Rights include Sui Generis Database Rights that
306 | apply to Your use of the Licensed Material:
307 |
308 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
309 | to extract, reuse, reproduce, and Share all or a substantial
310 | portion of the contents of the database for NonCommercial purposes
311 | only;
312 |
313 | b. if You include all or a substantial portion of the database
314 | contents in a database in which You have Sui Generis Database
315 | Rights, then the database in which You have Sui Generis Database
316 | Rights (but not its individual contents) is Adapted Material,
317 | including for purposes of Section 3(b); and
318 |
319 | c. You must comply with the conditions in Section 3(a) if You Share
320 | all or a substantial portion of the contents of the database.
321 |
322 | For the avoidance of doubt, this Section 4 supplements and does not
323 | replace Your obligations under this Public License where the Licensed
324 | Rights include other Copyright and Similar Rights.
325 |
326 |
327 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
328 |
329 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
330 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
331 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
332 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
333 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
334 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
335 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
336 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
337 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
338 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
339 |
340 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
341 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
342 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
343 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
344 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
345 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
346 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
347 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
348 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
349 |
350 | c. The disclaimer of warranties and limitation of liability provided
351 | above shall be interpreted in a manner that, to the extent
352 | possible, most closely approximates an absolute disclaimer and
353 | waiver of all liability.
354 |
355 |
356 | Section 6 -- Term and Termination.
357 |
358 | a. This Public License applies for the term of the Copyright and
359 | Similar Rights licensed here. However, if You fail to comply with
360 | this Public License, then Your rights under this Public License
361 | terminate automatically.
362 |
363 | b. Where Your right to use the Licensed Material has terminated under
364 | Section 6(a), it reinstates:
365 |
366 | 1. automatically as of the date the violation is cured, provided
367 | it is cured within 30 days of Your discovery of the
368 | violation; or
369 |
370 | 2. upon express reinstatement by the Licensor.
371 |
372 | For the avoidance of doubt, this Section 6(b) does not affect any
373 | right the Licensor may have to seek remedies for Your violations
374 | of this Public License.
375 |
376 | c. For the avoidance of doubt, the Licensor may also offer the
377 | Licensed Material under separate terms or conditions or stop
378 | distributing the Licensed Material at any time; however, doing so
379 | will not terminate this Public License.
380 |
381 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
382 | License.
383 |
384 |
385 | Section 7 -- Other Terms and Conditions.
386 |
387 | a. The Licensor shall not be bound by any additional or different
388 | terms or conditions communicated by You unless expressly agreed.
389 |
390 | b. Any arrangements, understandings, or agreements regarding the
391 | Licensed Material not stated herein are separate from and
392 | independent of the terms and conditions of this Public License.
393 |
394 |
395 | Section 8 -- Interpretation.
396 |
397 | a. For the avoidance of doubt, this Public License does not, and
398 | shall not be interpreted to, reduce, limit, restrict, or impose
399 | conditions on any use of the Licensed Material that could lawfully
400 | be made without permission under this Public License.
401 |
402 | b. To the extent possible, if any provision of this Public License is
403 | deemed unenforceable, it shall be automatically reformed to the
404 | minimum extent necessary to make it enforceable. If the provision
405 | cannot be reformed, it shall be severed from this Public License
406 | without affecting the enforceability of the remaining terms and
407 | conditions.
408 |
409 | c. No term or condition of this Public License will be waived and no
410 | failure to comply consented to unless expressly agreed to by the
411 | Licensor.
412 |
413 | d. Nothing in this Public License constitutes or may be interpreted
414 | as a limitation upon, or waiver of, any privileges and immunities
415 | that apply to the Licensor or You, including from the legal
416 | processes of any jurisdiction or authority.
417 |
418 | =======================================================================
419 |
420 | Creative Commons is not a party to its public
421 | licenses. Notwithstanding, Creative Commons may elect to apply one of
422 | its public licenses to material it publishes and in those instances
423 | will be considered the “Licensor.” The text of the Creative Commons
424 | public licenses is dedicated to the public domain under the CC0 Public
425 | Domain Dedication. Except for the limited purpose of indicating that
426 | material is shared under a Creative Commons public license or as
427 | otherwise permitted by the Creative Commons policies published at
428 | creativecommons.org/policies, Creative Commons does not authorize the
429 | use of the trademark "Creative Commons" or any other trademark or logo
430 | of Creative Commons without its prior written consent including,
431 | without limitation, in connection with any unauthorized modifications
432 | to any of its public licenses or any other arrangements,
433 | understandings, or agreements concerning use of licensed material. For
434 | the avoidance of doubt, this paragraph does not form part of the
435 | public licenses.
436 |
437 | Creative Commons may be contacted at creativecommons.org.
438 |
--------------------------------------------------------------------------------