diff options
25 files changed, 390 insertions, 0 deletions
diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..4a08052 --- /dev/null +++ b/.classpath @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-core-4.2.1.jar" sourcepath="/smack-core/src"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-extensions-4.2.1.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/jxmpp-core-0.5.0.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/jxmpp-jid-0.5.0.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/xmlpull-1.1.3.1.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/xpp3_min-1.1.4c.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-experimental-4.2.1.jar" sourcepath="/smack-experimental"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-java7-4.2.1.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-resolver-minidns-4.2.1.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-tcp-4.2.1.jar" sourcepath="/smack-tcp"/> + <classpathentry kind="lib" path="libs/3rdParty/minidns-core-0.2.4.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/minidns-hla-0.2.4.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/minidns-iterative-resolver-0.2.4.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/minidns-dnssec-0.2.4.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/jxmpp-util-cache-0.5.0.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-im-4.2.1.jar"/> + <classpathentry kind="lib" path="libs/3rdParty/smack/smack-sasl-javax-4.2.1.jar"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84960ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin +.settings +dist diff --git a/.project b/.project new file mode 100644 index 0000000..b8d3538 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>MamHistoryLoader</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..fab966f --- /dev/null +++ b/build.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<project default="create_run_jar" name="Create Runnable Jar for Project MamHistoryLoader with libraries in sub-folder"> + <!--this file was created by Eclipse Runnable JAR Export Wizard--> + <!--ANT 1.7 is required --> + <!--define folder properties--> + <property name="dir.buildfile" value="."/> + <property name="dir.workspace" value="${dir.buildfile}/.."/> + <property name="dir.jarfile" value="${dir.buildfile}/dist"/> + <property name="dir.libs" value="${dir.jarfile}/libs"/> + <target name="create_run_jar"> + <delete dir="${dir.libs}"/> + <mkdir dir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-core-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-extensions-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/jxmpp-core-0.5.0.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/jxmpp-jid-0.5.0.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/xmlpull-1.1.3.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/xpp3_min-1.1.4c.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-experimental-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-java7-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-resolver-minidns-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-tcp-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/minidns-core-0.2.4.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/minidns-hla-0.2.4.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/minidns-iterative-resolver-0.2.4.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/minidns-dnssec-0.2.4.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/jxmpp-util-cache-0.5.0.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-im-4.2.1.jar" todir="${dir.libs}"/> + <copy file="${dir.buildfile}/libs/3rdParty/smack/smack-sasl-javax-4.2.1.jar" todir="${dir.libs}"/> + + <manifestclasspath property="mamloader.manifest.classpath" jarfile="${dir.jarfile}/MAMLoader.jar"> + <classpath> + <fileset dir="${dir.libs}" includes="*.jar" /> + </classpath> + </manifestclasspath> + + <jar destfile="${dir.jarfile}/MAMLoader.jar"> + <manifest> + <attribute name="Main-Class" value="de.thedevstack.xmpp.mamloader.MamLoader"/> + <attribute name="Class-Path" value="${mamloader.manifest.classpath}"/> + </manifest> + <fileset dir="${dir.buildfile}/bin"/> + </jar> + </target> +</project> diff --git a/libs/3rdParty/jxmpp-core-0.5.0.jar b/libs/3rdParty/jxmpp-core-0.5.0.jar Binary files differnew file mode 100644 index 0000000..ce5f193 --- /dev/null +++ b/libs/3rdParty/jxmpp-core-0.5.0.jar diff --git a/libs/3rdParty/jxmpp-jid-0.5.0.jar b/libs/3rdParty/jxmpp-jid-0.5.0.jar Binary files differnew file mode 100644 index 0000000..e65dee7 --- /dev/null +++ b/libs/3rdParty/jxmpp-jid-0.5.0.jar diff --git a/libs/3rdParty/jxmpp-util-cache-0.5.0.jar b/libs/3rdParty/jxmpp-util-cache-0.5.0.jar Binary files differnew file mode 100644 index 0000000..724629a --- /dev/null +++ b/libs/3rdParty/jxmpp-util-cache-0.5.0.jar diff --git a/libs/3rdParty/libidn-1.15.jar b/libs/3rdParty/libidn-1.15.jar Binary files differnew file mode 100644 index 0000000..79a44f9 --- /dev/null +++ b/libs/3rdParty/libidn-1.15.jar diff --git a/libs/3rdParty/minidns-core-0.2.4.jar b/libs/3rdParty/minidns-core-0.2.4.jar Binary files differnew file mode 100644 index 0000000..bed0382 --- /dev/null +++ b/libs/3rdParty/minidns-core-0.2.4.jar diff --git a/libs/3rdParty/minidns-dnssec-0.2.4.jar b/libs/3rdParty/minidns-dnssec-0.2.4.jar Binary files differnew file mode 100644 index 0000000..85436bb --- /dev/null +++ b/libs/3rdParty/minidns-dnssec-0.2.4.jar diff --git a/libs/3rdParty/minidns-hla-0.2.4.jar b/libs/3rdParty/minidns-hla-0.2.4.jar Binary files differnew file mode 100644 index 0000000..9f7ec99 --- /dev/null +++ b/libs/3rdParty/minidns-hla-0.2.4.jar diff --git a/libs/3rdParty/minidns-iterative-resolver-0.2.4.jar b/libs/3rdParty/minidns-iterative-resolver-0.2.4.jar Binary files differnew file mode 100644 index 0000000..176fa04 --- /dev/null +++ b/libs/3rdParty/minidns-iterative-resolver-0.2.4.jar diff --git a/libs/3rdParty/smack/smack-core-4.2.1.jar b/libs/3rdParty/smack/smack-core-4.2.1.jar Binary files differnew file mode 100644 index 0000000..8026a4f --- /dev/null +++ b/libs/3rdParty/smack/smack-core-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-experimental-4.2.1.jar b/libs/3rdParty/smack/smack-experimental-4.2.1.jar Binary files differnew file mode 100644 index 0000000..2949d80 --- /dev/null +++ b/libs/3rdParty/smack/smack-experimental-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-extensions-4.2.1.jar b/libs/3rdParty/smack/smack-extensions-4.2.1.jar Binary files differnew file mode 100644 index 0000000..858bbd0 --- /dev/null +++ b/libs/3rdParty/smack/smack-extensions-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-im-4.2.1.jar b/libs/3rdParty/smack/smack-im-4.2.1.jar Binary files differnew file mode 100644 index 0000000..6e9c61a --- /dev/null +++ b/libs/3rdParty/smack/smack-im-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-java7-4.2.1.jar b/libs/3rdParty/smack/smack-java7-4.2.1.jar Binary files differnew file mode 100644 index 0000000..15f12b3 --- /dev/null +++ b/libs/3rdParty/smack/smack-java7-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-resolver-minidns-4.2.1.jar b/libs/3rdParty/smack/smack-resolver-minidns-4.2.1.jar Binary files differnew file mode 100644 index 0000000..788dc91 --- /dev/null +++ b/libs/3rdParty/smack/smack-resolver-minidns-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-sasl-javax-4.2.1.jar b/libs/3rdParty/smack/smack-sasl-javax-4.2.1.jar Binary files differnew file mode 100644 index 0000000..54295bc --- /dev/null +++ b/libs/3rdParty/smack/smack-sasl-javax-4.2.1.jar diff --git a/libs/3rdParty/smack/smack-tcp-4.2.1.jar b/libs/3rdParty/smack/smack-tcp-4.2.1.jar Binary files differnew file mode 100644 index 0000000..b09eed4 --- /dev/null +++ b/libs/3rdParty/smack/smack-tcp-4.2.1.jar diff --git a/libs/3rdParty/xmlpull-1.1.3.1.jar b/libs/3rdParty/xmlpull-1.1.3.1.jar Binary files differnew file mode 100644 index 0000000..cbc149d --- /dev/null +++ b/libs/3rdParty/xmlpull-1.1.3.1.jar diff --git a/libs/3rdParty/xpp3_min-1.1.4c.jar b/libs/3rdParty/xpp3_min-1.1.4c.jar Binary files differnew file mode 100644 index 0000000..813a9a8 --- /dev/null +++ b/libs/3rdParty/xpp3_min-1.1.4c.jar 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<Forwarded> loadHistory(String jid) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { + return this.loadHistory(jid, null, null); + } + + public List<Forwarded> loadHistory(String jid, Date start) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { + return this.loadHistory(jid, start, null); + } + + public List<Forwarded> loadHistory(String jid, Date start, Date end) throws XmppStringprepException, NoResponseException, XMPPErrorException, NotConnectedException, NotLoggedInException, InterruptedException { + List<Forwarded> 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<Forwarded> loadHistory(String jid, int limit) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, NotLoggedInException, XmppStringprepException { + List<Forwarded> 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<Forwarded> filterAndSort(List<Forwarded> messages) { + return messages.stream() + .filter(forwarded -> forwarded.getForwardedStanza() instanceof Message + && ((Message)forwarded.getForwardedStanza()).getBody() != null) + .sorted(new Comparator<Forwarded>() { + @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<Forwarded> 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<Forwarded> 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; + } +} |