fix
This commit is contained in:
@@ -2,18 +2,22 @@ package org.to.telegramfinalproject.Client;
|
|||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
import org.to.telegramfinalproject.Database.PrivateChatDatabase;
|
||||||
|
import org.to.telegramfinalproject.Database.ContactDatabase;
|
||||||
import org.to.telegramfinalproject.Models.ChatEntry;
|
import org.to.telegramfinalproject.Models.ChatEntry;
|
||||||
import org.to.telegramfinalproject.Models.ContactEntry;
|
import org.to.telegramfinalproject.Models.ContactEntry;
|
||||||
import org.to.telegramfinalproject.Models.SearchRequestModel;
|
import org.to.telegramfinalproject.Models.SearchRequestModel;
|
||||||
|
import org.to.telegramfinalproject.Models.SearchResultModel;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
import java.nio.file.Files;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.io.PrintWriter;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
public class ActionHandler {
|
public class ActionHandler {
|
||||||
@@ -22,7 +26,6 @@ public class ActionHandler {
|
|||||||
private final Scanner scanner;
|
private final Scanner scanner;
|
||||||
public static volatile boolean forceExitChat = false;
|
public static volatile boolean forceExitChat = false;
|
||||||
public static ActionHandler instance;
|
public static ActionHandler instance;
|
||||||
private final DataOutputStream outBin;
|
|
||||||
|
|
||||||
//use for UI
|
//use for UI
|
||||||
private volatile String lastStatus = "error"; // success | error
|
private volatile String lastStatus = "error"; // success | error
|
||||||
@@ -54,12 +57,12 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionHandler(PrintWriter out, BufferedReader in, DataOutputStream outBin, Scanner scanner) {
|
public ActionHandler(PrintWriter out, BufferedReader in, Scanner scanner) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.outBin = outBin;
|
|
||||||
this.scanner = scanner;
|
this.scanner = scanner;
|
||||||
ActionHandler.instance = this;
|
ActionHandler.instance = this;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void login(String username , String password){
|
public void login(String username , String password){
|
||||||
@@ -542,12 +545,6 @@ public class ActionHandler {
|
|||||||
case "register":
|
case "register":
|
||||||
Session.currentUser = response.getJSONObject("data");
|
Session.currentUser = response.getJSONObject("data");
|
||||||
|
|
||||||
//for downloaded medias
|
|
||||||
UUID accountId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
|
||||||
Session.downloadsIndex = new DownloadsIndex(accountId);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
JSONArray chatListJson = Session.currentUser.getJSONArray("chat_list");
|
JSONArray chatListJson = Session.currentUser.getJSONArray("chat_list");
|
||||||
JSONArray Archived = Session.currentUser.getJSONArray("archived_chat_list");
|
JSONArray Archived = Session.currentUser.getJSONArray("archived_chat_list");
|
||||||
JSONArray Active = Session.currentUser.getJSONArray("active_chat_list");
|
JSONArray Active = Session.currentUser.getJSONArray("active_chat_list");
|
||||||
@@ -662,6 +659,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Session.activeChats = activeChats;
|
Session.activeChats = activeChats;
|
||||||
Session.archivedChats = archivedChats;
|
Session.archivedChats = archivedChats;
|
||||||
Session.chatList = chatList;
|
Session.chatList = chatList;
|
||||||
@@ -751,7 +749,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
openChat(existing);
|
openChat(existing);
|
||||||
} else {
|
} else {
|
||||||
ChatEntry preview = new ChatEntry();
|
ChatEntry preview = new ChatEntry();
|
||||||
preview.setId(String.valueOf(uuid));
|
preview.setId(String.valueOf(uuid));
|
||||||
preview.setDisplayId(selected.getString("id"));
|
preview.setDisplayId(selected.getString("id"));
|
||||||
@@ -860,13 +858,13 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case "create_group":
|
case "create_group":
|
||||||
case "create_channel":
|
case "create_channel":
|
||||||
if (response.has("data")) {
|
if (response.has("data")) {
|
||||||
JSONObject chatJson = response.getJSONObject("data");
|
JSONObject chatJson = response.getJSONObject("data");
|
||||||
|
|
||||||
ChatEntry chat = new ChatEntry(
|
ChatEntry chat = new ChatEntry(
|
||||||
UUID.fromString(chatJson.getString("internal_id")),
|
UUID.fromString(chatJson.getString("internal_id")),
|
||||||
@@ -881,12 +879,12 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
refreshChatList();
|
refreshChatList();
|
||||||
System.out.println("✅ Created and opening chat...");
|
System.out.println("✅ Created and opening chat...");
|
||||||
refreshChatList();
|
refreshChatList();
|
||||||
openChat(chat);
|
openChat(chat);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "get_messages":
|
case "get_messages":
|
||||||
JSONArray messages = response.getJSONObject("data").getJSONArray("messages");
|
JSONArray messages = response.getJSONObject("data").getJSONArray("messages");
|
||||||
@@ -1471,7 +1469,7 @@ public class ActionHandler {
|
|||||||
JSONObject m = messages.getJSONObject(i);
|
JSONObject m = messages.getJSONObject(i);
|
||||||
String senderId = m.getString("sender_id");
|
String senderId = m.getString("sender_id");
|
||||||
String senderName = m.optString("sender_name", "Other");
|
String senderName = m.optString("sender_name", "Other");
|
||||||
String content = m.optString("content", "");
|
String content = m.getString("content");
|
||||||
String time = m.getString("send_at");
|
String time = m.getString("send_at");
|
||||||
|
|
||||||
String label = senderId.equals(Session.currentUser.getString("internal_uuid")) ? "You" : senderName;
|
String label = senderId.equals(Session.currentUser.getString("internal_uuid")) ? "You" : senderName;
|
||||||
@@ -1693,7 +1691,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
String input = scanner.nextLine().trim();
|
String input = scanner.nextLine().trim();
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case "1" -> sendMessageInteractive(chatId, "private");
|
case "1" -> sendMessage(chatId, "private");
|
||||||
case "2" -> { viewMessagesInChat(chat); }
|
case "2" -> { viewMessagesInChat(chat); }
|
||||||
case "3" -> { return false; }
|
case "3" -> { return false; }
|
||||||
default -> System.out.println("Invalid choice.");
|
default -> System.out.println("Invalid choice.");
|
||||||
@@ -1712,7 +1710,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
String input = scanner.nextLine().trim();
|
String input = scanner.nextLine().trim();
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case "1" -> sendMessageInteractive(chat.getId(), "private");
|
case "1" -> sendMessage(chatId, "private");
|
||||||
case "2" -> toggleBlock(chat.getOtherUserId());
|
case "2" -> toggleBlock(chat.getOtherUserId());
|
||||||
case "3" -> { deleteChat(chatId, false); return true; }
|
case "3" -> { deleteChat(chatId, false); return true; }
|
||||||
case "4" -> { deleteChat(chatId, true); return true; }
|
case "4" -> { deleteChat(chatId, true); return true; }
|
||||||
@@ -1808,7 +1806,7 @@ public class ActionHandler {
|
|||||||
|
|
||||||
String input = scanner.nextLine();
|
String input = scanner.nextLine();
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case "1" -> sendMessageInteractive(chat.getId(), "group");
|
case "1" -> sendMessage(chat.getId(), "group");
|
||||||
case "2" -> viewGroupMembers(chat.getId());
|
case "2" -> viewGroupMembers(chat.getId());
|
||||||
case "3" -> {
|
case "3" -> {
|
||||||
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false)))
|
if (isOwner || (isAdmin && perms.optBoolean("can_add_members", false)))
|
||||||
@@ -1935,7 +1933,7 @@ public class ActionHandler {
|
|||||||
switch (input) {
|
switch (input) {
|
||||||
case "1" -> {
|
case "1" -> {
|
||||||
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
|
if (isOwner || (isAdmin && perms.optBoolean("can_post", false))) {
|
||||||
sendMessageInteractive(chat.getId(), "channel");
|
sendMessage(chat.getId(), "channel");
|
||||||
} else {
|
} else {
|
||||||
System.out.println("❌ You don't have permission to post.");
|
System.out.println("❌ You don't have permission to post.");
|
||||||
}
|
}
|
||||||
@@ -3675,135 +3673,82 @@ public class ActionHandler {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// public void sendMessage(UUID chatId, String receiverType) {
|
public void sendMessage(UUID chatId, String receiverType) {
|
||||||
// Scanner scanner = new Scanner(System.in);
|
Scanner scanner = new Scanner(System.in);
|
||||||
//
|
|
||||||
// System.out.print("Enter your message: ");
|
|
||||||
// String content = scanner.nextLine();
|
|
||||||
//
|
|
||||||
// System.out.print("Enter message type (TEXT / IMAGE / VIDEO / FILE): ");
|
|
||||||
// String messageType = scanner.nextLine().toUpperCase();
|
|
||||||
// Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
|
||||||
// while (!allowedTypes.contains(messageType)) {
|
|
||||||
// System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / VIDEO / FILE): ");
|
|
||||||
// messageType = scanner.nextLine().toUpperCase();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// JSONArray attachmentsArray = new JSONArray();
|
|
||||||
// System.out.print("Do you want to attach files? (yes/no): ");
|
|
||||||
// if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
|
||||||
// while (true) {
|
|
||||||
// System.out.print("File URL: ");
|
|
||||||
// String fileUrl = scanner.nextLine();
|
|
||||||
// System.out.print("File Type (IMAGE / VIDEO / FILE): ");
|
|
||||||
// String fileType = scanner.nextLine().toUpperCase();
|
|
||||||
//
|
|
||||||
// JSONObject fileJson = new JSONObject();
|
|
||||||
// fileJson.put("file_url", fileUrl);
|
|
||||||
// fileJson.put("file_type", fileType);
|
|
||||||
// attachmentsArray.put(fileJson);
|
|
||||||
//
|
|
||||||
// System.out.print("Add another file? (yes/no): ");
|
|
||||||
// if (!scanner.nextLine().equalsIgnoreCase("yes")) break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// JSONObject messageJson = new JSONObject();
|
|
||||||
// messageJson.put("action", "send_message");
|
|
||||||
// messageJson.put("receiver_type", receiverType);
|
|
||||||
// messageJson.put("receiver_id", chatId.toString());
|
|
||||||
// messageJson.put("content", content);
|
|
||||||
// messageJson.put("message_type", messageType);
|
|
||||||
//
|
|
||||||
// if (!attachmentsArray.isEmpty()) {
|
|
||||||
// messageJson.put("attachments", attachmentsArray);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// JSONObject response = sendWithResponse(messageJson);
|
|
||||||
// if (response != null && response.getString("status").equals("success")) {
|
|
||||||
// System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
|
||||||
// } else {
|
|
||||||
// System.out.println("❌ Failed to send message: " + (response != null ? response.getString("message") : "No response"));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
System.out.print("Enter your message: ");
|
||||||
|
String content = scanner.nextLine();
|
||||||
|
|
||||||
// public void sendMessage(UUID chatId, String receiverType) {
|
System.out.print("Enter message type (TEXT / IMAGE / VIDEO / FILE / AUDIO): ");
|
||||||
// Scanner scanner = new Scanner(System.in);
|
String messageType = scanner.nextLine().toUpperCase();
|
||||||
//
|
Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
||||||
// System.out.print("Enter your message (leave empty if file only): ");
|
while (!allowedTypes.contains(messageType)) {
|
||||||
// String content = scanner.nextLine();
|
System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / VIDEO / FILE / AUDIO): ");
|
||||||
//
|
messageType = scanner.nextLine().toUpperCase();
|
||||||
// System.out.print("Enter message type (TEXT / IMAGE / AUDIO / FILE / GIF): ");
|
}
|
||||||
// String messageType = scanner.nextLine().toUpperCase();
|
|
||||||
// Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "AUDIO", "FILE", "GIF");
|
JSONArray attachmentsArray = new JSONArray();
|
||||||
// while (!allowedTypes.contains(messageType)) {
|
System.out.print("Do you want to attach files? (yes/no): ");
|
||||||
// System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / AUDIO / FILE / GIF): ");
|
if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
||||||
// messageType = scanner.nextLine().toUpperCase();
|
while (true) {
|
||||||
// }
|
System.out.print("File URL: ");
|
||||||
//
|
String fileUrl = scanner.nextLine();
|
||||||
// JSONArray attachmentsArray = new JSONArray();
|
|
||||||
// System.out.print("Attach files? (yes/no): ");
|
// URL validation
|
||||||
// if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
if (fileUrl.isEmpty()) {
|
||||||
// while (true) {
|
System.out.print("URL can not be empty. Try again.");
|
||||||
// System.out.println("Paste the JSON you got from /upload (or leave empty to enter minimal fields):");
|
continue;
|
||||||
// String jsonLine = scanner.nextLine().trim();
|
}
|
||||||
//
|
|
||||||
// JSONObject fileJson;
|
if (fileUrl.contains(" ")) {
|
||||||
// if (!jsonLine.isEmpty()) {
|
System.out.println("URL cannot contain spaces. Try again.");
|
||||||
// // انتظار خروجی کامل /upload
|
continue;
|
||||||
// fileJson = new JSONObject(jsonLine);
|
}
|
||||||
// // اگه خروجی /upload تو ریشهست، تبدیلش کن به ساختار attachment
|
|
||||||
// fileJson = new JSONObject()
|
if (!fileUrl.isEmpty() && !fileUrl.matches("^(http|https)://.*$")) {
|
||||||
// .put("file_url", fileJson.optString("file_url", ""))
|
System.out.println("Invalid URL format. Please enter a valid HTTP/HTTPS link.");
|
||||||
// .put("file_type", fileJson.optString("file_type", "FILE"))
|
continue;
|
||||||
// .put("file_name", fileJson.optString("file_name", ""))
|
}
|
||||||
// .put("file_size", fileJson.optLong("file_size", 0))
|
|
||||||
// .put("mime_type", fileJson.optString("mime_type", ""))
|
System.out.print("File Type (IMAGE / VIDEO / FILE / AUDIO): ");
|
||||||
// .put("width", fileJson.isNull("width") ? JSONObject.NULL : fileJson.optInt("width"))
|
String fileType = scanner.nextLine().toUpperCase();
|
||||||
// .put("height", fileJson.isNull("height") ? JSONObject.NULL : fileJson.optInt("height"))
|
|
||||||
// .put("duration_seconds", fileJson.isNull("duration_seconds") ? JSONObject.NULL : fileJson.optInt("duration_seconds"))
|
Set<String> allowedFileTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
||||||
// .put("thumbnail_url", fileJson.isNull("thumbnail_url") ? JSONObject.NULL : fileJson.optString("thumbnail_url", null));
|
while (!allowedFileTypes.contains(fileType)) {
|
||||||
// } else {
|
System.out.print("❌ Invalid type. Try again (IMAGE / VIDEO / FILE / AUDIO): ");
|
||||||
// // ورودی حداقلی
|
fileType = scanner.nextLine().toUpperCase();
|
||||||
// System.out.print("File URL: ");
|
}
|
||||||
// String fileUrl = scanner.nextLine();
|
|
||||||
// System.out.print("File Type (IMAGE / AUDIO / FILE / GIF): ");
|
JSONObject fileJson = new JSONObject();
|
||||||
// String fileType = scanner.nextLine().toUpperCase();
|
fileJson.put("file_url", fileUrl);
|
||||||
//
|
fileJson.put("file_type", fileType);
|
||||||
// fileJson = new JSONObject();
|
attachmentsArray.put(fileJson);
|
||||||
// fileJson.put("file_url", fileUrl);
|
|
||||||
// fileJson.put("file_type", fileType);
|
System.out.print("Add another file? (yes/no): ");
|
||||||
// }
|
if (!scanner.nextLine().equalsIgnoreCase("yes")) break;
|
||||||
//
|
}
|
||||||
// attachmentsArray.put(fileJson);
|
}
|
||||||
//
|
|
||||||
// System.out.print("Add another file? (yes/no): ");
|
JSONObject messageJson = new JSONObject();
|
||||||
// if (!scanner.nextLine().equalsIgnoreCase("yes")) break;
|
messageJson.put("action", "send_message");
|
||||||
// }
|
messageJson.put("receiver_type", receiverType);
|
||||||
// }
|
messageJson.put("receiver_id", chatId.toString());
|
||||||
//
|
messageJson.put("content", content);
|
||||||
// JSONObject messageJson = new JSONObject();
|
messageJson.put("message_type", messageType);
|
||||||
// messageJson.put("action", "send_message");
|
|
||||||
// messageJson.put("receiver_type", receiverType); // "private"/"group"/"channel"
|
if (!attachmentsArray.isEmpty()) {
|
||||||
// messageJson.put("receiver_id", chatId.toString()); // در private = chat_id
|
messageJson.put("attachments", attachmentsArray);
|
||||||
// messageJson.put("content", content);
|
}
|
||||||
// messageJson.put("message_type", messageType);
|
|
||||||
// if (attachmentsArray.length() > 0) {
|
JSONObject response = sendWithResponse(messageJson);
|
||||||
// messageJson.put("attachments", attachmentsArray);
|
if (response != null && response.getString("status").equals("success")) {
|
||||||
// }
|
System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
||||||
//
|
} else {
|
||||||
// JSONObject response = sendWithResponse(messageJson);
|
System.out.println("❌ Failed to send message: " + (response != null ? response.getString("message") : "No response"));
|
||||||
// if (response != null && response.getString("status").equals("success")) {
|
}
|
||||||
// System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
}
|
||||||
// } else {
|
|
||||||
// System.out.println("❌ Failed to send message: " + (response != null ? response.optString("message","No message") : "No response"));
|
public void refreshContactList() {
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
private void refreshContactList() {
|
|
||||||
JSONObject req = new JSONObject();
|
JSONObject req = new JSONObject();
|
||||||
req.put("action", "get_contact_list");
|
req.put("action", "get_contact_list");
|
||||||
req.put("user_id", Session.currentUser.getString("user_id"));
|
req.put("user_id", Session.currentUser.getString("user_id"));
|
||||||
@@ -3915,18 +3860,6 @@ public class ActionHandler {
|
|||||||
replyLabel = "↪️ Reply to " + repliedSender + ": \"" + repliedContent + "\"";
|
replyLabel = "↪️ Reply to " + repliedSender + ": \"" + repliedContent + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONArray atts = msg.optJSONArray("attachments");
|
|
||||||
if (atts != null && atts.length() > 0) {
|
|
||||||
System.out.println(" 📎 " + atts.length() + " attachment(s)");
|
|
||||||
for (int a = 0; a < atts.length(); a++) {
|
|
||||||
JSONObject att = atts.getJSONObject(a);
|
|
||||||
String fn = att.optString("file_name", "(unnamed)");
|
|
||||||
long sz = att.optLong("file_size", 0);
|
|
||||||
System.out.printf(" - #%d %s (%s)\n", a + 1, fn, humanSize(sz));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JSONArray reactions = msg.optJSONArray("reactions");
|
JSONArray reactions = msg.optJSONArray("reactions");
|
||||||
if (reactions != null && !reactions.isEmpty()) {
|
if (reactions != null && !reactions.isEmpty()) {
|
||||||
System.out.print(" 💬 Reactions: ");
|
System.out.print(" 💬 Reactions: ");
|
||||||
@@ -3961,7 +3894,7 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(input.equalsIgnoreCase("S")){
|
if(input.equalsIgnoreCase("S")){
|
||||||
sendMessageInteractive(chat.getId(), chat.getType());
|
sendMessage(chat.getId(), chat.getType());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int index = Integer.parseInt(input);
|
int index = Integer.parseInt(input);
|
||||||
@@ -3976,10 +3909,6 @@ public class ActionHandler {
|
|||||||
boolean isSender = senderId.toString().equals(Session.currentUser.getString("internal_uuid"));
|
boolean isSender = senderId.toString().equals(Session.currentUser.getString("internal_uuid"));
|
||||||
boolean isChannel = chat.getType().equals("channel");
|
boolean isChannel = chat.getType().equals("channel");
|
||||||
boolean isOwnerOrAdmin = chat.isOwner() || chat.isAdmin();
|
boolean isOwnerOrAdmin = chat.isOwner() || chat.isAdmin();
|
||||||
//for media
|
|
||||||
JSONArray atts = selected.optJSONArray("attachments");
|
|
||||||
boolean hasAttachments = (atts != null && atts.length() > 0);
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println("\n🎯 Selected message by " + selected.getString("sender_name"));
|
System.out.println("\n🎯 Selected message by " + selected.getString("sender_name"));
|
||||||
|
|
||||||
@@ -4005,9 +3934,6 @@ public class ActionHandler {
|
|||||||
System.out.println("5. Delete");
|
System.out.println("5. Delete");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAttachments) {
|
|
||||||
System.out.println("D. Download attachment");
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("0. Back to message list");
|
System.out.println("0. Back to message list");
|
||||||
System.out.print("➤ Select an action: ");
|
System.out.print("➤ Select an action: ");
|
||||||
@@ -4040,15 +3966,6 @@ public class ActionHandler {
|
|||||||
System.out.println("❌ You are not allowed to delete this message.");
|
System.out.println("❌ You are not allowed to delete this message.");
|
||||||
}
|
}
|
||||||
case "0" -> {}
|
case "0" -> {}
|
||||||
|
|
||||||
case "D", "d" -> {
|
|
||||||
if (hasAttachments) {
|
|
||||||
downloadAttachmentFlow(chat, selected);
|
|
||||||
} else {
|
|
||||||
System.out.println("🚫 No attachments to download.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default -> System.out.println("❌ Invalid option.");
|
default -> System.out.println("❌ Invalid option.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4059,122 +3976,6 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void editMessage(UUID messageId) {
|
public void editMessage(UUID messageId) {
|
||||||
private void downloadAttachmentFlow(ChatEntry chat, JSONObject msg) {
|
|
||||||
JSONArray atts = msg.optJSONArray("attachments");
|
|
||||||
if (atts == null || atts.length() == 0) {
|
|
||||||
System.out.println("🚫 No attachments.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int idx = 0;
|
|
||||||
if (atts.length() > 1) {
|
|
||||||
System.out.print("Which attachment [1.." + atts.length() + "]? ");
|
|
||||||
try {
|
|
||||||
String ans = scanner.nextLine().trim();
|
|
||||||
if (!ans.isEmpty()) {
|
|
||||||
int n = Integer.parseInt(ans);
|
|
||||||
if (n >= 1 && n <= atts.length()) idx = n - 1;
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) { idx = 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject att = atts.getJSONObject(idx);
|
|
||||||
String mediaKeyStr = att.optString("media_key", "");
|
|
||||||
if (mediaKeyStr.isBlank()) {
|
|
||||||
System.out.println("❌ Attachment missing media_key.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID mediaKey = UUID.fromString(mediaKeyStr);
|
|
||||||
String rawName = att.optString("file_name", mediaKey.toString());
|
|
||||||
String fileName = sanitizeFileName(rawName);
|
|
||||||
long declaredSize = att.optLong("file_size", 0L);
|
|
||||||
|
|
||||||
// ~/Downloads/TeleSock/<Account>/<Chat>/
|
|
||||||
String accFolder = accountFolderName();
|
|
||||||
String chatFolder = chatFolderName(chat);
|
|
||||||
Path saveDir = Paths.get(System.getProperty("user.home"),
|
|
||||||
"Downloads", "TeleSock", accFolder, chatFolder);
|
|
||||||
|
|
||||||
System.out.println("👤 AccountFolder = " + accFolder);
|
|
||||||
System.out.println("💬 ChatFolder = " + chatFolder);
|
|
||||||
System.out.println("📁 SaveDir = " + saveDir);
|
|
||||||
|
|
||||||
try { Files.createDirectories(saveDir); }
|
|
||||||
catch (IOException e) {
|
|
||||||
System.out.println("❌ Cannot create folder: " + saveDir + " -> " + e.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DownloadsIndex di = Session.downloadsIndex;
|
|
||||||
if (di != null) {
|
|
||||||
Path existing = di.find(mediaKey);
|
|
||||||
if (existing != null) {
|
|
||||||
System.out.println("✅ Already downloaded: " + existing);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Path target = uniquePath(saveDir, fileName);
|
|
||||||
|
|
||||||
TelegramClient.mediaBusy.set(true);
|
|
||||||
try {
|
|
||||||
Path saved = TelegramClient.getDownloader()
|
|
||||||
.download(mediaKey, saveDir, target.getFileName().toString());
|
|
||||||
|
|
||||||
long sizeToRecord = declaredSize > 0 ? declaredSize : Files.size(saved);
|
|
||||||
if (di != null) di.put(mediaKey, saved, sizeToRecord);
|
|
||||||
|
|
||||||
System.out.println("✅ Saved to: " + saved + " (" + humanSize(sizeToRecord) + ")");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.out.println("❌ Download failed: " + ex.getMessage());
|
|
||||||
} finally {
|
|
||||||
TelegramClient.mediaBusy.set(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static Path uniquePath(Path dir, String fileName) {
|
|
||||||
Path p = dir.resolve(fileName);
|
|
||||||
if (!Files.exists(p)) return p;
|
|
||||||
|
|
||||||
String name = fileName;
|
|
||||||
String ext = "";
|
|
||||||
int dot = fileName.lastIndexOf('.');
|
|
||||||
if (dot > 0 && dot < fileName.length()-1) {
|
|
||||||
name = fileName.substring(0, dot);
|
|
||||||
ext = fileName.substring(dot); // includes dot
|
|
||||||
}
|
|
||||||
int i = 1;
|
|
||||||
while (true) {
|
|
||||||
Path cand = dir.resolve(String.format("%s (%d)%s", name, i, ext));
|
|
||||||
if (!Files.exists(cand)) return cand;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String sanitizeFileName(String s) {
|
|
||||||
s = s.replace("\\", "/");
|
|
||||||
if (s.contains("/")) s = s.substring(s.lastIndexOf('/') + 1);
|
|
||||||
s = s.replaceAll("[\\\\/:*?\"<>|]", "_");
|
|
||||||
if (s.equals(".") || s.equals("..") || s.isBlank()) s = "file";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String humanSize(long b) {
|
|
||||||
if (b <= 0) return "0 B";
|
|
||||||
String[] u = {"B","KB","MB","GB","TB"};
|
|
||||||
int i = (int) Math.floor(Math.log(b) / Math.log(1024));
|
|
||||||
if (i < 0) i = 0;
|
|
||||||
if (i >= u.length) i = u.length - 1;
|
|
||||||
double v = b / Math.pow(1024, i);
|
|
||||||
return String.format("%.1f %s", v, u[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void editMessage(UUID messageId) {
|
|
||||||
System.out.print("📝 Enter new content: ");
|
System.out.print("📝 Enter new content: ");
|
||||||
String newContent = scanner.nextLine().trim();
|
String newContent = scanner.nextLine().trim();
|
||||||
|
|
||||||
@@ -4390,183 +4191,4 @@ public class ActionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
public void sendMessageInteractive(UUID receiverId, String receiverType) {
|
|
||||||
Scanner sc = new Scanner(System.in);
|
|
||||||
|
|
||||||
System.out.print("Type (TEXT / IMAGE / AUDIO): ");
|
|
||||||
String type = sc.nextLine().trim().toUpperCase();
|
|
||||||
while (!Set.of("TEXT","IMAGE","AUDIO").contains(type)) {
|
|
||||||
System.out.print("❌ Invalid. Try (TEXT / IMAGE / AUDIO): ");
|
|
||||||
type = sc.nextLine().trim().toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.print("Text (optional for media; empty = no caption): ");
|
|
||||||
String text = sc.nextLine();
|
|
||||||
|
|
||||||
if ("TEXT".equals(type)) {
|
|
||||||
sendTextMessage(receiverId, receiverType, text);
|
|
||||||
} else {
|
|
||||||
System.out.print("File path: ");
|
|
||||||
String path = sc.nextLine().trim();
|
|
||||||
File f = new File(path);
|
|
||||||
if (!f.isFile()) {
|
|
||||||
System.out.println("❌ File not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
sendMediaMessage(receiverId, receiverType, type, f, text);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.out.println("❌ Media send failed: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendTextMessage(UUID receiverId, String receiverType, String content) {
|
|
||||||
JSONObject req = new JSONObject()
|
|
||||||
.put("action", "send_message")
|
|
||||||
.put("receiver_type", receiverType)
|
|
||||||
.put("receiver_id", receiverId.toString())
|
|
||||||
.put("message_type", "TEXT")
|
|
||||||
.put("content", content == null ? "" : content);
|
|
||||||
|
|
||||||
JSONObject resp = sendWithResponse(req);
|
|
||||||
if (resp != null && "success".equalsIgnoreCase(resp.optString("status"))) {
|
|
||||||
System.out.println("✅ Sent. id=" + resp.optJSONObject("data").optString("message_id",""));
|
|
||||||
} else {
|
|
||||||
System.out.println("❌ Failed: " + (resp != null ? resp.optString("message") : "no response"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void sendMediaMessage(UUID receiverId, String receiverType, String type /* IMAGE/AUDIO */, File file, String caption) {
|
|
||||||
if (file == null) {
|
|
||||||
System.out.println("❌ File is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!file.exists()) {
|
|
||||||
System.out.println("❌ File not found: " + file.getAbsolutePath());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
System.out.println("❌ Path is a directory, expected a file: " + file.getAbsolutePath());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final UUID messageId = UUID.randomUUID();
|
|
||||||
|
|
||||||
try {
|
|
||||||
String mime = detectMime(file, type.toUpperCase());
|
|
||||||
if (mime == null) mime = type.equalsIgnoreCase("IMAGE") ? "image/*" : "audio/*";
|
|
||||||
|
|
||||||
JSONObject header = new JSONObject()
|
|
||||||
.put("message_id", messageId.toString())
|
|
||||||
.put("sender_id", TelegramClient.loggedInUserId.toString())
|
|
||||||
.put("receiver_type", receiverType) // private|group|channel
|
|
||||||
.put("receiver_id", receiverId.toString())
|
|
||||||
.put("message_type", type.toUpperCase()) // IMAGE | AUDIO
|
|
||||||
.put("file_name", file.getName())
|
|
||||||
.put("mime_type", mime)
|
|
||||||
.put("text", caption == null ? "" : caption);
|
|
||||||
|
|
||||||
byte[] headerBytes = header.toString().getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
|
||||||
long contentLen = file.length();
|
|
||||||
|
|
||||||
BlockingQueue<JSONObject> q = new LinkedBlockingQueue<>(1);
|
|
||||||
TelegramClient.pendingResponses.put(messageId.toString(), q);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
outBin.write("MEDIA\n".getBytes(java.nio.charset.StandardCharsets.US_ASCII));
|
|
||||||
outBin.flush();
|
|
||||||
|
|
||||||
// 2) binary frame: magic + headerLen + header + contentLen + content
|
|
||||||
outBin.writeInt(0x4D444D31); // "MDM1"
|
|
||||||
outBin.writeInt(headerBytes.length); // headerLen (int)
|
|
||||||
outBin.write(headerBytes); // header
|
|
||||||
outBin.writeLong(contentLen); // contentLen (long)
|
|
||||||
|
|
||||||
try (InputStream fis = new BufferedInputStream(new FileInputStream(file))) {
|
|
||||||
byte[] buf = new byte[8192];
|
|
||||||
int n;
|
|
||||||
while ((n = fis.read(buf)) != -1) {
|
|
||||||
outBin.write(buf, 0, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outBin.flush();
|
|
||||||
|
|
||||||
JSONObject ack = q.poll(20, java.util.concurrent.TimeUnit.SECONDS);
|
|
||||||
if (ack == null) {
|
|
||||||
System.out.println("❌ Media ACK timeout for " + messageId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String status = ack.optString("status", "error");
|
|
||||||
if ("success".equalsIgnoreCase(status)) {
|
|
||||||
System.out.println("✅ Media sent. id=" + ack.optString("message_id") +
|
|
||||||
" url=" + ack.optString("file_url"));
|
|
||||||
} else {
|
|
||||||
System.out.println("❌ Media failed: " + ack.optString("message"));
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
TelegramClient.pendingResponses.remove(messageId.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.out.println("❌ sendMediaMessage error: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static String detectMime(File f, String typeUpper /* IMAGE or AUDIO */) {
|
|
||||||
try {
|
|
||||||
String m = java.nio.file.Files.probeContentType(f.toPath());
|
|
||||||
if (m != null) return m;
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
String name = f.getName().toLowerCase();
|
|
||||||
if (name.endsWith(".png")) return "image/png";
|
|
||||||
if (name.endsWith(".jpg") || name.endsWith(".jpeg")) return "image/jpeg";
|
|
||||||
if (name.endsWith(".gif")) return "image/gif";
|
|
||||||
if (name.endsWith(".mp3")) return "audio/mpeg";
|
|
||||||
if (name.endsWith(".wav")) return "audio/wav";
|
|
||||||
if (name.endsWith(".ogg")) return "audio/ogg";
|
|
||||||
return typeUpper.equals("IMAGE") ? "image/*" : "audio/*";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static String safeName(String s) {
|
|
||||||
if (s == null) return "unknown";
|
|
||||||
s = s.replace("\\", "/");
|
|
||||||
if (s.contains("/")) s = s.substring(s.lastIndexOf('/') + 1);
|
|
||||||
s = s.replaceAll("[\\\\/:*?\"<>|]", "_").trim();
|
|
||||||
if (s.isEmpty() || s.equals(".") || s.equals("..")) s = "unknown";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String accountFolderName() {
|
|
||||||
JSONObject me = Session.currentUser;
|
|
||||||
String acc = me.optString("username",
|
|
||||||
me.optString("user_id",
|
|
||||||
me.optString("profile_name",
|
|
||||||
me.optString("internal_uuid", "me"))));
|
|
||||||
return safeName(acc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String chatFolderName(ChatEntry chat) {
|
|
||||||
String name = chat.getName();
|
|
||||||
if (name == null || name.isBlank()) {
|
|
||||||
name = chat.getDisplayId() != null && !chat.getDisplayId().isBlank()
|
|
||||||
? chat.getDisplayId()
|
|
||||||
: String.valueOf(chat.getId());
|
|
||||||
}
|
|
||||||
return safeName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -8,9 +8,6 @@ import org.to.telegramfinalproject.UI.MainController;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -18,7 +15,6 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
|
|
||||||
public class IncomingMessageListener implements Runnable {
|
public class IncomingMessageListener implements Runnable {
|
||||||
private final BufferedReader in;
|
private final BufferedReader in;
|
||||||
private volatile boolean running = true;
|
|
||||||
public enum UIMode { CONSOLE, UI }
|
public enum UIMode { CONSOLE, UI }
|
||||||
private final UIMode uiMode; // runtime mode
|
private final UIMode uiMode; // runtime mode
|
||||||
|
|
||||||
@@ -40,47 +36,16 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
try {
|
try {
|
||||||
System.out.println("👂 Real-Time Listener started.");
|
System.out.println("👂 Real-Time Listener started.");
|
||||||
|
|
||||||
while (running) {
|
String line;
|
||||||
if (TelegramClient.mediaBusy.get()) {
|
while ((line = in.readLine()) != null) {
|
||||||
try { Thread.sleep(15); } catch (InterruptedException ignored) {}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!in.ready()) {
|
|
||||||
try { Thread.sleep(10); } catch (InterruptedException ignored) {}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String line = in.readLine();
|
|
||||||
if (line == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.isBlank()) continue;
|
|
||||||
|
|
||||||
final JSONObject response;
|
|
||||||
try {
|
|
||||||
response = new JSONObject(line);
|
|
||||||
} catch (Exception badJson) {
|
|
||||||
System.out.println("⚠️ [Listener] Non-JSON line ignored: " + line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
JSONObject response = new JSONObject(line);
|
||||||
System.out.println("📥 Received raw line: " + line);
|
System.out.println("📥 Received raw line: " + line);
|
||||||
|
|
||||||
// --- Media ACK routing by message_id ---
|
//if it has reqID answer
|
||||||
String mid = response.optString("message_id", "");
|
|
||||||
if (!mid.isEmpty()) {
|
|
||||||
BlockingQueue<JSONObject> q = TelegramClient.pendingResponses.get(mid);
|
|
||||||
if (q != null) {
|
|
||||||
q.put(response);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- General request_id response routing ---
|
|
||||||
if (response.has("request_id")) {
|
if (response.has("request_id")) {
|
||||||
String requestId = response.optString("request_id", "");
|
String requestId = response.getString("request_id");
|
||||||
System.out.println("📬 Response with request_id: " + requestId);
|
System.out.println("📬 Response with request_id: " + requestId);
|
||||||
System.out.println("📬 Full response: " + response.toString(2));
|
System.out.println("📬 Full response: " + response.toString(2));
|
||||||
|
|
||||||
@@ -91,12 +56,15 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
System.out.println("⚠️ No pending queue for request_id = " + requestId + ". Putting in responseQueue...");
|
System.out.println("⚠️ No pending queue for request_id = " + requestId + ". Putting in responseQueue...");
|
||||||
TelegramClient.responseQueue.put(response);
|
TelegramClient.responseQueue.put(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Real-time actions ---
|
|
||||||
|
|
||||||
|
//if it has action check it
|
||||||
if (response.has("action")) {
|
if (response.has("action")) {
|
||||||
String action = response.optString("action", "");
|
String action = response.getString("action");
|
||||||
System.out.println("🎯 [Listener] Action received: " + response.toString(2));
|
System.out.println("🎯 [Listener] Action received: " + response.toString(2));
|
||||||
System.out.println("🎯 Received action: " + action);
|
System.out.println("🎯 Received action: " + action);
|
||||||
|
|
||||||
@@ -105,12 +73,11 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
} else {
|
} else {
|
||||||
TelegramClient.responseQueue.put(response);
|
TelegramClient.responseQueue.put(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (response.has("status") && response.has("message")) {
|
} else if (response.has("status") && response.has("message")) {
|
||||||
// General success/error
|
TelegramClient.responseQueue.put(response); // general answer
|
||||||
TelegramClient.responseQueue.put(response);
|
|
||||||
} else {
|
} else {
|
||||||
// Fallback
|
TelegramClient.responseQueue.put(response); // fallback
|
||||||
TelegramClient.responseQueue.put(response);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,9 +94,7 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
"update_group_or_channel", "chat_deleted",
|
"update_group_or_channel", "chat_deleted",
|
||||||
"blocked_by_user", "unblocked_by_user", "message_seen",
|
"blocked_by_user", "unblocked_by_user", "message_seen",
|
||||||
"removed_from_group", "removed_from_channel",
|
"removed_from_group", "removed_from_channel",
|
||||||
"became_admin", "removed_admin", "ownership_transferred",
|
"became_admin", "removed_admin", "ownership_transferred","admin_permissions_updated","created_private_chat" , "message_reacted" , "message_unreacted","chat_updated" -> true;
|
||||||
"admin_permissions_updated", "created_private_chat",
|
|
||||||
"message_reacted", "message_unreacted" , "chat_updated"-> true;
|
|
||||||
default -> false;
|
default -> false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -148,11 +113,9 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
System.out.println("🔄 Chat list changed. Updating...");
|
System.out.println("🔄 Chat list changed. Updating...");
|
||||||
Session.forceRefreshChatList = true;
|
Session.forceRefreshChatList = true;
|
||||||
|
|
||||||
String chatId = msg.optString("chat_id", "");
|
String chatId = msg.getString("chat_id");
|
||||||
String chatType = msg.optString("chat_type", "");
|
String chatType = msg.getString("chat_type");
|
||||||
if (!chatId.isBlank() && !chatType.isBlank()) {
|
ActionHandler.requestChatInfo(chatId, chatType);
|
||||||
ActionHandler.requestChatInfo(chatId, chatType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.equals("removed_from_group") || action.equals("removed_from_channel") || action.equals("chat_deleted")) {
|
if (action.equals("removed_from_group") || action.equals("removed_from_channel") || action.equals("chat_deleted")) {
|
||||||
System.out.println("🚫 You were removed from the chat or chat was deleted. Exiting...");
|
System.out.println("🚫 You were removed from the chat or chat was deleted. Exiting...");
|
||||||
@@ -227,7 +190,7 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
case "message_edited", "message_deleted_global", "message_reacted", "message_unreacted"
|
case "message_edited", "message_deleted_global", "message_reacted", "message_unreacted"
|
||||||
, "blocked_by_user", "unblocked_by_user", "message_seen" -> {
|
, "blocked_by_user", "unblocked_by_user", "message_seen" -> {
|
||||||
displayRealTimeMessage(action, msg);
|
displayRealTimeMessage(action, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,136 +198,78 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
System.out.println("\n❓ Unknown real-time action: " + action);
|
System.out.println("\n❓ Unknown real-time action: " + action);
|
||||||
System.out.println(msg.toString(2));
|
System.out.println(msg.toString(2));
|
||||||
}
|
}
|
||||||
default -> displayRealTimeMessage(action, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.print(">> ");
|
System.out.print(">> ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void updateLastMessageTime(JSONObject msg) {
|
|
||||||
// try {
|
|
||||||
// UUID chatUUID = UUID.fromString(msg.getString("chat_id"));
|
|
||||||
// String newTime = msg.optString("last_message_time", null);
|
|
||||||
//
|
|
||||||
// Session.chatList.stream().filter(chat -> chat.getId().equals(chatUUID)).findFirst()
|
|
||||||
// .ifPresent(chat -> {
|
|
||||||
// chat.setLastMessageTime(newTime);
|
|
||||||
// System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// Session.activeChats.stream().filter(chat -> chat.getId().equals(chatUUID)).findFirst()
|
|
||||||
// .ifPresent(chat -> {
|
|
||||||
// chat.setLastMessageTime(newTime);
|
|
||||||
// System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// Session.archivedChats.stream().filter(chat -> chat.getId().equals(chatUUID)).findFirst()
|
|
||||||
// .ifPresent(chat -> {
|
|
||||||
// chat.setLastMessageTime(newTime);
|
|
||||||
// System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// Session.chatList.sort((c1, c2) -> {
|
|
||||||
// if (c1.getLastMessageTime() == null && c2.getLastMessageTime() == null) return 0;
|
|
||||||
// if (c1.getLastMessageTime() == null) return 1;
|
|
||||||
// if (c2.getLastMessageTime() == null) return -1;
|
|
||||||
// return c2.getLastMessageTime().compareTo(c1.getLastMessageTime());
|
|
||||||
// });
|
|
||||||
// Session.activeChats.sort((c1, c2) -> {
|
|
||||||
// if (c1.getLastMessageTime() == null && c2.getLastMessageTime() == null) return 0;
|
|
||||||
// if (c1.getLastMessageTime() == null) return 1;
|
|
||||||
// if (c2.getLastMessageTime() == null) return -1;
|
|
||||||
// return c2.getLastMessageTime().compareTo(c1.getLastMessageTime());
|
|
||||||
// });
|
|
||||||
// Session.archivedChats.sort((c1, c2) -> {
|
|
||||||
// if (c1.getLastMessageTime() == null && c2.getLastMessageTime() == null) return 0;
|
|
||||||
// if (c1.getLastMessageTime() == null) return 1;
|
|
||||||
// if (c2.getLastMessageTime() == null) return -1;
|
|
||||||
// return c2.getLastMessageTime().compareTo(c1.getLastMessageTime());
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// if (Session.inChatListMenu) {
|
|
||||||
// ActionHandler.displayChatList();
|
|
||||||
// System.out.print("Select a chat by number: ");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// System.out.println("❌ Failed to update last message time: " + e.getMessage());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
private void updateLastMessageTime(JSONObject msg) {
|
private void updateLastMessageTime(JSONObject msg) {
|
||||||
try {
|
try {
|
||||||
UUID chatUUID = UUID.fromString(msg.getString("chat_id"));
|
UUID chatUUID = UUID.fromString(msg.getString("chat_id"));
|
||||||
String newTime = msg.optString("last_message_time", null);
|
String newTime = msg.optString("last_message_time", null);
|
||||||
if (newTime == null || newTime.isBlank()) return;
|
|
||||||
|
|
||||||
updateOneList(Session.chatList, chatUUID, newTime);
|
Session.chatList.stream()
|
||||||
updateOneList(Session.activeChats, chatUUID, newTime);
|
.filter(chat -> chat.getId().equals(chatUUID))
|
||||||
updateOneList(Session.archivedChats, chatUUID, newTime);
|
.findFirst()
|
||||||
|
.ifPresent(chat -> {
|
||||||
|
chat.setLastMessageTime(newTime);
|
||||||
|
System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
||||||
|
});
|
||||||
|
|
||||||
|
Session.activeChats.stream()
|
||||||
|
.filter(chat -> chat.getId().equals(chatUUID))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(chat -> {
|
||||||
|
chat.setLastMessageTime(newTime);
|
||||||
|
System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
||||||
|
});
|
||||||
|
|
||||||
|
Session.archivedChats.stream()
|
||||||
|
.filter(chat -> chat.getId().equals(chatUUID))
|
||||||
|
.findFirst()
|
||||||
|
.ifPresent(chat -> {
|
||||||
|
chat.setLastMessageTime(newTime);
|
||||||
|
System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
||||||
|
});
|
||||||
|
|
||||||
|
Session.chatList.sort((c1, c2) -> {
|
||||||
|
if (c1.getLastMessageTime() == null && c2.getLastMessageTime() == null) return 0;
|
||||||
|
if (c1.getLastMessageTime() == null) return 1;
|
||||||
|
if (c2.getLastMessageTime() == null) return -1;
|
||||||
|
return c2.getLastMessageTime().compareTo(c1.getLastMessageTime()); // descending
|
||||||
|
});
|
||||||
|
Session.activeChats.sort((c1, c2) -> {
|
||||||
|
if (c1.getLastMessageTime() == null && c2.getLastMessageTime() == null) return 0;
|
||||||
|
if (c1.getLastMessageTime() == null) return 1;
|
||||||
|
if (c2.getLastMessageTime() == null) return -1;
|
||||||
|
return c2.getLastMessageTime().compareTo(c1.getLastMessageTime()); // descending
|
||||||
|
});
|
||||||
|
Session.archivedChats.sort((c1, c2) -> {
|
||||||
|
if (c1.getLastMessageTime() == null && c2.getLastMessageTime() == null) return 0;
|
||||||
|
if (c1.getLastMessageTime() == null) return 1;
|
||||||
|
if (c2.getLastMessageTime() == null) return -1;
|
||||||
|
return c2.getLastMessageTime().compareTo(c1.getLastMessageTime()); // descending
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sortByLastMessageTime(Session.chatList);
|
|
||||||
sortByLastMessageTime(Session.activeChats);
|
|
||||||
sortByLastMessageTime(Session.archivedChats);
|
|
||||||
|
|
||||||
if (Session.inChatListMenu) {
|
if (Session.inChatListMenu) {
|
||||||
ActionHandler.displayChatList();
|
ActionHandler.displayChatList();
|
||||||
System.out.print("Select a chat by number: ");
|
System.out.print("Select a chat by number: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("❌ Failed to update last message time: " + e.getMessage());
|
System.out.println("❌ Failed to update last message time: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOneList(List<ChatEntry> list, UUID chatUUID, String newTime) {
|
|
||||||
if (list == null) return;
|
|
||||||
for (ChatEntry chat : list) {
|
|
||||||
if (chatUUID.equals(chat.getId())) { // ✅ internal UUID
|
|
||||||
chat.setLastMessageTime(newTime);
|
|
||||||
System.out.println("✅ Updated last message time for chat: " + chat.getDisplayId());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void sortByLastMessageTime(java.util.List<ChatEntry> list) {
|
|
||||||
if (list == null) return;
|
|
||||||
list.sort((a, b) -> {
|
|
||||||
var ta = parseTs(String.valueOf(a.getLastMessageTime()));
|
|
||||||
var tb = parseTs(String.valueOf(b.getLastMessageTime()));
|
|
||||||
if (ta == null && tb == null) return 0;
|
|
||||||
if (ta == null) return 1;
|
|
||||||
if (tb == null) return -1;
|
|
||||||
return tb.compareTo(ta);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
if (list.get(i).isSavedMessages()) {
|
|
||||||
list.add(0, list.remove(i));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static java.time.LocalDateTime parseTs(String s) {
|
|
||||||
if (s == null) return null;
|
|
||||||
s = s.trim();
|
|
||||||
if (s.isEmpty() || s.equalsIgnoreCase("null")) return null;
|
|
||||||
try { return java.time.OffsetDateTime.parse(s).toLocalDateTime(); } catch (Exception ignore) {}
|
|
||||||
try { return java.time.LocalDateTime.parse(s, java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME); } catch (Exception ignore) {}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void handleAdminRoleChanged(JSONObject data) throws IOException {
|
private void handleAdminRoleChanged(JSONObject data) throws IOException {
|
||||||
String chatType = data.optString("chat_type", "");
|
String chatType = data.getString("chat_type");
|
||||||
String chatId = data.optString("group_id",
|
String chatId = data.optString("group_id", data.optString("channel_id", data.optString("chat_id", null)));
|
||||||
data.optString("channel_id", data.optString("chat_id", "")));
|
|
||||||
|
|
||||||
if (chatId.isBlank()) {
|
if (chatId == null) {
|
||||||
System.out.println("⚠️ No valid ID found in real-time data: " + data.toString(2));
|
System.out.println("⚠️ No valid ID found in real-time data: " + data.toString(2));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -372,10 +277,11 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
System.out.println("\n🔄 Your admin status changed. Updating chat info...");
|
System.out.println("\n🔄 Your admin status changed. Updating chat info...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
JSONObject chatInfoReq = new JSONObject()
|
// 1. get chat info
|
||||||
.put("action", "get_chat_info")
|
JSONObject chatInfoReq = new JSONObject();
|
||||||
.put("receiver_id", chatId)
|
chatInfoReq.put("action", "get_chat_info");
|
||||||
.put("receiver_type", chatType);
|
chatInfoReq.put("receiver_id", chatId);
|
||||||
|
chatInfoReq.put("receiver_type", chatType);
|
||||||
System.out.println("📤 Sending get_chat_info: " + chatInfoReq);
|
System.out.println("📤 Sending get_chat_info: " + chatInfoReq);
|
||||||
JSONObject chatInfoResp = ActionHandler.sendWithResponse(chatInfoReq);
|
JSONObject chatInfoResp = ActionHandler.sendWithResponse(chatInfoReq);
|
||||||
JSONObject chatData = chatInfoResp.getJSONObject("data");
|
JSONObject chatData = chatInfoResp.getJSONObject("data");
|
||||||
@@ -401,17 +307,21 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
Session.currentChatEntry = chat;
|
Session.currentChatEntry = chat;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 2. get permission
|
||||||
JSONObject permissionReq = new JSONObject();
|
JSONObject permissionReq = new JSONObject();
|
||||||
if (chatType.equalsIgnoreCase("group")) {
|
if (chatType.equalsIgnoreCase("group")) {
|
||||||
permissionReq.put("action", "get_group_permissions").put("group_id", chatId);
|
permissionReq.put("action", "get_group_permissions");
|
||||||
|
permissionReq.put("group_id", chatId);
|
||||||
} else {
|
} else {
|
||||||
permissionReq.put("action", "get_channel_permissions").put("channel_id", chatId);
|
permissionReq.put("action", "get_channel_permissions");
|
||||||
|
permissionReq.put("channel_id", chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject permissionResp = ActionHandler.sendWithResponse(permissionReq);
|
JSONObject permissionResp = ActionHandler.sendWithResponse(permissionReq);
|
||||||
JSONObject perm = permissionResp.getJSONObject("data");
|
JSONObject perm = permissionResp.getJSONObject("data");
|
||||||
entry.ifPresent(chat -> chat.setPermissions(perm));
|
entry.ifPresent(chat -> chat.setPermissions(perm));
|
||||||
|
|
||||||
|
// 3. set currentChatId
|
||||||
Session.currentChatId = chatUUID.toString();
|
Session.currentChatId = chatUUID.toString();
|
||||||
|
|
||||||
System.out.println("🧪 Checking refresh conditions...");
|
System.out.println("🧪 Checking refresh conditions...");
|
||||||
@@ -434,11 +344,20 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void displayRealTimeMessage(String action, JSONObject msg) {
|
private void displayRealTimeMessage(String action, JSONObject msg) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "new_message" -> {
|
case "new_message" -> {
|
||||||
String senderName = msg.optString("sender_name","Unknown");
|
String senderName = msg.optString("sender_name","Unknown");
|
||||||
String content = msg.optString("content","");
|
String content = msg.optString("content","(empty)");
|
||||||
String sendAt = msg.optString("send_at","-");
|
String sendAt = msg.optString("send_at","-");
|
||||||
String chatId = msg.optString("receiver_id", msg.optString("chat_id",""));
|
String chatId = msg.optString("receiver_id", msg.optString("chat_id",""));
|
||||||
String kind = msg.optString("kind","plain");
|
String kind = msg.optString("kind","plain");
|
||||||
@@ -457,47 +376,47 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
Session.currentChatId != null && Session.currentChatId.equals(chatId);
|
Session.currentChatId != null && Session.currentChatId.equals(chatId);
|
||||||
|
|
||||||
if (isInCurrentChat) {
|
if (isInCurrentChat) {
|
||||||
if (content.isBlank()) content = "(no content)"; // برای مدیا بدون کپشن
|
|
||||||
System.out.println(senderName + ": " + prefix + content + " (" + sendAt + ")");
|
System.out.println(senderName + ": " + prefix + content + " (" + sendAt + ")");
|
||||||
} else {
|
} else {
|
||||||
String preview = content.isBlank() ? "[media]" : content;
|
System.out.println("💬 Message from " + senderName + ": " + prefix + content);
|
||||||
System.out.println("💬 Message from " + senderName + ": " + prefix + preview);
|
|
||||||
Session.forceRefreshChatList = true;
|
Session.forceRefreshChatList = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
case "message_edited" -> {
|
case "message_edited" -> {
|
||||||
System.out.println("\n✏️ Message Edited:");
|
System.out.println("\n✏️ Message Edited:");
|
||||||
System.out.println("ID: " + msg.optString("message_id",""));
|
System.out.println("ID: " + msg.getString("message_id"));
|
||||||
System.out.println("New Content: " + msg.optString("new_content",""));
|
System.out.println("New Content: " + msg.getString("new_content"));
|
||||||
System.out.println("Edit Time: " + msg.optString("edited_at",""));
|
System.out.println("Edit Time: " + msg.getString("edited_at"));
|
||||||
}
|
}
|
||||||
case "message_deleted_global" -> {
|
case "message_deleted_global" -> {
|
||||||
System.out.println("\n🗑️ Message Deleted:");
|
System.out.println("\n🗑️ Message Deleted:");
|
||||||
System.out.println("Message ID: " + msg.optString("message_id",""));
|
System.out.println("Message ID: " + msg.getString("message_id"));
|
||||||
}
|
}
|
||||||
case "message_reacted", "message_unreacted" -> {
|
case "message_reacted", "message_unreacted" -> {
|
||||||
String mid = msg.optString("message_id","");
|
String mid = msg.getString("message_id");
|
||||||
String emoji = msg.optString("emoji","");
|
String emoji = msg.getString("emoji");
|
||||||
|
JSONObject counts = msg.optJSONObject("counts");
|
||||||
int n = msg.optInt("count_for_emoji", 0);
|
int n = msg.optInt("count_for_emoji", 0);
|
||||||
System.out.println("\n⭐ Reaction update on " + mid + " : " + emoji + " → " + n);
|
System.out.println("\n⭐ Reaction update on " + mid + " : " + emoji + " → " + n);
|
||||||
}
|
}
|
||||||
|
|
||||||
case "user_status_changed" -> {
|
case "user_status_changed" -> {
|
||||||
System.out.println("\n🔄 User Status Changed:");
|
System.out.println("\n🔄 User Status Changed:");
|
||||||
System.out.println("User: " + msg.optString("user_id",""));
|
System.out.println("User: " + msg.getString("user_id"));
|
||||||
System.out.println("Status: " + msg.optString("status",""));
|
System.out.println("Status: " + msg.getString("status"));
|
||||||
}
|
}
|
||||||
case "blocked_by_user" -> {
|
case "blocked_by_user" -> {
|
||||||
System.out.println("\n⛔ You were blocked by user: " + msg.optString("blocker_id",""));
|
System.out.println("\n⛔ You were blocked by user: " + msg.getString("blocker_id"));
|
||||||
}
|
}
|
||||||
case "unblocked_by_user" -> {
|
case "unblocked_by_user" -> {
|
||||||
System.out.println("\n✅ You were unblocked by user: " + msg.optString("unblocker_id",""));
|
System.out.println("\n✅ You were unblocked by user: " + msg.getString("unblocker_id"));
|
||||||
}
|
}
|
||||||
case "message_seen" -> {
|
case "message_seen" -> {
|
||||||
System.out.println("\n👁️ Your message was seen:");
|
System.out.println("\n👁️ Your message was seen:");
|
||||||
System.out.println("Message ID: " + msg.optString("message_id",""));
|
System.out.println("Message ID: " + msg.getString("message_id"));
|
||||||
System.out.println("Seen at: " + msg.optString("seen_at",""));
|
System.out.println("Seen at: " + msg.getString("seen_at"));
|
||||||
}
|
}
|
||||||
default -> {
|
default -> {
|
||||||
System.out.println("\n❓ Unknown real-time action: " + action);
|
System.out.println("\n❓ Unknown real-time action: " + action);
|
||||||
@@ -508,9 +427,6 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static LocalDateTime parseIsoFlexible(String iso) {
|
private static LocalDateTime parseIsoFlexible(String iso) {
|
||||||
if (iso == null || iso.isBlank()) return null;
|
if (iso == null || iso.isBlank()) return null;
|
||||||
try { return LocalDateTime.parse(iso); } catch (Exception ignore) {}
|
try { return LocalDateTime.parse(iso); } catch (Exception ignore) {}
|
||||||
@@ -562,4 +478,4 @@ public class IncomingMessageListener implements Runnable {
|
|||||||
} catch (Exception e) { System.err.println("[RT] bumpChatListFromMessage: " + e.getMessage()); }
|
} catch (Exception e) { System.err.println("[RT] bumpChatListFromMessage: " + e.getMessage()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,10 @@ package org.to.telegramfinalproject.Client;
|
|||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -137,11 +140,9 @@ import java.util.UUID;
|
|||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public class TelegramClient {
|
public class TelegramClient {
|
||||||
private static final String SERVER_HOST = "localhost";
|
private static final String SERVER_HOST = "localhost";
|
||||||
private static final int SERVER_PORT = 8080;
|
|
||||||
private static final int SERVER_PORT = 8000;
|
private static final int SERVER_PORT = 8000;
|
||||||
|
|
||||||
private static TelegramClient instance;
|
private static TelegramClient instance;
|
||||||
@@ -157,13 +158,6 @@ public class TelegramClient {
|
|||||||
public static final BlockingQueue<JSONObject> responseQueue = new LinkedBlockingQueue<>();
|
public static final BlockingQueue<JSONObject> responseQueue = new LinkedBlockingQueue<>();
|
||||||
public static final Map<String, BlockingQueue<JSONObject>> pendingResponses = new ConcurrentHashMap<>();
|
public static final Map<String, BlockingQueue<JSONObject>> pendingResponses = new ConcurrentHashMap<>();
|
||||||
public static UUID loggedInUserId = null;
|
public static UUID loggedInUserId = null;
|
||||||
public static final Map<String, BlockingQueue<JSONObject>> pendingResponses = new ConcurrentHashMap<>();
|
|
||||||
private DataInputStream inBin; // NEW
|
|
||||||
private static SocketMediaDownloader downloader; // NEW
|
|
||||||
public static final AtomicBoolean mediaBusy = new AtomicBoolean(false); //
|
|
||||||
private DownloadsIndex downloadIndex;
|
|
||||||
|
|
||||||
private static TelegramClient instance;
|
|
||||||
|
|
||||||
private volatile boolean listenerStarted = false;
|
private volatile boolean listenerStarted = false;
|
||||||
|
|
||||||
@@ -174,14 +168,8 @@ public class TelegramClient {
|
|||||||
|
|
||||||
public static synchronized TelegramClient getInstance() {
|
public static synchronized TelegramClient getInstance() {
|
||||||
if (instance == null) instance = new TelegramClient();
|
if (instance == null) instance = new TelegramClient();
|
||||||
public static SocketMediaDownloader getDownloader() {
|
|
||||||
return downloader;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TelegramClient getInstance() {
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
private DataOutputStream outBin;
|
|
||||||
|
|
||||||
// public void startConsole() {
|
// public void startConsole() {
|
||||||
// try {
|
// try {
|
||||||
@@ -196,18 +184,6 @@ public class TelegramClient {
|
|||||||
|
|
||||||
public void startConsole() {
|
public void startConsole() {
|
||||||
try {
|
try {
|
||||||
socket = new Socket(SERVER_HOST, SERVER_PORT);
|
|
||||||
InputStream rawIn = socket.getInputStream();
|
|
||||||
OutputStream rawOut = socket.getOutputStream();
|
|
||||||
in = new BufferedReader(new InputStreamReader(rawIn, StandardCharsets.UTF_8));
|
|
||||||
out = new PrintWriter(new OutputStreamWriter(rawOut, StandardCharsets.UTF_8), true);
|
|
||||||
|
|
||||||
inBin = new DataInputStream(rawIn);
|
|
||||||
outBin = new DataOutputStream(rawOut);
|
|
||||||
downloader = new SocketMediaDownloader(out, inBin, outBin);
|
|
||||||
|
|
||||||
System.out.println("✅ Connected to Telegram Server");
|
|
||||||
handler = new ActionHandler(out, in, outBin, scanner);
|
|
||||||
connectIfNeeded();
|
connectIfNeeded();
|
||||||
initHandlerIfNeeded();
|
initHandlerIfNeeded();
|
||||||
startListenerOnce(IncomingMessageListener.UIMode.CONSOLE); // ← کنسول
|
startListenerOnce(IncomingMessageListener.UIMode.CONSOLE); // ← کنسول
|
||||||
@@ -293,7 +269,7 @@ public class TelegramClient {
|
|||||||
|
|
||||||
UUID internalId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
UUID internalId = UUID.fromString(Session.currentUser.getString("internal_uuid"));
|
||||||
loggedInUserId = internalId;
|
loggedInUserId = internalId;
|
||||||
this.downloadIndex = DownloadIndexRegistry.forAccount(internalId);
|
|
||||||
handler.userMenu(internalId);
|
handler.userMenu(internalId);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("❌ Login failed.");
|
System.out.println("❌ Login failed.");
|
||||||
@@ -334,5 +310,4 @@ public class TelegramClient {
|
|||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
package org.to.telegramfinalproject.Database;
|
package org.to.telegramfinalproject.Database;
|
||||||
|
|
||||||
import org.to.telegramfinalproject.Models.FileAttachment;
|
import org.to.telegramfinalproject.Models.FileAttachment;
|
||||||
import org.to.telegramfinalproject.Models.MediaRow;
|
|
||||||
import org.to.telegramfinalproject.Models.Message;
|
import org.to.telegramfinalproject.Models.Message;
|
||||||
import org.to.telegramfinalproject.Utils.ChannelPermissionUtil;
|
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -68,134 +66,6 @@ public class MessageDatabase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean insertMessageTx(Connection conn, UUID messageId, UUID senderId, UUID receiverId,
|
|
||||||
String receiverType, String content, String messageType) throws SQLException {
|
|
||||||
String sql = "INSERT INTO messages (message_id, sender_id, receiver_type, receiver_id, content, message_type) " +
|
|
||||||
"VALUES (?, ?, ?, ?, ?, ?)";
|
|
||||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
|
||||||
ps.setObject(1, messageId);
|
|
||||||
ps.setObject(2, senderId);
|
|
||||||
ps.setString(3, receiverType);
|
|
||||||
ps.setObject(4, receiverId);
|
|
||||||
if (content == null || content.isBlank()) ps.setNull(5, java.sql.Types.VARCHAR); else ps.setString(5, content);
|
|
||||||
ps.setString(6, messageType);
|
|
||||||
return ps.executeUpdate() > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean insertAttachmentsTx(Connection conn, UUID messageId, List<FileAttachment> attachments) throws SQLException {
|
|
||||||
if (attachments == null || attachments.isEmpty()) return true;
|
|
||||||
|
|
||||||
final String sql = """
|
|
||||||
INSERT INTO message_attachments(
|
|
||||||
attachment_id, message_id,
|
|
||||||
file_url, file_type, file_name, file_size, mime_type,
|
|
||||||
width, height, duration_seconds, thumbnail_url,
|
|
||||||
media_key, storage_path
|
|
||||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
||||||
""";
|
|
||||||
|
|
||||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
|
||||||
for (FileAttachment att : attachments) {
|
|
||||||
if (att == null) throw new IllegalArgumentException("Attachment is null");
|
|
||||||
UUID attachmentId = att.getAttachmentId() != null ? att.getAttachmentId() : UUID.randomUUID();
|
|
||||||
UUID mediaKey = att.getMediaKey() != null ? att.getMediaKey() : attachmentId; // سادهترین حالت
|
|
||||||
|
|
||||||
String ft = att.getFileType();
|
|
||||||
if (!"IMAGE".equalsIgnoreCase(ft) && !"AUDIO".equalsIgnoreCase(ft)) {
|
|
||||||
throw new IllegalArgumentException("file_type must be IMAGE or AUDIO");
|
|
||||||
}
|
|
||||||
if (att.getStoragePath() == null || att.getStoragePath().isBlank()) {
|
|
||||||
throw new IllegalArgumentException("storage_path is required for socket downloads");
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
ps.setObject(i++, attachmentId);
|
|
||||||
ps.setObject(i++, messageId);
|
|
||||||
//file url (display link)
|
|
||||||
if (att.getFileUrl() == null || att.getFileUrl().isBlank()) ps.setNull(i++, java.sql.Types.VARCHAR);
|
|
||||||
else ps.setString(i++, att.getFileUrl());
|
|
||||||
|
|
||||||
ps.setString(i++, ft.toUpperCase());
|
|
||||||
ps.setString(i++, att.getFileName());
|
|
||||||
if (att.getFileSize() == null) ps.setNull(i++, java.sql.Types.BIGINT); else ps.setLong(i++, att.getFileSize());
|
|
||||||
if (att.getMimeType() == null) ps.setNull(i++, java.sql.Types.VARCHAR); else ps.setString(i++, att.getMimeType());
|
|
||||||
if (att.getWidth() == null) ps.setNull(i++, java.sql.Types.INTEGER); else ps.setInt(i++, att.getWidth());
|
|
||||||
if (att.getHeight() == null) ps.setNull(i++, java.sql.Types.INTEGER); else ps.setInt(i++, att.getHeight());
|
|
||||||
if (att.getDurationSeconds() == null) ps.setNull(i++, java.sql.Types.INTEGER); else ps.setInt(i++, att.getDurationSeconds());
|
|
||||||
if (att.getThumbnailUrl() == null || att.getThumbnailUrl().isBlank()) ps.setNull(i++, java.sql.Types.VARCHAR);
|
|
||||||
else ps.setString(i++, att.getThumbnailUrl());
|
|
||||||
|
|
||||||
ps.setObject(i++, mediaKey);
|
|
||||||
ps.setString(i++, att.getStoragePath());
|
|
||||||
|
|
||||||
ps.addBatch();
|
|
||||||
|
|
||||||
att.setAttachmentId(attachmentId);
|
|
||||||
att.setMediaKey(mediaKey);
|
|
||||||
}
|
|
||||||
ps.executeBatch();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean saveMessageWithOptionalAttachments(
|
|
||||||
UUID messageId, UUID senderId, UUID receiverId,
|
|
||||||
String receiverType, String content, String messageType,
|
|
||||||
List<FileAttachment> attachments
|
|
||||||
) {
|
|
||||||
Connection conn = null;
|
|
||||||
try {
|
|
||||||
conn = ConnectionDb.connect();
|
|
||||||
conn.setAutoCommit(false);
|
|
||||||
|
|
||||||
boolean isText = "TEXT".equalsIgnoreCase(messageType);
|
|
||||||
boolean isImage = "IMAGE".equalsIgnoreCase(messageType);
|
|
||||||
boolean isAudio = "AUDIO".equalsIgnoreCase(messageType);
|
|
||||||
if (!isText && !isImage && !isAudio) {
|
|
||||||
throw new IllegalArgumentException("messageType must be TEXT, IMAGE, or AUDIO");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isText) {
|
|
||||||
if (attachments != null && !attachments.isEmpty())
|
|
||||||
throw new IllegalArgumentException("TEXT must not have attachments");
|
|
||||||
if (content == null || content.isBlank())
|
|
||||||
throw new IllegalArgumentException("TEXT must have non-empty content");
|
|
||||||
} else {
|
|
||||||
if (attachments == null || attachments.isEmpty())
|
|
||||||
throw new IllegalArgumentException("Non-TEXT must have at least one attachment");
|
|
||||||
|
|
||||||
for (FileAttachment a : attachments) {
|
|
||||||
if (a == null) throw new IllegalArgumentException("Attachment is null");
|
|
||||||
String ft = a.getFileType();
|
|
||||||
if (isImage && !"IMAGE".equalsIgnoreCase(ft))
|
|
||||||
throw new IllegalArgumentException("All attachments must be IMAGE for messageType=IMAGE");
|
|
||||||
if (isAudio && !"AUDIO".equalsIgnoreCase(ft))
|
|
||||||
throw new IllegalArgumentException("All attachments must be AUDIO for messageType=AUDIO");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insertMessageTx(conn, messageId, senderId, receiverId, receiverType, content, messageType.toUpperCase());
|
|
||||||
if (!isText) insertAttachmentsTx(conn, messageId, attachments);
|
|
||||||
|
|
||||||
conn.commit();
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (conn != null) try { conn.rollback(); } catch (SQLException ignored) {}
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
if (conn != null) {
|
|
||||||
try { conn.setAutoCommit(true); } catch (SQLException ignored) {}
|
|
||||||
try { conn.close(); } catch (SQLException ignored) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void markGloballyDeleted(UUID chatId) {
|
public static void markGloballyDeleted(UUID chatId) {
|
||||||
String sql = "UPDATE messages SET is_deleted_globally = true WHERE receiver_id = ? AND receiver_type = 'private'";
|
String sql = "UPDATE messages SET is_deleted_globally = true WHERE receiver_id = ? AND receiver_type = 'private'";
|
||||||
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
|
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||||
@@ -684,34 +554,30 @@ public class MessageDatabase {
|
|||||||
|
|
||||||
public static List<FileAttachment> getAttachments(UUID messageId) {
|
public static List<FileAttachment> getAttachments(UUID messageId) {
|
||||||
List<FileAttachment> attachments = new ArrayList<>();
|
List<FileAttachment> attachments = new ArrayList<>();
|
||||||
String sql = "SELECT file_url, file_type, file_name, file_size, mime_type, width, height, duration_seconds, thumbnail_url " +
|
String sql = "SELECT file_url, file_type FROM message_attachments WHERE message_id = ?";
|
||||||
"FROM message_attachments WHERE message_id = ? ORDER BY uploaded_at";
|
|
||||||
try (Connection conn = ConnectionDb.connect();
|
try (Connection conn = ConnectionDb.connect();
|
||||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||||
|
|
||||||
stmt.setObject(1, messageId);
|
stmt.setObject(1, messageId);
|
||||||
ResultSet rs = stmt.executeQuery();
|
ResultSet rs = stmt.executeQuery();
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
attachments.add(new FileAttachment(
|
attachments.add(new FileAttachment(
|
||||||
rs.getString("file_url"),
|
rs.getString("file_url"),
|
||||||
rs.getString("file_type"),
|
rs.getString("file_type")
|
||||||
rs.getString("file_name"),
|
|
||||||
(Long) rs.getObject("file_size"),
|
|
||||||
rs.getString("mime_type"),
|
|
||||||
(Integer) rs.getObject("width"),
|
|
||||||
(Integer) rs.getObject("height"),
|
|
||||||
(Integer) rs.getObject("duration_seconds"),
|
|
||||||
rs.getString("thumbnail_url")
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachments;
|
return attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static LocalDateTime getLastMessageTimeBetween(UUID user1, UUID user2, String type) {
|
public static LocalDateTime getLastMessageTimeBetween(UUID user1, UUID user2, String type) {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT MAX(send_at) FROM messages
|
SELECT MAX(send_at) FROM messages
|
||||||
@@ -779,7 +645,7 @@ public class MessageDatabase {
|
|||||||
(UUID) rs.getObject("forwarded_from"),
|
(UUID) rs.getObject("forwarded_from"),
|
||||||
rs.getBoolean("is_deleted_globally"),
|
rs.getBoolean("is_deleted_globally"),
|
||||||
(rs.getTimestamp("edited_at") != null) ? rs.getTimestamp("edited_at").toLocalDateTime() : null
|
(rs.getTimestamp("edited_at") != null) ? rs.getTimestamp("edited_at").toLocalDateTime() : null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1297,173 +1163,6 @@ public class MessageDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// public static MediaRow findMediaByKey(UUID mediaKey) throws SQLException {
|
|
||||||
// final String sql = """
|
|
||||||
// SELECT a.message_id, a.storage_path, a.file_name, a.mime_type, a.file_size,
|
|
||||||
// m.receiver_type, m.receiver_id, m.sender_id
|
|
||||||
// FROM message_attachments a
|
|
||||||
// JOIN messages m ON m.message_id = a.message_id
|
|
||||||
// WHERE a.media_key = ?
|
|
||||||
// """;
|
|
||||||
// try (Connection c = ConnectionDb.connect();
|
|
||||||
// PreparedStatement ps = c.prepareStatement(sql)) {
|
|
||||||
// ps.setObject(1, mediaKey);
|
|
||||||
// try (ResultSet rs = ps.executeQuery()) {
|
|
||||||
// if (!rs.next()) return null;
|
|
||||||
// MediaRow mr = new MediaRow();
|
|
||||||
// mr.messageId = (UUID) rs.getObject(1);
|
|
||||||
// mr.storagePath = rs.getString(2);
|
|
||||||
// mr.fileName = rs.getString(3);
|
|
||||||
// mr.mimeType = rs.getString(4);
|
|
||||||
// mr.fileSize = rs.getLong(5);
|
|
||||||
// mr.receiverType= rs.getString(6);
|
|
||||||
// mr.receiverId = (UUID) rs.getObject(7);
|
|
||||||
// mr.senderId = (UUID) rs.getObject(8);
|
|
||||||
// return mr;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static boolean canAccess(UUID requester, MediaRow mr) {
|
|
||||||
// if ("private".equals(mr.receiverType)) {
|
|
||||||
// return requester.equals(mr.senderId) || requester.equals(mr.receiverId);
|
|
||||||
// } else if ("group".equals(mr.receiverType)) {
|
|
||||||
// return GroupDatabase.isMember(mr.receiverId, requester);
|
|
||||||
// } else if ("channel".equals(mr.receiverType)) {
|
|
||||||
// return ChannelDatabase.isUserInChannel(mr.receiverId, requester);
|
|
||||||
// }
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static Map<UUID, List<MediaRow>> findAttachmentsForMessages(List<UUID> ids) throws SQLException {
|
|
||||||
Map<UUID, List<MediaRow>> map = new java.util.HashMap<>();
|
|
||||||
if (ids == null || ids.isEmpty()) return map;
|
|
||||||
|
|
||||||
// ساخت IN بهصورت امن
|
|
||||||
String placeholders = ids.stream().map(x -> "?").collect(java.util.stream.Collectors.joining(","));
|
|
||||||
String sql = """
|
|
||||||
SELECT attachment_id, message_id, media_key, file_name, file_size, mime_type, file_type,
|
|
||||||
width, height, duration_seconds, thumbnail_url, file_url, storage_path
|
|
||||||
FROM message_attachments
|
|
||||||
WHERE message_id IN (""" + placeholders + ") ORDER BY uploaded_at ASC";
|
|
||||||
|
|
||||||
try (Connection c = ConnectionDb.connect();
|
|
||||||
PreparedStatement ps = c.prepareStatement(sql)) {
|
|
||||||
int i = 1;
|
|
||||||
for (UUID id : ids) ps.setObject(i++, id);
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
|
||||||
while (rs.next()) {
|
|
||||||
MediaRow a = new MediaRow();
|
|
||||||
a.attachmentId = (UUID) rs.getObject("attachment_id");
|
|
||||||
a.messageId = (UUID) rs.getObject("message_id");
|
|
||||||
a.mediaKey = (UUID) rs.getObject("media_key");
|
|
||||||
a.fileName = rs.getString("file_name");
|
|
||||||
long sz = rs.getLong("file_size");
|
|
||||||
a.fileSize = rs.wasNull() ? null : sz;
|
|
||||||
a.mimeType = rs.getString("mime_type");
|
|
||||||
a.fileType = rs.getString("file_type");
|
|
||||||
int w = rs.getInt("width");
|
|
||||||
a.width = rs.wasNull() ? null : w;
|
|
||||||
int h = rs.getInt("height");
|
|
||||||
a.height = rs.wasNull() ? null : h;
|
|
||||||
int d = rs.getInt("duration_seconds");
|
|
||||||
a.durationSeconds = rs.wasNull() ? null : d;
|
|
||||||
a.thumbnailUrl = rs.getString("thumbnail_url");
|
|
||||||
a.fileUrl = rs.getString("file_url");
|
|
||||||
a.storagePath = rs.getString("storage_path");
|
|
||||||
|
|
||||||
map.computeIfAbsent(a.messageId, k -> new java.util.ArrayList<>()).add(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static MediaRow findMediaByKey(UUID mediaKey) throws SQLException {
|
|
||||||
String sql = """
|
|
||||||
SELECT
|
|
||||||
ma.attachment_id,
|
|
||||||
ma.message_id,
|
|
||||||
ma.media_key,
|
|
||||||
ma.file_name,
|
|
||||||
ma.file_size,
|
|
||||||
ma.mime_type,
|
|
||||||
ma.file_type,
|
|
||||||
ma.width,
|
|
||||||
ma.height,
|
|
||||||
ma.duration_seconds,
|
|
||||||
ma.thumbnail_url,
|
|
||||||
ma.file_url,
|
|
||||||
ma.storage_path,
|
|
||||||
m.receiver_type,
|
|
||||||
m.receiver_id,
|
|
||||||
m.sender_id
|
|
||||||
FROM message_attachments ma
|
|
||||||
JOIN messages m ON m.message_id = ma.message_id
|
|
||||||
WHERE ma.media_key = ?
|
|
||||||
LIMIT 1
|
|
||||||
""";
|
|
||||||
|
|
||||||
try (Connection c = ConnectionDb.connect();
|
|
||||||
PreparedStatement ps = c.prepareStatement(sql)) {
|
|
||||||
ps.setObject(1, mediaKey);
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
|
||||||
if (!rs.next()) return null;
|
|
||||||
|
|
||||||
MediaRow a = new MediaRow();
|
|
||||||
a.attachmentId = (UUID) rs.getObject("attachment_id");
|
|
||||||
a.messageId = (UUID) rs.getObject("message_id");
|
|
||||||
a.mediaKey = (UUID) rs.getObject("media_key");
|
|
||||||
a.fileName = rs.getString("file_name");
|
|
||||||
|
|
||||||
long sz = rs.getLong("file_size");
|
|
||||||
a.fileSize = rs.wasNull() ? null : sz; // MediaRow.fileSize = Long
|
|
||||||
|
|
||||||
a.mimeType = rs.getString("mime_type");
|
|
||||||
a.fileType = rs.getString("file_type");
|
|
||||||
int w = rs.getInt("width"); a.width = rs.wasNull() ? null : w;
|
|
||||||
int h = rs.getInt("height"); a.height = rs.wasNull() ? null : h;
|
|
||||||
int d = rs.getInt("duration_seconds"); a.durationSeconds = rs.wasNull() ? null : d;
|
|
||||||
a.thumbnailUrl = rs.getString("thumbnail_url");
|
|
||||||
a.fileUrl = rs.getString("file_url");
|
|
||||||
a.storagePath = rs.getString("storage_path");
|
|
||||||
a.receiverType = rs.getString("receiver_type");
|
|
||||||
a.receiverId = (UUID) rs.getObject("receiver_id");
|
|
||||||
a.senderId = (UUID) rs.getObject("sender_id");
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean canAccess(UUID requester, MediaRow mr) {
|
|
||||||
if (requester == null || mr == null || mr.receiverType == null) return false;
|
|
||||||
|
|
||||||
// اختیاری: فرستنده همیشه مجاز
|
|
||||||
if (requester.equals(mr.senderId)) return true;
|
|
||||||
|
|
||||||
switch (mr.receiverType.toLowerCase(Locale.ROOT)) {
|
|
||||||
case "private":
|
|
||||||
// receiver_id در پیامهای private = UUID چت خصوصی
|
|
||||||
return PrivateChatDatabase.isParticipant(mr.receiverId, requester);
|
|
||||||
|
|
||||||
case "group":
|
|
||||||
return GroupDatabase.isMember(mr.receiverId, requester);
|
|
||||||
|
|
||||||
case "channel":
|
|
||||||
return ChannelPermissionUtil.isUserInChannel(requester, mr.receiverId);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Message getLastMessage(UUID targetId, String type) {
|
public static Message getLastMessage(UUID targetId, String type) {
|
||||||
final String sql =
|
final String sql =
|
||||||
"SELECT * FROM messages " +
|
"SELECT * FROM messages " +
|
||||||
@@ -1640,4 +1339,4 @@ public class MessageDatabase {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -40,7 +40,7 @@ public class LoginController {
|
|||||||
visiblePasswordField.textProperty().bindBidirectional(passwordField.textProperty());
|
visiblePasswordField.textProperty().bindBidirectional(passwordField.textProperty());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connection = new ClientConnection("localhost", 8000);
|
connection = new ClientConnection("localhost", 8080);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("Could not connect to server: " + e.getMessage());
|
System.out.println("Could not connect to server: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user