src/main/java/de/unixwork/im/Xmpp.java

Mon, 30 Dec 2024 13:15:48 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 30 Dec 2024 13:15:48 +0100
changeset 5
d05262580576
parent 4
856befba7674
permissions
-rw-r--r--

add exec maven plugin


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 net.java.otr4j.OtrException;
import net.java.otr4j.OtrPolicy;
import net.java.otr4j.OtrPolicyImpl;
import net.java.otr4j.OtrSessionManager;
import net.java.otr4j.OtrSessionManagerImpl;
import net.java.otr4j.session.InstanceTag;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionID;
import net.java.otr4j.session.SessionImpl;
import net.java.otr4j.session.TLV;
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.packet.Presence;
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.jid.Jid;
import org.jxmpp.stringprep.XmppStringprepException;

public class Xmpp extends Thread {
    private final XMPPTCPConnectionConfiguration config;
    
    private XMPPTCPConnection connection = null;
    
    private final OTR otr;
    
    private final OtrSessionManager otrSM;
    
    // BlockingQueue for event-driven communication
    private final BlockingQueue<XmppEvent> eventQueue = new LinkedBlockingQueue<>();
    
    public Xmpp(XMPPTCPConnectionConfiguration xmppConfig) {
        config = xmppConfig;
        otr = new OTR(this);
        otrSM = new OtrSessionManagerImpl(otr);
    }
    
    public OTR getOTR() {
        return otr;
    }
    
    public OtrSessionManager getOtrSM() {
        return otrSM;
    }
    
    public void startOTR(String xid) {
        String account = config.getUsername() + "@" + config.getHostString() + "/IM5";
        SessionID sid = new SessionID(account, xid, "xmpp");
        
        Session session = otrSM.getSession(sid); //new SessionImpl(sid, otr);
        try {
            System.out.println("otr session start");
            session.startSession();
        } catch (OtrException ex) {
            Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
    // 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);
        }
    }
    
    public void send(String to, String message) {
        sendMessage(to, message, false);
    }
    
    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();
                        boolean isSecure = false;
                        if(jid != null) {
                            String body = ((Message)stanza).getBody();
                            if(body.startsWith("?OTR")) {
                                String account = config.getUsername() + "@" + config.getHostString() + "/IM5";
                                SessionID sid = new SessionID(account, jid.asBareJid().toString(), "xmpp");
                                Session sn = otrSM.getSession(sid);
                                String cryptoMsg = body;
                                body = null;
                                try {
                                    String otrMsg = sn.transformReceiving(cryptoMsg);
                                    System.out.println("otr transformed: " + otrMsg);
                                    body = otrMsg;
                                    isSecure = true;
                                } catch (OtrException ex) {
                                    Logger.getLogger(Xmpp.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }
                            
                            if(body != null) {
                                App.getInstance().dispatchMessage(jid, body, isSecure);
                            }
                        }
                    }), MessageWithBodiesFilter.INSTANCE);
            connection.addAsyncStanzaListener(stanza -> {
            if (stanza instanceof Presence) {
                Presence presence = (Presence) stanza;
                Jid from = presence.getFrom();
                Presence.Type type = presence.getType();
                App.getInstance().handlePresence(from, type);
            }
        }, stanza -> stanza instanceof Presence);
            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);
        }
    }
}

mercurial