001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.provider.ftp;
018
019import java.net.Proxy;
020import java.time.Duration;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.List;
024
025import org.apache.commons.lang3.Range;
026import org.apache.commons.net.ftp.FTPReply;
027import org.apache.commons.net.ftp.parser.FTPFileEntryParserFactory;
028import org.apache.commons.vfs2.FileContent;
029import org.apache.commons.vfs2.FileSystem;
030import org.apache.commons.vfs2.FileSystemConfigBuilder;
031import org.apache.commons.vfs2.FileSystemOptions;
032
033/**
034 * The config builder for various FTP configuration options.
035 */
036public class FtpFileSystemConfigBuilder extends FileSystemConfigBuilder {
037
038    private static final String PREFIX = FtpFileSystemConfigBuilder.class.getName();
039
040    private static final FtpFileSystemConfigBuilder BUILDER = new FtpFileSystemConfigBuilder();
041
042    private static final String AUTODETECT_UTF8 = PREFIX + ".AUTODETECT_UTF8";
043    private static final String CONNECT_TIMEOUT = PREFIX + ".CONNECT_TIMEOUT";
044    private static final String DATA_TIMEOUT = PREFIX + ".DATA_TIMEOUT";
045    private static final String DEFAULT_DATE_FORMAT = PREFIX + ".DEFAULT_DATE_FORMAT";
046    private static final String ENCODING = PREFIX + ".ENCODING";
047    private static final String FACTORY_KEY = FTPFileEntryParserFactory.class.getName() + ".KEY";
048    private static final String FILE_TYPE = PREFIX + ".FILE_TYPE";
049    private static final String PASSIVE_MODE = PREFIX + ".PASSIVE";
050    private static final String ACTIVE_PORT_RANGE = PREFIX + ".ACTIVE_PORT_RANGE";
051    private static final String PROXY = PREFIX + ".PROXY";
052    private static final String RECENT_DATE_FORMAT = PREFIX + ".RECENT_DATE_FORMAT";
053    private static final String REMOTE_VERIFICATION = PREFIX + ".REMOTE_VERIFICATION";
054    private static final String SERVER_LANGUAGE_CODE = PREFIX + ".SERVER_LANGUAGE_CODE";
055    private static final String SERVER_TIME_ZONE_ID = PREFIX + ".SERVER_TIME_ZONE_ID";
056    private static final String SHORT_MONTH_NAMES = PREFIX + ".SHORT_MONTH_NAMES";
057    private static final String SO_TIMEOUT = PREFIX + ".SO_TIMEOUT";
058    private static final String CONTROL_KEEP_ALIVE_TIMEOUT = PREFIX + ".CONTROL_KEEP_ALIVE_TIMEOUT";
059    private static final String CONTROL_KEEP_ALIVE_REPLY_TIMEOUT = PREFIX + ".CONTROL_KEEP_ALIVE_REPLY_TIMEOUT";
060    private static final String USER_DIR_IS_ROOT = PREFIX + ".USER_DIR_IS_ROOT";
061    private static final String TRANSFER_ABORTED_OK_REPLY_CODES = PREFIX + ".TRANSFER_ABORTED_OK_REPLY_CODES";
062    private static final String MDTM_LAST_MODIFED_TIME = PREFIX + ".MDTM_LAST_MODIFED_TIME";
063
064    /**
065     * Gets the singleton instance.
066     *
067     * @return the singleton instance.
068     */
069    public static FtpFileSystemConfigBuilder getInstance() {
070        return BUILDER;
071    }
072
073    /**
074     * Gets special retry code.
075     *
076     * See VFS-674, its accompanying PR and https://github.com/apache/commons-vfs/pull/51 as to why 426 and 550 are here.
077     *
078     * @return special retry code.
079     */
080    public static List<Integer> getSaneTransferAbortedOkReplyCodes() {
081        // See VFS-674, its accompanying PR and https://github.com/apache/commons-vfs/pull/51 as to why 426 and 550 are here
082        return new ArrayList<>(Arrays.asList(FTPReply.TRANSFER_ABORTED, FTPReply.FILE_UNAVAILABLE));
083    }
084
085    private FtpFileSystemConfigBuilder() {
086        super("ftp.");
087    }
088
089    /**
090     * Create new config builder with specified prefix string.
091     *
092     * @param prefix prefix string to use for parameters of this config builder.
093     * @since 2.1
094     */
095    protected FtpFileSystemConfigBuilder(final String prefix) {
096        super(prefix);
097    }
098
099    /**
100     * Gets the active port range.
101     *
102     * @param options The FileSystemOptions.
103     * @return the Range of active ports
104     * @since 2.10.0
105     */
106    public Range<Integer> getActivePortRange(final FileSystemOptions options) {
107        return getParam(options, ACTIVE_PORT_RANGE);
108    }
109
110    /**
111     * Gets whether to try to autodetect the server encoding (only UTF8 is supported).
112     *
113     * @param options The FileSystemOptions.
114     * @return True if autodetection should be done.
115     * @since 2.4
116     */
117    public Boolean getAutodetectUtf8(final FileSystemOptions options) {
118        return getBoolean(options, AUTODETECT_UTF8);
119    }
120
121    @Override
122    protected Class<? extends FileSystem> getConfigClass() {
123        return FtpFileSystem.class;
124    }
125
126    /**
127     * Gets the timeout in milliseconds to use for the socket connection.
128     *
129     * @param options The FileSystemOptions.
130     * @return The timeout in milliseconds to use for the socket connection.
131     * @since 2.1
132     * @deprecated Use {@link #getConnectTimeoutDuration(FileSystemOptions)}.
133     */
134    @Deprecated
135    public Integer getConnectTimeout(final FileSystemOptions options) {
136        return getDurationInteger(options, CONNECT_TIMEOUT);
137    }
138
139    /**
140     * Gets the timeout in milliseconds to use for the socket connection.
141     *
142     * @param options The FileSystemOptions.
143     * @return The timeout in milliseconds to use for the socket connection.
144     * @since 2.8.0
145     */
146    public Duration getConnectTimeoutDuration(final FileSystemOptions options) {
147        return getDuration(options, CONNECT_TIMEOUT);
148    }
149
150    /**
151     * Gets the control encoding.
152     *
153     * @param options The FileSystemOptions.
154     * @return The control encoding.
155     * @since 2.0
156     */
157    public String getControlEncoding(final FileSystemOptions options) {
158        return getString(options, ENCODING);
159    }
160
161    /**
162     * Gets the controlKeepAliveReplyTimeout duration.
163     *
164     * @param options The FileSystem options
165     * @return The controlKeepAliveReplyTimeout duration.
166     * @since 2.8.0
167     */
168    public Duration getControlKeepAliveReplyTimeout(final FileSystemOptions options) {
169        return getDuration(options, CONTROL_KEEP_ALIVE_REPLY_TIMEOUT);
170    }
171
172    /**
173     * Gets the controlKeepAliveTimeout duration.
174     *
175     * @param options The FileSystem options
176     * @return The controlKeepAliveTimeout duration.
177     * @since 2.8.0
178     */
179    public Duration getControlKeepAliveTimeout(final FileSystemOptions options) {
180        return getDuration(options, CONTROL_KEEP_ALIVE_TIMEOUT);
181    }
182
183    /**
184     * Gets timeout for opening the data channel in milliseconds.
185     *
186     * @param options The FileSystemOptions.
187     * @return The timeout for opening the data channel in milliseconds.
188     * @see #setDataTimeout
189     * @deprecated Use {@link #getDataTimeoutDuration(FileSystemOptions)}.
190     */
191    @Deprecated
192    public Integer getDataTimeout(final FileSystemOptions options) {
193        return getDurationInteger(options, DATA_TIMEOUT);
194    }
195
196    /**
197     * Gets the timeout for opening the data channel.
198     *
199     * @param options The FileSystemOptions.
200     * @return The timeout for opening the data channel.
201     * @see #setDataTimeout
202     * @since 2.8.0
203     */
204    public Duration getDataTimeoutDuration(final FileSystemOptions options) {
205        return getDuration(options, DATA_TIMEOUT);
206    }
207
208    /**
209     * Gets the default date format used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for
210     * details and examples.
211     *
212     * @param options The FileSystemOptions
213     * @return The default date format.
214     */
215    public String getDefaultDateFormat(final FileSystemOptions options) {
216        return getString(options, DEFAULT_DATE_FORMAT);
217    }
218
219    /**
220     * Gets the key to the EntryParser.
221     *
222     * @param options The FileSystemOptions.
223     * @see #setEntryParser
224     * @return the key to the EntryParser.
225     */
226    public String getEntryParser(final FileSystemOptions options) {
227        return getString(options, FACTORY_KEY);
228    }
229
230    /**
231     * Gets the FTPFileEntryParserFactory parameter.
232     *
233     * @param options The FileSystemOptions.
234     * @see #setEntryParserFactory
235     * @return The FTPFileEntryParserFactory parameter.
236     */
237    public FTPFileEntryParserFactory getEntryParserFactory(final FileSystemOptions options) {
238        return getParam(options, FTPFileEntryParserFactory.class.getName());
239    }
240
241    /**
242     * Gets the file type parameter.
243     *
244     * @param options The FileSystemOptions.
245     * @return A FtpFileType
246     * @since 2.1
247     */
248    public FtpFileType getFileType(final FileSystemOptions options) {
249        return getEnum(FtpFileType.class, options, FILE_TYPE);
250    }
251
252    /**
253     * Gets the option to use FTP MDTM for {@link FileContent#getLastModifiedTime()}.
254     *
255     * @param options The FileSystemOptions.
256     * @return true if MDTM should be used.
257     * @since 2.8.0
258     */
259    public Boolean getMdtmLastModifiedTime(final FileSystemOptions options) {
260        return getBoolean(options, MDTM_LAST_MODIFED_TIME);
261    }
262
263    /**
264     * Tests whether passive mode is set.
265     *
266     * @param options The FileSystemOptions.
267     * @return whether passive mode is set.
268     * @see #setPassiveMode
269     */
270    public Boolean getPassiveMode(final FileSystemOptions options) {
271        return getBoolean(options, PASSIVE_MODE);
272    }
273
274    /**
275     * Gets the Proxy.
276     *
277     * @param options The FileSystemOptions.
278     * @return the Proxy
279     * @since 2.1
280     */
281    public Proxy getProxy(final FileSystemOptions options) {
282        return getParam(options, PROXY);
283    }
284
285    /**
286     * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
287     *
288     * @param options The FileSystemOptions.
289     * @return The recent date format.
290     */
291    public String getRecentDateFormat(final FileSystemOptions options) {
292        return getString(options, RECENT_DATE_FORMAT);
293    }
294
295    /**
296     * Gets whether to use remote verification.
297     *
298     * @param options The FileSystemOptions.
299     * @return True if remote verification should be done.
300     */
301    public Boolean getRemoteVerification(final FileSystemOptions options) {
302        return getBoolean(options, REMOTE_VERIFICATION);
303    }
304
305    /**
306     * Gets the language code used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and
307     * examples.
308     *
309     * @param options The FilesystemOptions.
310     * @return The language code of the server.
311     */
312    public String getServerLanguageCode(final FileSystemOptions options) {
313        return getString(options, SERVER_LANGUAGE_CODE);
314    }
315
316    /**
317     * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
318     *
319     * @param options The FileSystemOptions.
320     * @return The server timezone id.
321     */
322    public String getServerTimeZoneId(final FileSystemOptions options) {
323        return getString(options, SERVER_TIME_ZONE_ID);
324    }
325
326    /**
327     * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
328     *
329     * @param options The FileSystemOptions.
330     * @return An array of short month names.
331     */
332    public String[] getShortMonthNames(final FileSystemOptions options) {
333        return getParam(options, SHORT_MONTH_NAMES);
334    }
335
336    /**
337     * Gets The so timeout duration in milliseconds.
338     *
339     * @param options The FileSystem options.
340     * @return The so timeout duration in milliseconds.
341     * @see #getDataTimeout
342     * @since 2.0
343     * @deprecated Use {@link #getSoTimeoutDuration(FileSystemOptions)}.
344     */
345    @Deprecated
346    public Integer getSoTimeout(final FileSystemOptions options) {
347        return getDurationInteger(options, SO_TIMEOUT);
348    }
349
350    /**
351     * Gets The so timeout duration.
352     *
353     * @param options The FileSystem options.
354     * @return The timeout value in milliseconds.
355     * @see #getDataTimeout
356     * @since 2.8.0
357     */
358    public Duration getSoTimeoutDuration(final FileSystemOptions options) {
359        return getDuration(options, SO_TIMEOUT);
360    }
361
362    /**
363     * Gets the list of reply codes (apart from 200) that are considered as OK when prematurely closing a stream.
364     *
365     * @param options The FileSystem options.
366     * @return The list of reply codes (apart from 200) that are considered as OK when prematurely closing a stream.
367     * @since 2.4
368     */
369    public List<Integer> getTransferAbortedOkReplyCodes(final FileSystemOptions options) {
370        return getParam(options, TRANSFER_ABORTED_OK_REPLY_CODES);
371    }
372
373    /**
374     * Tests whether if VFS should treat the user directory as the root directory. Defaults to
375     * {@code Boolean.TRUE} if the method {@link #setUserDirIsRoot(FileSystemOptions, boolean)} has not been
376     * invoked.
377     *
378     * @param options The FileSystemOptions.
379     * @return {@code Boolean.TRUE} if VFS treats the user directory as the root directory.
380     * @see #setUserDirIsRoot
381     */
382    public Boolean getUserDirIsRoot(final FileSystemOptions options) {
383        return getBoolean(options, USER_DIR_IS_ROOT, Boolean.TRUE);
384    }
385
386    /**
387     * Sets the active port range.
388     *
389     * @param options   The FileSystemOptions.
390     * @param portRange the Range of active ports
391     * @since 2.10.0
392     */
393    public void setActivePortRange(final FileSystemOptions options, final Range<Integer> portRange) {
394        setParam(options, ACTIVE_PORT_RANGE, portRange);
395    }
396
397    /**
398     * Sets whether to try to autodetect the server encoding (only UTF8 is supported).
399     *
400     * @param options The FileSystemOptions.
401     * @param autodetectUTF8 true if autodetection should be done.
402     * @since 2.4
403     */
404    public void setAutodetectUtf8(final FileSystemOptions options, final Boolean autodetectUTF8) {
405        setParam(options, AUTODETECT_UTF8, autodetectUTF8);
406    }
407
408    /**
409     * Sets the timeout for the initial control connection.
410     * <p>
411     * If you set the connectTimeout to {@code null} no connectTimeout will be set.
412     * </p>
413     *
414     * @param options The FileSystemOptions.
415     * @param duration the timeout duration in milliseconds
416     * @since 2.8.0
417     */
418    public void setConnectTimeout(final FileSystemOptions options, final Duration duration) {
419        setParam(options, CONNECT_TIMEOUT, duration);
420    }
421
422    /**
423     * Sets the timeout for the initial control connection.
424     * <p>
425     * If you set the connectTimeout to {@code null} no connectTimeout will be set.
426     * </p>
427     *
428     * @param options The FileSystemOptions.
429     * @param duration the timeout duration.
430     * @since 2.1
431     * @deprecated Use {@link #setConnectTimeout(FileSystemOptions, Duration)}.
432     */
433    @Deprecated
434    public void setConnectTimeout(final FileSystemOptions options, final Integer duration) {
435        setConnectTimeout(options, Duration.ofMillis(duration));
436    }
437
438    /**
439     * See {@link org.apache.commons.net.ftp.FTP#setControlEncoding} for details and examples.
440     *
441     * @param options The FileSystemOptions.
442     * @param encoding the encoding to use
443     * @since 2.0
444     */
445    public void setControlEncoding(final FileSystemOptions options, final String encoding) {
446        setParam(options, ENCODING, encoding);
447    }
448
449    /**
450     * Sets the control keep alive reply timeout for the FTP client.
451     *
452     * @param options The FileSystem options.
453     * @param duration timeout duration.
454     * @since 2.8.0
455     */
456    public void setControlKeepAliveReplyTimeout(final FileSystemOptions options, final Duration duration) {
457        setParam(options, CONTROL_KEEP_ALIVE_REPLY_TIMEOUT, duration);
458    }
459
460    /**
461     * Sets the control keep alive timeout for the FTP client.
462     * <p>
463     * Sets the {@code controlKeepAliveTimeout} to ensure the socket be alive after download huge file.
464     * </p>
465     *
466     * @param options The FileSystem options.
467     * @param duration The timeout duration.
468     * @since 2.8.0
469     */
470    public void setControlKeepAliveTimeout(final FileSystemOptions options, final Duration duration) {
471        setParam(options, CONTROL_KEEP_ALIVE_TIMEOUT, duration);
472    }
473
474    /**
475     * Sets the data timeout for the FTP client.
476     * <p>
477     * If you set the {@code dataTimeout} to {@code null}, no dataTimeout will be set on the FTP client.
478     * </p>
479     *
480     * @param options The FileSystemOptions.
481     * @param duration The timeout duration.
482     * @since 2.8.0
483     */
484    public void setDataTimeout(final FileSystemOptions options, final Duration duration) {
485        setParam(options, DATA_TIMEOUT, duration);
486    }
487
488    /**
489     * Sets the data timeout for the FTP client.
490     * <p>
491     * If you set the {@code dataTimeout} to {@code null}, no dataTimeout will be set on the FTP client.
492     * </p>
493     *
494     * @param options The FileSystemOptions.
495     * @param duration The timeout value.
496     * @deprecated Use {@link #setDataTimeout(FileSystemOptions, Duration)}.
497     */
498    @Deprecated
499    public void setDataTimeout(final FileSystemOptions options, final Integer duration) {
500        setDataTimeout(options, Duration.ofMillis(duration));
501    }
502
503    /**
504     * Sets the default date format used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for
505     * details and examples.
506     *
507     * @param options The FileSystemOptions.
508     * @param defaultDateFormat The default date format.
509     */
510    public void setDefaultDateFormat(final FileSystemOptions options, final String defaultDateFormat) {
511        setParam(options, DEFAULT_DATE_FORMAT, defaultDateFormat);
512    }
513
514    /**
515     * Sets the FQCN of your FileEntryParser used to parse the directory listing from your server.
516     * <p>
517     * If you do not use the default commons-net FTPFileEntryParserFactory e.g. by using {@link #setEntryParserFactory}
518     * this is the "key" parameter passed as argument into your custom factory.
519     * </p>
520     *
521     * @param options The FileSystemOptions.
522     * @param key The key.
523     */
524    public void setEntryParser(final FileSystemOptions options, final String key) {
525        setParam(options, FACTORY_KEY, key);
526    }
527
528    /**
529     * FTPFileEntryParserFactory which will be used for ftp-entry parsing.
530     *
531     * @param options The FileSystemOptions.
532     * @param factory instance of your factory
533     */
534    public void setEntryParserFactory(final FileSystemOptions options, final FTPFileEntryParserFactory factory) {
535        setParam(options, FTPFileEntryParserFactory.class.getName(), factory);
536    }
537
538    /**
539     * Sets the file type parameter.
540     *
541     * @param options The FileSystemOptions.
542     * @param ftpFileType A FtpFileType
543     * @since 2.1
544     */
545    public void setFileType(final FileSystemOptions options, final FtpFileType ftpFileType) {
546        setParam(options, FILE_TYPE, ftpFileType);
547    }
548
549    /**
550     * Sets the option to use FTP MDTM for {@link FileContent#getLastModifiedTime()}.
551     *
552     * @param options The FileSystemOptions.
553     * @param mdtm true if MDTM should be used.
554     * @since 2.8.0
555     */
556    public void setMdtmLastModifiedTime(final FileSystemOptions options, final boolean mdtm) {
557        setParam(options, MDTM_LAST_MODIFED_TIME, toBooleanObject(mdtm));
558    }
559
560    /**
561     * Enter into passive mode.
562     *
563     * @param options The FileSystemOptions.
564     * @param passiveMode true if passive mode should be used.
565     */
566    public void setPassiveMode(final FileSystemOptions options, final boolean passiveMode) {
567        setParam(options, PASSIVE_MODE, toBooleanObject(passiveMode));
568    }
569
570    /**
571     * Sets the Proxy.
572     * <p>
573     * You might need to make sure that {@link #setPassiveMode(FileSystemOptions, boolean) passive mode} is activated.
574     * </p>
575     *
576     * @param options the FileSystem options.
577     * @param proxy the Proxy
578     * @since 2.1
579     */
580    public void setProxy(final FileSystemOptions options, final Proxy proxy) {
581        setParam(options, PROXY, proxy);
582    }
583
584    /**
585     * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
586     *
587     * @param options The FileSystemOptions.
588     * @param recentDateFormat The recent date format.
589     */
590    public void setRecentDateFormat(final FileSystemOptions options, final String recentDateFormat) {
591        setParam(options, RECENT_DATE_FORMAT, recentDateFormat);
592    }
593
594    /**
595     * Sets whether to use remote verification.
596     *
597     * @param options The FileSystemOptions.
598     * @param remoteVerification True if verification should be done.
599     */
600    public void setRemoteVerification(final FileSystemOptions options, final boolean remoteVerification) {
601        setParam(options, REMOTE_VERIFICATION, remoteVerification);
602    }
603
604    /**
605     * Sets the language code used by the server. See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and
606     * examples.
607     *
608     * @param options The FileSystemOptions.
609     * @param serverLanguageCode The servers language code.
610     */
611    public void setServerLanguageCode(final FileSystemOptions options, final String serverLanguageCode) {
612        setParam(options, SERVER_LANGUAGE_CODE, serverLanguageCode);
613    }
614
615    /**
616     * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
617     *
618     * @param options The FileSystemOptions.
619     * @param serverTimeZoneId The server timezone id.
620     */
621    public void setServerTimeZoneId(final FileSystemOptions options, final String serverTimeZoneId) {
622        setParam(options, SERVER_TIME_ZONE_ID, serverTimeZoneId);
623    }
624
625    /**
626     * See {@link org.apache.commons.net.ftp.FTPClientConfig} for details and examples.
627     *
628     * @param options The FileSystemOptions.
629     * @param shortMonthNames an array of short month name Strings.
630     */
631    public void setShortMonthNames(final FileSystemOptions options, final String[] shortMonthNames) {
632        String[] clone = null;
633        if (shortMonthNames != null) {
634            clone = Arrays.copyOf(shortMonthNames, shortMonthNames.length);
635        }
636
637        setParam(options, SHORT_MONTH_NAMES, clone);
638    }
639
640    /**
641     * Sets the socket timeout for the FTP client.
642     * <p>
643     * If you set the {@code soTimeout} to {@code null}, no socket timeout will be set on the FTP client.
644     * </p>
645     *
646     * @param options The FileSystem options.
647     * @param timeout The timeout value in milliseconds.
648     * @since 2.8.0
649     */
650    public void setSoTimeout(final FileSystemOptions options, final Duration timeout) {
651        setParam(options, SO_TIMEOUT, timeout);
652    }
653
654    /**
655     * Sets the socket timeout for the FTP client.
656     * <p>
657     * If you set the {@code soTimeout} to {@code null}, no socket timeout will be set on the FTP client.
658     * </p>
659     *
660     * @param options The FileSystem options.
661     * @param timeout The timeout value in milliseconds.
662     * @since 2.0
663     * @deprecated Use {@link #setSoTimeout(FileSystemOptions, Duration)}.
664     */
665    @Deprecated
666    public void setSoTimeout(final FileSystemOptions options, final Integer timeout) {
667        setSoTimeout(options, Duration.ofMillis(timeout));
668    }
669
670    /**
671     * Sets the list of reply codes that are considered as OK when prematurely closing a stream.
672     * <p>
673     * If you set the {@code replyCodes} to an empty list, all reply codes besides 200 will be
674     * considered as an error.
675     * </p>
676     *
677     * @param options The FileSystem options.
678     * @param replyCodes The reply codes.
679     * @since 2.4
680     */
681    public void setTransferAbortedOkReplyCodes(final FileSystemOptions options, final List<Integer> replyCodes) {
682        setParam(options, TRANSFER_ABORTED_OK_REPLY_CODES, replyCodes);
683    }
684
685    /**
686     * Use user directory as root (do not change to fs root).
687     *
688     * @param options The FileSystemOptions.
689     * @param userDirIsRoot true if the user directory should be treated as the root.
690     */
691    public void setUserDirIsRoot(final FileSystemOptions options, final boolean userDirIsRoot) {
692        setParam(options, USER_DIR_IS_ROOT, toBooleanObject(userDirIsRoot));
693    }
694}