added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.ftpupload</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,30 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
|
||||
== Third-party Content
|
||||
|
||||
mina-core
|
||||
* License: Apache 2.0 License
|
||||
* Project: https://mina.apache.org/mina-project
|
||||
* Source: https://gitbox.apache.org/repos/asf?p=mina.git
|
||||
|
||||
ftpserver-core
|
||||
* License: Apache 2.0 License
|
||||
* Project: http://mina.apache.org/ftpserver-project
|
||||
* Source: https://gitbox.apache.org/repos/asf?p=mina.git
|
||||
|
||||
ftplet-api
|
||||
* License: Apache 2.0 License
|
||||
* Project: https://mina.apache.org/ftpserver-project/ftplet.html
|
||||
* Source: https://gitbox.apache.org/repos/asf?p=mina.git
|
||||
@@ -0,0 +1,183 @@
|
||||
# FTP Upload Binding
|
||||
|
||||
This binding can be used to receive image files from FTP clients.
|
||||
The binding acts as a FTP server.
|
||||
Images stored on the FTP server are not saved to the file system, therefore the binding shouldn't cause any problems on flash based openHAB installations if files are uploaded to FTP server continuously (e.g. network camera images).
|
||||
|
||||
## Supported Things
|
||||
|
||||
This binding supports Things of type `ftpupload`.
|
||||
Every Thing is identified by FTP user name.
|
||||
Therefore, every thing should use unique user name to login FTP server.
|
||||
|
||||
## Discovery
|
||||
|
||||
Automatic discovery is not supported.
|
||||
|
||||
## Binding Configuration
|
||||
|
||||
The binding has the following configuration options:
|
||||
|
||||
| Parameter | Name | Description | Required | Default value |
|
||||
|-------------|--------------|------------------------------------------------------------------------------------------------------------------------|----------|---------------|
|
||||
| port | TCP Port | TCP port of the FTP server | no | 2121 |
|
||||
| idleTimeout | Idle timeout | The number of seconds before an inactive client is disconnected. If this value is set to 0, the idle time is disabled. | no | 60 |
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The `ftpupload` Thing has the following configuration parameters:
|
||||
|
||||
| Parameter | Description | Required | Default value |
|
||||
|-----------------------------|---------------------------------------------------------------------------------------------------------------------|----------|---------------|
|
||||
| userName | User name to login to the FTP server. User name is used to identify the Thing, so it should be unique per Thing. | yes | |
|
||||
| password | Password to login to the FTP server. | yes | |
|
||||
|
||||
|
||||
## Channels
|
||||
|
||||
This binding currently supports the following channels:
|
||||
|
||||
| Channel | Channel Type Id | Item Type | Description |
|
||||
|-----------------|-----------------|--------------|----------------------------------------------------------------------------------------|
|
||||
| image | image-channel | Image | Image file received via FTP. |
|
||||
|
||||
Additionally user can introduce custom image-channel's to Thing (see examples).
|
||||
When an image file is uploaded to FTP server, the binding tries to find the channel whose filename matches the uploaded image filename.
|
||||
If no match is found, no channel is updated.
|
||||
The filename parameter supports regular expression patterns.
|
||||
See more details in the Things example.
|
||||
|
||||
Image channel supports following options:
|
||||
|
||||
| Parameter | Name | Description | Required | Default value |
|
||||
|-------------|--------------|--------------------------------------------------------------------------|----------|---------------|
|
||||
| filename | Filename | Filename to match received files. Supports regular expression patterns. | yes | .* |
|
||||
|
||||
|
||||
### Trigger Channels
|
||||
|
||||
| Channel Type ID | Options | Description |
|
||||
|-----------------|------------------------|-----------------------------------------------------|
|
||||
| image-received | IMAGE_RECEIVED | Triggered when image file received from FTP client. |
|
||||
|
||||
When an image file is uploaded to FTP server, the binding tries to find the trigger channel whose filename matches the upload image filename.
|
||||
If no match is found, no channel is updated.
|
||||
The filename parameter supports regular expression patterns.
|
||||
See more details in the Things example.
|
||||
|
||||
Trigger channels supports following options:
|
||||
|
||||
| Parameter | Name | Description | Required | Default value |
|
||||
|-------------|--------------|--------------------------------------------------------------------------|----------|---------------|
|
||||
| filename | Filename | Filename to match received files. Supports regular expression patterns. | yes | .* |
|
||||
|
||||
## Full Example
|
||||
|
||||
Things:
|
||||
|
||||
```
|
||||
Thing ftpupload:imagereceiver:images1 [ userName="test1", password="12345" ] {
|
||||
|
||||
Thing ftpupload:imagereceiver:images2 [ userName="test2", password="12345" ] {
|
||||
Channels:
|
||||
Type image-channel : my_image1 "My Image channel 1" [
|
||||
filename="test12[0-9]{2}.png" // match to filename test12xx.png, where xx can be numbers between 00-99
|
||||
]
|
||||
Type image-channel : my_image2 "My Image channel 2" [
|
||||
filename="test.jpg"
|
||||
]
|
||||
Trigger String : my_image_trigger1 [
|
||||
filename="test12[0-9]{2}.png"
|
||||
]
|
||||
Trigger String : my_image_trigger2 [
|
||||
filename="test.jpg"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Items:
|
||||
|
||||
```
|
||||
Image Image1 { channel="ftpupload:imagereceiver:images1:image" }
|
||||
Image Image2 { channel="ftpupload:imagereceiver:images2:my_image1" }
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
```
|
||||
rule "example trigger rule 1"
|
||||
when
|
||||
Channel 'ftpupload:imagereceiver:images1:image-received' triggered IMAGE_RECEIVED
|
||||
then
|
||||
logInfo("Test","Image received")
|
||||
end
|
||||
|
||||
rule "example trigger rule 2"
|
||||
when
|
||||
Channel 'ftpupload:imagereceiver:images2:my_image_trigger1' triggered IMAGE_RECEIVED
|
||||
then
|
||||
logInfo("Test","Image received")
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
Sitemap:
|
||||
|
||||
```
|
||||
Frame label="FTP images" {
|
||||
Image item=Image1
|
||||
Image item=Image2
|
||||
}
|
||||
```
|
||||
|
||||
## Use case example
|
||||
|
||||
The binding can be used to receive images from network cameras that send images to a FTP server when motion or sound is detected.
|
||||
|
||||
Things:
|
||||
|
||||
```
|
||||
Thing ftpupload:imagereceiver:garagecamera [ userName="garage", password="12345" ]
|
||||
```
|
||||
|
||||
Items:
|
||||
|
||||
```
|
||||
Image Garage_NetworkCamera_Motion_Image { channel="ftpupload:imagereceiver:garagecamera:image" }
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
```
|
||||
rule "example trigger rule"
|
||||
when
|
||||
Channel 'ftpupload:imagereceiver:garagecamera:image-received' triggered IMAGE_RECEIVED
|
||||
then
|
||||
logInfo("Test","Garage motion detected")
|
||||
end
|
||||
```
|
||||
|
||||
Sitemap:
|
||||
|
||||
```
|
||||
Frame label="Garage network camera" icon="camera" {
|
||||
Image item=Garage_NetworkCamera_Motion_Image
|
||||
}
|
||||
```
|
||||
|
||||
## Logging and Problem Solving
|
||||
|
||||
For problem solving, if binding logging is not enough, Apache FTP server logging can also be enabled by the following command in the Karaf console:
|
||||
|
||||
```
|
||||
log:set DEBUG org.apache.ftpserver
|
||||
```
|
||||
|
||||
and set back to default level:
|
||||
|
||||
```
|
||||
log:set DEFAULT org.apache.ftpserver
|
||||
```
|
||||
|
||||
If you meet any problems to receive images from the network cameras, you could test connection to binding with any FTP client.
|
||||
You can send image files via FTP client and thing channels should be updated accordingly.
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.ftpupload</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: FTP Upload Binding</name>
|
||||
|
||||
<properties>
|
||||
<bnd.importpackage>org.springframework.*;resolution:="optional"</bnd.importpackage>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.ftpserver</groupId>
|
||||
<artifactId>ftplet-api</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.ftpserver</groupId>
|
||||
<artifactId>ftpserver-core</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>2.0.21</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.ftpupload-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-ftpupload" description="FTP Upload Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.ftpupload/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link FtpUploadBinding} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FtpUploadBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "ftpupload";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_IMAGERECEIVER = new ThingTypeUID(BINDING_ID, "imagereceiver");
|
||||
|
||||
// List of all Channel ids
|
||||
public static final String IMAGE = "image";
|
||||
public static final String IMAGE_RECEIVED_TRIGGER = "image-received";
|
||||
|
||||
// List of all channel parameters
|
||||
public static final String PARAM_FILENAME_PATTERN = "filename";
|
||||
|
||||
public static final String EVENT_IMAGE_RECEIVED = "IMAGE_RECEIVED";
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal;
|
||||
|
||||
import static org.openhab.binding.ftpupload.internal.FtpUploadBindingConstants.THING_TYPE_IMAGERECEIVER;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Dictionary;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.ftpserver.FtpServerConfigurationException;
|
||||
import org.apache.ftpserver.ftplet.FtpException;
|
||||
import org.openhab.binding.ftpupload.internal.ftp.FtpServer;
|
||||
import org.openhab.binding.ftpupload.internal.handler.FtpUploadHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link FtpUploadHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.ftpupload")
|
||||
public class FtpUploadHandlerFactory extends BaseThingHandlerFactory {
|
||||
private final Logger logger = LoggerFactory.getLogger(FtpUploadHandlerFactory.class);
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_IMAGERECEIVER);
|
||||
|
||||
private final int DEFAULT_PORT = 2121;
|
||||
private final int DEFAULT_IDLE_TIMEOUT = 60;
|
||||
|
||||
private FtpServer ftpServer;
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(THING_TYPE_IMAGERECEIVER)) {
|
||||
if (ftpServer.getStartUpErrorReason() != null) {
|
||||
thing.setStatusInfo(new ThingStatusInfo(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
ftpServer.getStartUpErrorReason()));
|
||||
}
|
||||
return new FtpUploadHandler(thing, ftpServer);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void activate(ComponentContext componentContext) {
|
||||
super.activate(componentContext);
|
||||
ftpServer = new FtpServer();
|
||||
modified(componentContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void deactivate(ComponentContext componentContext) {
|
||||
stopFtpServer();
|
||||
ftpServer = null;
|
||||
super.deactivate(componentContext);
|
||||
}
|
||||
|
||||
protected synchronized void modified(ComponentContext componentContext) {
|
||||
stopFtpServer();
|
||||
Dictionary<String, Object> properties = componentContext.getProperties();
|
||||
|
||||
int port = DEFAULT_PORT;
|
||||
int idleTimeout = DEFAULT_IDLE_TIMEOUT;
|
||||
|
||||
if (properties.get("port") != null) {
|
||||
String strPort = properties.get("port").toString();
|
||||
if (StringUtils.isNotEmpty(strPort)) {
|
||||
try {
|
||||
port = Integer.valueOf(strPort);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("Invalid port number '{}', using default port {}", strPort, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.get("idleTimeout") != null) {
|
||||
String strIdleTimeout = properties.get("idleTimeout").toString();
|
||||
if (StringUtils.isNotEmpty(strIdleTimeout)) {
|
||||
try {
|
||||
idleTimeout = Integer.valueOf(strIdleTimeout);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("Invalid idle timeout '{}', using default timeout {}", strIdleTimeout, idleTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
logger.debug("Starting FTP server, port={}, idleTimeout={}", port, idleTimeout);
|
||||
ftpServer.startServer(port, idleTimeout);
|
||||
} catch (FtpException | FtpServerConfigurationException e) {
|
||||
logger.warn("FTP server starting failed, reason: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void stopFtpServer() {
|
||||
logger.debug("Stopping FTP server");
|
||||
ftpServer.stopServer();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration class for {@link FtpUploadBinding} device.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
|
||||
public class FtpUploadConfig {
|
||||
|
||||
public String userName;
|
||||
public String password;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = "";
|
||||
|
||||
str += "userName = " + userName;
|
||||
str += ", password = *****";
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ftpserver.ftplet.Authority;
|
||||
import org.apache.ftpserver.ftplet.AuthorizationRequest;
|
||||
import org.apache.ftpserver.ftplet.User;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple FTP user implementation.
|
||||
*
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class FTPUser implements User {
|
||||
private static Logger logger = LoggerFactory.getLogger(FTPUser.class);
|
||||
|
||||
private final String login;
|
||||
private int idleTimeout;
|
||||
|
||||
public FTPUser(String login, int idleTimeout) {
|
||||
this.login = login;
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationRequest authorize(final AuthorizationRequest authRequest) {
|
||||
logger.trace("authorize: {}", authRequest);
|
||||
return authRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getEnabled() {
|
||||
logger.trace("getEnabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHomeDirectory() {
|
||||
logger.trace("getHomeDirectory");
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxIdleTime() {
|
||||
logger.trace("getMaxIdleTime");
|
||||
return idleTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
logger.trace("getName");
|
||||
return this.login;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Authority> getAuthorities() {
|
||||
logger.trace("getAuthorities");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Authority> getAuthorities(Class<? extends Authority> arg0) {
|
||||
logger.trace("getAuthorities: {}", arg0);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
logger.trace("getPassword");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ftpserver.ftplet.Authentication;
|
||||
import org.apache.ftpserver.ftplet.AuthenticationFailedException;
|
||||
import org.apache.ftpserver.ftplet.FtpException;
|
||||
import org.apache.ftpserver.ftplet.User;
|
||||
import org.apache.ftpserver.ftplet.UserManager;
|
||||
import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple FTP user manager implementation.
|
||||
*
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class FTPUserManager implements UserManager {
|
||||
private final Logger logger = LoggerFactory.getLogger(FTPUserManager.class);
|
||||
|
||||
private int idleTimeout;
|
||||
private Map<String, UsernamePassword> authenticationData = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public User authenticate(final Authentication inAuth) throws AuthenticationFailedException {
|
||||
logger.trace("authenticate: {}", inAuth);
|
||||
|
||||
UsernamePasswordAuthentication upa = (UsernamePasswordAuthentication) inAuth;
|
||||
String login = upa.getUsername();
|
||||
String password = upa.getPassword();
|
||||
|
||||
if (!autheticate(login, password)) {
|
||||
throw new AuthenticationFailedException();
|
||||
}
|
||||
return new FTPUser(login, idleTimeout);
|
||||
}
|
||||
|
||||
private boolean autheticate(String login, String password) {
|
||||
boolean result = false;
|
||||
|
||||
if (login != null && password != null) {
|
||||
UsernamePassword credential = authenticationData.get(login);
|
||||
|
||||
if (credential != null) {
|
||||
if (login.equals(credential.getUsername()) && password.equals(credential.getPassword())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(int idleTimeout) {
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public synchronized void addAuthenticationCredentials(String username, String password)
|
||||
throws IllegalArgumentException {
|
||||
if (authenticationData.containsKey(username)) {
|
||||
throw new IllegalArgumentException("Credentials for user '" + username + "' already exists!");
|
||||
}
|
||||
authenticationData.put(username, new UsernamePassword(username, password));
|
||||
}
|
||||
|
||||
public synchronized void removeAuthenticationCredentials(String username) {
|
||||
authenticationData.remove(username);
|
||||
}
|
||||
|
||||
@Override
|
||||
public User getUserByName(final String login) throws FtpException {
|
||||
logger.trace("getUserByName: {}", login);
|
||||
return new FTPUser(login, idleTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String arg0) throws FtpException {
|
||||
logger.trace("delete: {}", arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesExist(String arg0) throws FtpException {
|
||||
logger.trace("doesExist: {}", arg0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdminName() throws FtpException {
|
||||
logger.trace("getAdminName");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAllUserNames() throws FtpException {
|
||||
logger.trace("getAllUserNames");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdmin(String arg0) throws FtpException {
|
||||
logger.trace("isAdmin: {}", arg0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(User arg0) throws FtpException {
|
||||
logger.trace("save: {}", arg0);
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.ftpserver.FtpServerConfigurationException;
|
||||
import org.apache.ftpserver.FtpServerFactory;
|
||||
import org.apache.ftpserver.ftplet.DefaultFtplet;
|
||||
import org.apache.ftpserver.ftplet.FileSystemFactory;
|
||||
import org.apache.ftpserver.ftplet.FileSystemView;
|
||||
import org.apache.ftpserver.ftplet.FtpException;
|
||||
import org.apache.ftpserver.ftplet.FtpRequest;
|
||||
import org.apache.ftpserver.ftplet.FtpSession;
|
||||
import org.apache.ftpserver.ftplet.FtpStatistics;
|
||||
import org.apache.ftpserver.ftplet.Ftplet;
|
||||
import org.apache.ftpserver.ftplet.FtpletContext;
|
||||
import org.apache.ftpserver.ftplet.FtpletResult;
|
||||
import org.apache.ftpserver.ftplet.User;
|
||||
import org.apache.ftpserver.listener.Listener;
|
||||
import org.apache.ftpserver.listener.ListenerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple FTP server implementation to receive files via FTP.
|
||||
*
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class FtpServer {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FtpServer.class);
|
||||
|
||||
private int port;
|
||||
int idleTimeout;
|
||||
|
||||
private org.apache.ftpserver.FtpServer server;
|
||||
private List<FtpServerEventListener> listeners;
|
||||
private MyFTPLet myFTPLet;
|
||||
private FTPUserManager FTPUserManager;
|
||||
private String ftpStartUpErrorReason;
|
||||
|
||||
public FtpServer() {
|
||||
listeners = new ArrayList<>();
|
||||
FTPUserManager = new FTPUserManager();
|
||||
}
|
||||
|
||||
public void startServer(int port, int idleTimeout) throws FtpException {
|
||||
stopServer();
|
||||
this.port = port;
|
||||
this.idleTimeout = idleTimeout;
|
||||
FTPUserManager.setIdleTimeout(idleTimeout);
|
||||
initServer();
|
||||
}
|
||||
|
||||
public void stopServer() {
|
||||
if (server != null) {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public String getStartUpErrorReason() {
|
||||
return ftpStartUpErrorReason;
|
||||
}
|
||||
|
||||
public synchronized void addEventListener(FtpServerEventListener listener) {
|
||||
if (!listeners.contains(listener)) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addAuthenticationCredentials(String username, String password)
|
||||
throws IllegalArgumentException {
|
||||
FTPUserManager.addAuthenticationCredentials(username, password);
|
||||
}
|
||||
|
||||
public synchronized void removeAuthenticationCredentials(String username) {
|
||||
FTPUserManager.removeAuthenticationCredentials(username);
|
||||
}
|
||||
|
||||
public synchronized void removeEventListener(FtpServerEventListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
private void sendMsgToListeners(String userName, String filename, byte[] data) {
|
||||
Iterator<FtpServerEventListener> iterator = listeners.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
try {
|
||||
iterator.next().fileReceived(userName, filename, data);
|
||||
} catch (Exception e) {
|
||||
// catch all exceptions give all handlers a fair chance of handling the messages
|
||||
logger.debug("Event listener invoking error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void printStats() {
|
||||
FtpStatistics ftpStats = myFTPLet.getStats();
|
||||
|
||||
logger.debug("TotalConnectionNumber: {}", ftpStats.getTotalConnectionNumber());
|
||||
logger.debug("TotalLoginNumber: {}", ftpStats.getTotalLoginNumber());
|
||||
logger.debug("TotalFailedLoginNumber: {}", ftpStats.getTotalFailedLoginNumber());
|
||||
logger.debug("TotalUploadNumber: {}", ftpStats.getTotalUploadNumber());
|
||||
logger.debug("TotalUploadSize: {}", ftpStats.getTotalUploadSize());
|
||||
|
||||
logger.debug("CurrentConnectionNumber: {}", ftpStats.getCurrentConnectionNumber());
|
||||
logger.debug("CurrentLoginNumber: {}", ftpStats.getCurrentLoginNumber());
|
||||
}
|
||||
|
||||
private void initServer() throws FtpException {
|
||||
FtpServerFactory serverFactory = new FtpServerFactory();
|
||||
ListenerFactory listenerFactory = new ListenerFactory();
|
||||
listenerFactory.setPort(port);
|
||||
listenerFactory.setIdleTimeout(idleTimeout);
|
||||
|
||||
Listener listener = listenerFactory.createListener();
|
||||
|
||||
serverFactory.addListener("default", listener);
|
||||
|
||||
Map<String, Ftplet> ftplets = new LinkedHashMap<>();
|
||||
myFTPLet = new MyFTPLet();
|
||||
|
||||
ftplets.put("ftplet", myFTPLet);
|
||||
|
||||
serverFactory.setFtplets(ftplets);
|
||||
serverFactory.setFileSystem(new FileSystemFactory() {
|
||||
@Override
|
||||
public FileSystemView createFileSystemView(User user) throws FtpException {
|
||||
logger.debug("createFileSystemView: {}", user.getName());
|
||||
return new SimpleFileSystemView();
|
||||
}
|
||||
});
|
||||
|
||||
// set the user manager
|
||||
serverFactory.setUserManager(FTPUserManager);
|
||||
server = serverFactory.createServer();
|
||||
|
||||
try {
|
||||
server.start();
|
||||
ftpStartUpErrorReason = null;
|
||||
} catch (FtpException | FtpServerConfigurationException e) {
|
||||
ftpStartUpErrorReason = "Failed to start FTP server";
|
||||
if (!e.getMessage().isEmpty()) {
|
||||
ftpStartUpErrorReason += ": " + e.getMessage();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyFTPLet extends DefaultFtplet {
|
||||
FtpletContext ftpletContext;
|
||||
|
||||
public FtpStatistics getStats() {
|
||||
return ftpletContext.getFtpStatistics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FtpletContext ftpletContext) throws FtpException {
|
||||
this.ftpletContext = ftpletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
logger.trace("destroy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FtpletResult onConnect(FtpSession session) throws FtpException, IOException {
|
||||
logger.debug("User connected to FtpServer");
|
||||
return super.onConnect(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FtpletResult onUploadEnd(final FtpSession session, final FtpRequest request)
|
||||
throws FtpException, IOException {
|
||||
String userRoot = session.getUser().getHomeDirectory();
|
||||
String currDir = session.getFileSystemView().getWorkingDirectory().getAbsolutePath();
|
||||
String fileName = request.getArgument();
|
||||
|
||||
logger.debug("File {} upload to FTP server", userRoot + currDir + "/" + fileName);
|
||||
|
||||
SimpleFtpFile file = (SimpleFtpFile) session.getFileSystemView().getFile(fileName);
|
||||
byte[] data = file.getData();
|
||||
|
||||
sendMsgToListeners(session.getUser().getName(), fileName, data);
|
||||
return FtpletResult.SKIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* This interface defines interface to receive data from FTP server.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public interface FtpServerEventListener {
|
||||
|
||||
/**
|
||||
* Procedure for receive raw data from FTP server.
|
||||
*
|
||||
* @param userName User name.
|
||||
* @param filename Received filename.
|
||||
* @param data Received raw data.
|
||||
*/
|
||||
void fileReceived(@NonNull String userName, @NonNull String filename, byte[] data);
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
import org.apache.ftpserver.ftplet.FileSystemView;
|
||||
import org.apache.ftpserver.ftplet.FtpException;
|
||||
import org.apache.ftpserver.ftplet.FtpFile;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple FTP file system view implementation.
|
||||
*
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class SimpleFileSystemView implements FileSystemView {
|
||||
private Logger logger = LoggerFactory.getLogger(SimpleFileSystemView.class);
|
||||
|
||||
SimpleFtpFile file = new SimpleFtpFile();
|
||||
|
||||
@Override
|
||||
public boolean changeWorkingDirectory(String arg0) throws FtpException {
|
||||
logger.trace("changeWorkingDirectory: {}", arg0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.trace("dispose");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FtpFile getFile(String arg0) throws FtpException {
|
||||
logger.trace("getFile: {}", arg0);
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FtpFile getHomeDirectory() throws FtpException {
|
||||
logger.trace("getHomeDirectory");
|
||||
return new SimpleFtpFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FtpFile getWorkingDirectory() throws FtpException {
|
||||
logger.trace("getWorkingDirectory");
|
||||
return new SimpleFtpFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRandomAccessible() throws FtpException {
|
||||
logger.trace("isRandomAccessible");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ftpserver.ftplet.FtpFile;
|
||||
import org.openhab.core.util.HexUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Simple FTP file implementation.
|
||||
*
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class SimpleFtpFile implements FtpFile {
|
||||
private Logger logger = LoggerFactory.getLogger(SimpleFtpFile.class);
|
||||
|
||||
MyOutputStream file;
|
||||
|
||||
public byte[] getData() {
|
||||
return file.getData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream createInputStream(long arg0) throws IOException {
|
||||
logger.trace("createInputStream: {}", arg0);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream createOutputStream(long arg0) throws IOException {
|
||||
logger.trace("createOutputStream: {}", arg0);
|
||||
file = new MyOutputStream();
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete() {
|
||||
logger.trace("delete");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesExist() {
|
||||
logger.trace("doesExist");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAbsolutePath() {
|
||||
logger.trace("getAbsolutePath");
|
||||
return "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupName() {
|
||||
logger.trace("getGroupName");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified() {
|
||||
logger.trace("getLastModified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLinkCount() {
|
||||
logger.trace("getLinkCount");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
logger.trace("getName");
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOwnerName() {
|
||||
logger.trace("getOwnerName");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
logger.trace("getSize");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
logger.trace("isDirectory");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
logger.trace("isFile");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHidden() {
|
||||
logger.trace("isHidden");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadable() {
|
||||
logger.trace("isReadable");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRemovable() {
|
||||
logger.trace("isRemovable");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
logger.trace("isWritable");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FtpFile> listFiles() {
|
||||
logger.trace("listFiles");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mkdir() {
|
||||
logger.trace("mkdir");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean move(FtpFile arg0) {
|
||||
logger.trace("move: {}", arg0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setLastModified(long arg0) {
|
||||
logger.trace("setLastModified: {}", arg0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPhysicalFile() {
|
||||
logger.trace("getPhysicalFile");
|
||||
return null;
|
||||
}
|
||||
|
||||
private class MyOutputStream extends OutputStream {
|
||||
private StringBuilder data = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
data.append(String.format("%02X", (byte) b));
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
try {
|
||||
byte[] d = HexUtils.hexToBytes(data.toString());
|
||||
logger.debug("File len: {}", d.length);
|
||||
return d;
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.debug("Exception occured during data conversion: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.ftp;
|
||||
|
||||
/**
|
||||
* Simple wrapper class to store user name and password pairs.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
class UsernamePassword {
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
UsernamePassword(String username, String password) {
|
||||
this.setUsername(username);
|
||||
this.setPassword(password);
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.ftpupload.internal.handler;
|
||||
|
||||
import static org.openhab.binding.ftpupload.internal.FtpUploadBindingConstants.*;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.openhab.binding.ftpupload.internal.config.FtpUploadConfig;
|
||||
import org.openhab.binding.ftpupload.internal.ftp.FtpServer;
|
||||
import org.openhab.binding.ftpupload.internal.ftp.FtpServerEventListener;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.library.types.RawType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link FtpUploadHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Pauli Anttila - Initial contribution
|
||||
*/
|
||||
public class FtpUploadHandler extends BaseThingHandler implements FtpServerEventListener {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(FtpUploadHandler.class);
|
||||
|
||||
private FtpUploadConfig configuration;
|
||||
private FtpServer ftpServer;
|
||||
|
||||
public FtpUploadHandler(Thing thing, FtpServer ftpServer) {
|
||||
super(thing);
|
||||
this.ftpServer = ftpServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand for channel {}: {}", channelUID.getId(), command.toString());
|
||||
logger.debug("Command sending not supported by this binding");
|
||||
|
||||
if (command.equals(RefreshType.REFRESH)) {
|
||||
ftpServer.printStats();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing handler for FTP Upload Binding");
|
||||
configuration = getConfigAs(FtpUploadConfig.class);
|
||||
logger.debug("Using configuration: {}", configuration.toString());
|
||||
|
||||
ftpServer.addEventListener(this);
|
||||
try {
|
||||
ftpServer.addAuthenticationCredentials(configuration.userName, configuration.password);
|
||||
} catch (IllegalArgumentException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
ftpServer.removeAuthenticationCredentials(configuration.userName);
|
||||
ftpServer.removeEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileReceived(String userName, String filename, byte[] data) {
|
||||
if (configuration.userName.equals(userName)) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
updateChannels(filename, data);
|
||||
updateTriggers(filename);
|
||||
}
|
||||
}
|
||||
|
||||
private String guessMimeTypeFromData(byte[] data) {
|
||||
String mimeType = HttpUtil.guessContentTypeFromData(data);
|
||||
logger.debug("Mime type guess from content: {}", mimeType);
|
||||
if (mimeType == null) {
|
||||
mimeType = RawType.DEFAULT_MIME_TYPE;
|
||||
}
|
||||
logger.debug("Mime type: {}", mimeType);
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
private void updateChannels(String filename, byte[] data) {
|
||||
for (Channel channel : thing.getChannels()) {
|
||||
String channelConf = (String) channel.getConfiguration().get(PARAM_FILENAME_PATTERN);
|
||||
if (channelConf != null) {
|
||||
if (filenameMatch(filename, channelConf)) {
|
||||
if ("Image".equals(channel.getAcceptedItemType())) {
|
||||
updateState(channel.getUID().getId(), new RawType(data, guessMimeTypeFromData(data)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTriggers(String filename) {
|
||||
for (Channel channel : thing.getChannels()) {
|
||||
String channelConf = (String) channel.getConfiguration().get(PARAM_FILENAME_PATTERN);
|
||||
if (channelConf != null) {
|
||||
if (filenameMatch(filename, channelConf)) {
|
||||
if ("TRIGGER".equals(channel.getKind().toString())) {
|
||||
triggerChannel(channel.getUID().getId(), EVENT_IMAGE_RECEIVED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean filenameMatch(String filename, String pattern) {
|
||||
try {
|
||||
return Pattern.compile(pattern).matcher(filename).find();
|
||||
} catch (PatternSyntaxException e) {
|
||||
logger.warn("Invalid filename pattern '{}', reason: {}", pattern, e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="ftpupload" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>FTP Upload Binding</name>
|
||||
<description>This binding is for receiving files via FTP.</description>
|
||||
<author>Pauli Anttila</author>
|
||||
|
||||
<config-description>
|
||||
<parameter name="port" type="integer" min="1" max="65535">
|
||||
<label>TCP Port</label>
|
||||
<description>TCP port of the FTP server</description>
|
||||
<default>2121</default>
|
||||
</parameter>
|
||||
<parameter name="idleTimeout" type="integer" min="0" max="65535">
|
||||
<label>Idle Timeout</label>
|
||||
<description>The number of seconds before an inactive client is disconnected. If this value is set to 0, the idle
|
||||
time is disabled.</description>
|
||||
<default>60</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="ftpupload"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="imagereceiver" extensible="image-channel, image-received">
|
||||
<label>Image Receiver</label>
|
||||
<description>Receive image files via FTP.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="image" typeId="image-channel"/>
|
||||
<channel id="image-received" typeId="image-received"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="userName" type="text" required="true">
|
||||
<label>User Name</label>
|
||||
<description>Username</description>
|
||||
</parameter>
|
||||
<parameter name="password" type="text" required="true">
|
||||
<label>Password</label>
|
||||
<description>Password</description>
|
||||
<context>password</context>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="image-channel">
|
||||
<item-type>Image</item-type>
|
||||
<label>Image</label>
|
||||
<description>Image received via FTP</description>
|
||||
<state readOnly="true"></state>
|
||||
<config-description>
|
||||
<parameter name="filename" type="text" required="true">
|
||||
<label>Filename</label>
|
||||
<description>Filename to match received files. Supports regular expression patterns.</description>
|
||||
<default>.*</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
<channel-type id="image-received">
|
||||
<kind>trigger</kind>
|
||||
<label>Image File Received Trigger Channel</label>
|
||||
<event>
|
||||
<options>
|
||||
<option value="IMAGE_RECEIVED">Image received</option>
|
||||
</options>
|
||||
</event>
|
||||
<config-description>
|
||||
<parameter name="filename" type="text" required="true">
|
||||
<label>Filename</label>
|
||||
<description>Filename to match received files. Supports regular expression patterns.</description>
|
||||
<default>.*</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user