1 package ch
.cyberduck
.core
.ftp
;
4 * Copyright (c) 2002-2013 David Kocher. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * Bug fixes, suggestions and comments should be sent to feedback@cyberduck.ch
20 import ch
.cyberduck
.core
.DisabledHostKeyCallback
;
21 import ch
.cyberduck
.core
.DisabledLoginCallback
;
22 import ch
.cyberduck
.core
.DisabledPasswordStore
;
23 import ch
.cyberduck
.core
.DisabledTranscriptListener
;
24 import ch
.cyberduck
.core
.HostPasswordStore
;
25 import ch
.cyberduck
.core
.LoginCallback
;
26 import ch
.cyberduck
.core
.LoginConnectionService
;
27 import ch
.cyberduck
.core
.PathCache
;
28 import ch
.cyberduck
.core
.ProgressListener
;
29 import ch
.cyberduck
.core
.exception
.AccessDeniedException
;
30 import ch
.cyberduck
.core
.exception
.BackgroundException
;
31 import ch
.cyberduck
.core
.exception
.ConnectionTimeoutException
;
32 import ch
.cyberduck
.core
.exception
.InteroperabilityException
;
33 import ch
.cyberduck
.core
.exception
.NotfoundException
;
34 import ch
.cyberduck
.core
.preferences
.PreferencesFactory
;
36 import org
.apache
.log4j
.Logger
;
38 import java
.io
.IOException
;
43 public class FTPDataFallback
{
44 private static final Logger log
= Logger
.getLogger(FTPDataFallback
.class);
46 private final FTPSession session
;
48 private final HostPasswordStore keychain
;
50 private final LoginCallback prompt
;
52 public FTPDataFallback(final FTPSession session
) {
53 this(session
, new DisabledPasswordStore(), new DisabledLoginCallback());
56 public FTPDataFallback(final FTPSession session
, final HostPasswordStore keychain
, final LoginCallback prompt
) {
57 this.session
= session
;
58 this.keychain
= keychain
;
63 * @param action Action that needs to open a data connection
64 * @param listener Progress callback
65 * @return True if action was successful
67 protected <T
> T
data(final DataConnectionAction
<T
> action
, final ProgressListener listener
)
68 throws IOException
, BackgroundException
{
70 // Make sure to always configure data mode because connect event sets defaults.
71 if(session
.getConnectMode().equals(FTPConnectMode
.passive
)) {
72 session
.getClient().enterLocalPassiveMode();
74 else if(session
.getConnectMode().equals(FTPConnectMode
.active
)) {
75 session
.getClient().enterLocalActiveMode();
77 return action
.execute();
79 catch(ConnectionTimeoutException failure
) {
80 log
.warn(String
.format("Timeout opening data socket %s", failure
.getMessage()));
82 if(PreferencesFactory
.get().getBoolean("ftp.connectmode.fallback")) {
85 session
.getClient().completePendingCommand();
86 // Expect 421 response
87 log
.warn(String
.format("Aborted connection %d %s",
88 session
.getClient().getReplyCode(), session
.getClient().getReplyString()));
90 catch(IOException e
) {
91 log
.warn(String
.format("Ignore failure completing pending command %s", e
.getMessage()));
93 new LoginConnectionService(
95 new DisabledHostKeyCallback(),
98 new DisabledTranscriptListener()
99 ).connect(session
, PathCache
.empty());
101 return this.fallback(action
);
103 catch(BackgroundException e
) {
104 log
.warn(String
.format("Connect mode fallback failed with %s", e
.getMessage()));
105 // Throw original error message
110 catch(InteroperabilityException
| NotfoundException
| AccessDeniedException failure
) {
111 log
.warn(String
.format("Server denied data socket operation with %s", failure
.getMessage()));
113 if(PreferencesFactory
.get().getBoolean("ftp.connectmode.fallback")) {
115 return this.fallback(action
);
117 catch(BackgroundException e
) {
118 log
.warn(String
.format("Connect mode fallback failed with %s", e
.getMessage()));
119 // Throw original error message
127 * @param action Action that needs to open a data connection
128 * @return True if action was successful
130 protected <T
> T
fallback(final DataConnectionAction
<T
> action
) throws BackgroundException
{
131 // Fallback to other connect mode
132 if(session
.getClient().getDataConnectionMode() == FTPClient
.PASSIVE_LOCAL_DATA_CONNECTION_MODE
) {
133 log
.warn("Fallback to active data connection");
134 session
.getClient().enterLocalActiveMode();
136 else if(session
.getClient().getDataConnectionMode() == FTPClient
.ACTIVE_LOCAL_DATA_CONNECTION_MODE
) {
137 log
.warn("Fallback to passive data connection");
138 session
.getClient().enterLocalPassiveMode();
140 return action
.execute();