From 5cacf94ecca5b45ffdaba0d85506d64117643fd8 Mon Sep 17 00:00:00 2001 From: steckbrief Date: Sun, 12 Nov 2017 14:22:01 +0100 Subject: Initial commit --- .../thedevstack/xmpp/mamloader/MamLoadClient.java | 121 ++++++++++++++++++ src/de/thedevstack/xmpp/mamloader/MamLoader.java | 135 +++++++++++++++++++++ src/de/thedevstack/xmpp/mamloader/SSLHelper.java | 46 +++++++ 3 files changed, 302 insertions(+) create mode 100644 src/de/thedevstack/xmpp/mamloader/MamLoadClient.java create mode 100644 src/de/thedevstack/xmpp/mamloader/MamLoader.java create mode 100644 src/de/thedevstack/xmpp/mamloader/SSLHelper.java (limited to 'src/de') diff --git a/src/de/thedevstack/xmpp/mamloader/MamLoadClient.java b/src/de/thedevstack/xmpp/mamloader/MamLoadClient.java new file mode 100644 index 0000000..66e8969 --- /dev/null +++ b/src/de/thedevstack/xmpp/mamloader/MamLoadClient.java @@ -0,0 +1,121 @@ +package de.thedevstack.xmpp.mamloader; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.jivesoftware.smack.AbstractXMPPConnection; +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.SmackException.NoResponseException; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.SmackException.NotLoggedInException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.tcp.XMPPTCPConnection; +import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.mam.MamManager; +import org.jivesoftware.smackx.mam.MamManager.MamQueryResult; +import org.jxmpp.jid.BareJid; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.stringprep.XmppStringprepException; + +public class MamLoadClient { + private static final int LIMIT_PER_REQUEST = 50; + private AbstractXMPPConnection connection; + private MamManager mamManager; + private boolean debug; + + public MamLoadClient(boolean debug) { + this.debug = debug; + } + + public void connectAndLogin(String username, String password) throws SmackException, IOException, XMPPException, InterruptedException { + BareJid userJid = JidCreate.bareFrom(username); + this.connectAndLogin(userJid.getLocalpartOrThrow().toString(), password, userJid.getDomain().toString()); + } + + private void connectAndLogin(String username, String password, String host) throws SmackException, IOException, XMPPException, InterruptedException { + XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder() + .setUsernameAndPassword(username, password) + .setXmppDomain(host) + .setHost(host) + .setDebuggerEnabled(this.debug) + //.setCustomSSLContext(SSLHelper.createNaiveSSLContext()) + .setResource("MAMLoader_" + UUID.randomUUID()) + .setSendPresence(false) + .build(); + connection = new XMPPTCPConnection(config); + connection.connect(); + connection.login(); + + mamManager = MamManager.getInstanceFor(connection); + } + + public void disconnect() { + this.connection.disconnect(); + } + + public List loadHistory(String jid) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { + return this.loadHistory(jid, null, null); + } + + public List loadHistory(String jid, Date start) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { + return this.loadHistory(jid, start, null); + } + + public List loadHistory(String jid, Date start, Date end) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { + List allMessages = new ArrayList<>(); + if (mamManager.isSupported()) { + Jid withJid = JidCreate.bareFrom(jid); + MamQueryResult archive = mamManager.queryArchive(null, start, end, withJid, null); + allMessages.addAll(archive.forwardedMessages); + while (!archive.mamFin.isComplete()) { + archive = mamManager.pageNext(archive, LIMIT_PER_REQUEST); + allMessages.addAll(archive.forwardedMessages); + } + + allMessages = this.filterAndSort(allMessages); + } + + return allMessages; + } + + public List loadHistory(String jid, int limit) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotLoggedInException, XmppStringprepException { + List allMessages = new ArrayList<>(); + if (mamManager.isSupported()) { + Jid withJid = JidCreate.bareFrom(jid); + MamQueryResult archive = mamManager.mostRecentPage(withJid, LIMIT_PER_REQUEST); + + allMessages.addAll(archive.forwardedMessages); + while (!archive.mamFin.isComplete() && limit > allMessages.size()) { + int requestLimit = limit - allMessages.size(); + archive = mamManager.pagePrevious(archive, (requestLimit < LIMIT_PER_REQUEST ? requestLimit : LIMIT_PER_REQUEST)); + allMessages.addAll(archive.forwardedMessages); + } + + allMessages = this.filterAndSort(allMessages); + } + + return allMessages; + } + + private List filterAndSort(List messages) { + return messages.stream() + .filter(forwarded -> forwarded.getForwardedStanza() instanceof Message + && ((Message)forwarded.getForwardedStanza()).getBody() != null) + .sorted(new Comparator() { + @Override + public int compare(Forwarded o1, Forwarded o2) { + return o1.getDelayInformation().getStamp().compareTo(o2.getDelayInformation().getStamp()); + } + }) + .collect(Collectors.toList()); + } +} diff --git a/src/de/thedevstack/xmpp/mamloader/MamLoader.java b/src/de/thedevstack/xmpp/mamloader/MamLoader.java new file mode 100644 index 0000000..f60c91a --- /dev/null +++ b/src/de/thedevstack/xmpp/mamloader/MamLoader.java @@ -0,0 +1,135 @@ +package de.thedevstack.xmpp.mamloader; + +import java.io.BufferedReader; +import java.io.Console; +import java.io.IOException; +import java.io.InputStreamReader; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smackx.forward.packet.Forwarded; + +public class MamLoader { + private static final SimpleDateFormat SDF = new SimpleDateFormat("dd.MM.YYYY HH:mm:ss"); + private static final SimpleDateFormat INPUT = new SimpleDateFormat("dd.MM.YYYY"); + + public static void main(String[] args) throws InterruptedException, SmackException, IOException, XMPPException { + if (2 > args.length) { + System.err.println("Your JID and the JID of your chatpartner is needed."); + System.exit(1); + } + String myjid = args[0]; + String jid = args[1]; + String password; + boolean debug = false; + Date start = null; + Date end = null; + int limit = -1; + + for (int i = 2; i < args.length; i++) { + switch (args[i]) { + case "-debug": + debug = true; + break; + case "-from": + start = parseDate(args[++i]); + break; + case "-to": + end = parseDate(args[++i]); + break; + case "-limit": + limit = Integer.parseInt(args[++i]); + break; + } + } + + if (null != end && null == start) { + System.err.println("End without start not supported."); + System.exit(1); + } else if (null != start && -1 < limit) { + System.err.println("Limit not supported if start date is given."); + System.exit(1); + } else if (null == jid || null == myjid) { + System.err.println("Your JID and the JID of your chatpartner is needed."); + System.exit(1); + } + + Console console = System.console(); + if (null == console) { + System.out.println("Testenvironment!"); + System.out.println("Warning: Password will be shown."); + System.out.print("Password: "); + BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + password = reader.readLine(); + } else { + password = String.valueOf(console.readPassword("Password: ")); + } + + System.out.println("Loading history for chats with " + jid); + MamLoadClient mlc = new MamLoadClient(debug); + try { + mlc.connectAndLogin(myjid, password); +// mlc.loadHistory(jid, Date.from(LocalDate.of(2017, 11, 8).atStartOfDay().toInstant(ZoneOffset.UTC)), Date.from(LocalDate.of(2017, 11, 9).atStartOfDay().toInstant(ZoneOffset.UTC))); +// mlc.loadHistory(jid); + List messages = null; + + if (start == null && -1 == limit) { + messages = mlc.loadHistory(jid); + } else if (start == null && -1 < limit) { + messages = mlc.loadHistory(jid, limit); + } else if (start != null && end == null) { + messages = mlc.loadHistory(jid, start); + } else { + messages = mlc.loadHistory(jid, start, end); + } + + + System.out.println(messages.size() + " messages found"); + printMessagesWithBody(messages, jid); + } finally { + mlc.disconnect(); + } + } + + private static Date parseDate(String dateToParse) { + try { + return INPUT.parse(dateToParse); + } catch (ParseException e) { + System.err.println("Could not parse date: " + dateToParse); + System.err.println("Needed format: dd.MM.YYYY"); + System.exit(1); + + return null; + } + } + + private static void printMessagesWithBody(List messages, String withJid) { + for (Forwarded f : messages) { + Stanza stanza = f.getForwardedStanza(); + if (stanza instanceof Message) { + StringBuilder sb = new StringBuilder(); + Message message = (Message) stanza; + + if (null != message.getBody()) { + if (withJid.equals(message.getFrom().asBareJid().toString())) { + sb.append("<"); + } else { + sb.append(">"); + } + sb.append(" "); + sb.append(SDF.format(f.getDelayInformation().getStamp())); + sb.append(": "); + sb.append(message.getBody()); + System.out.println(sb.toString()); + } + } + } + } + +} diff --git a/src/de/thedevstack/xmpp/mamloader/SSLHelper.java b/src/de/thedevstack/xmpp/mamloader/SSLHelper.java new file mode 100644 index 0000000..8108f2c --- /dev/null +++ b/src/de/thedevstack/xmpp/mamloader/SSLHelper.java @@ -0,0 +1,46 @@ +package de.thedevstack.xmpp.mamloader; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +public final class SSLHelper { + + + public static final SSLContext createNaiveSSLContext() { + SSLContext sslContext = null; + try { + sslContext = SSLContext.getInstance("TLS"); + // Create a trust manager that does not validate certificate chains + TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { + + @Override + public X509Certificate[] getAcceptedIssuers() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + System.out.println(arg0[0].getSubjectDN()); + } + + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + System.out.println(arg0[0].getSubjectDN()); + } + } }; + sslContext.init(null, trustAllCerts, new SecureRandom()); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return sslContext; + } +} -- cgit v1.2.3