From 6aae296280da44244fea0301a7abe59d4c83437f Mon Sep 17 00:00:00 2001 From: steckbrief Date: Sat, 4 Nov 2017 21:04:04 +0100 Subject: initial version of filetransfer:http extension (support for request type=list) --- .../smackx/filetransferhttp/FileTransferHttp.java | 5 + .../filetransferhttp/FileTransferHttpManager.java | 77 ++++++++++++++ .../smackx/filetransferhttp/element/FileList.java | 40 +++++++ .../filetransferhttp/element/RemoteFile.java | 79 ++++++++++++++ .../filetransferhttp/element/RemoteFileInfo.java | 54 ++++++++++ .../smackx/filetransferhttp/element/Request.java | 19 ++++ .../provider/FileListProvider.java | 118 +++++++++++++++++++++ 7 files changed, 392 insertions(+) create mode 100644 src/de/thedevstack/smackx/filetransferhttp/FileTransferHttp.java create mode 100644 src/de/thedevstack/smackx/filetransferhttp/FileTransferHttpManager.java create mode 100644 src/de/thedevstack/smackx/filetransferhttp/element/FileList.java create mode 100644 src/de/thedevstack/smackx/filetransferhttp/element/RemoteFile.java create mode 100644 src/de/thedevstack/smackx/filetransferhttp/element/RemoteFileInfo.java create mode 100644 src/de/thedevstack/smackx/filetransferhttp/element/Request.java create mode 100644 src/de/thedevstack/smackx/filetransferhttp/provider/FileListProvider.java (limited to 'src/de/thedevstack') diff --git a/src/de/thedevstack/smackx/filetransferhttp/FileTransferHttp.java b/src/de/thedevstack/smackx/filetransferhttp/FileTransferHttp.java new file mode 100644 index 0000000..2b00ed4 --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/FileTransferHttp.java @@ -0,0 +1,5 @@ +package de.thedevstack.smackx.filetransferhttp; + +public interface FileTransferHttp { + String NAMESPACE = "urn:xmpp:filetransfer:http"; +} diff --git a/src/de/thedevstack/smackx/filetransferhttp/FileTransferHttpManager.java b/src/de/thedevstack/smackx/filetransferhttp/FileTransferHttpManager.java new file mode 100644 index 0000000..fffbcbd --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/FileTransferHttpManager.java @@ -0,0 +1,77 @@ +package de.thedevstack.smackx.filetransferhttp; + +import java.util.Map; +import java.util.WeakHashMap; +import java.util.logging.Logger; + +import org.jivesoftware.smack.ConnectionCreationListener; +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPConnectionRegistry; +import org.jivesoftware.smack.SmackException.NoResponseException; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; + +import de.thedevstack.smackx.filetransferhttp.element.FileList; +import de.thedevstack.smackx.filetransferhttp.element.Request; + +public class FileTransferHttpManager extends Manager { + + private static final Logger LOGGER = Logger.getLogger(FileTransferHttpManager.class.getName()); + + static { + XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { + @Override + public void connectionCreated(XMPPConnection connection) { + getInstanceFor(connection); + } + }); + } + + private static final Map INSTANCES = new WeakHashMap<>(); + + + /** + * Obtain the HttpFileUploadManager responsible for a connection. + * + * @param connection the connection object. + * @return a HttpFileUploadManager instance + */ + public static synchronized FileTransferHttpManager getInstanceFor(XMPPConnection connection) { + FileTransferHttpManager fileTransferHttpManager = INSTANCES.get(connection); + + if (fileTransferHttpManager == null) { + fileTransferHttpManager = new FileTransferHttpManager(connection); + INSTANCES.put(connection, fileTransferHttpManager); + } + + return fileTransferHttpManager; + } + + private FileTransferHttpManager(XMPPConnection connection) { + super(connection); + } + + public FileList requestFileList() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + final XMPPConnection connection = connection(); + Request request = new Request(); + request.setTo(connection.getXMPPServiceDomain()); + return connection.createStanzaCollectorAndSend(request).nextResultOrThrow(); + } + + + /** + * Returns true if XMPP Carbons are supported by the server. + * + * @return true if supported + * @throws NotConnectedException + * @throws XMPPErrorException + * @throws NoResponseException + * @throws InterruptedException + */ + public boolean isSupportedByServer() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + return ServiceDiscoveryManager.getInstanceFor(connection()).serverSupportsFeature(FileTransferHttp.NAMESPACE); + } + +} diff --git a/src/de/thedevstack/smackx/filetransferhttp/element/FileList.java b/src/de/thedevstack/smackx/filetransferhttp/element/FileList.java new file mode 100644 index 0000000..563ca15 --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/element/FileList.java @@ -0,0 +1,40 @@ +package de.thedevstack.smackx.filetransferhttp.element; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; + +import de.thedevstack.smackx.filetransferhttp.FileTransferHttp; + +public class FileList extends IQ { + private List files = new ArrayList<>(); + + public FileList() { + super("list", FileTransferHttp.NAMESPACE); + } + + public List getFiles() { + return files; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.rightAngleBracket(); + + if (0 < this.files.size()) { + for (RemoteFile file : this.files) { + xml.append(file.toXML()); + } + } else { + xml.emptyElement("empty"); + } + + return xml; + } + + public void addRemoteFile(RemoteFile remoteFile) { + this.files.add(remoteFile); + } + +} diff --git a/src/de/thedevstack/smackx/filetransferhttp/element/RemoteFile.java b/src/de/thedevstack/smackx/filetransferhttp/element/RemoteFile.java new file mode 100644 index 0000000..483d8b3 --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/element/RemoteFile.java @@ -0,0 +1,79 @@ +package de.thedevstack.smackx.filetransferhttp.element; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class RemoteFile implements NamedElement { + private String url; + private long timestamp; + private RemoteFileInfo fileInfo; + private String from; + private String to; + + public RemoteFile(String url, long timestamp) { + this.url = url; + this.timestamp = timestamp; + } + + public String getFilename() { + return (null != fileInfo) ? fileInfo.getFilename() : null; + } + + public long getSize() { + return (null != fileInfo) ? fileInfo.getSize() : -1; + } + + public String getContentType() { + return (null != fileInfo) ? fileInfo.getContentType() : null; + } + + public RemoteFileInfo getFileInfo() { + return fileInfo; + } + + public void setFileInfo(RemoteFileInfo fileInfo) { + this.fileInfo = fileInfo; + } + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getUrl() { + return url; + } + + public long getTimestamp() { + return timestamp; + } + + @Override + public String getElementName() { + return "file"; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.attribute("timestamp", String.valueOf(this.timestamp)); + xml.optAttribute("from", this.from); + xml.optAttribute("to", this.to); + xml.rightAngleBracket(); + xml.element("url", this.url); + xml.append(fileInfo.toXML()); + xml.closeElement(this); + return xml; + } +} diff --git a/src/de/thedevstack/smackx/filetransferhttp/element/RemoteFileInfo.java b/src/de/thedevstack/smackx/filetransferhttp/element/RemoteFileInfo.java new file mode 100644 index 0000000..caeb2c8 --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/element/RemoteFileInfo.java @@ -0,0 +1,54 @@ +package de.thedevstack.smackx.filetransferhttp.element; + +import org.jivesoftware.smack.packet.NamedElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public class RemoteFileInfo implements NamedElement { + private final String filename; + private final long size; + private String contentType; + + public RemoteFileInfo(String filename, long size) { + this.filename = filename; + this.size = size; + } + + public RemoteFileInfo(String filename, long size, String contentType) { + this(filename, size); + this.contentType = contentType; + } + + + + public String getFilename() { + return filename; + } + + public long getSize() { + return size; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + @Override + public String getElementName() { + return "file-info"; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.rightAngleBracket(); + xml.element("filename", this.filename); + xml.optElement("size", this.size); + xml.optElement("content-type", this.contentType); + xml.closeElement(this); + return xml; + } +} diff --git a/src/de/thedevstack/smackx/filetransferhttp/element/Request.java b/src/de/thedevstack/smackx/filetransferhttp/element/Request.java new file mode 100644 index 0000000..ac974b9 --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/element/Request.java @@ -0,0 +1,19 @@ +package de.thedevstack.smackx.filetransferhttp.element; + +import org.jivesoftware.smack.packet.IQ; + +import de.thedevstack.smackx.filetransferhttp.FileTransferHttp; + +public class Request extends IQ { + public Request() { + super("request", FileTransferHttp.NAMESPACE); + setType(Type.get); + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.attribute("type", "list"); + xml.setEmptyElement(); + return xml; + } +} diff --git a/src/de/thedevstack/smackx/filetransferhttp/provider/FileListProvider.java b/src/de/thedevstack/smackx/filetransferhttp/provider/FileListProvider.java new file mode 100644 index 0000000..d6738b6 --- /dev/null +++ b/src/de/thedevstack/smackx/filetransferhttp/provider/FileListProvider.java @@ -0,0 +1,118 @@ +package de.thedevstack.smackx.filetransferhttp.provider; + +import java.io.IOException; + +import org.jivesoftware.smack.SmackException; +import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smack.util.ParserUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import de.thedevstack.smackx.filetransferhttp.element.FileList; +import de.thedevstack.smackx.filetransferhttp.element.RemoteFile; +import de.thedevstack.smackx.filetransferhttp.element.RemoteFileInfo; + +public class FileListProvider extends IQProvider { + + @Override + public FileList parse(XmlPullParser parser, int initialDepth) throws Exception { + String namespace = parser.getNamespace(); + FileList fileList = new FileList(); + + int event = -1; + int currentDepth = -1; + do { + event = parser.next(); + currentDepth = parser.getDepth(); + + if (XmlPullParser.START_TAG == event) { + String name = parser.getName(); + switch (name) { + case "file": + RemoteFile remoteFile = this.parseRemoteFile(parser, currentDepth); + if (null != remoteFile) { + fileList.addRemoteFile(remoteFile); + } + break; + } + } + + } while (event != XmlPullParser.END_TAG && currentDepth != initialDepth); + + return fileList; + } + + protected RemoteFile parseRemoteFile(XmlPullParser parser, int initialDepth) throws IOException, XmlPullParserException { + long timestamp = ParserUtils.getLongAttribute(parser, "timestamp"); + String to = parser.getAttributeValue("", "to"); + String from = parser.getAttributeValue("", "from"); + String url = null; + RemoteFileInfo remoteFileInfo = null; + + int event = -1; + int currentDepth = -1; + do { + event = parser.next(); + currentDepth = parser.getDepth(); + + if (XmlPullParser.START_TAG == event) { + String name = parser.getName(); + switch (name) { + case "url": + url = parser.nextText(); + break; + case "file-info": + remoteFileInfo = parseRemoteFileInfo(parser, currentDepth); + break; + } + } + + } while (event != XmlPullParser.END_TAG && currentDepth != initialDepth); + + RemoteFile remoteFile = new RemoteFile(url, timestamp); + remoteFile.setFileInfo(remoteFileInfo); + remoteFile.setTo(to); + remoteFile.setFrom(from); + + return remoteFile; + } + + protected RemoteFileInfo parseRemoteFileInfo(XmlPullParser parser, int initialDepth) throws XmlPullParserException, IOException { + long size = -1; + String contentType = null; + String filename = null; + + int event = -1; + int currentDepth = -1; + do { + event = parser.next(); + currentDepth = parser.getDepth(); + + if (XmlPullParser.START_TAG == event) { + String name = parser.getName(); + switch (name) { + case "filename": + filename = parser.nextText(); + break; + case "size": + String sizeString = parser.nextText(); + if (null != sizeString) { + size = Long.valueOf(sizeString); + } + break; + case "content-type": + contentType = parser.nextText(); + break; + } + } + + } while (event != XmlPullParser.END_TAG && currentDepth != initialDepth); + + if (0 >= size || null == filename || filename.isEmpty()) { + return null; + } + + return new RemoteFileInfo(filename, size, contentType); + } + +} -- cgit v1.2.3