--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/de/unixwork/im/Xmpp.java Wed Dec 25 21:49:48 2024 +0100 @@ -0,0 +1,144 @@ + +package de.unixwork.im; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jivesoftware.smack.ConnectionConfiguration; +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.filter.MessageWithBodiesFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.MessageBuilder; +import org.jivesoftware.smack.roster.Roster; +import org.jivesoftware.smack.roster.RosterEntry; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; +import org.jxmpp.stringprep.XmppStringprepException; + +public class Xmpp extends Thread { + private final XMPPTCPConnectionConfiguration config; + + private XMPPTCPConnection connection = null; + + // BlockingQueue for event-driven communication + private final BlockingQueue<XmppEvent> eventQueue = new LinkedBlockingQueue<>(); + + public Xmpp(XMPPTCPConnectionConfiguration xmppConfig) { + config = xmppConfig; + } + + // Method to send a message (this will be called from another thread) + public void sendMessage(String to, String message, boolean encrypted) { + try { + XmppMessage event = new XmppMessage(to, message, encrypted); + eventQueue.put(event); // Block if the queue is full + } catch (InterruptedException e) { + Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, "Error adding event to queue", e); + } + } + + private void connect() throws SmackException, IOException, XMPPException, InterruptedException { + connection = new XMPPTCPConnection(config); + connection.setUseStreamManagement(false); + connection.connect(); + connection.login(); + + } + + public List<RosterEntry> getRosterItems() throws SmackException.NotLoggedInException, SmackException.NotConnectedException, InterruptedException { + try { + // Ensure we are connected + if (connection != null && connection.isConnected()) { + // Get the roster instance + Roster roster = Roster.getInstanceFor(connection); + + // Fetch all roster entries (contacts) + roster.reload(); + + // Add all roster entries to the list + ArrayList<RosterEntry> rosterList = new ArrayList<>(16); + roster.getEntries().forEach(entry -> rosterList.add(entry)); + + // Optionally, print the list to verify + System.out.println("Roster List: "); + for (RosterEntry entry : rosterList) { + System.out.println("Contact: " + entry.getUser()); + } + + return rosterList; + } else { + System.out.println("Not connected to XMPP server."); + } + } catch (SmackException e) { + Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, "Error getting roster items", e); + } + + return null; + } + + @Override + public void run() { + try { + connect(); + connection.addAsyncStanzaListener((stanza -> { + var jid = stanza.getFrom(); + if(jid != null) { + String body = ((Message)stanza).getBody(); + App.getInstance().dispatchMessage(jid, body, true); + } + }), MessageWithBodiesFilter.INSTANCE); + List<RosterEntry> roster = getRosterItems(); + if(roster != null) { + App.getInstance().setContacts(roster); + } + + while (true) { + // Wait for an event (message to send) + XmppEvent event = eventQueue.take(); // This will block until an event is available + event.exec(this, connection); + } + } catch (SmackException ex) { + Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, null, ex); + } catch (IOException ex) { + Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, null, ex); + } catch (XMPPException ex) { + Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, null, ex); + } catch (InterruptedException ex) { + Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, null, ex); + } + } +} + +class XmppMessage implements XmppEvent { + String to; + String message; + boolean encrypted; + + XmppMessage(String to, String message, boolean encrypted) { + this.to = to; + this.message = message; + this.encrypted = encrypted; + } + + public void exec(Xmpp xmpp, XMPPTCPConnection conn) { + final Message msg; + try { + msg = MessageBuilder.buildMessage() + .to(to) + .setBody(message) + .build(); + conn.sendStanza(msg); + } catch (XmppStringprepException ex) { + Logger.getLogger(XmppMessage.class.getName()).log(Level.SEVERE, null, ex); + } catch (SmackException.NotConnectedException ex) { + Logger.getLogger(XmppMessage.class.getName()).log(Level.SEVERE, null, ex); + } catch (InterruptedException ex) { + Logger.getLogger(XmppMessage.class.getName()).log(Level.SEVERE, null, ex); + } + } +} \ No newline at end of file