msg_set = new HashSet<>();
+ msg_set = sp.getStringSet(Define.SP_MSG_SET_KEY, msg_set);
+ Log.d(TAG, "msg_set.toString()" + msg_set.toString());
+ String getMsg = "";
+ for (String str : msg_set) {
+ getMsg += str + "\n";
+ }
+ return getMsg;
+ }
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SendMailUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SendMailUtil.java
new file mode 100644
index 00000000..129e04ea
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SendMailUtil.java
@@ -0,0 +1,85 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.util.Log;
+
+import java.io.File;
+
+
+public class SendMailUtil {
+ private static String TAG = "SendMailUtil";
+ //qq
+// private static final String HOST = "smtp.qq.com";
+// private static final String PORT = "587";
+// private static final String FROM_ADD = "teprinciple@foxmail.com"; //发送方邮箱
+// private static final String FROM_PSW = "lfrlpganzjrwbeci";//发送方邮箱授权码
+
+// //163
+// private static final String HOST = "smtp.163.com";
+// private static final String PORT = "465"; //nossl 25或者ssl465 994
+// private static final String FROM_ADD = "xxxxxx@163.com";
+// private static final String FROM_PSW = "xx";
+
+ public static void send(final File file, String toAdd, String title, String content) {
+ Log.d(TAG, "send file to " + toAdd);
+ final MailInfo mailInfo = creatMail(toAdd, title, content);
+ final MailSender sms = new MailSender();
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ sms.sendFileMail(mailInfo, file);
+ }
+ }).start();
+ }
+
+ public static void send(String toAdd, String title, String content) {
+ Log.d(TAG, "send to " + toAdd);
+ final MailInfo mailInfo = creatMail(toAdd, title, content);
+ final MailSender sms = new MailSender();
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ sms.sendTextMail(mailInfo);
+ }
+ }).start();
+ }
+
+ private static MailInfo creatMail(String toAdd, String title, String content) {
+ Log.d(TAG, "creatMail to " + toAdd);
+ final MailInfo mailInfo = new MailInfo();
+ mailInfo.setMailServerHost(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_HOST_KEY));
+ mailInfo.setMailServerPort(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_PORT_KEY));
+ mailInfo.setValidate(true);
+ mailInfo.ssl(true);
+ mailInfo.setUserName(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_FROMADD_KEY)); // 你的邮箱地址
+ mailInfo.setPassword(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_PSW_KEY));// 您的邮箱密码
+ mailInfo.setFromAddress(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_FROMADD_KEY)); // 发送的邮箱
+ mailInfo.setToAddress(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_TOADD_KEY)); // 发到哪个邮件去
+ mailInfo.setSubject(title); // 邮件主题
+ mailInfo.setContent(content); // 邮件文本
+ return mailInfo;
+ }
+}
+
+/**
+ * public void sendFileMail(View view) {
+ *
+ * File file = new File(Environment.getExternalStorageDirectory()+File.separator+"test.txt");
+ * OutputStream os = null;
+ * try {
+ * os = new FileOutputStream(file);
+ * String str = "hello world";
+ * byte[] data = str.getBytes();
+ * os.write(data);
+ * } catch (FileNotFoundException e) {
+ * e.printStackTrace();
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * }finally{
+ * try {
+ * if (os != null)os.close();
+ * } catch (IOException e) {
+ * }
+ * }
+ * SendMailUtil.send(file,editText.getText().toString());
+ * }
+ */
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtil.java
new file mode 100644
index 00000000..429f022e
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtil.java
@@ -0,0 +1,234 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.alibaba.fastjson.JSON;
+import com.idormy.sms.forwarder.model.LogModel;
+import com.idormy.sms.forwarder.model.RuleModel;
+import com.idormy.sms.forwarder.model.SenderModel;
+import com.idormy.sms.forwarder.model.vo.BarkSettingVo;
+import com.idormy.sms.forwarder.model.vo.DingDingSettingVo;
+import com.idormy.sms.forwarder.model.vo.EmailSettingVo;
+import com.idormy.sms.forwarder.model.vo.QYWXGroupRobotSettingVo;
+import com.idormy.sms.forwarder.model.vo.SmsVo;
+import com.idormy.sms.forwarder.model.vo.WebNotifySettingVo;
+
+import java.util.List;
+
+import static com.idormy.sms.forwarder.model.RuleModel.CHECK_CONTAIN;
+import static com.idormy.sms.forwarder.model.RuleModel.CHECK_END_WITH;
+import static com.idormy.sms.forwarder.model.RuleModel.CHECK_IS;
+import static com.idormy.sms.forwarder.model.RuleModel.CHECK_NOT_IS;
+import static com.idormy.sms.forwarder.model.RuleModel.CHECK_START_WITH;
+import static com.idormy.sms.forwarder.model.RuleModel.FILED_MSG_CONTENT;
+import static com.idormy.sms.forwarder.model.RuleModel.FILED_PHONE_NUM;
+import static com.idormy.sms.forwarder.model.RuleModel.FILED_TRANSPOND_ALL;
+import static com.idormy.sms.forwarder.model.SenderModel.TYPE_BARK;
+import static com.idormy.sms.forwarder.model.SenderModel.TYPE_DINGDING;
+import static com.idormy.sms.forwarder.model.SenderModel.TYPE_EMAIL;
+import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_GROUP_ROBOT;
+import static com.idormy.sms.forwarder.model.SenderModel.TYPE_WEB_NOTIFY;
+
+public class SendUtil {
+ private static String TAG = "SendUtil";
+
+ public static void send_msg(String msg) {
+ if (SettingUtil.using_dingding()) {
+ try {
+ SenderDingdingMsg.sendMsg(msg);
+ } catch (Exception e) {
+ Log.d(TAG, "发送出错:" + e.getMessage());
+ }
+
+ }
+ if (SettingUtil.using_email()) {
+// SenderMailMsg.send(SettingUtil.get_send_util_email(Define.SP_MSG_SEND_UTIL_EMAIL_TOADD_KEY),"转发",msg);
+ }
+
+ }
+
+ public static void send_msg_list(Context context, List smsVoList) {
+ Log.i(TAG, "send_msg_list size: " + smsVoList.size());
+ for (SmsVo smsVo : smsVoList) {
+ SendUtil.send_msg(context, smsVo);
+ }
+ }
+
+ public static void send_msg(Context context, SmsVo smsVo) {
+ Log.i(TAG, "send_msg smsVo:" + smsVo);
+ RuleUtil.init(context);
+ LogUtil.init(context);
+
+ List rulelist = RuleUtil.getRule(null, null);
+ if (!rulelist.isEmpty()) {
+ SenderUtil.init(context);
+ for (RuleModel ruleModel : rulelist
+ ) {
+ boolean canSend = false;
+ //使用转发规则制定的字段 匹配
+ switch (ruleModel.getFiled()) {
+ case FILED_TRANSPOND_ALL:
+ canSend = true;
+ break;
+ case FILED_PHONE_NUM:
+ switch (ruleModel.getCheck()) {
+ case CHECK_IS:
+ if (smsVo.getMobile() != null && smsVo.getMobile().equals(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_NOT_IS:
+ if (smsVo.getMobile() != null && !smsVo.getMobile().equals(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_START_WITH:
+ if (smsVo.getMobile() != null && smsVo.getMobile().startsWith(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_END_WITH:
+ if (smsVo.getMobile() != null && smsVo.getMobile().endsWith(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_CONTAIN:
+ if (smsVo.getMobile() != null && smsVo.getMobile().contains(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ }
+ break;
+ case FILED_MSG_CONTENT:
+ switch (ruleModel.getCheck()) {
+ case CHECK_IS:
+ if (smsVo.getContent() != null && smsVo.getContent().equals(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_NOT_IS:
+ if (smsVo.getContent() != null && !smsVo.getContent().equals(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_START_WITH:
+ if (smsVo.getContent() != null && smsVo.getContent().startsWith(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_END_WITH:
+ if (smsVo.getContent() != null && smsVo.getContent().endsWith(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ case CHECK_CONTAIN:
+ if (smsVo.getContent() != null && smsVo.getContent().contains(ruleModel.getValue())) {
+ canSend = true;
+ }
+ break;
+ }
+ break;
+
+ }
+ //规则匹配发现需要发送
+ if (canSend) {
+ List senderModels = SenderUtil.getSender(ruleModel.getSenderId(), null);
+ for (SenderModel senderModel : senderModels
+ ) {
+ LogUtil.addLog(new LogModel(smsVo.getMobile(), smsVo.getContent(), senderModel.getId()));
+ SendUtil.senderSendMsg(smsVo, senderModel);
+ }
+ }
+
+ }
+
+ }
+ }
+
+ public static void senderSendMsg(SmsVo smsVo, SenderModel senderModel) {
+
+ Log.i(TAG, "senderSendMsg smsVo:" + smsVo + "senderModel:" + senderModel);
+ switch (senderModel.getType()) {
+ case TYPE_DINGDING:
+ //try phrase json setting
+ if (senderModel.getJsonSetting() != null) {
+ DingDingSettingVo dingDingSettingVo = JSON.parseObject(senderModel.getJsonSetting(), DingDingSettingVo.class);
+ if (dingDingSettingVo != null) {
+ try {
+ SenderDingdingMsg.sendMsg(null, dingDingSettingVo.getToken(), dingDingSettingVo.getSecret(), dingDingSettingVo.getAtMobils(), dingDingSettingVo.getAtAll(), smsVo.getSmsVoForSend());
+ } catch (Exception e) {
+ Log.e(TAG, "senderSendMsg: dingding error " + e.getMessage());
+ }
+
+ }
+ }
+
+ break;
+ case TYPE_EMAIL:
+ //try phrase json setting
+ if (senderModel.getJsonSetting() != null) {
+ EmailSettingVo emailSettingVo = JSON.parseObject(senderModel.getJsonSetting(), EmailSettingVo.class);
+ if (emailSettingVo != null) {
+ try {
+ SenderMailMsg.sendEmail(null, emailSettingVo.getHost(), emailSettingVo.getPort(), emailSettingVo.getSsl(), emailSettingVo.getFromEmail(),
+ emailSettingVo.getPwd(), emailSettingVo.getToEmail(), smsVo.getMobile(), smsVo.getSmsVoForSend());
+ } catch (Exception e) {
+ Log.e(TAG, "senderSendMsg: SenderMailMsg error " + e.getMessage());
+ }
+
+ }
+ }
+
+ break;
+ case TYPE_WEB_NOTIFY:
+ //try phrase json setting
+ if (senderModel.getJsonSetting() != null) {
+ WebNotifySettingVo webNotifySettingVo = JSON.parseObject(senderModel.getJsonSetting(), WebNotifySettingVo.class);
+ if (webNotifySettingVo != null) {
+ try {
+ SenderWebNotifyMsg.sendMsg(null, webNotifySettingVo.getToken(), webNotifySettingVo.getSecret(), smsVo.getMobile(), smsVo.getSmsVoForSend());
+ } catch (Exception e) {
+ Log.e(TAG, "senderSendMsg: SenderWebNotifyMsg error " + e.getMessage());
+ }
+
+ }
+ }
+
+ break;
+ case TYPE_QYWX_GROUP_ROBOT:
+ //try phrase json setting
+ if (senderModel.getJsonSetting() != null) {
+ QYWXGroupRobotSettingVo qywxGroupRobotSettingVo = JSON.parseObject(senderModel.getJsonSetting(), QYWXGroupRobotSettingVo.class);
+ if (qywxGroupRobotSettingVo != null) {
+ try {
+ SenderQyWxGroupRobotMsg.sendMsg(null, qywxGroupRobotSettingVo.getWebHook(), smsVo.getMobile(), smsVo.getSmsVoForSend());
+ } catch (Exception e) {
+ Log.e(TAG, "senderSendMsg: SenderQyWxGroupRobotMsg error " + e.getMessage());
+ }
+
+ }
+ }
+
+ break;
+ case TYPE_BARK:
+ //try phrase json setting
+ if (senderModel.getJsonSetting() != null) {
+ BarkSettingVo barkSettingVo = JSON.parseObject(senderModel.getJsonSetting(), BarkSettingVo.class);
+ if (barkSettingVo != null) {
+ try {
+ SenderBarkMsg.sendMsg(null, barkSettingVo.getServer(), smsVo.getMobile(), smsVo.getContent());
+ } catch (Exception e) {
+ Log.e(TAG, "senderSendMsg: SenderBarkMsg error " + e.getMessage());
+ }
+
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SenderBarkMsg.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderBarkMsg.java
new file mode 100644
index 00000000..2e52a1ba
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderBarkMsg.java
@@ -0,0 +1,89 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
+
+public class SenderBarkMsg {
+
+ static String TAG = "SenderBarkMsg";
+
+ public static void sendMsg(final Handler handError, String barkServer, String from, String content) throws Exception {
+ Log.i(TAG, "sendMsg barkServer:" + barkServer + " from:" + from + " content:" + content);
+
+ if (barkServer == null || barkServer.isEmpty()) {
+ return;
+ }
+
+ barkServer += URLEncoder.encode(from, "UTF-8");
+ String body = "短信内容:" + content + "\n转发时间:" + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ barkServer += "/" + URLEncoder.encode(content, "UTF-8");
+ barkServer += "?isArchive=1"; //自动保存
+ int isCode = content.indexOf("验证码");
+ if (isCode != -1) {
+ Pattern p = Pattern.compile("(\\d{4,6})");
+ Matcher m = p.matcher(content);
+ if (m.find()) {
+ System.out.println(m.group());
+ barkServer += "&automaticallyCopy=1©=" + m.group();
+ }
+ }
+
+ OkHttpClient client = new OkHttpClient();
+ final Request request = new Request.Builder()
+ .url(barkServer)
+ .addHeader("Content-Type", "application/json; charset=utf-8")
+ .get()
+ .build();
+ Call call = client.newCall(request);
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, final IOException e) {
+ Log.d(TAG, "onFailure:" + e.getMessage());
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送失败:" + e.getMessage());
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ final String responseStr = response.body().string();
+ Log.d(TAG, "Code:" + response.code() + responseStr);
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送状态:" + responseStr);
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ Log.d(TAG, "Response:" + response.code() + responseStr);
+ }
+
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SenderDingdingMsg.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderDingdingMsg.java
new file mode 100644
index 00000000..ed40e3d1
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderDingdingMsg.java
@@ -0,0 +1,184 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import com.alibaba.fastjson.JSON;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
+
+public class SenderDingdingMsg {
+
+ static String TAG = "SenderDingdingMsg";
+
+ public static void sendMsg(String msg) throws Exception {
+
+ String webhook_token = "https://oapi.dingtalk.com/robot/send?access_token=" + SettingUtil.get_using_dingding_token();
+ String webhook_secret = SettingUtil.get_using_dingding_secret();
+ if (webhook_token.equals("")) {
+ return;
+ }
+ if (!webhook_secret.equals("")) {
+ Long timestamp = System.currentTimeMillis();
+
+ String stringToSign = timestamp + "\n" + webhook_secret;
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(webhook_secret.getBytes("UTF-8"), "HmacSHA256"));
+ byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+ String sign = URLEncoder.encode(new String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8");
+ webhook_token += "×tamp=" + timestamp + "&sign=" + sign;
+ Log.i(TAG, "webhook_token:" + webhook_token);
+
+ }
+
+ final String msgf = msg;
+ String textMsg = "{ \"msgtype\": \"text\", \"text\": {\"content\": \"" + msg + "\"}}";
+ OkHttpClient client = new OkHttpClient();
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),
+ textMsg);
+
+ final Request request = new Request.Builder()
+ .url(webhook_token)
+ .addHeader("Content-Type", "application/json; charset=utf-8")
+ .post(requestBody)
+ .build();
+ Call call = client.newCall(request);
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ Log.d(TAG, "onFailure:" + e.getMessage());
+ SendHistory.addHistory("钉钉转发:" + msgf + "onFailure:" + e.getMessage());
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ final String responseStr = response.body().string();
+ Log.d(TAG, "Code:" + String.valueOf(response.code()) + responseStr);
+ SendHistory.addHistory("钉钉转发:" + msgf + "Code:" + String.valueOf(response.code()) + responseStr);
+ }
+ });
+ }
+
+ public static void sendMsg(final Handler handError, String token, String secret, String atMobiles, Boolean atAll, String msg) throws Exception {
+ Log.i(TAG, "sendMsg token:" + token + " secret:" + secret + " atMobiles:" + atMobiles + " atAll:" + atAll + " msg:" + msg);
+
+ if (token == null || token.isEmpty()) {
+ return;
+ }
+ if (secret != null && !secret.isEmpty()) {
+ Long timestamp = System.currentTimeMillis();
+
+ String stringToSign = timestamp + "\n" + secret;
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
+ byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+ String sign = URLEncoder.encode(new String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8");
+ token = "https://oapi.dingtalk.com/robot/send?access_token=" + token;
+ token += "×tamp=" + timestamp + "&sign=" + sign;
+ Log.i(TAG, "webhook_token:" + token);
+
+ }
+
+ Map textMsgMap = new HashMap();
+ textMsgMap.put("msgtype", "text");
+ Map textText = new HashMap();
+ textText.put("content", msg);
+ textMsgMap.put("text", textText);
+ if (atMobiles != null || atAll != null) {
+ Map AtMap = new HashMap();
+ if (atMobiles != null) {
+ String[] atMobilesArray = atMobiles.split(",");
+ List atMobilesList = new ArrayList<>();
+ for (String atMobile : atMobilesArray
+ ) {
+ if (TextUtils.isDigitsOnly(atMobile)) {
+ atMobilesList.add(atMobile);
+ }
+ }
+ if (!atMobilesList.isEmpty()) {
+ AtMap.put("atMobiles", atMobilesList);
+
+ }
+ }
+
+ AtMap.put("isAtAll", false);
+ if (atAll != null) {
+ AtMap.put("isAtAll", atAll);
+
+ }
+
+ textMsgMap.put("at", AtMap);
+ }
+
+ String textMsg = JSON.toJSONString(textMsgMap);
+ Log.i(TAG, "textMsg:" + textMsg);
+
+ OkHttpClient client = new OkHttpClient();
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),
+ textMsg);
+
+ final Request request = new Request.Builder()
+ .url(token)
+ .addHeader("Content-Type", "application/json; charset=utf-8")
+ .post(requestBody)
+ .build();
+ Call call = client.newCall(request);
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, final IOException e) {
+ Log.d(TAG, "onFailure:" + e.getMessage());
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送失败:" + e.getMessage());
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ final String responseStr = response.body().string();
+ Log.d(TAG, "Code:" + String.valueOf(response.code()) + responseStr);
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送状态:" + responseStr);
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ Log.d(TAG, "Coxxyyde:" + String.valueOf(response.code()) + responseStr);
+ }
+
+ }
+ });
+ }
+
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SenderMailMsg.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderMailMsg.java
new file mode 100644
index 00000000..37641217
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderMailMsg.java
@@ -0,0 +1,148 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import java.util.Date;
+import java.util.Properties;
+
+import javax.mail.Address;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+
+import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
+
+
+public class SenderMailMsg {
+ private static String TAG = "SenderMailMsg";
+ //qq
+// private static final String HOST = "smtp.qq.com";
+// private static final String PORT = "587";
+// private static final String FROM_ADD = "teprinciple@foxmail.com"; //发送方邮箱
+// private static final String FROM_PSW = "lfrlpganzjrwbeci";//发送方邮箱授权码
+
+// //163
+// private static final String HOST = "smtp.163.com";
+// private static final String PORT = "465"; //nossl 25或者ssl465 994
+// private static final String FROM_ADD = "xxxxxx@163.com";
+// private static final String FROM_PSW = "xx";
+
+ public static void sendEmail(final Handler handError, final String host, final String port, final boolean ssl, final String fromemail, final String pwd, final String toAdd, final String title, final String content) {
+
+ Log.d(TAG, "sendEmail: host:" + host + " port:" + port + " ssl:" + ssl + " fromemail:" + fromemail + " pwd:" + pwd + " toAdd:" + toAdd);
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+
+ try {
+ final MailSenderInfo mailInfo = new MailSenderInfo();
+ mailInfo.setMailServerHost(host);
+ mailInfo.setMailServerPort(port);
+ mailInfo.setValidate(true);
+ mailInfo.setUserName(fromemail); //你的邮箱地址
+ mailInfo.setPassword(pwd);//您的邮箱密码
+ mailInfo.setFromAddress(fromemail);//和上面username的邮箱地址一致
+ mailInfo.setToAddress(toAdd);
+ mailInfo.setSubject(title);
+ mailInfo.setContent(content);
+ mailInfo.setSsl(ssl);
+
+ //这个类主要来发送邮件
+ // 判断是否需要身份认证
+ MyAuthenticator authenticator = null;
+ Properties pro = mailInfo.getProperties();
+ if (mailInfo.isValidate()) {
+ // 如果需要身份认证,则创建一个密码验证器
+ authenticator = new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword());
+ }
+ // 根据邮件会话属性和密码验证器构造一个发送邮件的session
+ Session sendMailSession = Session.getDefaultInstance(pro, authenticator);
+ try {
+ // 根据session创建一个邮件消息
+ final Message mailMessage = new MimeMessage(sendMailSession);
+ // 创建邮件发送者地址
+ Address from = new InternetAddress(mailInfo.getFromAddress());
+ // 设置邮件消息的发送者
+ mailMessage.setFrom(from);
+ // 创建邮件的接收者地址,并设置到邮件消息中
+ Address to = new InternetAddress(mailInfo.getToAddress());
+ mailMessage.setRecipient(Message.RecipientType.TO, to);
+ // 设置邮件消息的主题
+ mailMessage.setSubject(mailInfo.getSubject());
+ // 设置邮件消息发送的时间
+ mailMessage.setSentDate(new Date());
+ // 设置邮件消息的主要内容
+ String mailContent = mailInfo.getContent();
+ mailMessage.setText(mailContent);
+ // 发送邮件
+ Transport.send(mailMessage);
+
+ } catch (MessagingException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "error" + ex.getMessage());
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", ex.getMessage());
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+ }
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送成功");
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+ Log.e(TAG, "sendEmail success");//sms.sendHtmlMail(mailInfo);//发送html格式
+
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage(), e);
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", e.getMessage());
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+ }
+ }
+ }).start();
+ }
+}
+
+/**
+ * public void sendFileMail(View view) {
+ *
+ * File file = new File(Environment.getExternalStorageDirectory()+File.separator+"test.txt");
+ * OutputStream os = null;
+ * try {
+ * os = new FileOutputStream(file);
+ * String str = "hello world";
+ * byte[] data = str.getBytes();
+ * os.write(data);
+ * } catch (FileNotFoundException e) {
+ * e.printStackTrace();
+ * } catch (IOException e) {
+ * e.printStackTrace();
+ * }finally{
+ * try {
+ * if (os != null)os.close();
+ * } catch (IOException e) {
+ * }
+ * }
+ * SenderMailMsg.send(file,editText.getText().toString());
+ * }
+ */
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SenderQyWxGroupRobotMsg.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderQyWxGroupRobotMsg.java
new file mode 100644
index 00000000..63dadbc3
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderQyWxGroupRobotMsg.java
@@ -0,0 +1,79 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import java.io.IOException;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
+
+public class SenderQyWxGroupRobotMsg {
+
+ static String TAG = "SenderQyWxGroupRobotMsg";
+
+ public static void sendMsg(final Handler handError, String webHook, String from, String content) throws Exception {
+ Log.i(TAG, "sendMsg webHook:" + webHook + " from:" + from + " content:" + content);
+
+ if (webHook == null || webHook.isEmpty()) {
+ return;
+ }
+
+ String textMsg = "{ \"msgtype\": \"text\", \"text\": {\"content\": \"" + from + " : " + content + "\"}}";
+ OkHttpClient client = new OkHttpClient();
+ RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),
+ textMsg);
+
+ final Request request = new Request.Builder()
+ .url(webHook)
+ .addHeader("Content-Type", "application/json; charset=utf-8")
+ .post(requestBody)
+ .build();
+ Call call = client.newCall(request);
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, final IOException e) {
+ Log.d(TAG, "onFailure:" + e.getMessage());
+
+// SendHistory.addHistory("钉钉转发:"+msgf+"onFailure:" + e.getMessage());
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送失败:" + e.getMessage());
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ final String responseStr = response.body().string();
+ Log.d(TAG, "Code:" + String.valueOf(response.code()) + responseStr);
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送状态:" + responseStr);
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ Log.d(TAG, "Coxxyyde:" + String.valueOf(response.code()) + responseStr);
+ }
+
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SenderUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderUtil.java
new file mode 100644
index 00000000..1ea75100
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderUtil.java
@@ -0,0 +1,194 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.provider.BaseColumns;
+import android.util.Log;
+
+import com.idormy.sms.forwarder.model.SenderModel;
+import com.idormy.sms.forwarder.model.SenderTable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SenderUtil {
+ static String TAG = "SenderUtil";
+ static Boolean hasInit = false;
+
+ static Context context;
+ static DbHelper dbHelper;
+ static SQLiteDatabase db;
+
+ public static void init(Context context1) {
+ synchronized (hasInit) {
+ if (hasInit) return;
+ hasInit = true;
+ context = context1;
+ dbHelper = new DbHelper(context);
+ // Gets the data repository in write mode
+ db = dbHelper.getReadableDatabase();
+ }
+
+ }
+
+ public static long addSender(SenderModel senderModel) {
+
+ // Create a new map of values, where column names are the keys
+ ContentValues values = new ContentValues();
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_NAME, senderModel.getName());
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_TYPE, senderModel.getType());
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_STATUS, senderModel.getStatus());
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING, senderModel.getJsonSetting());
+
+ // Insert the new row, returning the primary key value of the new row
+
+ return db.insert(SenderTable.SenderEntry.TABLE_NAME, null, values);
+ }
+
+ public static long updateSender(SenderModel senderModel) {
+ if (senderModel == null) return 0;
+
+ // Create a new map of values, where column names are the keys
+ ContentValues values = new ContentValues();
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_NAME, senderModel.getName());
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_TYPE, senderModel.getType());
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_STATUS, senderModel.getStatus());
+ values.put(SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING, senderModel.getJsonSetting());
+
+ String selection = SenderTable.SenderEntry._ID + " = ? ";
+ String[] whereArgs = {String.valueOf(senderModel.getId())};
+
+ return db.update(SenderTable.SenderEntry.TABLE_NAME, values, selection, whereArgs);
+ }
+
+ public static int delSender(Long id) {
+ // Define 'where' part of query.
+ String selection = " 1 ";
+ // Specify arguments in placeholder order.
+ List selectionArgList = new ArrayList<>();
+ if (id != null) {
+ // Define 'where' part of query.
+ selection += " and " + SenderTable.SenderEntry._ID + " = ? ";
+ // Specify arguments in placeholder order.
+ selectionArgList.add(String.valueOf(id));
+
+ }
+ String[] selectionArgs = selectionArgList.toArray(new String[selectionArgList.size()]);
+ // Issue SQL statement.
+ return db.delete(SenderTable.SenderEntry.TABLE_NAME, selection, selectionArgs);
+
+ }
+
+ public static List getSender(Long id, String key) {
+ // Define a projection that specifies which columns from the database
+ // you will actually use after this query.
+ String[] projection = {
+ BaseColumns._ID,
+ SenderTable.SenderEntry.COLUMN_NAME_NAME,
+ SenderTable.SenderEntry.COLUMN_NAME_TYPE,
+ SenderTable.SenderEntry.COLUMN_NAME_STATUS,
+ SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING,
+ SenderTable.SenderEntry.COLUMN_NAME_TIME
+ };
+ // Define 'where' part of query.
+ String selection = " 1 ";
+ // Specify arguments in placeholder order.
+ List selectionArgList = new ArrayList<>();
+ if (id != null) {
+ // Define 'where' part of query.
+ selection += " and " + SenderTable.SenderEntry._ID + " = ? ";
+ // Specify arguments in placeholder order.
+ selectionArgList.add(String.valueOf(id));
+ }
+
+ if (key != null) {
+ // Define 'where' part of query.
+ selection = " and (" + SenderTable.SenderEntry.COLUMN_NAME_NAME + " LIKE ? or " + SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING + " LIKE ? ) ";
+ // Specify arguments in placeholder order.
+ selectionArgList.add(key);
+ selectionArgList.add(key);
+ }
+ String[] selectionArgs = selectionArgList.toArray(new String[selectionArgList.size()]);
+
+ // How you want the results sorted in the resulting Cursor
+ String sortOrder =
+ SenderTable.SenderEntry._ID + " DESC";
+
+ Cursor cursor = db.query(
+ SenderTable.SenderEntry.TABLE_NAME, // The table to query
+ projection, // The array of columns to return (pass null to get all)
+ selection, // The columns for the WHERE clause
+ selectionArgs, // The values for the WHERE clause
+ null, // don't group the rows
+ null, // don't filter by row groups
+ sortOrder // The sort order
+ );
+ List tSenders = new ArrayList<>();
+ while (cursor.moveToNext()) {
+
+ long itemId = cursor.getLong(
+ cursor.getColumnIndexOrThrow(SenderTable.SenderEntry._ID));
+ String itemName = cursor.getString(
+ cursor.getColumnIndexOrThrow(SenderTable.SenderEntry.COLUMN_NAME_NAME));
+ int itemStatus = cursor.getInt(
+ cursor.getColumnIndexOrThrow(SenderTable.SenderEntry.COLUMN_NAME_STATUS));
+ int itemType = cursor.getInt(
+ cursor.getColumnIndexOrThrow(SenderTable.SenderEntry.COLUMN_NAME_TYPE));
+ String itemJsonSetting = cursor.getString(
+ cursor.getColumnIndexOrThrow(SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING));
+ long itemTime = cursor.getLong(
+ cursor.getColumnIndexOrThrow(SenderTable.SenderEntry.COLUMN_NAME_TIME));
+ Log.d(TAG, "getSender: itemId" + itemId);
+
+ SenderModel senderModel = new SenderModel();
+ senderModel.setId(itemId);
+ senderModel.setName(itemName);
+ senderModel.setStatus(itemStatus);
+ senderModel.setType(itemType);
+ senderModel.setJsonSetting(itemJsonSetting);
+ senderModel.setTime(itemTime);
+
+ tSenders.add(senderModel);
+ }
+ cursor.close();
+ return tSenders;
+ }
+
+ public static int countSender(String key) {
+ // Define a projection that specifies which columns from the database
+ // you will actually use after this query.
+ String[] projection = {
+ };
+ // Define 'where' part of query.
+ String selection = " 1 ";
+ // Specify arguments in placeholder order.
+ List selectionArgList = new ArrayList<>();
+
+ if (key != null) {
+ // Define 'where' part of query.
+ selection = " and (" + SenderTable.SenderEntry.COLUMN_NAME_NAME + " LIKE ? or " + SenderTable.SenderEntry.COLUMN_NAME_JSON_SETTING + " LIKE ? ) ";
+ // Specify arguments in placeholder order.
+ selectionArgList.add(key);
+ selectionArgList.add(key);
+ }
+ String[] selectionArgs = selectionArgList.toArray(new String[selectionArgList.size()]);
+
+ // How you want the results sorted in the resulting Cursor
+
+ Cursor cursor = db.query(
+ SenderTable.SenderEntry.TABLE_NAME, // The table to query
+ projection, // The array of columns to return (pass null to get all)
+ selection, // The columns for the WHERE clause
+ selectionArgs, // The values for the WHERE clause
+ null, // don't group the rows
+ null, // don't filter by row groups
+ null // The sort order
+ );
+ int count = cursor.getCount();
+ cursor.close();
+ return count;
+ }
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SenderWebNotifyMsg.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderWebNotifyMsg.java
new file mode 100644
index 00000000..54560215
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SenderWebNotifyMsg.java
@@ -0,0 +1,100 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Base64;
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.MediaType;
+import okhttp3.MultipartBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
+
+public class SenderWebNotifyMsg {
+
+ static String TAG = "SenderWebNotifyMsg";
+
+ public static void sendMsg(final Handler handError, String token, String secret, String from, String content) throws Exception {
+ Log.i(TAG, "sendMsg token:" + token + " from:" + from + " content:" + content);
+
+ if (token == null || token.isEmpty()) {
+ return;
+ }
+
+ OkHttpClient client = new OkHttpClient().newBuilder()
+ .build();
+ MediaType mediaType = MediaType.parse("text/plain");
+ MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM)
+ .addFormDataPart("from", from)
+ .addFormDataPart("content", content);
+
+ if (secret != null && !secret.isEmpty()) {
+ Long timestamp = System.currentTimeMillis();
+
+ String stringToSign = timestamp + "\n" + secret;
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
+ byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+ String sign = URLEncoder.encode(new String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8");
+ Log.i(TAG, "sign:" + sign);
+ builder.addFormDataPart("content", content);
+ }
+
+ RequestBody body = builder.build();
+ Request request = new Request.Builder()
+ .url(token)
+ .method("POST", body)
+ .build();
+// Response response = client.newCall(request).execute();
+
+
+ Call call = client.newCall(request);
+ call.enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, final IOException e) {
+ Log.d(TAG, "onFailure:" + e.getMessage());
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送失败:" + e.getMessage());
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ }
+
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ final String responseStr = response.body().string();
+ Log.d(TAG, "Code:" + String.valueOf(response.code()) + responseStr);
+
+ if (handError != null) {
+ android.os.Message msg = new android.os.Message();
+ msg.what = NOTIFY;
+ Bundle bundle = new Bundle();
+ bundle.putString("DATA", "发送状态:" + responseStr);
+ msg.setData(bundle);
+ handError.sendMessage(msg);
+ Log.d(TAG, "Coxxyyde:" + String.valueOf(response.code()) + responseStr);
+ }
+
+ }
+ });
+ }
+
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtil.java
new file mode 100644
index 00000000..213cab6f
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtil.java
@@ -0,0 +1,74 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+public class SettingUtil {
+ static Boolean hasInit = false;
+ private static String TAG = "SettingUtil";
+ private static SharedPreferences sp_setting = null;
+ private static Context context = null;
+
+ public static void init(Context context1) {
+ synchronized (hasInit) {
+ if (hasInit) return;
+ hasInit = true;
+ context = context1;
+ Log.d(TAG, "init ");
+ sp_setting = PreferenceManager.getDefaultSharedPreferences(context1);
+
+ }
+ }
+
+ public static boolean option_withreboot() {
+ return sp_setting.getBoolean("option_withreboot", false);
+ }
+
+ public static boolean using_dingding() {
+ return sp_setting.getBoolean("option_dingding_on", false);
+ }
+
+ public static String get_using_dingding_token() {
+ return sp_setting.getString("option_dingding_token", "");
+ }
+
+ public static String get_using_dingding_secret() {
+ return sp_setting.getString("option_dingding_secret", "");
+ }
+
+ public static boolean using_email() {
+ return sp_setting.getBoolean("option_email_on", false);
+ }
+
+ public static void set_send_util_email(String host, String port, String from_add, String psw, String to_add) {
+ Log.d(TAG, "set_send_util_email host:" + host + "port" + port + "from_add" + from_add + "psw" + psw + "to_add" + to_add);
+ //验证
+ if (host.equals("") || port.equals("") || from_add.equals("") || psw.equals("") || to_add.equals("")) {
+ return;
+ }
+ sp_setting.edit()
+ .putString(Define.SP_MSG_SEND_UTIL_EMAIL_HOST_KEY, host)
+ .putString(Define.SP_MSG_SEND_UTIL_EMAIL_PORT_KEY, port)
+ .putString(Define.SP_MSG_SEND_UTIL_EMAIL_FROMADD_KEY, from_add)
+ .putString(Define.SP_MSG_SEND_UTIL_EMAIL_PSW_KEY, psw)
+ .putString(Define.SP_MSG_SEND_UTIL_EMAIL_TOADD_KEY, to_add)
+ .apply();
+ }
+
+ public static String get_send_util_email(String key) {
+ Log.d(TAG, "get_send_util_email key" + key);
+ String defaultstt = "";
+ if (key.equals(Define.SP_MSG_SEND_UTIL_EMAIL_HOST_KEY)) defaultstt = "stmp服务器";
+ if (key.equals(Define.SP_MSG_SEND_UTIL_EMAIL_PORT_KEY)) defaultstt = "端口";
+ if (key.equals(Define.SP_MSG_SEND_UTIL_EMAIL_FROMADD_KEY)) defaultstt = "发送邮箱";
+ if (key.equals(Define.SP_MSG_SEND_UTIL_EMAIL_PSW_KEY)) defaultstt = "密码";
+ if (key.equals(Define.SP_MSG_SEND_UTIL_EMAIL_TOADD_KEY)) defaultstt = "接收邮箱";
+ return sp_setting.getString(key, defaultstt);
+ }
+
+ public static boolean saveMsgHistory() {
+ return sp_setting.getBoolean("option_save_history_on", false);
+ }
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/UpdateAppHttpUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/UpdateAppHttpUtil.java
new file mode 100644
index 00000000..76b75f4b
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/UpdateAppHttpUtil.java
@@ -0,0 +1,124 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import com.vector.update_app.HttpManager;
+import com.zhy.http.okhttp.OkHttpUtils;
+import com.zhy.http.okhttp.callback.FileCallBack;
+import com.zhy.http.okhttp.callback.StringCallback;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import okhttp3.Call;
+import okhttp3.Request;
+import okhttp3.Response;
+
+
+public class UpdateAppHttpUtil implements HttpManager {
+ /**
+ * 异步get
+ *
+ * @param url get请求地址
+ * @param params get参数
+ * @param callBack 回调
+ */
+ @Override
+ public void asyncGet(@NonNull String url, @NonNull Map params, @NonNull final HttpManager.Callback callBack) {
+ Log.i("UpdateAppHttpUtil", "asyncGet" + url);
+ Map headers = new HashMap<>();
+ headers.put("heada", "bb");
+ OkHttpUtils.get()
+ .url(url)
+ .headers(headers)
+ .params(params)
+ .build()
+ .execute(new StringCallback() {
+ @Override
+ public void onError(Call call, Response response, Exception e, int id) {
+ Log.i("UpdateAppHttpUtil", "err response" + response);
+ callBack.onError(validateError(e, response));
+ }
+
+ @Override
+ public void onResponse(String response, int id) {
+ Log.i("UpdateAppHttpUtil", "response" + response);
+ callBack.onResponse(response);
+ }
+ });
+ }
+
+ /**
+ * 异步post
+ *
+ * @param url post请求地址
+ * @param params post请求参数
+ * @param callBack 回调
+ */
+ @Override
+ public void asyncPost(@NonNull String url, @NonNull Map params, @NonNull final HttpManager.Callback callBack) {
+ Log.i("UpdateAppHttpUtil", "asyncPost" + url);
+
+// params.put("gggg","hhhh");
+ Map headers = new HashMap<>();
+ headers.put("heada", "bb");
+ OkHttpUtils.post()
+ .url(url)
+ .headers(headers)
+ .params(params)
+ .build()
+ .execute(new StringCallback() {
+ @Override
+ public void onError(Call call, Response response, Exception e, int id) {
+ callBack.onError(validateError(e, response));
+ }
+
+ @Override
+ public void onResponse(String response, int id) {
+ callBack.onResponse(response);
+ }
+ });
+
+ }
+
+ /**
+ * 下载
+ *
+ * @param url 下载地址
+ * @param path 文件保存路径
+ * @param fileName 文件名称
+ * @param callback 回调
+ */
+ @Override
+ public void download(@NonNull String url, @NonNull String path, @NonNull String fileName, @NonNull final HttpManager.FileCallback callback) {
+ OkHttpUtils.get()
+ .url(url)
+ .build()
+ .execute(new FileCallBack(path, fileName) {
+ @Override
+ public void inProgress(float progress, long total, int id) {
+ callback.onProgress(progress, total);
+ }
+
+ @Override
+ public void onError(Call call, Response response, Exception e, int id) {
+ callback.onError(validateError(e, response));
+ }
+
+ @Override
+ public void onResponse(File response, int id) {
+ callback.onResponse(response);
+
+ }
+
+ @Override
+ public void onBefore(Request request, int id) {
+ super.onBefore(request, id);
+ callback.onBefore();
+ }
+ });
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/aUtil.java b/app/src/main/java/com/idormy/sms/forwarder/utils/aUtil.java
new file mode 100644
index 00000000..7a138c29
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/aUtil.java
@@ -0,0 +1,56 @@
+package com.idormy.sms.forwarder.utils;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+public class aUtil {
+ private static String TAG = "aUtil";
+
+ private static Context context = null;
+
+ /**
+ * 判断是否为MIUI系统,参考http://blog.csdn.net/xx326664162/article/details/52438706
+ *
+ * @return
+ */
+ public static boolean isMIUI() {
+ try {
+ String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
+ String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
+ String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
+ Properties prop = new Properties();
+ prop.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
+
+ return prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null
+ || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null
+ || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null;
+ } catch (final IOException e) {
+ return false;
+ }
+ }
+
+ public static String getVersionName(Context context) throws Exception {
+ // 获取packagemanager的实例
+ PackageManager packageManager = context.getPackageManager();
+ // getPackageName()是你当前类的包名,0代表是获取版本信息
+ PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
+ String version = packInfo.versionName;
+ return version;
+ }
+
+ public static Integer getVersionCode(Context context) throws Exception {
+ // 获取packagemanager的实例
+ PackageManager packageManager = context.getPackageManager();
+ // getPackageName()是你当前类的包名,0代表是获取版本信息
+ PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
+ Integer versionCode = packInfo.versionCode;
+ return versionCode;
+ }
+}
diff --git a/app/src/main/qywx-playstore.png b/app/src/main/qywx-playstore.png
new file mode 100644
index 00000000..6816f0c1
Binary files /dev/null and b/app/src/main/qywx-playstore.png differ
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..1f6bb290
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_baseline_email_24.xml b/app/src/main/res/drawable/ic_baseline_email_24.xml
new file mode 100644
index 00000000..2c852177
--- /dev/null
+++ b/app/src/main/res/drawable/ic_baseline_email_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..07d5da9c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_alter_dialog_setview_bark.xml b/app/src/main/res/layout/activity_alter_dialog_setview_bark.xml
new file mode 100644
index 00000000..81120bf3
--- /dev/null
+++ b/app/src/main/res/layout/activity_alter_dialog_setview_bark.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_alter_dialog_setview_dingding.xml b/app/src/main/res/layout/activity_alter_dialog_setview_dingding.xml
new file mode 100644
index 00000000..fa6688cc
--- /dev/null
+++ b/app/src/main/res/layout/activity_alter_dialog_setview_dingding.xml
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_alter_dialog_setview_email.xml b/app/src/main/res/layout/activity_alter_dialog_setview_email.xml
new file mode 100644
index 00000000..9ea3dbd1
--- /dev/null
+++ b/app/src/main/res/layout/activity_alter_dialog_setview_email.xml
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_alter_dialog_setview_qywxgrouprobot.xml b/app/src/main/res/layout/activity_alter_dialog_setview_qywxgrouprobot.xml
new file mode 100644
index 00000000..a6b15ac1
--- /dev/null
+++ b/app/src/main/res/layout/activity_alter_dialog_setview_qywxgrouprobot.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_alter_dialog_setview_rule.xml b/app/src/main/res/layout/activity_alter_dialog_setview_rule.xml
new file mode 100644
index 00000000..35c97843
--- /dev/null
+++ b/app/src/main/res/layout/activity_alter_dialog_setview_rule.xml
@@ -0,0 +1,168 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_alter_dialog_setview_webnotify.xml b/app/src/main/res/layout/activity_alter_dialog_setview_webnotify.xml
new file mode 100644
index 00000000..0b5be390
--- /dev/null
+++ b/app/src/main/res/layout/activity_alter_dialog_setview_webnotify.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..cf69da21
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_rule.xml b/app/src/main/res/layout/activity_rule.xml
new file mode 100644
index 00000000..fb591f1b
--- /dev/null
+++ b/app/src/main/res/layout/activity_rule.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_sender.xml b/app/src/main/res/layout/activity_sender.xml
new file mode 100644
index 00000000..92d97e08
--- /dev/null
+++ b/app/src/main/res/layout/activity_sender.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml
new file mode 100644
index 00000000..433b1c79
--- /dev/null
+++ b/app/src/main/res/layout/activity_setting.xml
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_feedback.xml b/app/src/main/res/layout/dialog_feedback.xml
new file mode 100644
index 00000000..510c9b72
--- /dev/null
+++ b/app/src/main/res/layout/dialog_feedback.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/header_layout.xml b/app/src/main/res/layout/header_layout.xml
new file mode 100644
index 00000000..d5dc27e0
--- /dev/null
+++ b/app/src/main/res/layout/header_layout.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/rule_item.xml b/app/src/main/res/layout/rule_item.xml
new file mode 100644
index 00000000..72d1b345
--- /dev/null
+++ b/app/src/main/res/layout/rule_item.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/sender_item.xml b/app/src/main/res/layout/sender_item.xml
new file mode 100644
index 00000000..9e9ad19c
--- /dev/null
+++ b/app/src/main/res/layout/sender_item.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/tlog_item.xml b/app/src/main/res/layout/tlog_item.xml
new file mode 100644
index 00000000..ffe9cb92
--- /dev/null
+++ b/app/src/main/res/layout/tlog_item.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 00000000..33372dd1
--- /dev/null
+++ b/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,11 @@
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..be316184
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/qywx.xml b/app/src/main/res/mipmap-anydpi-v26/qywx.xml
new file mode 100644
index 00000000..38ab7075
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/qywx.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/qywx_round.xml b/app/src/main/res/mipmap-anydpi-v26/qywx_round.xml
new file mode 100644
index 00000000..38ab7075
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/qywx_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/dingding.jpg b/app/src/main/res/mipmap-hdpi/dingding.jpg
new file mode 100644
index 00000000..98f9ebaa
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/dingding.jpg differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..add64efd
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
new file mode 100644
index 00000000..38f87330
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..d93e2c0a
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..af2d5089
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launchert.jpg b/app/src/main/res/mipmap-hdpi/ic_launchert.jpg
new file mode 100644
index 00000000..af0d8fb5
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launchert.jpg differ
diff --git a/app/src/main/res/mipmap-hdpi/qywx.png b/app/src/main/res/mipmap-hdpi/qywx.png
new file mode 100644
index 00000000..91e36127
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/qywx.png differ
diff --git a/app/src/main/res/mipmap-hdpi/qywx_foreground.png b/app/src/main/res/mipmap-hdpi/qywx_foreground.png
new file mode 100644
index 00000000..2432fb61
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/qywx_foreground.png differ
diff --git a/app/src/main/res/mipmap-hdpi/qywx_round.png b/app/src/main/res/mipmap-hdpi/qywx_round.png
new file mode 100644
index 00000000..359d9db6
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/qywx_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/dingding.jpg b/app/src/main/res/mipmap-mdpi/dingding.jpg
new file mode 100644
index 00000000..98f9ebaa
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/dingding.jpg differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..4d63c259
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
new file mode 100644
index 00000000..14e969ff
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..77303fbe
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..886e713a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launchert.jpg b/app/src/main/res/mipmap-mdpi/ic_launchert.jpg
new file mode 100644
index 00000000..af0d8fb5
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launchert.jpg differ
diff --git a/app/src/main/res/mipmap-mdpi/qywx.png b/app/src/main/res/mipmap-mdpi/qywx.png
new file mode 100644
index 00000000..2ca8a36e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/qywx.png differ
diff --git a/app/src/main/res/mipmap-mdpi/qywx_foreground.png b/app/src/main/res/mipmap-mdpi/qywx_foreground.png
new file mode 100644
index 00000000..2db98a6a
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/qywx_foreground.png differ
diff --git a/app/src/main/res/mipmap-mdpi/qywx_round.png b/app/src/main/res/mipmap-mdpi/qywx_round.png
new file mode 100644
index 00000000..22c8f494
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/qywx_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/dingding.jpg b/app/src/main/res/mipmap-xhdpi/dingding.jpg
new file mode 100644
index 00000000..98f9ebaa
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/dingding.jpg differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..e5b4b58e
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
new file mode 100644
index 00000000..4ef75a9f
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..66b9054f
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..da2eaf06
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launchert.jpg b/app/src/main/res/mipmap-xhdpi/ic_launchert.jpg
new file mode 100644
index 00000000..af0d8fb5
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launchert.jpg differ
diff --git a/app/src/main/res/mipmap-xhdpi/qywx.png b/app/src/main/res/mipmap-xhdpi/qywx.png
new file mode 100644
index 00000000..5d37674e
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/qywx.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/qywx_foreground.png b/app/src/main/res/mipmap-xhdpi/qywx_foreground.png
new file mode 100644
index 00000000..0aefb27f
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/qywx_foreground.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/qywx_round.png b/app/src/main/res/mipmap-xhdpi/qywx_round.png
new file mode 100644
index 00000000..c1026191
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/qywx_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/dingding.jpg b/app/src/main/res/mipmap-xxhdpi/dingding.jpg
new file mode 100644
index 00000000..98f9ebaa
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/dingding.jpg differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..4c275d62
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
new file mode 100644
index 00000000..08475a35
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..985ca084
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..67ae2da1
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launchert.jpg b/app/src/main/res/mipmap-xxhdpi/ic_launchert.jpg
new file mode 100644
index 00000000..af0d8fb5
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launchert.jpg differ
diff --git a/app/src/main/res/mipmap-xxhdpi/qywx.png b/app/src/main/res/mipmap-xxhdpi/qywx.png
new file mode 100644
index 00000000..96616da7
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/qywx.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/qywx_foreground.png b/app/src/main/res/mipmap-xxhdpi/qywx_foreground.png
new file mode 100644
index 00000000..7e685ddd
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/qywx_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/qywx_round.png b/app/src/main/res/mipmap-xxhdpi/qywx_round.png
new file mode 100644
index 00000000..83eefa6d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/qywx_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/dingding.jpg b/app/src/main/res/mipmap-xxxhdpi/dingding.jpg
new file mode 100644
index 00000000..98f9ebaa
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/dingding.jpg differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..8097392c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
new file mode 100644
index 00000000..0876d22b
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 00000000..7679a22c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..1edf2294
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launchert.jpg b/app/src/main/res/mipmap-xxxhdpi/ic_launchert.jpg
new file mode 100644
index 00000000..af0d8fb5
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launchert.jpg differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/qywx.png b/app/src/main/res/mipmap-xxxhdpi/qywx.png
new file mode 100644
index 00000000..b99efc69
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/qywx.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/qywx_foreground.png b/app/src/main/res/mipmap-xxxhdpi/qywx_foreground.png
new file mode 100644
index 00000000..ae64c1ec
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/qywx_foreground.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/qywx_round.png b/app/src/main/res/mipmap-xxxhdpi/qywx_round.png
new file mode 100644
index 00000000..236dc47e
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/qywx_round.png differ
diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml
new file mode 100644
index 00000000..3b88dc46
--- /dev/null
+++ b/app/src/main/res/values/array.xml
@@ -0,0 +1,11 @@
+
+
+
+ - 转发到钉钉机器人
+ - 转发到邮箱
+ - 转发到其他手机
+ - 转发到网页
+ - 转发到企业微信群机器人
+ - 转发到Bark
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..69b22338
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/app/src/main/res/values/qywx_background.xml b/app/src/main/res/values/qywx_background.xml
new file mode 100644
index 00000000..3a9a5547
--- /dev/null
+++ b/app/src/main/res/values/qywx_background.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFAF0
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..fe57bf03
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,16 @@
+
+ 短信转发器
+ 确认
+ 确认
+ 删除
+ 测试
+ 设置钉钉机器人
+ 反馈建议
+ 设置转发规则
+ 设置邮箱
+ 设置网页通知
+ 设置企业微信群机器人
+ 设置Bark
+ 检查更新
+ 设置
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..5885930d
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/xml/preference_setting.xml b/app/src/main/res/xml/preference_setting.xml
new file mode 100644
index 00000000..312fa12f
--- /dev/null
+++ b/app/src/main/res/xml/preference_setting.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/idormy/sms/forwarder/ExampleUnitTest.kt b/app/src/test/java/com/idormy/sms/forwarder/ExampleUnitTest.kt
new file mode 100644
index 00000000..d5b4d719
--- /dev/null
+++ b/app/src/test/java/com/idormy/sms/forwarder/ExampleUnitTest.kt
@@ -0,0 +1,16 @@
+package com.idormy.sms.forwarder
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 00000000..7b10d277
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,31 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext.kotlin_version = '1.4.30'
+ repositories {
+ google()
+ jcenter()
+ maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/' }
+ maven { url 'https://dl.bintray.com/umsdk/release' }
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.1.2'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/' }
+ maven { url 'https://dl.bintray.com/umsdk/release' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/doc/POST_WEB.md b/doc/POST_WEB.md
new file mode 100644
index 00000000..d2fe704a
--- /dev/null
+++ b/doc/POST_WEB.md
@@ -0,0 +1,89 @@
+## 配置转发到WEB后,测试或者转发时会向配置的token即url发送POST请求
+
+url:
+https://api.sl.allmything.com/api/msg/pushMsg?token=p9EM2K4Po01UIJr3sISbRmBFYWCHOGQaqwqk6cgxdsfyevTXtz8hVUlNAunD5i
+
+#### 有一个已经实现好的站点[消息通知](https://msg.allmything.com)
+
+### 请求体如下
+> post form
+参数:
+
+| key | 类型 | 说明 |
+| ---- | ---- | ---- |
+| from | string | 来源手机号 |
+| content | string | 短信内容 |
+| sign | string | 当设置secret时,生成的sign签名,用于发送端校验,规则见下方sign校验规则 |
+
+### sign校验规则
+把timestamp+"\n"+密钥当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集)
+| 参数 | 说明 |
+| ---- | ---- |
+| timestamp | 当前时间戳,单位是毫秒,与请求调用时间误差不能超过1小时 |
+| secret | 密钥,web通知设置页面,secret |
+
+示例:
+```Java
+//java
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import org.apache.commons.codec.binary.Base64;
+import java.net.URLEncoder;
+
+public class Test {
+ public static void main(String[] args) throws Exception {
+ Long timestamp = System.currentTimeMillis();
+ String secret = "this is secret";
+
+ String stringToSign = timestamp + "\n" + secret;
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
+ byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
+ String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)),"UTF-8");
+ System.out.println(sign);
+ }
+
+}
+
+```
+
+```python
+#python 3.8
+import time
+import hmac
+import hashlib
+import base64
+import urllib.parse
+
+timestamp = str(round(time.time() * 1000))
+secret = 'this is secret'
+secret_enc = secret.encode('utf-8')
+string_to_sign = '{}\n{}'.format(timestamp, secret)
+string_to_sign_enc = string_to_sign.encode('utf-8')
+hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
+sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
+print(timestamp)
+print(sign)
+
+```
+```python
+#python 2.7
+import time
+import hmac
+import hashlib
+import base64
+import urllib
+
+timestamp = long(round(time.time() * 1000))
+secret = 'this is secret'
+secret_enc = bytes(secret).encode('utf-8')
+string_to_sign = '{}\n{}'.format(timestamp, secret)
+string_to_sign_enc = bytes(string_to_sign).encode('utf-8')
+hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
+sign = urllib.quote_plus(base64.b64encode(hmac_code))
+print(timestamp)
+print(sign)
+
+```
+
+
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 00000000..14874631
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,14 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f6b961fd
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..b3f32a33
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Feb 10 13:32:36 CST 2021
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
diff --git a/gradlew b/gradlew
new file mode 100644
index 00000000..cccdd3d5
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..f9553162
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/pic/app.jpg b/pic/app.jpg
new file mode 100644
index 00000000..a74b8fea
Binary files /dev/null and b/pic/app.jpg differ
diff --git a/pic/dingding.jpg b/pic/dingding.jpg
new file mode 100644
index 00000000..239bde1e
Binary files /dev/null and b/pic/dingding.jpg differ
diff --git a/pic/dingdingmsg.jpg b/pic/dingdingmsg.jpg
new file mode 100644
index 00000000..239bde1e
Binary files /dev/null and b/pic/dingdingmsg.jpg differ
diff --git a/pic/dingdingtokenset.jpg b/pic/dingdingtokenset.jpg
new file mode 100644
index 00000000..e3070680
Binary files /dev/null and b/pic/dingdingtokenset.jpg differ
diff --git a/pic/main.jpg b/pic/main.jpg
new file mode 100644
index 00000000..622eb484
Binary files /dev/null and b/pic/main.jpg differ
diff --git a/pic/maindetail.jpg b/pic/maindetail.jpg
new file mode 100644
index 00000000..491d6fbc
Binary files /dev/null and b/pic/maindetail.jpg differ
diff --git a/pic/rule.jpg b/pic/rule.jpg
new file mode 100644
index 00000000..42b6b2bb
Binary files /dev/null and b/pic/rule.jpg differ
diff --git a/pic/ruleset.jpg b/pic/ruleset.jpg
new file mode 100644
index 00000000..a5d4e17d
Binary files /dev/null and b/pic/ruleset.jpg differ
diff --git a/pic/sender.jpg b/pic/sender.jpg
new file mode 100644
index 00000000..31daf1ab
Binary files /dev/null and b/pic/sender.jpg differ
diff --git a/pic/sendersetdingding.jpg b/pic/sendersetdingding.jpg
new file mode 100644
index 00000000..7581f746
Binary files /dev/null and b/pic/sendersetdingding.jpg differ
diff --git a/pic/sendersetemail.jpg b/pic/sendersetemail.jpg
new file mode 100644
index 00000000..d63e0cfa
Binary files /dev/null and b/pic/sendersetemail.jpg differ
diff --git a/pic/sendersetwebnotify.jpg b/pic/sendersetwebnotify.jpg
new file mode 100644
index 00000000..05e61312
Binary files /dev/null and b/pic/sendersetwebnotify.jpg differ
diff --git a/pic/setting.jpg b/pic/setting.jpg
new file mode 100644
index 00000000..bf8ac4ec
Binary files /dev/null and b/pic/setting.jpg differ
diff --git a/pic/settingfeedback.jpg b/pic/settingfeedback.jpg
new file mode 100644
index 00000000..490a831c
Binary files /dev/null and b/pic/settingfeedback.jpg differ
diff --git a/pic/showpic.png b/pic/showpic.png
new file mode 100644
index 00000000..96b1cccd
Binary files /dev/null and b/pic/showpic.png differ
diff --git a/pic/taskbar.jpg b/pic/taskbar.jpg
new file mode 100644
index 00000000..fae0e64c
Binary files /dev/null and b/pic/taskbar.jpg differ
diff --git a/pic/tsms-icon-bg0.png b/pic/tsms-icon-bg0.png
new file mode 100644
index 00000000..bd5fd9e2
Binary files /dev/null and b/pic/tsms-icon-bg0.png differ
diff --git a/pic/tsms-icon.png b/pic/tsms-icon.png
new file mode 100644
index 00000000..a3492717
Binary files /dev/null and b/pic/tsms-icon.png differ
diff --git a/pic/tsms-icon.xcf b/pic/tsms-icon.xcf
new file mode 100644
index 00000000..73654332
Binary files /dev/null and b/pic/tsms-icon.xcf differ
diff --git a/pic/tsms-icon0.png b/pic/tsms-icon0.png
new file mode 100644
index 00000000..f85604f4
Binary files /dev/null and b/pic/tsms-icon0.png differ
diff --git a/pic/update-dingdingsecret.jpg b/pic/update-dingdingsecret.jpg
new file mode 100644
index 00000000..cee7a2c0
Binary files /dev/null and b/pic/update-dingdingsecret.jpg differ
diff --git a/pic/webnotify.jpg b/pic/webnotify.jpg
new file mode 100644
index 00000000..af58d42f
Binary files /dev/null and b/pic/webnotify.jpg differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 00000000..e7b4def4
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'