113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci#ifndef CURL_DISABLE_FTP 2713498266Sopenharmony_ci#include <curl/curl.h> 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#include "curl_fnmatch.h" 3013498266Sopenharmony_ci#include "curl_memory.h" 3113498266Sopenharmony_ci 3213498266Sopenharmony_ci/* The last #include file should be: */ 3313498266Sopenharmony_ci#include "memdebug.h" 3413498266Sopenharmony_ci 3513498266Sopenharmony_ci#ifndef HAVE_FNMATCH 3613498266Sopenharmony_ci 3713498266Sopenharmony_ci#define CURLFNM_CHARSET_LEN (sizeof(char) * 256) 3813498266Sopenharmony_ci#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15) 3913498266Sopenharmony_ci 4013498266Sopenharmony_ci#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN 4113498266Sopenharmony_ci 4213498266Sopenharmony_ci#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1) 4313498266Sopenharmony_ci#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2) 4413498266Sopenharmony_ci#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3) 4513498266Sopenharmony_ci#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4) 4613498266Sopenharmony_ci#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5) 4713498266Sopenharmony_ci#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6) 4813498266Sopenharmony_ci#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7) 4913498266Sopenharmony_ci#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8) 5013498266Sopenharmony_ci#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9) 5113498266Sopenharmony_ci#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10) 5213498266Sopenharmony_ci 5313498266Sopenharmony_citypedef enum { 5413498266Sopenharmony_ci CURLFNM_SCHS_DEFAULT = 0, 5513498266Sopenharmony_ci CURLFNM_SCHS_RIGHTBR, 5613498266Sopenharmony_ci CURLFNM_SCHS_RIGHTBRLEFTBR 5713498266Sopenharmony_ci} setcharset_state; 5813498266Sopenharmony_ci 5913498266Sopenharmony_citypedef enum { 6013498266Sopenharmony_ci CURLFNM_PKW_INIT = 0, 6113498266Sopenharmony_ci CURLFNM_PKW_DDOT 6213498266Sopenharmony_ci} parsekey_state; 6313498266Sopenharmony_ci 6413498266Sopenharmony_citypedef enum { 6513498266Sopenharmony_ci CCLASS_OTHER = 0, 6613498266Sopenharmony_ci CCLASS_DIGIT, 6713498266Sopenharmony_ci CCLASS_UPPER, 6813498266Sopenharmony_ci CCLASS_LOWER 6913498266Sopenharmony_ci} char_class; 7013498266Sopenharmony_ci 7113498266Sopenharmony_ci#define SETCHARSET_OK 1 7213498266Sopenharmony_ci#define SETCHARSET_FAIL 0 7313498266Sopenharmony_ci 7413498266Sopenharmony_cistatic int parsekeyword(unsigned char **pattern, unsigned char *charset) 7513498266Sopenharmony_ci{ 7613498266Sopenharmony_ci parsekey_state state = CURLFNM_PKW_INIT; 7713498266Sopenharmony_ci#define KEYLEN 10 7813498266Sopenharmony_ci char keyword[KEYLEN] = { 0 }; 7913498266Sopenharmony_ci int i; 8013498266Sopenharmony_ci unsigned char *p = *pattern; 8113498266Sopenharmony_ci bool found = FALSE; 8213498266Sopenharmony_ci for(i = 0; !found; i++) { 8313498266Sopenharmony_ci char c = *p++; 8413498266Sopenharmony_ci if(i >= KEYLEN) 8513498266Sopenharmony_ci return SETCHARSET_FAIL; 8613498266Sopenharmony_ci switch(state) { 8713498266Sopenharmony_ci case CURLFNM_PKW_INIT: 8813498266Sopenharmony_ci if(ISLOWER(c)) 8913498266Sopenharmony_ci keyword[i] = c; 9013498266Sopenharmony_ci else if(c == ':') 9113498266Sopenharmony_ci state = CURLFNM_PKW_DDOT; 9213498266Sopenharmony_ci else 9313498266Sopenharmony_ci return SETCHARSET_FAIL; 9413498266Sopenharmony_ci break; 9513498266Sopenharmony_ci case CURLFNM_PKW_DDOT: 9613498266Sopenharmony_ci if(c == ']') 9713498266Sopenharmony_ci found = TRUE; 9813498266Sopenharmony_ci else 9913498266Sopenharmony_ci return SETCHARSET_FAIL; 10013498266Sopenharmony_ci } 10113498266Sopenharmony_ci } 10213498266Sopenharmony_ci#undef KEYLEN 10313498266Sopenharmony_ci 10413498266Sopenharmony_ci *pattern = p; /* move caller's pattern pointer */ 10513498266Sopenharmony_ci if(strcmp(keyword, "digit") == 0) 10613498266Sopenharmony_ci charset[CURLFNM_DIGIT] = 1; 10713498266Sopenharmony_ci else if(strcmp(keyword, "alnum") == 0) 10813498266Sopenharmony_ci charset[CURLFNM_ALNUM] = 1; 10913498266Sopenharmony_ci else if(strcmp(keyword, "alpha") == 0) 11013498266Sopenharmony_ci charset[CURLFNM_ALPHA] = 1; 11113498266Sopenharmony_ci else if(strcmp(keyword, "xdigit") == 0) 11213498266Sopenharmony_ci charset[CURLFNM_XDIGIT] = 1; 11313498266Sopenharmony_ci else if(strcmp(keyword, "print") == 0) 11413498266Sopenharmony_ci charset[CURLFNM_PRINT] = 1; 11513498266Sopenharmony_ci else if(strcmp(keyword, "graph") == 0) 11613498266Sopenharmony_ci charset[CURLFNM_GRAPH] = 1; 11713498266Sopenharmony_ci else if(strcmp(keyword, "space") == 0) 11813498266Sopenharmony_ci charset[CURLFNM_SPACE] = 1; 11913498266Sopenharmony_ci else if(strcmp(keyword, "blank") == 0) 12013498266Sopenharmony_ci charset[CURLFNM_BLANK] = 1; 12113498266Sopenharmony_ci else if(strcmp(keyword, "upper") == 0) 12213498266Sopenharmony_ci charset[CURLFNM_UPPER] = 1; 12313498266Sopenharmony_ci else if(strcmp(keyword, "lower") == 0) 12413498266Sopenharmony_ci charset[CURLFNM_LOWER] = 1; 12513498266Sopenharmony_ci else 12613498266Sopenharmony_ci return SETCHARSET_FAIL; 12713498266Sopenharmony_ci return SETCHARSET_OK; 12813498266Sopenharmony_ci} 12913498266Sopenharmony_ci 13013498266Sopenharmony_ci/* Return the character class. */ 13113498266Sopenharmony_cistatic char_class charclass(unsigned char c) 13213498266Sopenharmony_ci{ 13313498266Sopenharmony_ci if(ISUPPER(c)) 13413498266Sopenharmony_ci return CCLASS_UPPER; 13513498266Sopenharmony_ci if(ISLOWER(c)) 13613498266Sopenharmony_ci return CCLASS_LOWER; 13713498266Sopenharmony_ci if(ISDIGIT(c)) 13813498266Sopenharmony_ci return CCLASS_DIGIT; 13913498266Sopenharmony_ci return CCLASS_OTHER; 14013498266Sopenharmony_ci} 14113498266Sopenharmony_ci 14213498266Sopenharmony_ci/* Include a character or a range in set. */ 14313498266Sopenharmony_cistatic void setcharorrange(unsigned char **pp, unsigned char *charset) 14413498266Sopenharmony_ci{ 14513498266Sopenharmony_ci unsigned char *p = (*pp)++; 14613498266Sopenharmony_ci unsigned char c = *p++; 14713498266Sopenharmony_ci 14813498266Sopenharmony_ci charset[c] = 1; 14913498266Sopenharmony_ci if(ISALNUM(c) && *p++ == '-') { 15013498266Sopenharmony_ci char_class cc = charclass(c); 15113498266Sopenharmony_ci unsigned char endrange = *p++; 15213498266Sopenharmony_ci 15313498266Sopenharmony_ci if(endrange == '\\') 15413498266Sopenharmony_ci endrange = *p++; 15513498266Sopenharmony_ci if(endrange >= c && charclass(endrange) == cc) { 15613498266Sopenharmony_ci while(c++ != endrange) 15713498266Sopenharmony_ci if(charclass(c) == cc) /* Chars in class may be not consecutive. */ 15813498266Sopenharmony_ci charset[c] = 1; 15913498266Sopenharmony_ci *pp = p; 16013498266Sopenharmony_ci } 16113498266Sopenharmony_ci } 16213498266Sopenharmony_ci} 16313498266Sopenharmony_ci 16413498266Sopenharmony_ci/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */ 16513498266Sopenharmony_cistatic int setcharset(unsigned char **p, unsigned char *charset) 16613498266Sopenharmony_ci{ 16713498266Sopenharmony_ci setcharset_state state = CURLFNM_SCHS_DEFAULT; 16813498266Sopenharmony_ci bool something_found = FALSE; 16913498266Sopenharmony_ci unsigned char c; 17013498266Sopenharmony_ci 17113498266Sopenharmony_ci memset(charset, 0, CURLFNM_CHSET_SIZE); 17213498266Sopenharmony_ci for(;;) { 17313498266Sopenharmony_ci c = **p; 17413498266Sopenharmony_ci if(!c) 17513498266Sopenharmony_ci return SETCHARSET_FAIL; 17613498266Sopenharmony_ci 17713498266Sopenharmony_ci switch(state) { 17813498266Sopenharmony_ci case CURLFNM_SCHS_DEFAULT: 17913498266Sopenharmony_ci if(c == ']') { 18013498266Sopenharmony_ci if(something_found) 18113498266Sopenharmony_ci return SETCHARSET_OK; 18213498266Sopenharmony_ci something_found = TRUE; 18313498266Sopenharmony_ci state = CURLFNM_SCHS_RIGHTBR; 18413498266Sopenharmony_ci charset[c] = 1; 18513498266Sopenharmony_ci (*p)++; 18613498266Sopenharmony_ci } 18713498266Sopenharmony_ci else if(c == '[') { 18813498266Sopenharmony_ci unsigned char *pp = *p + 1; 18913498266Sopenharmony_ci 19013498266Sopenharmony_ci if(*pp++ == ':' && parsekeyword(&pp, charset)) 19113498266Sopenharmony_ci *p = pp; 19213498266Sopenharmony_ci else { 19313498266Sopenharmony_ci charset[c] = 1; 19413498266Sopenharmony_ci (*p)++; 19513498266Sopenharmony_ci } 19613498266Sopenharmony_ci something_found = TRUE; 19713498266Sopenharmony_ci } 19813498266Sopenharmony_ci else if(c == '^' || c == '!') { 19913498266Sopenharmony_ci if(!something_found) { 20013498266Sopenharmony_ci if(charset[CURLFNM_NEGATE]) { 20113498266Sopenharmony_ci charset[c] = 1; 20213498266Sopenharmony_ci something_found = TRUE; 20313498266Sopenharmony_ci } 20413498266Sopenharmony_ci else 20513498266Sopenharmony_ci charset[CURLFNM_NEGATE] = 1; /* negate charset */ 20613498266Sopenharmony_ci } 20713498266Sopenharmony_ci else 20813498266Sopenharmony_ci charset[c] = 1; 20913498266Sopenharmony_ci (*p)++; 21013498266Sopenharmony_ci } 21113498266Sopenharmony_ci else if(c == '\\') { 21213498266Sopenharmony_ci c = *(++(*p)); 21313498266Sopenharmony_ci if(c) 21413498266Sopenharmony_ci setcharorrange(p, charset); 21513498266Sopenharmony_ci else 21613498266Sopenharmony_ci charset['\\'] = 1; 21713498266Sopenharmony_ci something_found = TRUE; 21813498266Sopenharmony_ci } 21913498266Sopenharmony_ci else { 22013498266Sopenharmony_ci setcharorrange(p, charset); 22113498266Sopenharmony_ci something_found = TRUE; 22213498266Sopenharmony_ci } 22313498266Sopenharmony_ci break; 22413498266Sopenharmony_ci case CURLFNM_SCHS_RIGHTBR: 22513498266Sopenharmony_ci if(c == '[') { 22613498266Sopenharmony_ci state = CURLFNM_SCHS_RIGHTBRLEFTBR; 22713498266Sopenharmony_ci charset[c] = 1; 22813498266Sopenharmony_ci (*p)++; 22913498266Sopenharmony_ci } 23013498266Sopenharmony_ci else if(c == ']') { 23113498266Sopenharmony_ci return SETCHARSET_OK; 23213498266Sopenharmony_ci } 23313498266Sopenharmony_ci else if(ISPRINT(c)) { 23413498266Sopenharmony_ci charset[c] = 1; 23513498266Sopenharmony_ci (*p)++; 23613498266Sopenharmony_ci state = CURLFNM_SCHS_DEFAULT; 23713498266Sopenharmony_ci } 23813498266Sopenharmony_ci else 23913498266Sopenharmony_ci /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a 24013498266Sopenharmony_ci * nonsense warning 'statement not reached' at end of the fnc when 24113498266Sopenharmony_ci * compiling on Solaris */ 24213498266Sopenharmony_ci goto fail; 24313498266Sopenharmony_ci break; 24413498266Sopenharmony_ci case CURLFNM_SCHS_RIGHTBRLEFTBR: 24513498266Sopenharmony_ci if(c == ']') 24613498266Sopenharmony_ci return SETCHARSET_OK; 24713498266Sopenharmony_ci state = CURLFNM_SCHS_DEFAULT; 24813498266Sopenharmony_ci charset[c] = 1; 24913498266Sopenharmony_ci (*p)++; 25013498266Sopenharmony_ci break; 25113498266Sopenharmony_ci } 25213498266Sopenharmony_ci } 25313498266Sopenharmony_cifail: 25413498266Sopenharmony_ci return SETCHARSET_FAIL; 25513498266Sopenharmony_ci} 25613498266Sopenharmony_ci 25713498266Sopenharmony_cistatic int loop(const unsigned char *pattern, const unsigned char *string, 25813498266Sopenharmony_ci int maxstars) 25913498266Sopenharmony_ci{ 26013498266Sopenharmony_ci unsigned char *p = (unsigned char *)pattern; 26113498266Sopenharmony_ci unsigned char *s = (unsigned char *)string; 26213498266Sopenharmony_ci unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 }; 26313498266Sopenharmony_ci 26413498266Sopenharmony_ci for(;;) { 26513498266Sopenharmony_ci unsigned char *pp; 26613498266Sopenharmony_ci 26713498266Sopenharmony_ci switch(*p) { 26813498266Sopenharmony_ci case '*': 26913498266Sopenharmony_ci if(!maxstars) 27013498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 27113498266Sopenharmony_ci /* Regroup consecutive stars and question marks. This can be done because 27213498266Sopenharmony_ci '*?*?*' can be expressed as '??*'. */ 27313498266Sopenharmony_ci for(;;) { 27413498266Sopenharmony_ci if(*++p == '\0') 27513498266Sopenharmony_ci return CURL_FNMATCH_MATCH; 27613498266Sopenharmony_ci if(*p == '?') { 27713498266Sopenharmony_ci if(!*s++) 27813498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 27913498266Sopenharmony_ci } 28013498266Sopenharmony_ci else if(*p != '*') 28113498266Sopenharmony_ci break; 28213498266Sopenharmony_ci } 28313498266Sopenharmony_ci /* Skip string characters until we find a match with pattern suffix. */ 28413498266Sopenharmony_ci for(maxstars--; *s; s++) { 28513498266Sopenharmony_ci if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH) 28613498266Sopenharmony_ci return CURL_FNMATCH_MATCH; 28713498266Sopenharmony_ci } 28813498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 28913498266Sopenharmony_ci case '?': 29013498266Sopenharmony_ci if(!*s) 29113498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 29213498266Sopenharmony_ci s++; 29313498266Sopenharmony_ci p++; 29413498266Sopenharmony_ci break; 29513498266Sopenharmony_ci case '\0': 29613498266Sopenharmony_ci return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH; 29713498266Sopenharmony_ci case '\\': 29813498266Sopenharmony_ci if(p[1]) 29913498266Sopenharmony_ci p++; 30013498266Sopenharmony_ci if(*s++ != *p++) 30113498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 30213498266Sopenharmony_ci break; 30313498266Sopenharmony_ci case '[': 30413498266Sopenharmony_ci pp = p + 1; /* Copy in case of syntax error in set. */ 30513498266Sopenharmony_ci if(setcharset(&pp, charset)) { 30613498266Sopenharmony_ci int found = FALSE; 30713498266Sopenharmony_ci if(!*s) 30813498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 30913498266Sopenharmony_ci if(charset[(unsigned int)*s]) 31013498266Sopenharmony_ci found = TRUE; 31113498266Sopenharmony_ci else if(charset[CURLFNM_ALNUM]) 31213498266Sopenharmony_ci found = ISALNUM(*s); 31313498266Sopenharmony_ci else if(charset[CURLFNM_ALPHA]) 31413498266Sopenharmony_ci found = ISALPHA(*s); 31513498266Sopenharmony_ci else if(charset[CURLFNM_DIGIT]) 31613498266Sopenharmony_ci found = ISDIGIT(*s); 31713498266Sopenharmony_ci else if(charset[CURLFNM_XDIGIT]) 31813498266Sopenharmony_ci found = ISXDIGIT(*s); 31913498266Sopenharmony_ci else if(charset[CURLFNM_PRINT]) 32013498266Sopenharmony_ci found = ISPRINT(*s); 32113498266Sopenharmony_ci else if(charset[CURLFNM_SPACE]) 32213498266Sopenharmony_ci found = ISSPACE(*s); 32313498266Sopenharmony_ci else if(charset[CURLFNM_UPPER]) 32413498266Sopenharmony_ci found = ISUPPER(*s); 32513498266Sopenharmony_ci else if(charset[CURLFNM_LOWER]) 32613498266Sopenharmony_ci found = ISLOWER(*s); 32713498266Sopenharmony_ci else if(charset[CURLFNM_BLANK]) 32813498266Sopenharmony_ci found = ISBLANK(*s); 32913498266Sopenharmony_ci else if(charset[CURLFNM_GRAPH]) 33013498266Sopenharmony_ci found = ISGRAPH(*s); 33113498266Sopenharmony_ci 33213498266Sopenharmony_ci if(charset[CURLFNM_NEGATE]) 33313498266Sopenharmony_ci found = !found; 33413498266Sopenharmony_ci 33513498266Sopenharmony_ci if(!found) 33613498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 33713498266Sopenharmony_ci p = pp + 1; 33813498266Sopenharmony_ci s++; 33913498266Sopenharmony_ci break; 34013498266Sopenharmony_ci } 34113498266Sopenharmony_ci /* Syntax error in set; mismatch! */ 34213498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 34313498266Sopenharmony_ci 34413498266Sopenharmony_ci default: 34513498266Sopenharmony_ci if(*p++ != *s++) 34613498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 34713498266Sopenharmony_ci break; 34813498266Sopenharmony_ci } 34913498266Sopenharmony_ci } 35013498266Sopenharmony_ci} 35113498266Sopenharmony_ci 35213498266Sopenharmony_ci/* 35313498266Sopenharmony_ci * @unittest: 1307 35413498266Sopenharmony_ci */ 35513498266Sopenharmony_ciint Curl_fnmatch(void *ptr, const char *pattern, const char *string) 35613498266Sopenharmony_ci{ 35713498266Sopenharmony_ci (void)ptr; /* the argument is specified by the curl_fnmatch_callback 35813498266Sopenharmony_ci prototype, but not used by Curl_fnmatch() */ 35913498266Sopenharmony_ci if(!pattern || !string) { 36013498266Sopenharmony_ci return CURL_FNMATCH_FAIL; 36113498266Sopenharmony_ci } 36213498266Sopenharmony_ci return loop((unsigned char *)pattern, (unsigned char *)string, 2); 36313498266Sopenharmony_ci} 36413498266Sopenharmony_ci#else 36513498266Sopenharmony_ci#include <fnmatch.h> 36613498266Sopenharmony_ci/* 36713498266Sopenharmony_ci * @unittest: 1307 36813498266Sopenharmony_ci */ 36913498266Sopenharmony_ciint Curl_fnmatch(void *ptr, const char *pattern, const char *string) 37013498266Sopenharmony_ci{ 37113498266Sopenharmony_ci (void)ptr; /* the argument is specified by the curl_fnmatch_callback 37213498266Sopenharmony_ci prototype, but not used by Curl_fnmatch() */ 37313498266Sopenharmony_ci if(!pattern || !string) { 37413498266Sopenharmony_ci return CURL_FNMATCH_FAIL; 37513498266Sopenharmony_ci } 37613498266Sopenharmony_ci 37713498266Sopenharmony_ci switch(fnmatch(pattern, string, 0)) { 37813498266Sopenharmony_ci case 0: 37913498266Sopenharmony_ci return CURL_FNMATCH_MATCH; 38013498266Sopenharmony_ci case FNM_NOMATCH: 38113498266Sopenharmony_ci return CURL_FNMATCH_NOMATCH; 38213498266Sopenharmony_ci default: 38313498266Sopenharmony_ci return CURL_FNMATCH_FAIL; 38413498266Sopenharmony_ci } 38513498266Sopenharmony_ci /* not reached */ 38613498266Sopenharmony_ci} 38713498266Sopenharmony_ci 38813498266Sopenharmony_ci#endif 38913498266Sopenharmony_ci 39013498266Sopenharmony_ci#endif /* if FTP is disabled */ 391