diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/lib/datatypes/Tuple5.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/lib/datatypes/Tuple5.java new file mode 100644 index 0000000..261c8cb --- /dev/null +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/lib/datatypes/Tuple5.java @@ -0,0 +1,19 @@ +package com.blackforestbytes.simplecloudnotifier.lib.datatypes; + +public class Tuple5 +{ + public final T1 Item1; + public final T2 Item2; + public final T3 Item3; + public final T4 Item4; + public final T5 Item5; + + public Tuple5(T1 i1, T2 i2, T3 i3, T4 i4, T5 i5) + { + Item1 = i1; + Item2 = i2; + Item3 = i3; + Item4 = i4; + Item5 = i5; + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/lib/lambda/Func5to0.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/lib/lambda/Func5to0.java new file mode 100644 index 0000000..0440a2f --- /dev/null +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/lib/lambda/Func5to0.java @@ -0,0 +1,6 @@ +package com.blackforestbytes.simplecloudnotifier.lib.lambda; + +@FunctionalInterface +public interface Func5to0 { + void invoke(TInput1 value1, TInput2 value2, TInput3 value3, TInput4 value4, TInput5 value5); +} diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/ServerCommunication.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/ServerCommunication.java index 414a601..680e388 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/ServerCommunication.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/model/ServerCommunication.java @@ -4,6 +4,9 @@ import android.util.Log; import android.view.View; import com.blackforestbytes.simplecloudnotifier.SCNApp; +import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple5; +import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func1to0; +import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func5to0; import com.blackforestbytes.simplecloudnotifier.lib.string.Str; import com.blackforestbytes.simplecloudnotifier.service.FBMService; @@ -57,7 +60,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -123,7 +126,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -185,7 +188,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -246,7 +249,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -329,7 +332,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -397,7 +400,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -452,7 +455,7 @@ public class ServerCommunication if (responseBody == null) throw new IOException("No response"); String r = responseBody.string(); - Log.d("Server::Response", r); + Log.d("Server::Response", request.url().toString()+"\n"+r); JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); @@ -471,6 +474,70 @@ public class ServerCommunication } } + public static void expand(int id, String key, long scn_msg_id, View loader, Func5to0 okResult) + { + try + { + Request request = new Request.Builder() + .url(BASE_URL + "expand.php?user_id=" + id + "&user_key=" + key + "&scn_msg_id=" + scn_msg_id) + .build(); + + client.newCall(request).enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + Log.e("SC:expand", e.toString()); + SCNApp.showToast("Communication with server failed", 4000); + SCNApp.runOnUiThread(() -> { + if (loader != null) loader.setVisibility(View.GONE); + }); + } + + @Override + public void onResponse(Call call, Response response) { + try (ResponseBody responseBody = response.body()) { + if (!response.isSuccessful()) + throw new IOException("Unexpected code " + response); + if (responseBody == null) throw new IOException("No response"); + + String r = responseBody.string(); + Log.d("Server::Response", request.url().toString()+"\n"+r); + + JSONObject json = (JSONObject) new JSONTokener(r).nextValue(); + + if (!json_bool(json, "success")) + { + SCNApp.showToast(json_str(json, "message"), 4000); + return; + } + + JSONObject o = json.getJSONObject("data"); + + long time = json_lng(o, "timestamp"); + String title = json_str(o, "title"); + String content = json_str(o, "body"); + PriorityEnum prio = PriorityEnum.parseAPI(json_int(o, "priority")); + long scn_id = json_lng(o, "scn_msg_id"); + + okResult.invoke(title, content, prio, time, scn_id); + + } catch (Exception e) { + Log.e("SC:expand", e.toString()); + SCNApp.showToast("Communication with server failed", 4000); + } finally { + SCNApp.runOnUiThread(() -> { + if (loader != null) loader.setVisibility(View.GONE); + }); + } + } + }); + } + catch (Exception e) + { + Log.e("SC:expand", e.toString()); + SCNApp.showToast("Communication with server failed", 4000); + } + } + private static boolean json_bool(JSONObject o, String key) throws JSONException { Object v = o.get(key); diff --git a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/service/FBMService.java b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/service/FBMService.java index 45c066d..ea057fd 100644 --- a/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/service/FBMService.java +++ b/android/app/src/main/java/com/blackforestbytes/simplecloudnotifier/service/FBMService.java @@ -4,6 +4,8 @@ import android.util.Log; import android.widget.Toast; import com.blackforestbytes.simplecloudnotifier.SCNApp; +import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple4; +import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple5; import com.blackforestbytes.simplecloudnotifier.model.CMessage; import com.blackforestbytes.simplecloudnotifier.model.CMessageList; import com.blackforestbytes.simplecloudnotifier.model.PriorityEnum; @@ -38,8 +40,16 @@ public class FBMService extends FirebaseMessagingService String content = remoteMessage.getData().get("body"); PriorityEnum prio = PriorityEnum.parseAPI(remoteMessage.getData().get("priority")); long scn_id = Long.parseLong(remoteMessage.getData().get("scn_msg_id")); + boolean trimmed = Boolean.parseBoolean(remoteMessage.getData().get("trimmed")); - recieveData(time, title, content, prio, scn_id, false); + if (trimmed) + { + ServerCommunication.expand(SCNSettings.inst().user_id, SCNSettings.inst().user_key, scn_id, null, (i1, i2, i3, i4, i5) -> recieveData(i4, i1, i2, i3, i5, false)); + } + else + { + recieveData(time, title, content, prio, scn_id, false); + } } catch (Exception e) { diff --git a/web/api/expand.php b/web/api/expand.php new file mode 100644 index 0000000..4a525b0 --- /dev/null +++ b/web/api/expand.php @@ -0,0 +1,53 @@ + false, 'errid'=>101, 'message' => 'Missing parameter [[user_id]]'])); +if (!isset($INPUT['user_key'])) die(json_encode(['success' => false, 'errid'=>102, 'message' => 'Missing parameter [[user_key]]'])); +if (!isset($INPUT['scn_msg_id'])) die(json_encode(['success' => false, 'errid'=>103, 'message' => 'Missing parameter [[scn_msg_id]]'])); + +$user_id = $INPUT['user_id']; +$user_key = $INPUT['user_key']; +$scn_msg_id = $INPUT['scn_msg_id']; + +//---------------------- + +$pdo = getDatabase(); + +$stmt = $pdo->prepare('SELECT user_id, user_key, quota_today, is_pro, quota_day, fcm_token FROM users WHERE user_id = :uid LIMIT 1'); +$stmt->execute(['uid' => $user_id]); +$datas = $stmt->fetchAll(PDO::FETCH_ASSOC); + +if (count($datas)<=0) die(json_encode(['success' => false, 'errid'=>201, 'message' => 'User not found'])); +$data = $datas[0]; + +if ($data === null) die(json_encode(['success' => false, 'errid'=>202, 'message' => 'User not found'])); +if ($data['user_id'] !== (int)$user_id) die(json_encode(['success' => false, 'errid'=>203, 'message' => 'UserID not found'])); +if ($data['user_key'] !== $user_key) die(json_encode(['success' => false, 'errid'=>204, 'message' => 'Authentification failed'])); + +$stmt = $pdo->prepare('SELECT * FROM messages WHERE scn_message_id=:smid AND sender_user_id=:uid LIMIT 1'); +$stmt->execute(['smid' => $scn_msg_id, 'uid' => $user_id]); +$datas = $stmt->fetchAll(PDO::FETCH_ASSOC); + +if (count($datas)<=0) die(json_encode(['success' => false, 'errid'=>301, 'message' => 'Message not found'])); + +$msg = $datas[0]; + +api_return(200, + [ + 'success' => true, + 'data' => + [ + 'title' => $msg['title'], + 'body' => $msg['content'], + 'trimmed' => false, + 'priority' => $msg['priority'], + 'timestamp' => strtotime($msg['timestamp']), + 'usr_msg_id' => $msg['usr_message_id'], + 'scn_msg_id' => $msg['scn_message_id'], + ], + 'message' => 'ok' + ]); \ No newline at end of file diff --git a/web/api/model.php b/web/api/model.php index b72b6d6..aad9e3a 100644 --- a/web/api/model.php +++ b/web/api/model.php @@ -35,6 +35,14 @@ class Statics public static $CFG = NULL; public static function quota_max($is_pro) { return $is_pro ? 1000 : 50; } + + public static function contentlen_max($is_pro) { return $is_pro ? 16384 : 2048; } +} + +function str_limit($str, $len) +{ + if (strlen($str)>$len) return substr($str, 0, $len-3)."..."; + return $str; } function getConfig() diff --git a/web/send.php b/web/send.php index d7556c3..a8d101d 100644 --- a/web/send.php +++ b/web/send.php @@ -32,8 +32,6 @@ try if ($priority !== '0' && $priority !== '1' && $priority !== '2') api_return(400, ['success' => false, 'error' => ERR::INVALID_PRIO, 'errhighlight' => 105, 'message' => 'Invalid priority']); if (strlen(trim($message)) == 0) api_return(400, ['success' => false, 'error' => ERR::NO_TITLE, 'errhighlight' => 103, 'message' => 'No title specified']); - if (strlen($message) > 120) api_return(400, ['success' => false, 'error' => ERR::TITLE_TOO_LONG, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']); - if (strlen($content) > 2048) api_return(400, ['success' => false, 'error' => ERR::CONTENT_TOO_LONG, 'errhighlight' => 104, 'message' => 'Content too long (10000 characters)']); if ($usrmsgid != null && strlen($usrmsgid) > 64) api_return(400, ['success' => false, 'error' => ERR::USR_MSG_ID_TOO_LONG, 'errhighlight' => -1, 'message' => 'MessageID too long (64 characters)']); //------------------------------------------------------------------ @@ -51,6 +49,13 @@ try if ($data['user_id'] !== (int)$user_id) api_return(401, ['success' => false, 'error' => ERR::USER_NOT_FOUND, 'errhighlight' => 101, 'message' => 'UserID not found']); if ($data['user_key'] !== $user_key) api_return(401, ['success' => false, 'error' => ERR::USER_AUTH_FAILED, 'errhighlight' => 102, 'message' => 'Authentification failed']); +//------------------------------------------------------------------ + + if (strlen($message) > 120) api_return(400, ['success' => false, 'error' => ERR::TITLE_TOO_LONG, 'errhighlight' => 103, 'message' => 'Title too long (120 characters)']); + if (strlen($content) > Statics::contentlen_max($data['is_pro'])) api_return(400, ['success' => false, 'error' => ERR::CONTENT_TOO_LONG, 'errhighlight' => 104, 'message' => 'Content too long ('.Statics::contentlen_max($data['is_pro']).' characters)']); + +//------------------------------------------------------------------ + $fcm = $data['fcm_token']; $new_quota = $data['quota_today'] + 1; @@ -115,14 +120,15 @@ try // 'body' => $content, //], 'data' => - [ - 'title' => $message, - 'body' => $content, - 'priority' => $priority, - 'timestamp' => time(), - 'usr_msg_id' => $usrmsgid, - 'scn_msg_id' => $scn_msg_id, - ] + [ + 'title' => $message, + 'body' => str_limit($content, 1900), + 'trimmed' => (strlen($content) > 1900), + 'priority' => $priority, + 'timestamp' => time(), + 'usr_msg_id' => $usrmsgid, + 'scn_msg_id' => $scn_msg_id, + ] ]); $header= [ @@ -148,6 +154,8 @@ try api_return(500, ['success' => false, 'error' => ERR::FIREBASE_COM_FAILED, 'errhighlight' => -1, 'message' => 'Communication with firebase service failed.'."\n\n".'Exception: ' . $e->getMessage()]); } +//------------------------------------------------------------------ + $stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1, quota_today=:q, quota_day=NOW() WHERE user_id = :uid'); $stmt->execute(['uid' => $user_id, 'q' => $new_quota]); @@ -156,6 +164,8 @@ try $pdo->commit(); +//------------------------------------------------------------------ + api_return(200, [ 'success' => true,