1
0
mirror of https://github.com/Rogiel/httpchannel synced 2025-12-05 23:22:51 +00:00

Implemented streaming http uploads and downloads for MegaUpload

This commit is contained in:
2011-09-07 21:50:35 -03:00
parent 143238ee53
commit 794efb6ced
43 changed files with 2361 additions and 90 deletions

33
pom.xml
View File

@@ -1,8 +1,39 @@
<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"> <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> <modelVersion>4.0.0</modelVersion>
<groupId>com.rogiel.seedbox</groupId> <groupId>com.rogiel.seedbox</groupId>
<artifactId>seedbox-httpchannel</artifactId> <artifactId>seedbox-httpchannel</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
<name>Seedbox - HTTP Channel library</name> <name>Seedbox - HTTP Channel library</name>
<description>Library capable of downloading and uploading files from free servers using channels.</description> <description>Library capable of downloading and uploading files from free servers using channels.</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<type>jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
</project> </project>

View File

@@ -0,0 +1,45 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
import com.rogiel.httpchannel.service.DownloadListener.TimerWaitReason;
import net.sf.f2s.util.ThreadUtils;
/**
* @author rogiel
*
*/
public abstract class AbstractDownloader implements Downloader {
protected void timer(DownloadListener listener, long timer) {
listener.timer(timer, TimerWaitReason.DOWNLOAD_TIMER);
ThreadUtils.sleep(timer);
}
protected boolean cooldown(DownloadListener listener, long cooldown)
throws IOException {
if (listener.timer(cooldown, TimerWaitReason.COOLDOWN)) {
ThreadUtils.sleep(cooldown);
return true;
} else {
throw new IOException("Timer " + TimerWaitReason.COOLDOWN
+ " aborted due to listener request");
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
/**
* Abstract base service for HTTP enabled services.
*
* @author Rogiel
* @since 1.0
*/
public abstract class AbstractHttpService<T extends ServiceConfiguration>
extends AbstractService<T> implements Service {
/**
* The {@link HttpClient} instance for this service
*/
protected HttpClient client = new DefaultHttpClient();
protected AbstractHttpService(T configuration) {
super(configuration);
}
}

View File

@@ -0,0 +1,43 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
/**
* This is an abstract {@link Service} implementation.
*
* @author Rogiel
* @version 1.0
* @param <T>
* The {@link ServiceConfiguration} <b>interface</b> type used by the
* {@link Service}. Note that this <b>must</b> be an interface!s
* @see ServiceConfiguration ServiceConfiguration for details on the configuration interface.
*/
public abstract class AbstractService<T extends ServiceConfiguration>
implements Service {
protected final T configuration;
protected AbstractService(T configuration) {
this.configuration = configuration;
}
@Override
public T getServiceConfiguration() {
return configuration;
}
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* Implements an service capable of authenticating into an account.
*
* @author Rogiel
* @since 1.0
*/
public interface AuthenticationService extends Service {
/**
* Creates {@link Authenticator} instance for this service. This instance is
* attached to an {@link Credential} and to its parent {@link Service}.
*
* @param credential
* the credential
* @return an new {@link Authenticator} instance
*/
Authenticator getAuthenticator(Credential credential);
/**
* Return the matrix of capabilities for this {@link Authenticator}.
*
* @return {@link CapabilityMatrix} with all capabilities of this
* {@link Authenticator}.
* @see AuthenticatorCapability
*/
CapabilityMatrix<AuthenticatorCapability> getAuthenticationCapability();
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
/**
* This interfaces provides authentication for an service.
*
* @author Rogiel
* @since 1.0
*/
public interface Authenticator {
/**
* Login into the {@link Service}. Once the authentication is done, it is
* persistent for the entire service's operation.<br>
* <b>Note</b>: If you want to logout the user, see
* {@link Authenticator#logout()}
*
* @param listener
* the listener do keep a track on the authentication progress
*/
void login(AuthenticatorListener listener) throws IOException;
/**
* Logout into the {@link Service}. The session is restored to an not
* logged-in state.
*
* @param listener
* the listener do keep a track on the logout progress
*/
void logout(AuthenticatorListener listener) throws IOException;
}

View File

@@ -0,0 +1,30 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* Capability an certain {@link Authenticator} can have.
*
* @author Rogiel
* @since 1.0
*/
public enum AuthenticatorCapability {
/**
* Mark an {@link Authenticator} capable of fetching account information.
*/
FETCH_ACCOUNT_INFORMATION;
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
/**
* This listener keeps an track on the Authentication process.
*
* @author Rogiel
* @since 1.0
*/
public interface AuthenticatorListener {
/**
* The username and password informed was not valid.
*
* @param credential
* the authenticating credential
*/
void invalidCredentials(Credential credential);
/**
* The username and password informed was valid. User is authenticated.
*
* @param credential
* the authenticating credential
*/
void loginSuccessful(Credential credential);
void logout(Credential credential);
void exception(IOException e) throws IOException;
}

View File

@@ -0,0 +1,58 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* This is an utility class to help manage Capabilities of all the services.
*
* @author Rogiel
* @param <T>
* the capability enumeration
* @since 1.0
*/
public class CapabilityMatrix<T> {
/**
* The list of all supported capabilities
*/
private final T[] matrix;
/**
* Creates a new matrix of capabilities
*
* @param matrix
* all the capabilities this service support
*/
public CapabilityMatrix(T... matrix) {
this.matrix = matrix;
}
/**
* Check whether an certatin capability is in the matrix or not.
*
* @param capability
* the capability being searched in the matrix
* @return true if existent, false otherwise
*/
public boolean has(T capability) {
for (final T capScan : matrix) {
if (capScan == capability) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,59 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* Pair of username-password used for authenticating into services.
*
* @author Rogiel
* @since 1.0
*/
public class Credential {
private final String username;
private final String password;
/**
* Creates a new pair of username-password credential
*
* @param username
* the username
* @param password
* the password
*/
public Credential(String username, String password) {
this.username = username;
this.password = password;
}
/**
* Get the username
*
* @return the username
*/
public String getUsername() {
return username;
}
/**
* Get the password
*
* @return the password
*/
public String getPassword() {
return password;
}
}

View File

@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>. * along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.rogiel.httpchannel; package com.rogiel.httpchannel.service;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
@@ -22,5 +22,7 @@ import java.nio.channels.ReadableByteChannel;
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public interface DownloadChannel extends ReadableByteChannel { public interface DownloadChannel extends ReadableByteChannel {
long getLength();
String getFilename();
} }

View File

@@ -0,0 +1,70 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import com.rogiel.httpchannel.service.captcha.Captcha;
/**
* This listener keeps an track on the progress on an {@link Downloader}
* service.
*
* @author Rogiel
* @since 1.0
*/
public interface DownloadListener {
/**
* Inform that the downloader will be waiting for an certain amount of time
* due to an timer in the download site.
*
* @param time
* the time in ms in which the service will be be waiting.
* @param reason
* the reason why this timer is running
* @return true if desires to wait, false otherwise
*/
boolean timer(long time, TimerWaitReason reason);
/**
* The reason why an certain timer is being ran.
*
* @author Rogiel
*/
public enum TimerWaitReason {
/**
* Normal download timer. An annoyance.
*/
DOWNLOAD_TIMER,
/**
* This IP has already download up to the limit, waiting for releasing
* of the block.
*/
COOLDOWN,
/**
* This is an unknown wait time.
*/
UNKNOWN;
}
/**
* Passes an captcha by parameter and waits for the response of the
* challenge.
*
* @param captcha
* the captcha challenge
*/
String captcha(Captcha captcha);
}

View File

@@ -16,42 +16,46 @@
*/ */
package com.rogiel.httpchannel.service; package com.rogiel.httpchannel.service;
import java.io.IOException; import java.net.URL;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import com.rogiel.httpchannel.DownloadChannel; import javax.tools.FileObject;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * Implements an service capable of downloading a file.
* *
* @author Rogiel
* @since 1.0
*/ */
public interface DownloadService { public interface DownloadService extends Service {
DownloadChannel download(URI uri, CaptchaResolver captchaResolver); /**
* Creates a new instance of the {@link Downloader}. This instance will be
* attached to the {@link URL}, {@link FileObject} provided through the the
* arguments and the parent {@link Service} instance.
*
* @param url
* the url to be downloaded
* @param file
* the destination file
* @return an new instance of {@link Downloader}
*/
Downloader getDownloader(URL url);
/** /**
* Simple delegating implementation for {@link DownloadChannel}. * Check if this {@link Service} can download from this URL. Implemtations
* might or might not perform network activity.
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @param url
* the url to be tested.
* @return true if supported, false otherwise.
*/ */
public abstract class SimpleDownloadChannel implements DownloadChannel { boolean matchURL(URL url);
protected final ReadableByteChannel channel;
public SimpleDownloadChannel(ReadableByteChannel channel) { /**
this.channel = channel; * Return the matrix of capabilities for this {@link Downloader}.
} *
* @return {@link CapabilityMatrix} with all capabilities of this
public int read(ByteBuffer dst) throws IOException { * {@link Downloader}.
return channel.read(dst); * @see DownloaderCapability
} */
CapabilityMatrix<DownloaderCapability> getDownloadCapabilities();
public boolean isOpen() {
return channel.isOpen();
}
public void close() throws IOException {
channel.close();
}
}
} }

View File

@@ -0,0 +1,35 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
/**
* This interfaces provides downloading for an service.
*
* @author Rogiel
* @since 1.0
*/
public interface Downloader {
/**
* Starts the download process.
*
* @param listener
* the listener to keep a track on the download progress
*/
DownloadChannel download(DownloadListener listener) throws IOException;
}

View File

@@ -0,0 +1,46 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* Capability an certain {@link Downloader} can have.
*
* @author Rogiel
* @since 1.0
*/
public enum DownloaderCapability {
/**
* Can download files while not authenticated
*/
UNAUTHENTICATED_DOWNLOAD,
/**
* Can download files while authenticated with non-premium account
*/
NON_PREMIUM_ACCOUNT_DOWNLOAD,
/**
* Can download files while authenticated with premium account
*/
PREMIUM_ACCOUNT_DOWNLOAD,
/**
* Resume interrupted downloads are possible and supported.
*/
RESUME,
/**
* Can check the status of the given link before starting download.
*/
STATUS_CHECK;
}

View File

@@ -16,10 +16,46 @@
*/ */
package com.rogiel.httpchannel.service; package com.rogiel.httpchannel.service;
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * Base interface for all the services. Whenever the operation suported by the
* {@link Service} it must implement this interface. Most of implementations
* will benefit from abstract instances of this interface:
* <ul>
* <li>{@link AbstractHttpService}: provides an basic support for HTTP services.
* </li>
* </ul>
* *
* @author Rogiel
* @since 1.0
*/ */
public interface Service { public interface Service {
/**
* Get the ServiceID.
*
* @return the id of the service
*/
String getId();
/**
* Get Major version of this service
*
* @return the major version
*/
int getMajorVersion();
/**
* Get the minor version of this service
*
* @return the minor version
*/
int getMinorVersion();
/**
* Returns this {@link ServiceConfiguration} instance
*
* @return the {@link ServiceConfiguration} instance
*/
ServiceConfiguration getServiceConfiguration();
} }

View File

@@ -0,0 +1,41 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
/**
* Base exception for any {@link Service}.
*
* @author Rogiel
* @since 1.0
*/
public class ServiceException extends IOException {
private static final long serialVersionUID = 1L;
public ServiceException(String message) {
super(message);
}
public ServiceException(Throwable t) {
super(t);
}
public ServiceException(String message, Throwable t) {
super(message, t);
}
}

View File

@@ -14,14 +14,17 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>. * along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.rogiel.httpchannel; package com.rogiel.httpchannel.service;
import java.net.URI;
import java.nio.channels.WritableByteChannel; import java.nio.channels.WritableByteChannel;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author <a href="http://www.rogiel.com">Rogiel</a>
*/ */
public interface UploadChannel extends WritableByteChannel { public interface UploadChannel extends WritableByteChannel {
URI getLink(); long getLength();
String getFilename();
String getDownloadLink();
} }

View File

@@ -0,0 +1,29 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* This listener keeps an track on the progress on an {@link Uploader} service.
*
* @author Rogiel
* @since 1.0
*/
public interface UploadListener {
long getFilesize();
String getFilename();
}

View File

@@ -0,0 +1,74 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import net.sf.f2s.util.ThreadUtils;
import org.apache.http.entity.mime.content.AbstractContentBody;
import org.apache.http.entity.mime.content.ContentBody;
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
/**
* {@link ContentBody} used to upload files in {@link Uploader} implementations.
*
* @author Rogiel
* @since 1.0
*/
public class UploadListenerContentBody extends AbstractContentBody {
private final LinkedUploadChannel channel;
public UploadListenerContentBody(LinkedUploadChannel channel) {
super("application/octet-stream");
this.channel = channel;
}
@Override
public String getFilename() {
return channel.getFilename();
}
@Override
public void writeTo(OutputStream out) throws IOException {
final WritableByteChannel outputChannel = Channels.newChannel(out);
channel.linkChannel(outputChannel);
while (channel.isOpen() && outputChannel.isOpen()) {
ThreadUtils.sleep(500);
}
}
@Override
public String getCharset() {
return null;
}
@Override
public long getContentLength() {
return channel.getLength();
}
@Override
public String getTransferEncoding() {
return "binary";
}
}

View File

@@ -16,38 +16,39 @@
*/ */
package com.rogiel.httpchannel.service; package com.rogiel.httpchannel.service;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import com.rogiel.httpchannel.UploadChannel;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * Implements an service capable of uploading a file.
*
* @author Rogiel
* @since 1.0
*/ */
public interface UploadService { public interface UploadService extends Service {
UploadChannel upload(String filename, long filesize); /**
* Creates a new instance of {@link Uploader}. This instance is attached
* with the parent {@link Service} instance.<br>
* <b>Note</b>: not all services might support <tt>description</tt>
*
* @param file
* the file to be uploaded
* @param description
* the description of the upload. If supported.
* @return the new {@link Uploader} instance
*/
Uploader getUploader(String description);
/** /**
* Simple delegating implementation for {@link UploadChannel}. * Get the maximum upload file size supported by this service.
* *
* @author <a href="http://www.rogiel.com">Rogiel</a> * @return the maximum filesize supported
*/ */
public abstract class SimpleUploadChannel implements UploadChannel { long getMaximumFilesize();
protected final WritableByteChannel channel;
public SimpleUploadChannel(WritableByteChannel channel) { /**
this.channel = channel; * Return the matrix of capabilities for this {@link Uploader}.
} *
* @return {@link CapabilityMatrix} with all capabilities of this
@Override * {@link Uploader}.
public int write(ByteBuffer src) throws IOException { * @see UploaderCapability
return channel.write(src); */
} CapabilityMatrix<UploaderCapability> getUploadCapabilities();
@Override
public boolean isOpen() {
return channel.isOpen();
}
}
} }

View File

@@ -0,0 +1,38 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
import java.io.IOException;
/**
* This interfaces provides uploading for an service.
*
* @author Rogiel
* @since 1.0
*/
public interface Uploader {
/**
* Starts the upload process on this service.
*
* @param listener
* the listener do keep an track on the upload process
* @throws UploadServiceException
* thrown if something went wrong
* @throws IOException
*/
UploadChannel upload(UploadListener listener) throws IOException;
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service;
/**
* Capability an certain {@link Uploader} can have.
*
* @author Rogiel
* @since 1.0
*/
public enum UploaderCapability {
/**
* Can upload while not authenticated into any account
*/
UNAUTHENTICATED_UPLOAD,
/**
* Can upload while authenticated with a non-premium account
*/
NON_PREMIUM_ACCOUNT_UPLOAD,
/**
* Can upload while authenticated with a premium account
*/
PREMIUM_ACCOUNT_UPLOAD;
}

View File

@@ -0,0 +1,26 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.captcha;
/**
* @author Rogiel
* @since 1.0
*/
public interface Captcha {
String getAnswer();
void setAnswer(String answer);
}

View File

@@ -0,0 +1,47 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.captcha;
import java.net.URL;
/**
* @author Rogiel
* @since 1.0
*/
public class ImageCaptcha implements Captcha {
private URL url;
private String answer;
public URL getUrl() {
return url;
}
public void setUrl(URL url) {
this.url = url;
}
@Override
public String getAnswer() {
return answer;
}
@Override
public void setAnswer(String answer) {
this.answer = answer;
}
}

View File

@@ -0,0 +1,69 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.channel;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import com.rogiel.httpchannel.service.DownloadChannel;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class InputStreamDownloadChannel implements DownloadChannel {
private final ReadableByteChannel channel;
private final long length;
private final String filename;
public InputStreamDownloadChannel(InputStream in, final long length,
final String filename) {
this.channel = Channels.newChannel(in);
this.length = length;
this.filename = filename;
}
@Override
public int read(ByteBuffer dst) throws IOException {
return channel.read(dst);
}
@Override
public boolean isOpen() {
return channel.isOpen();
}
@Override
public void close() throws IOException {
channel.close();
}
@Override
public long getLength() {
return length;
}
@Override
public String getFilename() {
return filename;
}
}

View File

@@ -0,0 +1,93 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.channel;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import com.rogiel.httpchannel.service.UploadChannel;
/**
* @author <a href="http://www.rogiel.com">Rogiel</a>
*
*/
public class LinkedUploadChannel implements UploadChannel {
private WritableByteChannel channel;
private final LinkedUploadChannelCloseCallback closeCallback;
private final long length;
private final String filename;
private String downloadLink;
private boolean open = true;
public LinkedUploadChannel(LinkedUploadChannelCloseCallback closeCallback,
long filesize, String filename) {
this.closeCallback = closeCallback;
this.filename = filename;
this.length = filesize;
}
@Override
public int write(ByteBuffer src) throws IOException {
if (channel == null)
throw new IOException("Channel is not linked yet");
return channel.write(src);
}
@Override
public boolean isOpen() {
return (channel != null ? channel.isOpen() : true) && open;
}
@Override
public void close() throws IOException {
open = false;
downloadLink = closeCallback.finish();
}
public interface LinkedUploadChannelCloseCallback {
String finish() throws IOException;
}
@Override
public long getLength() {
return length;
}
@Override
public String getFilename() {
return filename;
}
@Override
public String getDownloadLink() {
return downloadLink;
}
public void linkChannel(WritableByteChannel channel) throws IOException {
if(this.channel != null)
throw new IOException("This channel is already linked.");
this.channel = channel;
}
public boolean isLinked() {
return channel != null;
}
}

View File

@@ -0,0 +1,40 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.config;
import java.lang.reflect.Proxy;
import net.sf.f2s.util.transformer.Transformer;
/**
* This is an flag interface to indicate that an certain Interface is the
* configuration for the service.<br>
* <br>
* Every service must create an <tt>interface</tt> with the configuration
* methods, additionally an Annotation informing the default value.
* ServiceConfiguration implementations might use reflection ({@link Proxy}),
* hard-coding or any other way for fetching the data.<br>
* <br>
* String data stored in the annotation is converted to Java Types using the
* {@link Transformer} class.
*
* @author Rogiel
* @version 1.0
* @see Transformer
*/
public interface ServiceConfiguration {
}

View File

@@ -0,0 +1,112 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
import net.sf.f2s.util.transformer.TransformerFactory;
/**
* Helper class for {@link ServiceConfiguration} system.
*
* @author Rogiel
* @since 1.0
*/
public class ServiceConfigurationHelper {
/**
* Creates a Proxy Class that returns all the default values of
* configuration interfaces. The values are mapped by
* {@link ServiceConfigurationProperty} annotation.
*
* @param <T>
* the interface extending {@link ServiceConfiguration}. Service
* specific.
* @param type
* the type Class representing T.
* @return the proxied {@link ServiceConfiguration} instance.
*/
@SuppressWarnings("unchecked")
public static <T extends ServiceConfiguration> T defaultConfiguration(
Class<T> type) {
return (T) Proxy.newProxyInstance(
ServiceConfiguration.class.getClassLoader(),
new Class<?>[] { type }, new InvocationHandler() {
@Override
public Object invoke(Object object, Method method,
Object[] arguments) throws Throwable {
final ServiceConfigurationProperty property = method
.getAnnotation(ServiceConfigurationProperty.class);
if (property != null)
return TransformerFactory.getTransformer(
method.getReturnType()).transform(
property.defaultValue());
return null;
}
});
}
/**
* Creates a Proxy Class that returns all the default values of
* configuration interfaces. The values are mapped by
* {@link ServiceConfigurationProperty} annotation.
*
* @param <T>
* the interface extending {@link ServiceConfiguration}. Service
* specific.
* @param type
* the type Class representing T.
* @return the proxied {@link ServiceConfiguration} instance.
* @throws IOException
* @throws FileNotFoundException
*/
@SuppressWarnings("unchecked")
public static <T extends ServiceConfiguration> T file(Class<T> type,
File file) throws FileNotFoundException, IOException {
final Properties properties = new Properties();
properties.load(new FileInputStream(file));
return (T) Proxy.newProxyInstance(
ServiceConfiguration.class.getClassLoader(),
new Class<?>[] { type }, new InvocationHandler() {
@Override
public Object invoke(Object object, Method method,
Object[] arguments) throws Throwable {
final ServiceConfigurationProperty property = method
.getAnnotation(ServiceConfigurationProperty.class);
if (property != null)
return TransformerFactory.getTransformer(
method.getReturnType()).transform(
get(property));
return null;
}
private String get(ServiceConfigurationProperty property) {
String value = properties.getProperty(property.key());
if (value == null)
value = property.defaultValue();
return value;
}
});
}
}

View File

@@ -0,0 +1,51 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.config;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation that defines the default value for an {@link ServiceConfiguration}
* method.<br>
* <br>
* <h1>Usage example</h1>
*
* <pre>
* public interface DummyServiceConfiguration extends ServiceConfiguration {
* &#064;ServiceConfigurationProperty(defaultValue = &quot;true&quot;)
* boolean retryAllowed();
* }
* </pre>
*
* The default implementation created by
* {@link ServiceConfigurationHelper#defaultConfiguration()} will always return
* the <tt>defaultValue</tt>.
*
* @author Rogiel
* @version 1.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ServiceConfigurationProperty {
String key();
String defaultValue();
}

View File

@@ -17,35 +17,318 @@
package com.rogiel.httpchannel.service.impl; package com.rogiel.httpchannel.service.impl;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import com.rogiel.httpchannel.DownloadChannel; import net.sf.f2s.util.HttpClientUtils;
import com.rogiel.httpchannel.UploadChannel; import net.sf.f2s.util.PatternUtils;
import com.rogiel.httpchannel.service.CaptchaResolver; import net.sf.f2s.util.ThreadUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.StringBody;
import com.rogiel.httpchannel.service.AbstractDownloader;
import com.rogiel.httpchannel.service.AbstractHttpService;
import com.rogiel.httpchannel.service.AuthenticationService;
import com.rogiel.httpchannel.service.Authenticator;
import com.rogiel.httpchannel.service.AuthenticatorCapability;
import com.rogiel.httpchannel.service.AuthenticatorListener;
import com.rogiel.httpchannel.service.CapabilityMatrix;
import com.rogiel.httpchannel.service.Credential;
import com.rogiel.httpchannel.service.DownloadChannel;
import com.rogiel.httpchannel.service.DownloadListener;
import com.rogiel.httpchannel.service.DownloadService; import com.rogiel.httpchannel.service.DownloadService;
import com.rogiel.httpchannel.service.Downloader;
import com.rogiel.httpchannel.service.DownloaderCapability;
import com.rogiel.httpchannel.service.Service;
import com.rogiel.httpchannel.service.UploadChannel;
import com.rogiel.httpchannel.service.UploadListener;
import com.rogiel.httpchannel.service.UploadListenerContentBody;
import com.rogiel.httpchannel.service.UploadService; import com.rogiel.httpchannel.service.UploadService;
import com.rogiel.httpchannel.service.Uploader;
import com.rogiel.httpchannel.service.UploaderCapability;
import com.rogiel.httpchannel.service.channel.InputStreamDownloadChannel;
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel;
import com.rogiel.httpchannel.service.channel.LinkedUploadChannel.LinkedUploadChannelCloseCallback;
import com.rogiel.httpchannel.service.config.ServiceConfiguration;
import com.rogiel.httpchannel.service.config.ServiceConfigurationProperty;
import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadServiceConfiguration;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * This service handles login, upload and download to MegaUpload.com.
* *
* @author Rogiel
* @since 1.0
*/ */
public class MegaUploadService implements DownloadService, UploadService { public class MegaUploadService extends
public DownloadChannel download(URI uri, CaptchaResolver captchaResolver) { AbstractHttpService<MegaUploadServiceConfiguration> implements Service,
return new SimpleDownloadChannel(null) { UploadService, DownloadService, AuthenticationService {
}; private static final Pattern UPLOAD_URL_PATTERN = Pattern
} .compile("http://www([0-9]*)\\.megaupload\\.com/upload_done\\.php\\?UPLOAD_IDENTIFIER=[0-9]*");
public UploadChannel upload(String filename, long filesize) { private static final Pattern DOWNLOAD_DIRECT_LINK_PATTERN = Pattern
return new SimpleUploadChannel(null) { .compile("http://www([0-9]*)\\.megaupload\\.com/files/([A-Za-z0-9]*)/([^\"]*)");
@Override private static final Pattern DOWNLOAD_TIMER = Pattern
public void close() throws IOException { .compile("count=([0-9]*);");
// private static final Pattern DOWNLOAD_FILESIZE = Pattern
// .compile("[0-9]*(\\.[0-9]*)? (K|M|G)B");
private static final Pattern DOWNLOAD_URL_PATTERN = Pattern
.compile("http://www\\.megaupload\\.com/\\?d=([A-Za-z0-9]*)");
public MegaUploadService(final MegaUploadServiceConfiguration configuration) {
super(configuration);
} }
@Override @Override
public URI getLink() { public String getId() {
return "megaupload";
}
@Override
public int getMajorVersion() {
return 1;
}
@Override
public int getMinorVersion() {
return 0;
}
@Override
public Uploader getUploader(String description) {
return new MegaUploadUploader(description);
}
@Override
public long getMaximumFilesize() {
return 1 * 1024 * 1024 * 1024;
}
@Override
public CapabilityMatrix<UploaderCapability> getUploadCapabilities() {
return new CapabilityMatrix<UploaderCapability>(
UploaderCapability.UNAUTHENTICATED_UPLOAD,
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD,
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD);
}
@Override
public Downloader getDownloader(URL url) {
return new MegaUploadDownloader(url);
}
@Override
public boolean matchURL(URL url) {
return false;
}
@Override
public CapabilityMatrix<DownloaderCapability> getDownloadCapabilities() {
return new CapabilityMatrix<DownloaderCapability>(
DownloaderCapability.UNAUTHENTICATED_DOWNLOAD,
DownloaderCapability.NON_PREMIUM_ACCOUNT_DOWNLOAD,
DownloaderCapability.PREMIUM_ACCOUNT_DOWNLOAD);
}
@Override
public Authenticator getAuthenticator(Credential credential) {
return new MegaUploadAuthenticator(credential);
}
@Override
public CapabilityMatrix<AuthenticatorCapability> getAuthenticationCapability() {
return new CapabilityMatrix<AuthenticatorCapability>();
}
protected class MegaUploadUploader implements Uploader,
LinkedUploadChannelCloseCallback {
private final String description;
private Future<String> uploadFuture;
public MegaUploadUploader(String description) {
this.description = (description != null ? description
: configuration.getDefaultUploadDescription());
}
@Override
public UploadChannel upload(UploadListener listener) throws IOException {
final String body = HttpClientUtils.get(client,
"http://www.megaupload.com/multiupload/");
final String url = PatternUtils.find(UPLOAD_URL_PATTERN, body);
final HttpPost upload = new HttpPost(url);
final MultipartEntity entity = new MultipartEntity();
upload.setEntity(entity);
final LinkedUploadChannel channel = new LinkedUploadChannel(this,
listener.getFilesize(), listener.getFilename());
entity.addPart("multifile_0",
new UploadListenerContentBody(channel));
entity.addPart("multimessage_0", new StringBody(description));
uploadFuture = HttpClientUtils.executeAsync(client, upload);
while (!channel.isLinked() && !uploadFuture.isDone()) {
ThreadUtils.sleep(100);
}
return channel;
}
@Override
public String finish() throws IOException {
try {
return PatternUtils.find(DOWNLOAD_URL_PATTERN,
uploadFuture.get());
} catch (InterruptedException e) {
return null; return null;
} catch (ExecutionException e) {
throw (IOException) e.getCause();
} }
}; }
}
protected class MegaUploadDownloader extends AbstractDownloader {
private final URL url;
public MegaUploadDownloader(URL url) {
this.url = url;
}
@Override
public DownloadChannel download(DownloadListener listener)
throws IOException {
final HttpGet request = new HttpGet(url.toString());
final HttpResponse response = client.execute(request);
final String content = IOUtils.toString(response.getEntity()
.getContent());
// try to find timer
final String stringTimer = PatternUtils.find(DOWNLOAD_TIMER,
content, 1);
int timer = 0;
if (stringTimer != null && stringTimer.length() > 0) {
timer = Integer.parseInt(stringTimer);
}
if (timer > 0 && configuration.respectWaitTime()) {
timer(listener, timer * 1000);
}
final String downloadUrl = PatternUtils.find(
DOWNLOAD_DIRECT_LINK_PATTERN, content, 0);
if (downloadUrl != null && downloadUrl.length() > 0) {
final HttpGet downloadRequest = new HttpGet(downloadUrl);
final HttpResponse downloadResponse = client
.execute(downloadRequest);
if (downloadResponse.getStatusLine().getStatusCode() == HttpStatus.SC_FORBIDDEN
|| downloadResponse.getStatusLine().getStatusCode() == HttpStatus.SC_SERVICE_UNAVAILABLE) {
downloadResponse.getEntity().getContent().close();
if (cooldown(listener, 60 * 1000))
return download(listener); // retry download
} else {
final String filename = FilenameUtils.getName(downloadUrl);
// listener.fileName(filename);
final Header contentLengthHeader = downloadResponse
.getFirstHeader("Content-Length");
long contentLength = -1;
if (contentLengthHeader != null) {
contentLength = Long.valueOf(contentLengthHeader
.getValue());
// listener.fileSize(contentLength);
}
return new InputStreamDownloadChannel(downloadResponse
.getEntity().getContent(), contentLength, filename);
}
} else {
throw new IOException("Download link not found");
}
throw new IOException("Unknown error");
}
}
protected class MegaUploadAuthenticator implements Authenticator {
private final Credential credential;
public MegaUploadAuthenticator(Credential credential) {
this.credential = credential;
}
@Override
public void login(AuthenticatorListener listener) {
try {
final HttpPost login = new HttpPost(
"http://www.megaupload.com/?c=login");
final MultipartEntity entity = new MultipartEntity();
login.setEntity(entity);
entity.addPart("login", new StringBody("1"));
entity.addPart("username",
new StringBody(credential.getUsername()));
entity.addPart("password",
new StringBody(credential.getPassword()));
final String response = HttpClientUtils.execute(client, login);
if (response.contains("Username and password do "
+ "not match. Please try again!")) {
listener.invalidCredentials(credential);
return;
}
listener.loginSuccessful(credential);
} catch (IOException e) {
// throw new NestedLoginServiceException(e);
// TODO throw an exception here
}
}
@Override
public void logout(AuthenticatorListener listener) {
try {
final HttpPost logout = new HttpPost(
"http://www.megaupload.com/?c=account");
final MultipartEntity entity = new MultipartEntity();
logout.setEntity(entity);
entity.addPart("logout", new StringBody("1"));
HttpClientUtils.execute(client, logout);
// TODO check logout status
listener.logout(credential);
return;
} catch (IOException e) {
// throw new NestedLoginServiceException(e);
// TODO throw an exception here
}
}
}
public static interface MegaUploadServiceConfiguration extends
ServiceConfiguration {
@ServiceConfigurationProperty(key = "megaupload.wait", defaultValue = "true")
boolean respectWaitTime();
@ServiceConfigurationProperty(key = "megaupload.port", defaultValue = "80")
int getPreferedDownloadPort();
@ServiceConfigurationProperty(key = "megaupload.description", defaultValue = "Uploaded by seedbox-httpchannel")
String getDefaultUploadDescription();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " " + getMajorVersion() + "."
+ getMinorVersion();
} }
} }

View File

@@ -0,0 +1,63 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
public class HttpClientUtils {
private static final ExecutorService threadPool = Executors
.newCachedThreadPool();
public static String get(HttpClient client, String url) throws IOException {
return execute(client, new HttpGet(url));
}
public static String execute(HttpClient client, HttpUriRequest request)
throws IOException {
return toString(client.execute(request));
}
public static Future<String> executeAsync(final HttpClient client,
final HttpUriRequest request) throws IOException {
return threadPool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return HttpClientUtils.toString(client.execute(request));
}
});
}
public static String toString(HttpResponse response) throws IOException {
final InputStream in = response.getEntity().getContent();
try {
return IOUtils.toString(in);
} finally {
in.close();
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PatternUtils {
public static String find(Pattern pattern, String text) {
return find(pattern, text, 0);
}
public static String find(Pattern pattern, String text, int n) {
final Matcher matcher = pattern.matcher(text);
if (matcher.find()) {
return matcher.group(n);
}
return null;
}
public static String match(Pattern pattern, String text) {
return match(pattern, text, 0);
}
public static String match(Pattern pattern, String text, int n) {
final Matcher matcher = pattern.matcher(text);
if (matcher.matches()) {
return matcher.group(n);
}
return null;
}
}

View File

@@ -0,0 +1,30 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util;
/**
* @author Rogiel
* @since 1.0
*/
public class ThreadUtils {
public static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer;
/**
* @author Rogiel
* @since 1.0
*/
public class TransformationException extends Exception {
private static final long serialVersionUID = 1L;
public TransformationException() {
}
/**
* @param message
* the message
*/
public TransformationException(String message) {
super(message);
}
/**
* @param cause
* the cause
*/
public TransformationException(Throwable cause) {
super(cause);
}
/**
* @param message
* the message
* @param cause
* the cause
*/
public TransformationException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -14,12 +14,12 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>. * along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.rogiel.httpchannel.service; package net.sf.f2s.util.transformer;
/** /**
* @author <a href="http://www.rogiel.com">Rogiel</a> * @author rogiel
* *
*/ */
public interface CaptchaResolver { public interface Transformer<O> {
O transform(String data) throws TransformationException;
} }

View File

@@ -0,0 +1,47 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer;
import java.net.URL;
import net.sf.f2s.util.transformer.impl.BooleanTransformer;
import net.sf.f2s.util.transformer.impl.IntegerTransformer;
import net.sf.f2s.util.transformer.impl.LongTransformer;
import net.sf.f2s.util.transformer.impl.StringTransformer;
import net.sf.f2s.util.transformer.impl.URLTransformer;
/**
* @author Rogiel
* @since 1.0
*/
public class TransformerFactory {
@SuppressWarnings("unchecked")
public static <T> Transformer<T> getTransformer(Class<T> type) {
if (String.class.isAssignableFrom(type)) {
return (Transformer<T>) new StringTransformer();
} else if (Boolean.class.isAssignableFrom(type) || type == Boolean.TYPE) {
return (Transformer<T>) new BooleanTransformer();
} else if (Integer.class.isAssignableFrom(type) || type == Integer.TYPE) {
return (Transformer<T>) new IntegerTransformer();
} else if (Long.class.isAssignableFrom(type) || type == Long.TYPE) {
return (Transformer<T>) new LongTransformer();
} else if (URL.class.isAssignableFrom(type)) {
return (Transformer<T>) new URLTransformer();
}
return null;
}
}

View File

@@ -0,0 +1,30 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer.impl;
import net.sf.f2s.util.transformer.Transformer;
/**
* @author rogiel
*
*/
public class BooleanTransformer implements Transformer<Boolean> {
@Override
public Boolean transform(String data) {
return Boolean.parseBoolean(data);
}
}

View File

@@ -0,0 +1,30 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer.impl;
import net.sf.f2s.util.transformer.Transformer;
/**
* @author rogiel
*
*/
public class IntegerTransformer implements Transformer<Integer> {
@Override
public Integer transform(String data) {
return Integer.parseInt(data);
}
}

View File

@@ -0,0 +1,30 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer.impl;
import net.sf.f2s.util.transformer.Transformer;
/**
* @author rogiel
*
*/
public class LongTransformer implements Transformer<Long> {
@Override
public Long transform(String data) {
return Long.parseLong(data);
}
}

View File

@@ -0,0 +1,30 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer.impl;
import net.sf.f2s.util.transformer.Transformer;
/**
* @author rogiel
*
*/
public class StringTransformer implements Transformer<String> {
@Override
public String transform(String data) {
return data;
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.f2s.util.transformer.impl;
import java.net.MalformedURLException;
import java.net.URL;
import net.sf.f2s.util.transformer.TransformationException;
import net.sf.f2s.util.transformer.Transformer;
/**
* @author rogiel
*
*/
public class URLTransformer implements Transformer<URL> {
@Override
public URL transform(String data) throws TransformationException {
try {
return new URL(data);
} catch (MalformedURLException e) {
throw new TransformationException(e);
}
}
}

View File

@@ -0,0 +1,289 @@
/*
* This file is part of seedbox <github.com/seedbox>.
*
* seedbox is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* seedbox is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with seedbox. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rogiel.httpchannel.service.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.util.Properties;
import junit.framework.Assert;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
import com.rogiel.httpchannel.service.AuthenticationService;
import com.rogiel.httpchannel.service.AuthenticatorListener;
import com.rogiel.httpchannel.service.Credential;
import com.rogiel.httpchannel.service.DownloadChannel;
import com.rogiel.httpchannel.service.DownloadListener;
import com.rogiel.httpchannel.service.DownloadService;
import com.rogiel.httpchannel.service.Service;
import com.rogiel.httpchannel.service.UploadChannel;
import com.rogiel.httpchannel.service.UploadListener;
import com.rogiel.httpchannel.service.UploadService;
import com.rogiel.httpchannel.service.UploaderCapability;
import com.rogiel.httpchannel.service.captcha.Captcha;
import com.rogiel.httpchannel.service.config.ServiceConfigurationHelper;
import com.rogiel.httpchannel.service.impl.MegaUploadService.MegaUploadServiceConfiguration;
public class MegaUploadServiceTest {
private Service service;
/**
* See <b>src/test/resources/config/megaupload.properties</b>
* <p>
* Key: username
*/
private String VALID_USERNAME;
/**
* See <b>src/test/resources/config/megaupload.properties</b>
* <p>
* Key: password
*/
private String VALID_PASSWORD;
private static final String INVALID_USERNAME = "invalid";
private static final String INVALID_PASSWORD = "abc";
@Before
public void setUp() throws Exception {
// MegaUploadServiceConfiguration.class;
service = new MegaUploadService(
ServiceConfigurationHelper
.defaultConfiguration(MegaUploadServiceConfiguration.class));
final Properties properties = new Properties();
properties.load(new FileInputStream(
"src/test/resources/config/megaupload.properties"));
VALID_USERNAME = properties.getProperty("username");
VALID_PASSWORD = properties.getProperty("password");
}
@Test
public void testServiceId() {
System.out.println("Service: "+service.toString());
assertEquals("megaupload", service.getId());
}
@Test
public void testValidAuthenticator() throws IOException {
((AuthenticationService) service).getAuthenticator(
new Credential(VALID_USERNAME, VALID_PASSWORD)).login(
new AuthenticatorListener() {
@Override
public void invalidCredentials(Credential credential) {
fail("This login attemp should've been successful.");
}
@Override
public void loginSuccessful(Credential credential) {
}
@Override
public void logout(Credential credential) {
}
@Override
public void exception(IOException e) throws IOException {
throw e;
}
});
}
@Test
public void testInvalidAuthenticator() throws IOException {
((AuthenticationService) service).getAuthenticator(
new Credential(INVALID_USERNAME, INVALID_PASSWORD)).login(
new AuthenticatorListener() {
@Override
public void invalidCredentials(Credential credential) {
}
@Override
public void loginSuccessful(Credential credential) {
fail("This login attemp should't have been successful.");
}
@Override
public void logout(Credential credential) {
}
@Override
public void exception(IOException e) throws IOException {
throw e;
}
});
}
@Test
public void testNonLoguedInUploader() throws IOException {
assertTrue(
"This service does not have the capability UploadCapability.FREE_UPLOAD",
((UploadService) service).getUploadCapabilities().has(
UploaderCapability.NON_PREMIUM_ACCOUNT_UPLOAD));
final UploadChannel channel = ((UploadService) service).getUploader(
"Upload by httpchannel").upload(new UploadListener() {
@Override
public long getFilesize() {
return 10;
}
@Override
public String getFilename() {
return "test.bin";
}
});
final ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.flip();
channel.write(buffer);
channel.close();
Assert.assertNotNull(channel.getDownloadLink());
}
@Test
public void testLoguedInUploader() throws IOException {
assertTrue(
"This service does not have the capability UploadCapability.PREMIUM_UPLOAD",
((UploadService) service).getUploadCapabilities().has(
UploaderCapability.PREMIUM_ACCOUNT_UPLOAD));
((AuthenticationService) service).getAuthenticator(
new Credential(VALID_USERNAME, VALID_PASSWORD)).login(
new AuthenticatorListener() {
@Override
public void invalidCredentials(Credential credential) {
fail("Invalid credentials");
}
@Override
public void loginSuccessful(Credential credential) {
}
@Override
public void logout(Credential credential) {
}
@Override
public void exception(IOException e) throws IOException {
// TODO Auto-generated method stub
}
});
final UploadChannel channel = ((UploadService) service).getUploader(
"Upload by httpchannel").upload(new UploadListener() {
@Override
public long getFilesize() {
return 10;
}
@Override
public String getFilename() {
return "test.bin";
}
});
final ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.put((byte) 0x00);
buffer.flip();
channel.write(buffer);
channel.close();
Assert.assertNotNull(channel.getDownloadLink());
}
@Test
public void testDownloader() throws IOException, MalformedURLException {
final DownloadChannel channel = ((DownloadService) service)
.getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM"))
.download(new DownloadListener() {
@Override
public boolean timer(long time, TimerWaitReason reason) {
System.out.println("Waiting " + time + " in " + reason);
// if (reason == TimerWaitReason.DOWNLOAD_TIMER)
// return true;
return true;
}
@Override
public String captcha(Captcha captcha) {
return null;
}
});
final ByteArrayOutputStream bout = new ByteArrayOutputStream();
IOUtils.copy(Channels.newInputStream(channel), bout);
System.out.println(bout.size());
}
@Test
public void testNoWaitDownloader() throws IOException,
MalformedURLException {
service = new MegaUploadService(ServiceConfigurationHelper.file(
MegaUploadServiceConfiguration.class, new File(
"src/test/resources/megaupload-nowait.properties")));
final DownloadChannel channel = ((DownloadService) service)
.getDownloader(new URL("http://www.megaupload.com/?d=CVQKJ1KM"))
.download(new DownloadListener() {
@Override
public boolean timer(long time, TimerWaitReason reason) {
System.out.println("Waiting " + time + " in " + reason);
if (reason == TimerWaitReason.DOWNLOAD_TIMER)
return true;
return false;
}
@Override
public String captcha(Captcha captcha) {
// TODO Auto-generated method stub
return null;
}
});
}
}