pocxxeci 0.30.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pocxxeci might be problematic. Click here for more details.
- package/LICENSE +19 -0
- package/Makefile +18 -0
- package/README.md +52 -0
- package/binding.gyp +81 -0
- package/index.d.ts +273 -0
- package/index.js +45 -0
- package/lib/bindings.js +1 -0
- package/lib/document.js +122 -0
- package/lib/element.js +82 -0
- package/lib/sax_parser.js +38 -0
- package/package.json +70 -0
- package/src/html_document.cc +7 -0
- package/src/html_document.h +18 -0
- package/src/libxmljs.cc +252 -0
- package/src/libxmljs.h +53 -0
- package/src/xml_attribute.cc +173 -0
- package/src/xml_attribute.h +40 -0
- package/src/xml_comment.cc +117 -0
- package/src/xml_comment.h +30 -0
- package/src/xml_document.cc +810 -0
- package/src/xml_document.h +67 -0
- package/src/xml_element.cc +565 -0
- package/src/xml_element.h +61 -0
- package/src/xml_namespace.cc +158 -0
- package/src/xml_namespace.h +39 -0
- package/src/xml_node.cc +761 -0
- package/src/xml_node.h +73 -0
- package/src/xml_pi.cc +161 -0
- package/src/xml_pi.h +34 -0
- package/src/xml_sax_parser.cc +424 -0
- package/src/xml_sax_parser.h +73 -0
- package/src/xml_syntax_error.cc +66 -0
- package/src/xml_syntax_error.h +25 -0
- package/src/xml_text.cc +320 -0
- package/src/xml_text.h +48 -0
- package/src/xml_textwriter.cc +315 -0
- package/src/xml_textwriter.h +62 -0
- package/src/xml_xpath_context.cc +70 -0
- package/src/xml_xpath_context.h +23 -0
- package/vendor/libxml/Copyright +23 -0
- package/vendor/libxml/DOCBparser.c +305 -0
- package/vendor/libxml/HTMLparser.c +7287 -0
- package/vendor/libxml/HTMLtree.c +1200 -0
- package/vendor/libxml/Makefile +2983 -0
- package/vendor/libxml/SAX.c +180 -0
- package/vendor/libxml/SAX2.c +3036 -0
- package/vendor/libxml/buf.c +1351 -0
- package/vendor/libxml/buf.h +72 -0
- package/vendor/libxml/c14n.c +2234 -0
- package/vendor/libxml/catalog.c +3828 -0
- package/vendor/libxml/chvalid.c +336 -0
- package/vendor/libxml/config.h +294 -0
- package/vendor/libxml/config.h.gch +0 -0
- package/vendor/libxml/debugXML.c +3423 -0
- package/vendor/libxml/dict.c +1298 -0
- package/vendor/libxml/elfgcchack.h +17818 -0
- package/vendor/libxml/enc.h +32 -0
- package/vendor/libxml/encoding.c +3975 -0
- package/vendor/libxml/entities.c +1163 -0
- package/vendor/libxml/error.c +998 -0
- package/vendor/libxml/globals.c +1126 -0
- package/vendor/libxml/hash.c +1146 -0
- package/vendor/libxml/include/libxml/DOCBparser.h +96 -0
- package/vendor/libxml/include/libxml/HTMLparser.h +306 -0
- package/vendor/libxml/include/libxml/HTMLtree.h +147 -0
- package/vendor/libxml/include/libxml/Makefile +725 -0
- package/vendor/libxml/include/libxml/Makefile.am +54 -0
- package/vendor/libxml/include/libxml/Makefile.in +725 -0
- package/vendor/libxml/include/libxml/SAX.h +173 -0
- package/vendor/libxml/include/libxml/SAX2.h +178 -0
- package/vendor/libxml/include/libxml/c14n.h +128 -0
- package/vendor/libxml/include/libxml/catalog.h +182 -0
- package/vendor/libxml/include/libxml/chvalid.h +230 -0
- package/vendor/libxml/include/libxml/debugXML.h +217 -0
- package/vendor/libxml/include/libxml/dict.h +79 -0
- package/vendor/libxml/include/libxml/encoding.h +245 -0
- package/vendor/libxml/include/libxml/entities.h +151 -0
- package/vendor/libxml/include/libxml/globals.h +508 -0
- package/vendor/libxml/include/libxml/hash.h +236 -0
- package/vendor/libxml/include/libxml/list.h +137 -0
- package/vendor/libxml/include/libxml/nanoftp.h +163 -0
- package/vendor/libxml/include/libxml/nanohttp.h +81 -0
- package/vendor/libxml/include/libxml/parser.h +1243 -0
- package/vendor/libxml/include/libxml/parserInternals.h +644 -0
- package/vendor/libxml/include/libxml/pattern.h +100 -0
- package/vendor/libxml/include/libxml/relaxng.h +217 -0
- package/vendor/libxml/include/libxml/schemasInternals.h +958 -0
- package/vendor/libxml/include/libxml/schematron.h +142 -0
- package/vendor/libxml/include/libxml/threads.h +89 -0
- package/vendor/libxml/include/libxml/tree.h +1311 -0
- package/vendor/libxml/include/libxml/uri.h +94 -0
- package/vendor/libxml/include/libxml/valid.h +458 -0
- package/vendor/libxml/include/libxml/xinclude.h +129 -0
- package/vendor/libxml/include/libxml/xlink.h +189 -0
- package/vendor/libxml/include/libxml/xmlIO.h +368 -0
- package/vendor/libxml/include/libxml/xmlautomata.h +146 -0
- package/vendor/libxml/include/libxml/xmlerror.h +945 -0
- package/vendor/libxml/include/libxml/xmlexports.h +77 -0
- package/vendor/libxml/include/libxml/xmlmemory.h +224 -0
- package/vendor/libxml/include/libxml/xmlmodule.h +57 -0
- package/vendor/libxml/include/libxml/xmlreader.h +428 -0
- package/vendor/libxml/include/libxml/xmlregexp.h +222 -0
- package/vendor/libxml/include/libxml/xmlsave.h +88 -0
- package/vendor/libxml/include/libxml/xmlschemas.h +246 -0
- package/vendor/libxml/include/libxml/xmlschemastypes.h +151 -0
- package/vendor/libxml/include/libxml/xmlstring.h +140 -0
- package/vendor/libxml/include/libxml/xmlunicode.h +202 -0
- package/vendor/libxml/include/libxml/xmlversion.h +484 -0
- package/vendor/libxml/include/libxml/xmlwin32version.h +239 -0
- package/vendor/libxml/include/libxml/xmlwriter.h +488 -0
- package/vendor/libxml/include/libxml/xpath.h +564 -0
- package/vendor/libxml/include/libxml/xpathInternals.h +632 -0
- package/vendor/libxml/include/libxml/xpointer.h +114 -0
- package/vendor/libxml/include/win32config.h +122 -0
- package/vendor/libxml/include/wsockcompat.h +54 -0
- package/vendor/libxml/legacy.c +1343 -0
- package/vendor/libxml/libxml.h +134 -0
- package/vendor/libxml/list.c +779 -0
- package/vendor/libxml/nanoftp.c +2118 -0
- package/vendor/libxml/nanohttp.c +1899 -0
- package/vendor/libxml/parser.c +15553 -0
- package/vendor/libxml/parserInternals.c +2164 -0
- package/vendor/libxml/pattern.c +2621 -0
- package/vendor/libxml/relaxng.c +11101 -0
- package/vendor/libxml/rngparser.c +1595 -0
- package/vendor/libxml/runsuite.c +1157 -0
- package/vendor/libxml/save.h +36 -0
- package/vendor/libxml/schematron.c +1787 -0
- package/vendor/libxml/threads.c +1049 -0
- package/vendor/libxml/timsort.h +601 -0
- package/vendor/libxml/tree.c +10183 -0
- package/vendor/libxml/trio.c +6895 -0
- package/vendor/libxml/trio.h +230 -0
- package/vendor/libxml/triodef.h +228 -0
- package/vendor/libxml/trionan.c +914 -0
- package/vendor/libxml/trionan.h +84 -0
- package/vendor/libxml/triop.h +150 -0
- package/vendor/libxml/triostr.c +2112 -0
- package/vendor/libxml/triostr.h +144 -0
- package/vendor/libxml/uri.c +2561 -0
- package/vendor/libxml/valid.c +7138 -0
- package/vendor/libxml/xinclude.c +2657 -0
- package/vendor/libxml/xlink.c +183 -0
- package/vendor/libxml/xmlIO.c +4135 -0
- package/vendor/libxml/xmlcatalog.c +624 -0
- package/vendor/libxml/xmllint.c +3796 -0
- package/vendor/libxml/xmlmemory.c +1163 -0
- package/vendor/libxml/xmlmodule.c +468 -0
- package/vendor/libxml/xmlreader.c +6033 -0
- package/vendor/libxml/xmlregexp.c +8271 -0
- package/vendor/libxml/xmlsave.c +2735 -0
- package/vendor/libxml/xmlschemas.c +29173 -0
- package/vendor/libxml/xmlschemastypes.c +6276 -0
- package/vendor/libxml/xmlstring.c +1050 -0
- package/vendor/libxml/xmlunicode.c +3179 -0
- package/vendor/libxml/xmlwriter.c +4738 -0
- package/vendor/libxml/xpath.c +14734 -0
- package/vendor/libxml/xpointer.c +2969 -0
- package/vendor/libxml/xzlib.c +815 -0
- package/vendor/libxml/xzlib.h +19 -0
@@ -0,0 +1,2118 @@
|
|
1
|
+
/*
|
2
|
+
* nanoftp.c: basic FTP client support
|
3
|
+
*
|
4
|
+
* Reference: RFC 959
|
5
|
+
*/
|
6
|
+
|
7
|
+
#ifdef TESTING
|
8
|
+
#define STANDALONE
|
9
|
+
#define HAVE_STDLIB_H
|
10
|
+
#define HAVE_UNISTD_H
|
11
|
+
#define HAVE_SYS_SOCKET_H
|
12
|
+
#define HAVE_NETINET_IN_H
|
13
|
+
#define HAVE_NETDB_H
|
14
|
+
#define HAVE_SYS_TIME_H
|
15
|
+
#endif /* TESTING */
|
16
|
+
|
17
|
+
#define IN_LIBXML
|
18
|
+
#include "libxml.h"
|
19
|
+
|
20
|
+
#ifdef LIBXML_FTP_ENABLED
|
21
|
+
#include <string.h>
|
22
|
+
|
23
|
+
#ifdef HAVE_STDLIB_H
|
24
|
+
#include <stdlib.h>
|
25
|
+
#endif
|
26
|
+
#ifdef HAVE_UNISTD_H
|
27
|
+
#include <unistd.h>
|
28
|
+
#endif
|
29
|
+
#ifdef HAVE_SYS_SOCKET_H
|
30
|
+
#include <sys/socket.h>
|
31
|
+
#endif
|
32
|
+
#ifdef HAVE_NETINET_IN_H
|
33
|
+
#include <netinet/in.h>
|
34
|
+
#endif
|
35
|
+
#ifdef HAVE_ARPA_INET_H
|
36
|
+
#include <arpa/inet.h>
|
37
|
+
#endif
|
38
|
+
#ifdef HAVE_NETDB_H
|
39
|
+
#include <netdb.h>
|
40
|
+
#endif
|
41
|
+
#ifdef HAVE_FCNTL_H
|
42
|
+
#include <fcntl.h>
|
43
|
+
#endif
|
44
|
+
#ifdef HAVE_ERRNO_H
|
45
|
+
#include <errno.h>
|
46
|
+
#endif
|
47
|
+
#ifdef HAVE_SYS_TIME_H
|
48
|
+
#include <sys/time.h>
|
49
|
+
#endif
|
50
|
+
#ifdef HAVE_SYS_SELECT_H
|
51
|
+
#include <sys/select.h>
|
52
|
+
#endif
|
53
|
+
#ifdef HAVE_SYS_SOCKET_H
|
54
|
+
#include <sys/socket.h>
|
55
|
+
#endif
|
56
|
+
#ifdef HAVE_SYS_TYPES_H
|
57
|
+
#include <sys/types.h>
|
58
|
+
#endif
|
59
|
+
#ifdef HAVE_STRINGS_H
|
60
|
+
#include <strings.h>
|
61
|
+
#endif
|
62
|
+
|
63
|
+
#include <libxml/xmlmemory.h>
|
64
|
+
#include <libxml/parser.h>
|
65
|
+
#include <libxml/xmlerror.h>
|
66
|
+
#include <libxml/uri.h>
|
67
|
+
#include <libxml/nanoftp.h>
|
68
|
+
#include <libxml/globals.h>
|
69
|
+
|
70
|
+
/* #define DEBUG_FTP 1 */
|
71
|
+
#ifdef STANDALONE
|
72
|
+
#ifndef DEBUG_FTP
|
73
|
+
#define DEBUG_FTP 1
|
74
|
+
#endif
|
75
|
+
#endif
|
76
|
+
|
77
|
+
|
78
|
+
#if defined(_WIN32) && !defined(__CYGWIN__)
|
79
|
+
#include <wsockcompat.h>
|
80
|
+
#endif
|
81
|
+
|
82
|
+
/**
|
83
|
+
* A couple portability macros
|
84
|
+
*/
|
85
|
+
#ifndef _WINSOCKAPI_
|
86
|
+
#if !defined(__BEOS__) || defined(__HAIKU__)
|
87
|
+
#define closesocket(s) close(s)
|
88
|
+
#endif
|
89
|
+
#endif
|
90
|
+
|
91
|
+
#ifdef __BEOS__
|
92
|
+
#ifndef PF_INET
|
93
|
+
#define PF_INET AF_INET
|
94
|
+
#endif
|
95
|
+
#endif
|
96
|
+
|
97
|
+
#ifdef _AIX
|
98
|
+
#ifdef HAVE_BROKEN_SS_FAMILY
|
99
|
+
#define ss_family __ss_family
|
100
|
+
#endif
|
101
|
+
#endif
|
102
|
+
|
103
|
+
#ifndef XML_SOCKLEN_T
|
104
|
+
#define XML_SOCKLEN_T unsigned int
|
105
|
+
#endif
|
106
|
+
|
107
|
+
#define FTP_COMMAND_OK 200
|
108
|
+
#define FTP_SYNTAX_ERROR 500
|
109
|
+
#define FTP_GET_PASSWD 331
|
110
|
+
#define FTP_BUF_SIZE 1024
|
111
|
+
|
112
|
+
#define XML_NANO_MAX_URLBUF 4096
|
113
|
+
|
114
|
+
typedef struct xmlNanoFTPCtxt {
|
115
|
+
char *protocol; /* the protocol name */
|
116
|
+
char *hostname; /* the host name */
|
117
|
+
int port; /* the port */
|
118
|
+
char *path; /* the path within the URL */
|
119
|
+
char *user; /* user string */
|
120
|
+
char *passwd; /* passwd string */
|
121
|
+
#ifdef SUPPORT_IP6
|
122
|
+
struct sockaddr_storage ftpAddr; /* this is large enough to hold IPv6 address*/
|
123
|
+
#else
|
124
|
+
struct sockaddr_in ftpAddr; /* the socket address struct */
|
125
|
+
#endif
|
126
|
+
int passive; /* currently we support only passive !!! */
|
127
|
+
SOCKET controlFd; /* the file descriptor for the control socket */
|
128
|
+
SOCKET dataFd; /* the file descriptor for the data socket */
|
129
|
+
int state; /* WRITE / READ / CLOSED */
|
130
|
+
int returnValue; /* the protocol return value */
|
131
|
+
/* buffer for data received from the control connection */
|
132
|
+
char controlBuf[FTP_BUF_SIZE + 1];
|
133
|
+
int controlBufIndex;
|
134
|
+
int controlBufUsed;
|
135
|
+
int controlBufAnswer;
|
136
|
+
} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
|
137
|
+
|
138
|
+
static int initialized = 0;
|
139
|
+
static char *proxy = NULL; /* the proxy name if any */
|
140
|
+
static int proxyPort = 0; /* the proxy port if any */
|
141
|
+
static char *proxyUser = NULL; /* user for proxy authentication */
|
142
|
+
static char *proxyPasswd = NULL;/* passwd for proxy authentication */
|
143
|
+
static int proxyType = 0; /* uses TYPE or a@b ? */
|
144
|
+
|
145
|
+
#ifdef SUPPORT_IP6
|
146
|
+
static
|
147
|
+
int have_ipv6(void) {
|
148
|
+
int s;
|
149
|
+
|
150
|
+
s = socket (AF_INET6, SOCK_STREAM, 0);
|
151
|
+
if (s != -1) {
|
152
|
+
close (s);
|
153
|
+
return (1);
|
154
|
+
}
|
155
|
+
return (0);
|
156
|
+
}
|
157
|
+
#endif
|
158
|
+
|
159
|
+
/**
|
160
|
+
* xmlFTPErrMemory:
|
161
|
+
* @extra: extra information
|
162
|
+
*
|
163
|
+
* Handle an out of memory condition
|
164
|
+
*/
|
165
|
+
static void
|
166
|
+
xmlFTPErrMemory(const char *extra)
|
167
|
+
{
|
168
|
+
__xmlSimpleError(XML_FROM_FTP, XML_ERR_NO_MEMORY, NULL, NULL, extra);
|
169
|
+
}
|
170
|
+
|
171
|
+
/**
|
172
|
+
* xmlNanoFTPInit:
|
173
|
+
*
|
174
|
+
* Initialize the FTP protocol layer.
|
175
|
+
* Currently it just checks for proxy information,
|
176
|
+
* and get the hostname
|
177
|
+
*/
|
178
|
+
|
179
|
+
void
|
180
|
+
xmlNanoFTPInit(void) {
|
181
|
+
const char *env;
|
182
|
+
#ifdef _WINSOCKAPI_
|
183
|
+
WSADATA wsaData;
|
184
|
+
#endif
|
185
|
+
|
186
|
+
if (initialized)
|
187
|
+
return;
|
188
|
+
|
189
|
+
#ifdef _WINSOCKAPI_
|
190
|
+
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
|
191
|
+
return;
|
192
|
+
#endif
|
193
|
+
|
194
|
+
proxyPort = 21;
|
195
|
+
env = getenv("no_proxy");
|
196
|
+
if (env && ((env[0] == '*' ) && (env[1] == 0)))
|
197
|
+
return;
|
198
|
+
env = getenv("ftp_proxy");
|
199
|
+
if (env != NULL) {
|
200
|
+
xmlNanoFTPScanProxy(env);
|
201
|
+
} else {
|
202
|
+
env = getenv("FTP_PROXY");
|
203
|
+
if (env != NULL) {
|
204
|
+
xmlNanoFTPScanProxy(env);
|
205
|
+
}
|
206
|
+
}
|
207
|
+
env = getenv("ftp_proxy_user");
|
208
|
+
if (env != NULL) {
|
209
|
+
proxyUser = xmlMemStrdup(env);
|
210
|
+
}
|
211
|
+
env = getenv("ftp_proxy_password");
|
212
|
+
if (env != NULL) {
|
213
|
+
proxyPasswd = xmlMemStrdup(env);
|
214
|
+
}
|
215
|
+
initialized = 1;
|
216
|
+
}
|
217
|
+
|
218
|
+
/**
|
219
|
+
* xmlNanoFTPCleanup:
|
220
|
+
*
|
221
|
+
* Cleanup the FTP protocol layer. This cleanup proxy information.
|
222
|
+
*/
|
223
|
+
|
224
|
+
void
|
225
|
+
xmlNanoFTPCleanup(void) {
|
226
|
+
if (proxy != NULL) {
|
227
|
+
xmlFree(proxy);
|
228
|
+
proxy = NULL;
|
229
|
+
}
|
230
|
+
if (proxyUser != NULL) {
|
231
|
+
xmlFree(proxyUser);
|
232
|
+
proxyUser = NULL;
|
233
|
+
}
|
234
|
+
if (proxyPasswd != NULL) {
|
235
|
+
xmlFree(proxyPasswd);
|
236
|
+
proxyPasswd = NULL;
|
237
|
+
}
|
238
|
+
#ifdef _WINSOCKAPI_
|
239
|
+
if (initialized)
|
240
|
+
WSACleanup();
|
241
|
+
#endif
|
242
|
+
initialized = 0;
|
243
|
+
}
|
244
|
+
|
245
|
+
/**
|
246
|
+
* xmlNanoFTPProxy:
|
247
|
+
* @host: the proxy host name
|
248
|
+
* @port: the proxy port
|
249
|
+
* @user: the proxy user name
|
250
|
+
* @passwd: the proxy password
|
251
|
+
* @type: the type of proxy 1 for using SITE, 2 for USER a@b
|
252
|
+
*
|
253
|
+
* Setup the FTP proxy information.
|
254
|
+
* This can also be done by using ftp_proxy ftp_proxy_user and
|
255
|
+
* ftp_proxy_password environment variables.
|
256
|
+
*/
|
257
|
+
|
258
|
+
void
|
259
|
+
xmlNanoFTPProxy(const char *host, int port, const char *user,
|
260
|
+
const char *passwd, int type) {
|
261
|
+
if (proxy != NULL) {
|
262
|
+
xmlFree(proxy);
|
263
|
+
proxy = NULL;
|
264
|
+
}
|
265
|
+
if (proxyUser != NULL) {
|
266
|
+
xmlFree(proxyUser);
|
267
|
+
proxyUser = NULL;
|
268
|
+
}
|
269
|
+
if (proxyPasswd != NULL) {
|
270
|
+
xmlFree(proxyPasswd);
|
271
|
+
proxyPasswd = NULL;
|
272
|
+
}
|
273
|
+
if (host)
|
274
|
+
proxy = xmlMemStrdup(host);
|
275
|
+
if (user)
|
276
|
+
proxyUser = xmlMemStrdup(user);
|
277
|
+
if (passwd)
|
278
|
+
proxyPasswd = xmlMemStrdup(passwd);
|
279
|
+
proxyPort = port;
|
280
|
+
proxyType = type;
|
281
|
+
}
|
282
|
+
|
283
|
+
/**
|
284
|
+
* xmlNanoFTPScanURL:
|
285
|
+
* @ctx: an FTP context
|
286
|
+
* @URL: The URL used to initialize the context
|
287
|
+
*
|
288
|
+
* (Re)Initialize an FTP context by parsing the URL and finding
|
289
|
+
* the protocol host port and path it indicates.
|
290
|
+
*/
|
291
|
+
|
292
|
+
static void
|
293
|
+
xmlNanoFTPScanURL(void *ctx, const char *URL) {
|
294
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
295
|
+
xmlURIPtr uri;
|
296
|
+
|
297
|
+
/*
|
298
|
+
* Clear any existing data from the context
|
299
|
+
*/
|
300
|
+
if (ctxt->protocol != NULL) {
|
301
|
+
xmlFree(ctxt->protocol);
|
302
|
+
ctxt->protocol = NULL;
|
303
|
+
}
|
304
|
+
if (ctxt->hostname != NULL) {
|
305
|
+
xmlFree(ctxt->hostname);
|
306
|
+
ctxt->hostname = NULL;
|
307
|
+
}
|
308
|
+
if (ctxt->path != NULL) {
|
309
|
+
xmlFree(ctxt->path);
|
310
|
+
ctxt->path = NULL;
|
311
|
+
}
|
312
|
+
if (URL == NULL) return;
|
313
|
+
|
314
|
+
uri = xmlParseURIRaw(URL, 1);
|
315
|
+
if (uri == NULL)
|
316
|
+
return;
|
317
|
+
|
318
|
+
if ((uri->scheme == NULL) || (uri->server == NULL)) {
|
319
|
+
xmlFreeURI(uri);
|
320
|
+
return;
|
321
|
+
}
|
322
|
+
|
323
|
+
ctxt->protocol = xmlMemStrdup(uri->scheme);
|
324
|
+
ctxt->hostname = xmlMemStrdup(uri->server);
|
325
|
+
if (uri->path != NULL)
|
326
|
+
ctxt->path = xmlMemStrdup(uri->path);
|
327
|
+
else
|
328
|
+
ctxt->path = xmlMemStrdup("/");
|
329
|
+
if (uri->port != 0)
|
330
|
+
ctxt->port = uri->port;
|
331
|
+
|
332
|
+
if (uri->user != NULL) {
|
333
|
+
char *cptr;
|
334
|
+
if ((cptr=strchr(uri->user, ':')) == NULL)
|
335
|
+
ctxt->user = xmlMemStrdup(uri->user);
|
336
|
+
else {
|
337
|
+
ctxt->user = (char *)xmlStrndup((xmlChar *)uri->user,
|
338
|
+
(cptr - uri->user));
|
339
|
+
ctxt->passwd = xmlMemStrdup(cptr+1);
|
340
|
+
}
|
341
|
+
}
|
342
|
+
|
343
|
+
xmlFreeURI(uri);
|
344
|
+
|
345
|
+
}
|
346
|
+
|
347
|
+
/**
|
348
|
+
* xmlNanoFTPUpdateURL:
|
349
|
+
* @ctx: an FTP context
|
350
|
+
* @URL: The URL used to update the context
|
351
|
+
*
|
352
|
+
* Update an FTP context by parsing the URL and finding
|
353
|
+
* new path it indicates. If there is an error in the
|
354
|
+
* protocol, hostname, port or other information, the
|
355
|
+
* error is raised. It indicates a new connection has to
|
356
|
+
* be established.
|
357
|
+
*
|
358
|
+
* Returns 0 if Ok, -1 in case of error (other host).
|
359
|
+
*/
|
360
|
+
|
361
|
+
int
|
362
|
+
xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
|
363
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
364
|
+
xmlURIPtr uri;
|
365
|
+
|
366
|
+
if (URL == NULL)
|
367
|
+
return(-1);
|
368
|
+
if (ctxt == NULL)
|
369
|
+
return(-1);
|
370
|
+
if (ctxt->protocol == NULL)
|
371
|
+
return(-1);
|
372
|
+
if (ctxt->hostname == NULL)
|
373
|
+
return(-1);
|
374
|
+
|
375
|
+
uri = xmlParseURIRaw(URL, 1);
|
376
|
+
if (uri == NULL)
|
377
|
+
return(-1);
|
378
|
+
|
379
|
+
if ((uri->scheme == NULL) || (uri->server == NULL)) {
|
380
|
+
xmlFreeURI(uri);
|
381
|
+
return(-1);
|
382
|
+
}
|
383
|
+
if ((strcmp(ctxt->protocol, uri->scheme)) ||
|
384
|
+
(strcmp(ctxt->hostname, uri->server)) ||
|
385
|
+
((uri->port != 0) && (ctxt->port != uri->port))) {
|
386
|
+
xmlFreeURI(uri);
|
387
|
+
return(-1);
|
388
|
+
}
|
389
|
+
|
390
|
+
if (uri->port != 0)
|
391
|
+
ctxt->port = uri->port;
|
392
|
+
|
393
|
+
if (ctxt->path != NULL) {
|
394
|
+
xmlFree(ctxt->path);
|
395
|
+
ctxt->path = NULL;
|
396
|
+
}
|
397
|
+
|
398
|
+
if (uri->path == NULL)
|
399
|
+
ctxt->path = xmlMemStrdup("/");
|
400
|
+
else
|
401
|
+
ctxt->path = xmlMemStrdup(uri->path);
|
402
|
+
|
403
|
+
xmlFreeURI(uri);
|
404
|
+
|
405
|
+
return(0);
|
406
|
+
}
|
407
|
+
|
408
|
+
/**
|
409
|
+
* xmlNanoFTPScanProxy:
|
410
|
+
* @URL: The proxy URL used to initialize the proxy context
|
411
|
+
*
|
412
|
+
* (Re)Initialize the FTP Proxy context by parsing the URL and finding
|
413
|
+
* the protocol host port it indicates.
|
414
|
+
* Should be like ftp://myproxy/ or ftp://myproxy:3128/
|
415
|
+
* A NULL URL cleans up proxy information.
|
416
|
+
*/
|
417
|
+
|
418
|
+
void
|
419
|
+
xmlNanoFTPScanProxy(const char *URL) {
|
420
|
+
xmlURIPtr uri;
|
421
|
+
|
422
|
+
if (proxy != NULL) {
|
423
|
+
xmlFree(proxy);
|
424
|
+
proxy = NULL;
|
425
|
+
}
|
426
|
+
proxyPort = 0;
|
427
|
+
|
428
|
+
#ifdef DEBUG_FTP
|
429
|
+
if (URL == NULL)
|
430
|
+
xmlGenericError(xmlGenericErrorContext,
|
431
|
+
"Removing FTP proxy info\n");
|
432
|
+
else
|
433
|
+
xmlGenericError(xmlGenericErrorContext,
|
434
|
+
"Using FTP proxy %s\n", URL);
|
435
|
+
#endif
|
436
|
+
if (URL == NULL) return;
|
437
|
+
|
438
|
+
uri = xmlParseURIRaw(URL, 1);
|
439
|
+
if ((uri == NULL) || (uri->scheme == NULL) ||
|
440
|
+
(strcmp(uri->scheme, "ftp")) || (uri->server == NULL)) {
|
441
|
+
__xmlIOErr(XML_FROM_FTP, XML_FTP_URL_SYNTAX, "Syntax Error\n");
|
442
|
+
if (uri != NULL)
|
443
|
+
xmlFreeURI(uri);
|
444
|
+
return;
|
445
|
+
}
|
446
|
+
|
447
|
+
proxy = xmlMemStrdup(uri->server);
|
448
|
+
if (uri->port != 0)
|
449
|
+
proxyPort = uri->port;
|
450
|
+
|
451
|
+
xmlFreeURI(uri);
|
452
|
+
}
|
453
|
+
|
454
|
+
/**
|
455
|
+
* xmlNanoFTPNewCtxt:
|
456
|
+
* @URL: The URL used to initialize the context
|
457
|
+
*
|
458
|
+
* Allocate and initialize a new FTP context.
|
459
|
+
*
|
460
|
+
* Returns an FTP context or NULL in case of error.
|
461
|
+
*/
|
462
|
+
|
463
|
+
void*
|
464
|
+
xmlNanoFTPNewCtxt(const char *URL) {
|
465
|
+
xmlNanoFTPCtxtPtr ret;
|
466
|
+
char *unescaped;
|
467
|
+
|
468
|
+
ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
|
469
|
+
if (ret == NULL) {
|
470
|
+
xmlFTPErrMemory("allocating FTP context");
|
471
|
+
return(NULL);
|
472
|
+
}
|
473
|
+
|
474
|
+
memset(ret, 0, sizeof(xmlNanoFTPCtxt));
|
475
|
+
ret->port = 21;
|
476
|
+
ret->passive = 1;
|
477
|
+
ret->returnValue = 0;
|
478
|
+
ret->controlBufIndex = 0;
|
479
|
+
ret->controlBufUsed = 0;
|
480
|
+
ret->controlFd = INVALID_SOCKET;
|
481
|
+
|
482
|
+
unescaped = xmlURIUnescapeString(URL, 0, NULL);
|
483
|
+
if (unescaped != NULL) {
|
484
|
+
xmlNanoFTPScanURL(ret, unescaped);
|
485
|
+
xmlFree(unescaped);
|
486
|
+
} else if (URL != NULL)
|
487
|
+
xmlNanoFTPScanURL(ret, URL);
|
488
|
+
|
489
|
+
return(ret);
|
490
|
+
}
|
491
|
+
|
492
|
+
/**
|
493
|
+
* xmlNanoFTPFreeCtxt:
|
494
|
+
* @ctx: an FTP context
|
495
|
+
*
|
496
|
+
* Frees the context after closing the connection.
|
497
|
+
*/
|
498
|
+
|
499
|
+
void
|
500
|
+
xmlNanoFTPFreeCtxt(void * ctx) {
|
501
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
502
|
+
if (ctxt == NULL) return;
|
503
|
+
if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
|
504
|
+
if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
|
505
|
+
if (ctxt->path != NULL) xmlFree(ctxt->path);
|
506
|
+
if (ctxt->user != NULL) xmlFree(ctxt->user);
|
507
|
+
if (ctxt->passwd != NULL) xmlFree(ctxt->passwd);
|
508
|
+
ctxt->passive = 1;
|
509
|
+
if (ctxt->controlFd != INVALID_SOCKET) closesocket(ctxt->controlFd);
|
510
|
+
ctxt->controlFd = INVALID_SOCKET;
|
511
|
+
ctxt->controlBufIndex = -1;
|
512
|
+
ctxt->controlBufUsed = -1;
|
513
|
+
xmlFree(ctxt);
|
514
|
+
}
|
515
|
+
|
516
|
+
/**
|
517
|
+
* xmlNanoFTPParseResponse:
|
518
|
+
* @buf: the buffer containing the response
|
519
|
+
* @len: the buffer length
|
520
|
+
*
|
521
|
+
* Parsing of the server answer, we just extract the code.
|
522
|
+
*
|
523
|
+
* returns 0 for errors
|
524
|
+
* +XXX for last line of response
|
525
|
+
* -XXX for response to be continued
|
526
|
+
*/
|
527
|
+
static int
|
528
|
+
xmlNanoFTPParseResponse(char *buf, int len) {
|
529
|
+
int val = 0;
|
530
|
+
|
531
|
+
if (len < 3) return(-1);
|
532
|
+
if ((*buf >= '0') && (*buf <= '9'))
|
533
|
+
val = val * 10 + (*buf - '0');
|
534
|
+
else
|
535
|
+
return(0);
|
536
|
+
buf++;
|
537
|
+
if ((*buf >= '0') && (*buf <= '9'))
|
538
|
+
val = val * 10 + (*buf - '0');
|
539
|
+
else
|
540
|
+
return(0);
|
541
|
+
buf++;
|
542
|
+
if ((*buf >= '0') && (*buf <= '9'))
|
543
|
+
val = val * 10 + (*buf - '0');
|
544
|
+
else
|
545
|
+
return(0);
|
546
|
+
buf++;
|
547
|
+
if (*buf == '-')
|
548
|
+
return(-val);
|
549
|
+
return(val);
|
550
|
+
}
|
551
|
+
|
552
|
+
/**
|
553
|
+
* xmlNanoFTPGetMore:
|
554
|
+
* @ctx: an FTP context
|
555
|
+
*
|
556
|
+
* Read more information from the FTP control connection
|
557
|
+
* Returns the number of bytes read, < 0 indicates an error
|
558
|
+
*/
|
559
|
+
static int
|
560
|
+
xmlNanoFTPGetMore(void *ctx) {
|
561
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
562
|
+
int len;
|
563
|
+
int size;
|
564
|
+
|
565
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
|
566
|
+
|
567
|
+
if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
|
568
|
+
#ifdef DEBUG_FTP
|
569
|
+
xmlGenericError(xmlGenericErrorContext,
|
570
|
+
"xmlNanoFTPGetMore : controlBufIndex = %d\n",
|
571
|
+
ctxt->controlBufIndex);
|
572
|
+
#endif
|
573
|
+
return(-1);
|
574
|
+
}
|
575
|
+
|
576
|
+
if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
|
577
|
+
#ifdef DEBUG_FTP
|
578
|
+
xmlGenericError(xmlGenericErrorContext,
|
579
|
+
"xmlNanoFTPGetMore : controlBufUsed = %d\n",
|
580
|
+
ctxt->controlBufUsed);
|
581
|
+
#endif
|
582
|
+
return(-1);
|
583
|
+
}
|
584
|
+
if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
|
585
|
+
#ifdef DEBUG_FTP
|
586
|
+
xmlGenericError(xmlGenericErrorContext,
|
587
|
+
"xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
|
588
|
+
ctxt->controlBufIndex, ctxt->controlBufUsed);
|
589
|
+
#endif
|
590
|
+
return(-1);
|
591
|
+
}
|
592
|
+
|
593
|
+
/*
|
594
|
+
* First pack the control buffer
|
595
|
+
*/
|
596
|
+
if (ctxt->controlBufIndex > 0) {
|
597
|
+
memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
|
598
|
+
ctxt->controlBufUsed - ctxt->controlBufIndex);
|
599
|
+
ctxt->controlBufUsed -= ctxt->controlBufIndex;
|
600
|
+
ctxt->controlBufIndex = 0;
|
601
|
+
}
|
602
|
+
size = FTP_BUF_SIZE - ctxt->controlBufUsed;
|
603
|
+
if (size == 0) {
|
604
|
+
#ifdef DEBUG_FTP
|
605
|
+
xmlGenericError(xmlGenericErrorContext,
|
606
|
+
"xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
|
607
|
+
#endif
|
608
|
+
return(0);
|
609
|
+
}
|
610
|
+
|
611
|
+
/*
|
612
|
+
* Read the amount left on the control connection
|
613
|
+
*/
|
614
|
+
if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
|
615
|
+
size, 0)) < 0) {
|
616
|
+
__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
|
617
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
618
|
+
ctxt->controlFd = INVALID_SOCKET;
|
619
|
+
return(-1);
|
620
|
+
}
|
621
|
+
#ifdef DEBUG_FTP
|
622
|
+
xmlGenericError(xmlGenericErrorContext,
|
623
|
+
"xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
|
624
|
+
ctxt->controlBufUsed, ctxt->controlBufUsed + len);
|
625
|
+
#endif
|
626
|
+
ctxt->controlBufUsed += len;
|
627
|
+
ctxt->controlBuf[ctxt->controlBufUsed] = 0;
|
628
|
+
|
629
|
+
return(len);
|
630
|
+
}
|
631
|
+
|
632
|
+
/**
|
633
|
+
* xmlNanoFTPReadResponse:
|
634
|
+
* @ctx: an FTP context
|
635
|
+
*
|
636
|
+
* Read the response from the FTP server after a command.
|
637
|
+
* Returns the code number
|
638
|
+
*/
|
639
|
+
static int
|
640
|
+
xmlNanoFTPReadResponse(void *ctx) {
|
641
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
642
|
+
char *ptr, *end;
|
643
|
+
int len;
|
644
|
+
int res = -1, cur = -1;
|
645
|
+
|
646
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
|
647
|
+
|
648
|
+
get_more:
|
649
|
+
/*
|
650
|
+
* Assumes everything up to controlBuf[controlBufIndex] has been read
|
651
|
+
* and analyzed.
|
652
|
+
*/
|
653
|
+
len = xmlNanoFTPGetMore(ctx);
|
654
|
+
if (len < 0) {
|
655
|
+
return(-1);
|
656
|
+
}
|
657
|
+
if ((ctxt->controlBufUsed == 0) && (len == 0)) {
|
658
|
+
return(-1);
|
659
|
+
}
|
660
|
+
ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
|
661
|
+
end = &ctxt->controlBuf[ctxt->controlBufUsed];
|
662
|
+
|
663
|
+
#ifdef DEBUG_FTP
|
664
|
+
xmlGenericError(xmlGenericErrorContext,
|
665
|
+
"\n<<<\n%s\n--\n", ptr);
|
666
|
+
#endif
|
667
|
+
while (ptr < end) {
|
668
|
+
cur = xmlNanoFTPParseResponse(ptr, end - ptr);
|
669
|
+
if (cur > 0) {
|
670
|
+
/*
|
671
|
+
* Successfully scanned the control code, scratch
|
672
|
+
* till the end of the line, but keep the index to be
|
673
|
+
* able to analyze the result if needed.
|
674
|
+
*/
|
675
|
+
res = cur;
|
676
|
+
ptr += 3;
|
677
|
+
ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
|
678
|
+
while ((ptr < end) && (*ptr != '\n')) ptr++;
|
679
|
+
if (*ptr == '\n') ptr++;
|
680
|
+
if (*ptr == '\r') ptr++;
|
681
|
+
break;
|
682
|
+
}
|
683
|
+
while ((ptr < end) && (*ptr != '\n')) ptr++;
|
684
|
+
if (ptr >= end) {
|
685
|
+
ctxt->controlBufIndex = ctxt->controlBufUsed;
|
686
|
+
goto get_more;
|
687
|
+
}
|
688
|
+
if (*ptr != '\r') ptr++;
|
689
|
+
}
|
690
|
+
|
691
|
+
if (res < 0) goto get_more;
|
692
|
+
ctxt->controlBufIndex = ptr - ctxt->controlBuf;
|
693
|
+
#ifdef DEBUG_FTP
|
694
|
+
ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
|
695
|
+
xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
|
696
|
+
#endif
|
697
|
+
|
698
|
+
#ifdef DEBUG_FTP
|
699
|
+
xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
|
700
|
+
#endif
|
701
|
+
return(res / 100);
|
702
|
+
}
|
703
|
+
|
704
|
+
/**
|
705
|
+
* xmlNanoFTPGetResponse:
|
706
|
+
* @ctx: an FTP context
|
707
|
+
*
|
708
|
+
* Get the response from the FTP server after a command.
|
709
|
+
* Returns the code number
|
710
|
+
*/
|
711
|
+
|
712
|
+
int
|
713
|
+
xmlNanoFTPGetResponse(void *ctx) {
|
714
|
+
int res;
|
715
|
+
|
716
|
+
res = xmlNanoFTPReadResponse(ctx);
|
717
|
+
|
718
|
+
return(res);
|
719
|
+
}
|
720
|
+
|
721
|
+
/**
|
722
|
+
* xmlNanoFTPCheckResponse:
|
723
|
+
* @ctx: an FTP context
|
724
|
+
*
|
725
|
+
* Check if there is a response from the FTP server after a command.
|
726
|
+
* Returns the code number, or 0
|
727
|
+
*/
|
728
|
+
|
729
|
+
int
|
730
|
+
xmlNanoFTPCheckResponse(void *ctx) {
|
731
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
732
|
+
fd_set rfd;
|
733
|
+
struct timeval tv;
|
734
|
+
|
735
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
|
736
|
+
tv.tv_sec = 0;
|
737
|
+
tv.tv_usec = 0;
|
738
|
+
FD_ZERO(&rfd);
|
739
|
+
FD_SET(ctxt->controlFd, &rfd);
|
740
|
+
switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
|
741
|
+
case 0:
|
742
|
+
return(0);
|
743
|
+
case -1:
|
744
|
+
__xmlIOErr(XML_FROM_FTP, 0, "select");
|
745
|
+
return(-1);
|
746
|
+
|
747
|
+
}
|
748
|
+
|
749
|
+
return(xmlNanoFTPReadResponse(ctx));
|
750
|
+
}
|
751
|
+
|
752
|
+
/**
|
753
|
+
* Send the user authentication
|
754
|
+
*/
|
755
|
+
|
756
|
+
static int
|
757
|
+
xmlNanoFTPSendUser(void *ctx) {
|
758
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
759
|
+
char buf[200];
|
760
|
+
int len;
|
761
|
+
int res;
|
762
|
+
|
763
|
+
if (ctxt->user == NULL)
|
764
|
+
snprintf(buf, sizeof(buf), "USER anonymous\r\n");
|
765
|
+
else
|
766
|
+
snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
|
767
|
+
buf[sizeof(buf) - 1] = 0;
|
768
|
+
len = strlen(buf);
|
769
|
+
#ifdef DEBUG_FTP
|
770
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
771
|
+
#endif
|
772
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
773
|
+
if (res < 0) {
|
774
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
775
|
+
return(res);
|
776
|
+
}
|
777
|
+
return(0);
|
778
|
+
}
|
779
|
+
|
780
|
+
/**
|
781
|
+
* Send the password authentication
|
782
|
+
*/
|
783
|
+
|
784
|
+
static int
|
785
|
+
xmlNanoFTPSendPasswd(void *ctx) {
|
786
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
787
|
+
char buf[200];
|
788
|
+
int len;
|
789
|
+
int res;
|
790
|
+
|
791
|
+
if (ctxt->passwd == NULL)
|
792
|
+
snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
|
793
|
+
else
|
794
|
+
snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
|
795
|
+
buf[sizeof(buf) - 1] = 0;
|
796
|
+
len = strlen(buf);
|
797
|
+
#ifdef DEBUG_FTP
|
798
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
799
|
+
#endif
|
800
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
801
|
+
if (res < 0) {
|
802
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
803
|
+
return(res);
|
804
|
+
}
|
805
|
+
return(0);
|
806
|
+
}
|
807
|
+
|
808
|
+
/**
|
809
|
+
* xmlNanoFTPQuit:
|
810
|
+
* @ctx: an FTP context
|
811
|
+
*
|
812
|
+
* Send a QUIT command to the server
|
813
|
+
*
|
814
|
+
* Returns -1 in case of error, 0 otherwise
|
815
|
+
*/
|
816
|
+
|
817
|
+
|
818
|
+
int
|
819
|
+
xmlNanoFTPQuit(void *ctx) {
|
820
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
821
|
+
char buf[200];
|
822
|
+
int len, res;
|
823
|
+
|
824
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
|
825
|
+
|
826
|
+
snprintf(buf, sizeof(buf), "QUIT\r\n");
|
827
|
+
len = strlen(buf);
|
828
|
+
#ifdef DEBUG_FTP
|
829
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf); /* Just to be consistent, even though we know it can't have a % in it */
|
830
|
+
#endif
|
831
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
832
|
+
if (res < 0) {
|
833
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
834
|
+
return(res);
|
835
|
+
}
|
836
|
+
return(0);
|
837
|
+
}
|
838
|
+
|
839
|
+
/**
|
840
|
+
* xmlNanoFTPConnect:
|
841
|
+
* @ctx: an FTP context
|
842
|
+
*
|
843
|
+
* Tries to open a control connection
|
844
|
+
*
|
845
|
+
* Returns -1 in case of error, 0 otherwise
|
846
|
+
*/
|
847
|
+
|
848
|
+
int
|
849
|
+
xmlNanoFTPConnect(void *ctx) {
|
850
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
851
|
+
struct hostent *hp;
|
852
|
+
int port;
|
853
|
+
int res;
|
854
|
+
int addrlen = sizeof (struct sockaddr_in);
|
855
|
+
|
856
|
+
if (ctxt == NULL)
|
857
|
+
return(-1);
|
858
|
+
if (ctxt->hostname == NULL)
|
859
|
+
return(-1);
|
860
|
+
|
861
|
+
/*
|
862
|
+
* do the blocking DNS query.
|
863
|
+
*/
|
864
|
+
if (proxy) {
|
865
|
+
port = proxyPort;
|
866
|
+
} else {
|
867
|
+
port = ctxt->port;
|
868
|
+
}
|
869
|
+
if (port == 0)
|
870
|
+
port = 21;
|
871
|
+
|
872
|
+
memset (&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
|
873
|
+
|
874
|
+
#ifdef SUPPORT_IP6
|
875
|
+
if (have_ipv6 ()) {
|
876
|
+
struct addrinfo hints, *tmp, *result;
|
877
|
+
|
878
|
+
result = NULL;
|
879
|
+
memset (&hints, 0, sizeof(hints));
|
880
|
+
hints.ai_socktype = SOCK_STREAM;
|
881
|
+
|
882
|
+
if (proxy) {
|
883
|
+
if (getaddrinfo (proxy, NULL, &hints, &result) != 0) {
|
884
|
+
__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
|
885
|
+
return (-1);
|
886
|
+
}
|
887
|
+
}
|
888
|
+
else
|
889
|
+
if (getaddrinfo (ctxt->hostname, NULL, &hints, &result) != 0) {
|
890
|
+
__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
|
891
|
+
return (-1);
|
892
|
+
}
|
893
|
+
|
894
|
+
for (tmp = result; tmp; tmp = tmp->ai_next)
|
895
|
+
if (tmp->ai_family == AF_INET || tmp->ai_family == AF_INET6)
|
896
|
+
break;
|
897
|
+
|
898
|
+
if (!tmp) {
|
899
|
+
if (result)
|
900
|
+
freeaddrinfo (result);
|
901
|
+
__xmlIOErr(XML_FROM_FTP, 0, "getaddrinfo failed");
|
902
|
+
return (-1);
|
903
|
+
}
|
904
|
+
if ((size_t)tmp->ai_addrlen > sizeof(ctxt->ftpAddr)) {
|
905
|
+
if (result)
|
906
|
+
freeaddrinfo (result);
|
907
|
+
__xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
|
908
|
+
return (-1);
|
909
|
+
}
|
910
|
+
if (tmp->ai_family == AF_INET6) {
|
911
|
+
memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
|
912
|
+
((struct sockaddr_in6 *) &ctxt->ftpAddr)->sin6_port = htons (port);
|
913
|
+
ctxt->controlFd = socket (AF_INET6, SOCK_STREAM, 0);
|
914
|
+
}
|
915
|
+
else {
|
916
|
+
memcpy (&ctxt->ftpAddr, tmp->ai_addr, tmp->ai_addrlen);
|
917
|
+
((struct sockaddr_in *) &ctxt->ftpAddr)->sin_port = htons (port);
|
918
|
+
ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
|
919
|
+
}
|
920
|
+
addrlen = tmp->ai_addrlen;
|
921
|
+
freeaddrinfo (result);
|
922
|
+
}
|
923
|
+
else
|
924
|
+
#endif
|
925
|
+
{
|
926
|
+
if (proxy)
|
927
|
+
hp = gethostbyname (GETHOSTBYNAME_ARG_CAST proxy);
|
928
|
+
else
|
929
|
+
hp = gethostbyname (GETHOSTBYNAME_ARG_CAST ctxt->hostname);
|
930
|
+
if (hp == NULL) {
|
931
|
+
__xmlIOErr(XML_FROM_FTP, 0, "gethostbyname failed");
|
932
|
+
return (-1);
|
933
|
+
}
|
934
|
+
if ((unsigned int) hp->h_length >
|
935
|
+
sizeof(((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr)) {
|
936
|
+
__xmlIOErr(XML_FROM_FTP, 0, "gethostbyname address mismatch");
|
937
|
+
return (-1);
|
938
|
+
}
|
939
|
+
|
940
|
+
/*
|
941
|
+
* Prepare the socket
|
942
|
+
*/
|
943
|
+
((struct sockaddr_in *)&ctxt->ftpAddr)->sin_family = AF_INET;
|
944
|
+
memcpy (&((struct sockaddr_in *)&ctxt->ftpAddr)->sin_addr,
|
945
|
+
hp->h_addr_list[0], hp->h_length);
|
946
|
+
((struct sockaddr_in *)&ctxt->ftpAddr)->sin_port =
|
947
|
+
(unsigned short)htons ((unsigned short)port);
|
948
|
+
ctxt->controlFd = socket (AF_INET, SOCK_STREAM, 0);
|
949
|
+
addrlen = sizeof (struct sockaddr_in);
|
950
|
+
}
|
951
|
+
|
952
|
+
if (ctxt->controlFd == INVALID_SOCKET) {
|
953
|
+
__xmlIOErr(XML_FROM_FTP, 0, "socket failed");
|
954
|
+
return(-1);
|
955
|
+
}
|
956
|
+
|
957
|
+
/*
|
958
|
+
* Do the connect.
|
959
|
+
*/
|
960
|
+
if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
|
961
|
+
addrlen) < 0) {
|
962
|
+
__xmlIOErr(XML_FROM_FTP, 0, "Failed to create a connection");
|
963
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
964
|
+
ctxt->controlFd = INVALID_SOCKET;
|
965
|
+
return(-1);
|
966
|
+
}
|
967
|
+
|
968
|
+
/*
|
969
|
+
* Wait for the HELLO from the server.
|
970
|
+
*/
|
971
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
972
|
+
if (res != 2) {
|
973
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
974
|
+
ctxt->controlFd = INVALID_SOCKET;
|
975
|
+
return(-1);
|
976
|
+
}
|
977
|
+
|
978
|
+
/*
|
979
|
+
* State diagram for the login operation on the FTP server
|
980
|
+
*
|
981
|
+
* Reference: RFC 959
|
982
|
+
*
|
983
|
+
* 1
|
984
|
+
* +---+ USER +---+------------->+---+
|
985
|
+
* | B |---------->| W | 2 ---->| E |
|
986
|
+
* +---+ +---+------ | -->+---+
|
987
|
+
* | | | | |
|
988
|
+
* 3 | | 4,5 | | |
|
989
|
+
* -------------- ----- | | |
|
990
|
+
* | | | | |
|
991
|
+
* | | | | |
|
992
|
+
* | --------- |
|
993
|
+
* | 1| | | |
|
994
|
+
* V | | | |
|
995
|
+
* +---+ PASS +---+ 2 | ------>+---+
|
996
|
+
* | |---------->| W |------------->| S |
|
997
|
+
* +---+ +---+ ---------->+---+
|
998
|
+
* | | | | |
|
999
|
+
* 3 | |4,5| | |
|
1000
|
+
* -------------- -------- |
|
1001
|
+
* | | | | |
|
1002
|
+
* | | | | |
|
1003
|
+
* | -----------
|
1004
|
+
* | 1,3| | | |
|
1005
|
+
* V | 2| | |
|
1006
|
+
* +---+ ACCT +---+-- | ----->+---+
|
1007
|
+
* | |---------->| W | 4,5 -------->| F |
|
1008
|
+
* +---+ +---+------------->+---+
|
1009
|
+
*
|
1010
|
+
* Of course in case of using a proxy this get really nasty and is not
|
1011
|
+
* standardized at all :-(
|
1012
|
+
*/
|
1013
|
+
if (proxy) {
|
1014
|
+
int len;
|
1015
|
+
char buf[400];
|
1016
|
+
|
1017
|
+
if (proxyUser != NULL) {
|
1018
|
+
/*
|
1019
|
+
* We need proxy auth
|
1020
|
+
*/
|
1021
|
+
snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
|
1022
|
+
buf[sizeof(buf) - 1] = 0;
|
1023
|
+
len = strlen(buf);
|
1024
|
+
#ifdef DEBUG_FTP
|
1025
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1026
|
+
#endif
|
1027
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1028
|
+
if (res < 0) {
|
1029
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1030
|
+
closesocket(ctxt->controlFd);
|
1031
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1032
|
+
return(res);
|
1033
|
+
}
|
1034
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1035
|
+
switch (res) {
|
1036
|
+
case 2:
|
1037
|
+
if (proxyPasswd == NULL)
|
1038
|
+
break;
|
1039
|
+
/* Falls through. */
|
1040
|
+
case 3:
|
1041
|
+
if (proxyPasswd != NULL)
|
1042
|
+
snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
|
1043
|
+
else
|
1044
|
+
snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
|
1045
|
+
buf[sizeof(buf) - 1] = 0;
|
1046
|
+
len = strlen(buf);
|
1047
|
+
#ifdef DEBUG_FTP
|
1048
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1049
|
+
#endif
|
1050
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1051
|
+
if (res < 0) {
|
1052
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1053
|
+
closesocket(ctxt->controlFd);
|
1054
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1055
|
+
return(res);
|
1056
|
+
}
|
1057
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1058
|
+
if (res > 3) {
|
1059
|
+
closesocket(ctxt->controlFd);
|
1060
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1061
|
+
return(-1);
|
1062
|
+
}
|
1063
|
+
break;
|
1064
|
+
case 1:
|
1065
|
+
break;
|
1066
|
+
case 4:
|
1067
|
+
case 5:
|
1068
|
+
case -1:
|
1069
|
+
default:
|
1070
|
+
closesocket(ctxt->controlFd);
|
1071
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1072
|
+
return(-1);
|
1073
|
+
}
|
1074
|
+
}
|
1075
|
+
|
1076
|
+
/*
|
1077
|
+
* We assume we don't need more authentication to the proxy
|
1078
|
+
* and that it succeeded :-\
|
1079
|
+
*/
|
1080
|
+
switch (proxyType) {
|
1081
|
+
case 0:
|
1082
|
+
/* we will try in sequence */
|
1083
|
+
case 1:
|
1084
|
+
/* Using SITE command */
|
1085
|
+
snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
|
1086
|
+
buf[sizeof(buf) - 1] = 0;
|
1087
|
+
len = strlen(buf);
|
1088
|
+
#ifdef DEBUG_FTP
|
1089
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1090
|
+
#endif
|
1091
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1092
|
+
if (res < 0) {
|
1093
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1094
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1095
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1096
|
+
return(res);
|
1097
|
+
}
|
1098
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1099
|
+
if (res == 2) {
|
1100
|
+
/* we assume it worked :-\ 1 is error for SITE command */
|
1101
|
+
proxyType = 1;
|
1102
|
+
break;
|
1103
|
+
}
|
1104
|
+
if (proxyType == 1) {
|
1105
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1106
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1107
|
+
return(-1);
|
1108
|
+
}
|
1109
|
+
/* Falls through. */
|
1110
|
+
case 2:
|
1111
|
+
/* USER user@host command */
|
1112
|
+
if (ctxt->user == NULL)
|
1113
|
+
snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
|
1114
|
+
ctxt->hostname);
|
1115
|
+
else
|
1116
|
+
snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
|
1117
|
+
ctxt->user, ctxt->hostname);
|
1118
|
+
buf[sizeof(buf) - 1] = 0;
|
1119
|
+
len = strlen(buf);
|
1120
|
+
#ifdef DEBUG_FTP
|
1121
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1122
|
+
#endif
|
1123
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1124
|
+
if (res < 0) {
|
1125
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1126
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1127
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1128
|
+
return(res);
|
1129
|
+
}
|
1130
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1131
|
+
if ((res == 1) || (res == 2)) {
|
1132
|
+
/* we assume it worked :-\ */
|
1133
|
+
proxyType = 2;
|
1134
|
+
return(0);
|
1135
|
+
}
|
1136
|
+
if (ctxt->passwd == NULL)
|
1137
|
+
snprintf(buf, sizeof(buf), "PASS anonymous@\r\n");
|
1138
|
+
else
|
1139
|
+
snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
|
1140
|
+
buf[sizeof(buf) - 1] = 0;
|
1141
|
+
len = strlen(buf);
|
1142
|
+
#ifdef DEBUG_FTP
|
1143
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1144
|
+
#endif
|
1145
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1146
|
+
if (res < 0) {
|
1147
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1148
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1149
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1150
|
+
return(res);
|
1151
|
+
}
|
1152
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1153
|
+
if ((res == 1) || (res == 2)) {
|
1154
|
+
/* we assume it worked :-\ */
|
1155
|
+
proxyType = 2;
|
1156
|
+
return(0);
|
1157
|
+
}
|
1158
|
+
if (proxyType == 2) {
|
1159
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1160
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1161
|
+
return(-1);
|
1162
|
+
}
|
1163
|
+
/* Falls through. */
|
1164
|
+
case 3:
|
1165
|
+
/*
|
1166
|
+
* If you need support for other Proxy authentication scheme
|
1167
|
+
* send the code or at least the sequence in use.
|
1168
|
+
*/
|
1169
|
+
default:
|
1170
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1171
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1172
|
+
return(-1);
|
1173
|
+
}
|
1174
|
+
}
|
1175
|
+
/*
|
1176
|
+
* Non-proxy handling.
|
1177
|
+
*/
|
1178
|
+
res = xmlNanoFTPSendUser(ctxt);
|
1179
|
+
if (res < 0) {
|
1180
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1181
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1182
|
+
return(-1);
|
1183
|
+
}
|
1184
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1185
|
+
switch (res) {
|
1186
|
+
case 2:
|
1187
|
+
return(0);
|
1188
|
+
case 3:
|
1189
|
+
break;
|
1190
|
+
case 1:
|
1191
|
+
case 4:
|
1192
|
+
case 5:
|
1193
|
+
case -1:
|
1194
|
+
default:
|
1195
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1196
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1197
|
+
return(-1);
|
1198
|
+
}
|
1199
|
+
res = xmlNanoFTPSendPasswd(ctxt);
|
1200
|
+
if (res < 0) {
|
1201
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1202
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1203
|
+
return(-1);
|
1204
|
+
}
|
1205
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1206
|
+
switch (res) {
|
1207
|
+
case 2:
|
1208
|
+
break;
|
1209
|
+
case 3:
|
1210
|
+
__xmlIOErr(XML_FROM_FTP, XML_FTP_ACCNT,
|
1211
|
+
"FTP server asking for ACCNT on anonymous\n");
|
1212
|
+
/* Falls through. */
|
1213
|
+
case 1:
|
1214
|
+
case 4:
|
1215
|
+
case 5:
|
1216
|
+
case -1:
|
1217
|
+
default:
|
1218
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1219
|
+
ctxt->controlFd = INVALID_SOCKET;
|
1220
|
+
return(-1);
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
return(0);
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
/**
|
1227
|
+
* xmlNanoFTPConnectTo:
|
1228
|
+
* @server: an FTP server name
|
1229
|
+
* @port: the port (use 21 if 0)
|
1230
|
+
*
|
1231
|
+
* Tries to open a control connection to the given server/port
|
1232
|
+
*
|
1233
|
+
* Returns an fTP context or NULL if it failed
|
1234
|
+
*/
|
1235
|
+
|
1236
|
+
void*
|
1237
|
+
xmlNanoFTPConnectTo(const char *server, int port) {
|
1238
|
+
xmlNanoFTPCtxtPtr ctxt;
|
1239
|
+
int res;
|
1240
|
+
|
1241
|
+
xmlNanoFTPInit();
|
1242
|
+
if (server == NULL)
|
1243
|
+
return(NULL);
|
1244
|
+
if (port <= 0)
|
1245
|
+
return(NULL);
|
1246
|
+
ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
|
1247
|
+
if (ctxt == NULL)
|
1248
|
+
return(NULL);
|
1249
|
+
ctxt->hostname = xmlMemStrdup(server);
|
1250
|
+
if (ctxt->hostname == NULL) {
|
1251
|
+
xmlNanoFTPFreeCtxt(ctxt);
|
1252
|
+
return(NULL);
|
1253
|
+
}
|
1254
|
+
ctxt->port = port;
|
1255
|
+
res = xmlNanoFTPConnect(ctxt);
|
1256
|
+
if (res < 0) {
|
1257
|
+
xmlNanoFTPFreeCtxt(ctxt);
|
1258
|
+
return(NULL);
|
1259
|
+
}
|
1260
|
+
return(ctxt);
|
1261
|
+
}
|
1262
|
+
|
1263
|
+
/**
|
1264
|
+
* xmlNanoFTPCwd:
|
1265
|
+
* @ctx: an FTP context
|
1266
|
+
* @directory: a directory on the server
|
1267
|
+
*
|
1268
|
+
* Tries to change the remote directory
|
1269
|
+
*
|
1270
|
+
* Returns -1 in case of error, 1 if CWD worked, 0 if it failed
|
1271
|
+
*/
|
1272
|
+
|
1273
|
+
int
|
1274
|
+
xmlNanoFTPCwd(void *ctx, const char *directory) {
|
1275
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1276
|
+
char buf[400];
|
1277
|
+
int len;
|
1278
|
+
int res;
|
1279
|
+
|
1280
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
|
1281
|
+
if (directory == NULL) return 0;
|
1282
|
+
|
1283
|
+
/*
|
1284
|
+
* Expected response code for CWD:
|
1285
|
+
*
|
1286
|
+
* CWD
|
1287
|
+
* 250
|
1288
|
+
* 500, 501, 502, 421, 530, 550
|
1289
|
+
*/
|
1290
|
+
snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
|
1291
|
+
buf[sizeof(buf) - 1] = 0;
|
1292
|
+
len = strlen(buf);
|
1293
|
+
#ifdef DEBUG_FTP
|
1294
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1295
|
+
#endif
|
1296
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1297
|
+
if (res < 0) {
|
1298
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1299
|
+
return(res);
|
1300
|
+
}
|
1301
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1302
|
+
if (res == 4) {
|
1303
|
+
return(-1);
|
1304
|
+
}
|
1305
|
+
if (res == 2) return(1);
|
1306
|
+
if (res == 5) {
|
1307
|
+
return(0);
|
1308
|
+
}
|
1309
|
+
return(0);
|
1310
|
+
}
|
1311
|
+
|
1312
|
+
/**
|
1313
|
+
* xmlNanoFTPDele:
|
1314
|
+
* @ctx: an FTP context
|
1315
|
+
* @file: a file or directory on the server
|
1316
|
+
*
|
1317
|
+
* Tries to delete an item (file or directory) from server
|
1318
|
+
*
|
1319
|
+
* Returns -1 in case of error, 1 if DELE worked, 0 if it failed
|
1320
|
+
*/
|
1321
|
+
|
1322
|
+
int
|
1323
|
+
xmlNanoFTPDele(void *ctx, const char *file) {
|
1324
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1325
|
+
char buf[400];
|
1326
|
+
int len;
|
1327
|
+
int res;
|
1328
|
+
|
1329
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET) ||
|
1330
|
+
(file == NULL)) return(-1);
|
1331
|
+
|
1332
|
+
/*
|
1333
|
+
* Expected response code for DELE:
|
1334
|
+
*
|
1335
|
+
* DELE
|
1336
|
+
* 250
|
1337
|
+
* 450, 550
|
1338
|
+
* 500, 501, 502, 421, 530
|
1339
|
+
*/
|
1340
|
+
|
1341
|
+
snprintf(buf, sizeof(buf), "DELE %s\r\n", file);
|
1342
|
+
buf[sizeof(buf) - 1] = 0;
|
1343
|
+
len = strlen(buf);
|
1344
|
+
#ifdef DEBUG_FTP
|
1345
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1346
|
+
#endif
|
1347
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1348
|
+
if (res < 0) {
|
1349
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1350
|
+
return(res);
|
1351
|
+
}
|
1352
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1353
|
+
if (res == 4) {
|
1354
|
+
return(-1);
|
1355
|
+
}
|
1356
|
+
if (res == 2) return(1);
|
1357
|
+
if (res == 5) {
|
1358
|
+
return(0);
|
1359
|
+
}
|
1360
|
+
return(0);
|
1361
|
+
}
|
1362
|
+
/**
|
1363
|
+
* xmlNanoFTPGetConnection:
|
1364
|
+
* @ctx: an FTP context
|
1365
|
+
*
|
1366
|
+
* Try to open a data connection to the server. Currently only
|
1367
|
+
* passive mode is supported.
|
1368
|
+
*
|
1369
|
+
* Returns -1 in case of error, 0 otherwise
|
1370
|
+
*/
|
1371
|
+
|
1372
|
+
SOCKET
|
1373
|
+
xmlNanoFTPGetConnection(void *ctx) {
|
1374
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1375
|
+
char buf[200], *cur;
|
1376
|
+
int len, i;
|
1377
|
+
int res;
|
1378
|
+
unsigned char ad[6], *adp, *portp;
|
1379
|
+
unsigned int temp[6];
|
1380
|
+
#ifdef SUPPORT_IP6
|
1381
|
+
struct sockaddr_storage dataAddr;
|
1382
|
+
#else
|
1383
|
+
struct sockaddr_in dataAddr;
|
1384
|
+
#endif
|
1385
|
+
XML_SOCKLEN_T dataAddrLen;
|
1386
|
+
|
1387
|
+
if (ctxt == NULL) return INVALID_SOCKET;
|
1388
|
+
|
1389
|
+
memset (&dataAddr, 0, sizeof(dataAddr));
|
1390
|
+
#ifdef SUPPORT_IP6
|
1391
|
+
if ((ctxt->ftpAddr).ss_family == AF_INET6) {
|
1392
|
+
ctxt->dataFd = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP);
|
1393
|
+
((struct sockaddr_in6 *)&dataAddr)->sin6_family = AF_INET6;
|
1394
|
+
dataAddrLen = sizeof(struct sockaddr_in6);
|
1395
|
+
} else
|
1396
|
+
#endif
|
1397
|
+
{
|
1398
|
+
ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
1399
|
+
((struct sockaddr_in *)&dataAddr)->sin_family = AF_INET;
|
1400
|
+
dataAddrLen = sizeof (struct sockaddr_in);
|
1401
|
+
}
|
1402
|
+
|
1403
|
+
if (ctxt->dataFd == INVALID_SOCKET) {
|
1404
|
+
__xmlIOErr(XML_FROM_FTP, 0, "socket failed");
|
1405
|
+
return INVALID_SOCKET;
|
1406
|
+
}
|
1407
|
+
|
1408
|
+
if (ctxt->passive) {
|
1409
|
+
#ifdef SUPPORT_IP6
|
1410
|
+
if ((ctxt->ftpAddr).ss_family == AF_INET6)
|
1411
|
+
snprintf (buf, sizeof(buf), "EPSV\r\n");
|
1412
|
+
else
|
1413
|
+
#endif
|
1414
|
+
snprintf (buf, sizeof(buf), "PASV\r\n");
|
1415
|
+
len = strlen (buf);
|
1416
|
+
#ifdef DEBUG_FTP
|
1417
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1418
|
+
#endif
|
1419
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1420
|
+
if (res < 0) {
|
1421
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1422
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1423
|
+
return INVALID_SOCKET;
|
1424
|
+
}
|
1425
|
+
res = xmlNanoFTPReadResponse(ctx);
|
1426
|
+
if (res != 2) {
|
1427
|
+
if (res == 5) {
|
1428
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1429
|
+
return INVALID_SOCKET;
|
1430
|
+
} else {
|
1431
|
+
/*
|
1432
|
+
* retry with an active connection
|
1433
|
+
*/
|
1434
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1435
|
+
ctxt->passive = 0;
|
1436
|
+
}
|
1437
|
+
}
|
1438
|
+
cur = &ctxt->controlBuf[ctxt->controlBufAnswer];
|
1439
|
+
while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
|
1440
|
+
#ifdef SUPPORT_IP6
|
1441
|
+
if ((ctxt->ftpAddr).ss_family == AF_INET6) {
|
1442
|
+
if (sscanf (cur, "%u", &temp[0]) != 1) {
|
1443
|
+
__xmlIOErr(XML_FROM_FTP, XML_FTP_EPSV_ANSWER,
|
1444
|
+
"Invalid answer to EPSV\n");
|
1445
|
+
if (ctxt->dataFd != INVALID_SOCKET) {
|
1446
|
+
closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1447
|
+
}
|
1448
|
+
return INVALID_SOCKET;
|
1449
|
+
}
|
1450
|
+
memcpy (&((struct sockaddr_in6 *)&dataAddr)->sin6_addr, &((struct sockaddr_in6 *)&ctxt->ftpAddr)->sin6_addr, sizeof(struct in6_addr));
|
1451
|
+
((struct sockaddr_in6 *)&dataAddr)->sin6_port = htons (temp[0]);
|
1452
|
+
}
|
1453
|
+
else
|
1454
|
+
#endif
|
1455
|
+
{
|
1456
|
+
if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
|
1457
|
+
&temp[3], &temp[4], &temp[5]) != 6) {
|
1458
|
+
__xmlIOErr(XML_FROM_FTP, XML_FTP_PASV_ANSWER,
|
1459
|
+
"Invalid answer to PASV\n");
|
1460
|
+
if (ctxt->dataFd != INVALID_SOCKET) {
|
1461
|
+
closesocket (ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1462
|
+
}
|
1463
|
+
return INVALID_SOCKET;
|
1464
|
+
}
|
1465
|
+
for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
|
1466
|
+
memcpy (&((struct sockaddr_in *)&dataAddr)->sin_addr, &ad[0], 4);
|
1467
|
+
memcpy (&((struct sockaddr_in *)&dataAddr)->sin_port, &ad[4], 2);
|
1468
|
+
}
|
1469
|
+
|
1470
|
+
if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
|
1471
|
+
__xmlIOErr(XML_FROM_FTP, 0, "Failed to create a data connection");
|
1472
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1473
|
+
return INVALID_SOCKET;
|
1474
|
+
}
|
1475
|
+
} else {
|
1476
|
+
getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
|
1477
|
+
#ifdef SUPPORT_IP6
|
1478
|
+
if ((ctxt->ftpAddr).ss_family == AF_INET6)
|
1479
|
+
((struct sockaddr_in6 *)&dataAddr)->sin6_port = 0;
|
1480
|
+
else
|
1481
|
+
#endif
|
1482
|
+
((struct sockaddr_in *)&dataAddr)->sin_port = 0;
|
1483
|
+
|
1484
|
+
if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
|
1485
|
+
__xmlIOErr(XML_FROM_FTP, 0, "bind failed");
|
1486
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1487
|
+
return INVALID_SOCKET;
|
1488
|
+
}
|
1489
|
+
getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
|
1490
|
+
|
1491
|
+
if (listen(ctxt->dataFd, 1) < 0) {
|
1492
|
+
__xmlIOErr(XML_FROM_FTP, 0, "listen failed");
|
1493
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1494
|
+
return INVALID_SOCKET;
|
1495
|
+
}
|
1496
|
+
#ifdef SUPPORT_IP6
|
1497
|
+
if ((ctxt->ftpAddr).ss_family == AF_INET6) {
|
1498
|
+
char buf6[INET6_ADDRSTRLEN];
|
1499
|
+
inet_ntop (AF_INET6, &((struct sockaddr_in6 *)&dataAddr)->sin6_addr,
|
1500
|
+
buf6, INET6_ADDRSTRLEN);
|
1501
|
+
adp = (unsigned char *) buf6;
|
1502
|
+
portp = (unsigned char *) &((struct sockaddr_in6 *)&dataAddr)->sin6_port;
|
1503
|
+
snprintf (buf, sizeof(buf), "EPRT |2|%s|%s|\r\n", adp, portp);
|
1504
|
+
} else
|
1505
|
+
#endif
|
1506
|
+
{
|
1507
|
+
adp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_addr;
|
1508
|
+
portp = (unsigned char *) &((struct sockaddr_in *)&dataAddr)->sin_port;
|
1509
|
+
snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
|
1510
|
+
adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
|
1511
|
+
portp[0] & 0xff, portp[1] & 0xff);
|
1512
|
+
}
|
1513
|
+
|
1514
|
+
buf[sizeof(buf) - 1] = 0;
|
1515
|
+
len = strlen(buf);
|
1516
|
+
#ifdef DEBUG_FTP
|
1517
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1518
|
+
#endif
|
1519
|
+
|
1520
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1521
|
+
if (res < 0) {
|
1522
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1523
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1524
|
+
return INVALID_SOCKET;
|
1525
|
+
}
|
1526
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1527
|
+
if (res != 2) {
|
1528
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1529
|
+
return INVALID_SOCKET;
|
1530
|
+
}
|
1531
|
+
}
|
1532
|
+
return(ctxt->dataFd);
|
1533
|
+
|
1534
|
+
}
|
1535
|
+
|
1536
|
+
/**
|
1537
|
+
* xmlNanoFTPCloseConnection:
|
1538
|
+
* @ctx: an FTP context
|
1539
|
+
*
|
1540
|
+
* Close the data connection from the server
|
1541
|
+
*
|
1542
|
+
* Returns -1 in case of error, 0 otherwise
|
1543
|
+
*/
|
1544
|
+
|
1545
|
+
int
|
1546
|
+
xmlNanoFTPCloseConnection(void *ctx) {
|
1547
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1548
|
+
int res;
|
1549
|
+
fd_set rfd, efd;
|
1550
|
+
struct timeval tv;
|
1551
|
+
|
1552
|
+
if ((ctxt == NULL) || (ctxt->controlFd == INVALID_SOCKET)) return(-1);
|
1553
|
+
|
1554
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1555
|
+
tv.tv_sec = 15;
|
1556
|
+
tv.tv_usec = 0;
|
1557
|
+
FD_ZERO(&rfd);
|
1558
|
+
FD_SET(ctxt->controlFd, &rfd);
|
1559
|
+
FD_ZERO(&efd);
|
1560
|
+
FD_SET(ctxt->controlFd, &efd);
|
1561
|
+
res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
|
1562
|
+
if (res < 0) {
|
1563
|
+
#ifdef DEBUG_FTP
|
1564
|
+
perror("select");
|
1565
|
+
#endif
|
1566
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1567
|
+
return(-1);
|
1568
|
+
}
|
1569
|
+
if (res == 0) {
|
1570
|
+
#ifdef DEBUG_FTP
|
1571
|
+
xmlGenericError(xmlGenericErrorContext,
|
1572
|
+
"xmlNanoFTPCloseConnection: timeout\n");
|
1573
|
+
#endif
|
1574
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1575
|
+
} else {
|
1576
|
+
res = xmlNanoFTPGetResponse(ctxt);
|
1577
|
+
if (res != 2) {
|
1578
|
+
closesocket(ctxt->controlFd); ctxt->controlFd = INVALID_SOCKET;
|
1579
|
+
return(-1);
|
1580
|
+
}
|
1581
|
+
}
|
1582
|
+
return(0);
|
1583
|
+
}
|
1584
|
+
|
1585
|
+
/**
|
1586
|
+
* xmlNanoFTPParseList:
|
1587
|
+
* @list: some data listing received from the server
|
1588
|
+
* @callback: the user callback
|
1589
|
+
* @userData: the user callback data
|
1590
|
+
*
|
1591
|
+
* Parse at most one entry from the listing.
|
1592
|
+
*
|
1593
|
+
* Returns -1 in case of error, the length of data parsed otherwise
|
1594
|
+
*/
|
1595
|
+
|
1596
|
+
static int
|
1597
|
+
xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
|
1598
|
+
const char *cur = list;
|
1599
|
+
char filename[151];
|
1600
|
+
char attrib[11];
|
1601
|
+
char owner[11];
|
1602
|
+
char group[11];
|
1603
|
+
char month[4];
|
1604
|
+
int year = 0;
|
1605
|
+
int minute = 0;
|
1606
|
+
int hour = 0;
|
1607
|
+
int day = 0;
|
1608
|
+
unsigned long size = 0;
|
1609
|
+
int links = 0;
|
1610
|
+
int i;
|
1611
|
+
|
1612
|
+
if (!strncmp(cur, "total", 5)) {
|
1613
|
+
cur += 5;
|
1614
|
+
while (*cur == ' ') cur++;
|
1615
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1616
|
+
links = (links * 10) + (*cur++ - '0');
|
1617
|
+
while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
|
1618
|
+
cur++;
|
1619
|
+
return(cur - list);
|
1620
|
+
} else if (*list == '+') {
|
1621
|
+
return(0);
|
1622
|
+
} else {
|
1623
|
+
while ((*cur == ' ') || (*cur == '\n') || (*cur == '\r'))
|
1624
|
+
cur++;
|
1625
|
+
if (*cur == 0) return(0);
|
1626
|
+
i = 0;
|
1627
|
+
while (*cur != ' ') {
|
1628
|
+
if (i < 10)
|
1629
|
+
attrib[i++] = *cur;
|
1630
|
+
cur++;
|
1631
|
+
if (*cur == 0) return(0);
|
1632
|
+
}
|
1633
|
+
attrib[10] = 0;
|
1634
|
+
while (*cur == ' ') cur++;
|
1635
|
+
if (*cur == 0) return(0);
|
1636
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1637
|
+
links = (links * 10) + (*cur++ - '0');
|
1638
|
+
while (*cur == ' ') cur++;
|
1639
|
+
if (*cur == 0) return(0);
|
1640
|
+
i = 0;
|
1641
|
+
while (*cur != ' ') {
|
1642
|
+
if (i < 10)
|
1643
|
+
owner[i++] = *cur;
|
1644
|
+
cur++;
|
1645
|
+
if (*cur == 0) return(0);
|
1646
|
+
}
|
1647
|
+
owner[i] = 0;
|
1648
|
+
while (*cur == ' ') cur++;
|
1649
|
+
if (*cur == 0) return(0);
|
1650
|
+
i = 0;
|
1651
|
+
while (*cur != ' ') {
|
1652
|
+
if (i < 10)
|
1653
|
+
group[i++] = *cur;
|
1654
|
+
cur++;
|
1655
|
+
if (*cur == 0) return(0);
|
1656
|
+
}
|
1657
|
+
group[i] = 0;
|
1658
|
+
while (*cur == ' ') cur++;
|
1659
|
+
if (*cur == 0) return(0);
|
1660
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1661
|
+
size = (size * 10) + (*cur++ - '0');
|
1662
|
+
while (*cur == ' ') cur++;
|
1663
|
+
if (*cur == 0) return(0);
|
1664
|
+
i = 0;
|
1665
|
+
while (*cur != ' ') {
|
1666
|
+
if (i < 3)
|
1667
|
+
month[i++] = *cur;
|
1668
|
+
cur++;
|
1669
|
+
if (*cur == 0) return(0);
|
1670
|
+
}
|
1671
|
+
month[i] = 0;
|
1672
|
+
while (*cur == ' ') cur++;
|
1673
|
+
if (*cur == 0) return(0);
|
1674
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1675
|
+
day = (day * 10) + (*cur++ - '0');
|
1676
|
+
while (*cur == ' ') cur++;
|
1677
|
+
if (*cur == 0) return(0);
|
1678
|
+
if ((cur[1] == 0) || (cur[2] == 0)) return(0);
|
1679
|
+
if ((cur[1] == ':') || (cur[2] == ':')) {
|
1680
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1681
|
+
hour = (hour * 10) + (*cur++ - '0');
|
1682
|
+
if (*cur == ':') cur++;
|
1683
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1684
|
+
minute = (minute * 10) + (*cur++ - '0');
|
1685
|
+
} else {
|
1686
|
+
while ((*cur >= '0') && (*cur <= '9'))
|
1687
|
+
year = (year * 10) + (*cur++ - '0');
|
1688
|
+
}
|
1689
|
+
while (*cur == ' ') cur++;
|
1690
|
+
if (*cur == 0) return(0);
|
1691
|
+
i = 0;
|
1692
|
+
while ((*cur != '\n') && (*cur != '\r')) {
|
1693
|
+
if (i < 150)
|
1694
|
+
filename[i++] = *cur;
|
1695
|
+
cur++;
|
1696
|
+
if (*cur == 0) return(0);
|
1697
|
+
}
|
1698
|
+
filename[i] = 0;
|
1699
|
+
if ((*cur != '\n') && (*cur != '\r'))
|
1700
|
+
return(0);
|
1701
|
+
while ((*cur == '\n') || (*cur == '\r'))
|
1702
|
+
cur++;
|
1703
|
+
}
|
1704
|
+
if (callback != NULL) {
|
1705
|
+
callback(userData, filename, attrib, owner, group, size, links,
|
1706
|
+
year, month, day, hour, minute);
|
1707
|
+
}
|
1708
|
+
return(cur - list);
|
1709
|
+
}
|
1710
|
+
|
1711
|
+
/**
|
1712
|
+
* xmlNanoFTPList:
|
1713
|
+
* @ctx: an FTP context
|
1714
|
+
* @callback: the user callback
|
1715
|
+
* @userData: the user callback data
|
1716
|
+
* @filename: optional files to list
|
1717
|
+
*
|
1718
|
+
* Do a listing on the server. All files info are passed back
|
1719
|
+
* in the callbacks.
|
1720
|
+
*
|
1721
|
+
* Returns -1 in case of error, 0 otherwise
|
1722
|
+
*/
|
1723
|
+
|
1724
|
+
int
|
1725
|
+
xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
|
1726
|
+
const char *filename) {
|
1727
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1728
|
+
char buf[4096 + 1];
|
1729
|
+
int len, res;
|
1730
|
+
int indx = 0, base;
|
1731
|
+
fd_set rfd, efd;
|
1732
|
+
struct timeval tv;
|
1733
|
+
|
1734
|
+
if (ctxt == NULL) return (-1);
|
1735
|
+
if (filename == NULL) {
|
1736
|
+
if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
|
1737
|
+
return(-1);
|
1738
|
+
ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
|
1739
|
+
if (ctxt->dataFd == INVALID_SOCKET)
|
1740
|
+
return(-1);
|
1741
|
+
snprintf(buf, sizeof(buf), "LIST -L\r\n");
|
1742
|
+
} else {
|
1743
|
+
if (filename[0] != '/') {
|
1744
|
+
if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
|
1745
|
+
return(-1);
|
1746
|
+
}
|
1747
|
+
ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
|
1748
|
+
if (ctxt->dataFd == INVALID_SOCKET)
|
1749
|
+
return(-1);
|
1750
|
+
snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
|
1751
|
+
}
|
1752
|
+
buf[sizeof(buf) - 1] = 0;
|
1753
|
+
len = strlen(buf);
|
1754
|
+
#ifdef DEBUG_FTP
|
1755
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1756
|
+
#endif
|
1757
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1758
|
+
if (res < 0) {
|
1759
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1760
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1761
|
+
return(res);
|
1762
|
+
}
|
1763
|
+
res = xmlNanoFTPReadResponse(ctxt);
|
1764
|
+
if (res != 1) {
|
1765
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1766
|
+
return(-res);
|
1767
|
+
}
|
1768
|
+
|
1769
|
+
do {
|
1770
|
+
tv.tv_sec = 1;
|
1771
|
+
tv.tv_usec = 0;
|
1772
|
+
FD_ZERO(&rfd);
|
1773
|
+
FD_SET(ctxt->dataFd, &rfd);
|
1774
|
+
FD_ZERO(&efd);
|
1775
|
+
FD_SET(ctxt->dataFd, &efd);
|
1776
|
+
res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
|
1777
|
+
if (res < 0) {
|
1778
|
+
#ifdef DEBUG_FTP
|
1779
|
+
perror("select");
|
1780
|
+
#endif
|
1781
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1782
|
+
return(-1);
|
1783
|
+
}
|
1784
|
+
if (res == 0) {
|
1785
|
+
res = xmlNanoFTPCheckResponse(ctxt);
|
1786
|
+
if (res < 0) {
|
1787
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1788
|
+
ctxt->dataFd = INVALID_SOCKET;
|
1789
|
+
return(-1);
|
1790
|
+
}
|
1791
|
+
if (res == 2) {
|
1792
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1793
|
+
return(0);
|
1794
|
+
}
|
1795
|
+
|
1796
|
+
continue;
|
1797
|
+
}
|
1798
|
+
|
1799
|
+
if ((len = recv(ctxt->dataFd, &buf[indx], sizeof(buf) - (indx + 1), 0)) < 0) {
|
1800
|
+
__xmlIOErr(XML_FROM_FTP, 0, "recv");
|
1801
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1802
|
+
ctxt->dataFd = INVALID_SOCKET;
|
1803
|
+
return(-1);
|
1804
|
+
}
|
1805
|
+
#ifdef DEBUG_FTP
|
1806
|
+
write(1, &buf[indx], len);
|
1807
|
+
#endif
|
1808
|
+
indx += len;
|
1809
|
+
buf[indx] = 0;
|
1810
|
+
base = 0;
|
1811
|
+
do {
|
1812
|
+
res = xmlNanoFTPParseList(&buf[base], callback, userData);
|
1813
|
+
base += res;
|
1814
|
+
} while (res > 0);
|
1815
|
+
|
1816
|
+
memmove(&buf[0], &buf[base], indx - base);
|
1817
|
+
indx -= base;
|
1818
|
+
} while (len != 0);
|
1819
|
+
xmlNanoFTPCloseConnection(ctxt);
|
1820
|
+
return(0);
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
/**
|
1824
|
+
* xmlNanoFTPGetSocket:
|
1825
|
+
* @ctx: an FTP context
|
1826
|
+
* @filename: the file to retrieve (or NULL if path is in context).
|
1827
|
+
*
|
1828
|
+
* Initiate fetch of the given file from the server.
|
1829
|
+
*
|
1830
|
+
* Returns the socket for the data connection, or <0 in case of error
|
1831
|
+
*/
|
1832
|
+
|
1833
|
+
|
1834
|
+
SOCKET
|
1835
|
+
xmlNanoFTPGetSocket(void *ctx, const char *filename) {
|
1836
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1837
|
+
char buf[300];
|
1838
|
+
int res, len;
|
1839
|
+
if (ctx == NULL)
|
1840
|
+
return INVALID_SOCKET;
|
1841
|
+
if ((filename == NULL) && (ctxt->path == NULL))
|
1842
|
+
return INVALID_SOCKET;
|
1843
|
+
ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
|
1844
|
+
if (ctxt->dataFd == INVALID_SOCKET)
|
1845
|
+
return INVALID_SOCKET;
|
1846
|
+
|
1847
|
+
snprintf(buf, sizeof(buf), "TYPE I\r\n");
|
1848
|
+
len = strlen(buf);
|
1849
|
+
#ifdef DEBUG_FTP
|
1850
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1851
|
+
#endif
|
1852
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1853
|
+
if (res < 0) {
|
1854
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1855
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1856
|
+
return INVALID_SOCKET;
|
1857
|
+
}
|
1858
|
+
res = xmlNanoFTPReadResponse(ctxt);
|
1859
|
+
if (res != 2) {
|
1860
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1861
|
+
return INVALID_SOCKET;
|
1862
|
+
}
|
1863
|
+
if (filename == NULL)
|
1864
|
+
snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
|
1865
|
+
else
|
1866
|
+
snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
|
1867
|
+
buf[sizeof(buf) - 1] = 0;
|
1868
|
+
len = strlen(buf);
|
1869
|
+
#ifdef DEBUG_FTP
|
1870
|
+
xmlGenericError(xmlGenericErrorContext, "%s", buf);
|
1871
|
+
#endif
|
1872
|
+
res = send(ctxt->controlFd, SEND_ARG2_CAST buf, len, 0);
|
1873
|
+
if (res < 0) {
|
1874
|
+
__xmlIOErr(XML_FROM_FTP, 0, "send failed");
|
1875
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1876
|
+
return INVALID_SOCKET;
|
1877
|
+
}
|
1878
|
+
res = xmlNanoFTPReadResponse(ctxt);
|
1879
|
+
if (res != 1) {
|
1880
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1881
|
+
return INVALID_SOCKET;
|
1882
|
+
}
|
1883
|
+
return(ctxt->dataFd);
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
/**
|
1887
|
+
* xmlNanoFTPGet:
|
1888
|
+
* @ctx: an FTP context
|
1889
|
+
* @callback: the user callback
|
1890
|
+
* @userData: the user callback data
|
1891
|
+
* @filename: the file to retrieve
|
1892
|
+
*
|
1893
|
+
* Fetch the given file from the server. All data are passed back
|
1894
|
+
* in the callbacks. The last callback has a size of 0 block.
|
1895
|
+
*
|
1896
|
+
* Returns -1 in case of error, 0 otherwise
|
1897
|
+
*/
|
1898
|
+
|
1899
|
+
int
|
1900
|
+
xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
|
1901
|
+
const char *filename) {
|
1902
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1903
|
+
char buf[4096];
|
1904
|
+
int len = 0, res;
|
1905
|
+
fd_set rfd;
|
1906
|
+
struct timeval tv;
|
1907
|
+
|
1908
|
+
if (ctxt == NULL) return(-1);
|
1909
|
+
if ((filename == NULL) && (ctxt->path == NULL))
|
1910
|
+
return(-1);
|
1911
|
+
if (callback == NULL)
|
1912
|
+
return(-1);
|
1913
|
+
if (xmlNanoFTPGetSocket(ctxt, filename) == INVALID_SOCKET)
|
1914
|
+
return(-1);
|
1915
|
+
|
1916
|
+
do {
|
1917
|
+
tv.tv_sec = 1;
|
1918
|
+
tv.tv_usec = 0;
|
1919
|
+
FD_ZERO(&rfd);
|
1920
|
+
FD_SET(ctxt->dataFd, &rfd);
|
1921
|
+
res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
|
1922
|
+
if (res < 0) {
|
1923
|
+
#ifdef DEBUG_FTP
|
1924
|
+
perror("select");
|
1925
|
+
#endif
|
1926
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1927
|
+
return(-1);
|
1928
|
+
}
|
1929
|
+
if (res == 0) {
|
1930
|
+
res = xmlNanoFTPCheckResponse(ctxt);
|
1931
|
+
if (res < 0) {
|
1932
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1933
|
+
ctxt->dataFd = INVALID_SOCKET;
|
1934
|
+
return(-1);
|
1935
|
+
}
|
1936
|
+
if (res == 2) {
|
1937
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1938
|
+
return(0);
|
1939
|
+
}
|
1940
|
+
|
1941
|
+
continue;
|
1942
|
+
}
|
1943
|
+
if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
|
1944
|
+
__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
|
1945
|
+
callback(userData, buf, len);
|
1946
|
+
closesocket(ctxt->dataFd); ctxt->dataFd = INVALID_SOCKET;
|
1947
|
+
return(-1);
|
1948
|
+
}
|
1949
|
+
callback(userData, buf, len);
|
1950
|
+
} while (len != 0);
|
1951
|
+
|
1952
|
+
return(xmlNanoFTPCloseConnection(ctxt));
|
1953
|
+
}
|
1954
|
+
|
1955
|
+
/**
|
1956
|
+
* xmlNanoFTPRead:
|
1957
|
+
* @ctx: the FTP context
|
1958
|
+
* @dest: a buffer
|
1959
|
+
* @len: the buffer length
|
1960
|
+
*
|
1961
|
+
* This function tries to read @len bytes from the existing FTP connection
|
1962
|
+
* and saves them in @dest. This is a blocking call.
|
1963
|
+
*
|
1964
|
+
* Returns the number of byte read. 0 is an indication of an end of connection.
|
1965
|
+
* -1 indicates a parameter error.
|
1966
|
+
*/
|
1967
|
+
int
|
1968
|
+
xmlNanoFTPRead(void *ctx, void *dest, int len) {
|
1969
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
1970
|
+
|
1971
|
+
if (ctx == NULL) return(-1);
|
1972
|
+
if (ctxt->dataFd == INVALID_SOCKET) return(0);
|
1973
|
+
if (dest == NULL) return(-1);
|
1974
|
+
if (len <= 0) return(0);
|
1975
|
+
|
1976
|
+
len = recv(ctxt->dataFd, dest, len, 0);
|
1977
|
+
if (len <= 0) {
|
1978
|
+
if (len < 0)
|
1979
|
+
__xmlIOErr(XML_FROM_FTP, 0, "recv failed");
|
1980
|
+
xmlNanoFTPCloseConnection(ctxt);
|
1981
|
+
}
|
1982
|
+
#ifdef DEBUG_FTP
|
1983
|
+
xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
|
1984
|
+
#endif
|
1985
|
+
return(len);
|
1986
|
+
}
|
1987
|
+
|
1988
|
+
/**
|
1989
|
+
* xmlNanoFTPOpen:
|
1990
|
+
* @URL: the URL to the resource
|
1991
|
+
*
|
1992
|
+
* Start to fetch the given ftp:// resource
|
1993
|
+
*
|
1994
|
+
* Returns an FTP context, or NULL
|
1995
|
+
*/
|
1996
|
+
|
1997
|
+
void*
|
1998
|
+
xmlNanoFTPOpen(const char *URL) {
|
1999
|
+
xmlNanoFTPCtxtPtr ctxt;
|
2000
|
+
SOCKET sock;
|
2001
|
+
|
2002
|
+
xmlNanoFTPInit();
|
2003
|
+
if (URL == NULL) return(NULL);
|
2004
|
+
if (strncmp("ftp://", URL, 6)) return(NULL);
|
2005
|
+
|
2006
|
+
ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
|
2007
|
+
if (ctxt == NULL) return(NULL);
|
2008
|
+
if (xmlNanoFTPConnect(ctxt) < 0) {
|
2009
|
+
xmlNanoFTPFreeCtxt(ctxt);
|
2010
|
+
return(NULL);
|
2011
|
+
}
|
2012
|
+
sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
|
2013
|
+
if (sock == INVALID_SOCKET) {
|
2014
|
+
xmlNanoFTPFreeCtxt(ctxt);
|
2015
|
+
return(NULL);
|
2016
|
+
}
|
2017
|
+
return(ctxt);
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
/**
|
2021
|
+
* xmlNanoFTPClose:
|
2022
|
+
* @ctx: an FTP context
|
2023
|
+
*
|
2024
|
+
* Close the connection and both control and transport
|
2025
|
+
*
|
2026
|
+
* Returns -1 in case of error, 0 otherwise
|
2027
|
+
*/
|
2028
|
+
|
2029
|
+
int
|
2030
|
+
xmlNanoFTPClose(void *ctx) {
|
2031
|
+
xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
|
2032
|
+
|
2033
|
+
if (ctxt == NULL)
|
2034
|
+
return(-1);
|
2035
|
+
|
2036
|
+
if (ctxt->dataFd != INVALID_SOCKET) {
|
2037
|
+
closesocket(ctxt->dataFd);
|
2038
|
+
ctxt->dataFd = INVALID_SOCKET;
|
2039
|
+
}
|
2040
|
+
if (ctxt->controlFd != INVALID_SOCKET) {
|
2041
|
+
xmlNanoFTPQuit(ctxt);
|
2042
|
+
closesocket(ctxt->controlFd);
|
2043
|
+
ctxt->controlFd = INVALID_SOCKET;
|
2044
|
+
}
|
2045
|
+
xmlNanoFTPFreeCtxt(ctxt);
|
2046
|
+
return(0);
|
2047
|
+
}
|
2048
|
+
|
2049
|
+
#ifdef STANDALONE
|
2050
|
+
/************************************************************************
|
2051
|
+
* *
|
2052
|
+
* Basic test in Standalone mode *
|
2053
|
+
* *
|
2054
|
+
************************************************************************/
|
2055
|
+
static
|
2056
|
+
void ftpList(void *userData, const char *filename, const char* attrib,
|
2057
|
+
const char *owner, const char *group, unsigned long size, int links,
|
2058
|
+
int year, const char *month, int day, int hour, int minute) {
|
2059
|
+
xmlGenericError(xmlGenericErrorContext,
|
2060
|
+
"%s %s %s %ld %s\n", attrib, owner, group, size, filename);
|
2061
|
+
}
|
2062
|
+
static
|
2063
|
+
void ftpData(void *userData, const char *data, int len) {
|
2064
|
+
if (userData == NULL) return;
|
2065
|
+
if (len <= 0) {
|
2066
|
+
fclose((FILE*)userData);
|
2067
|
+
return;
|
2068
|
+
}
|
2069
|
+
fwrite(data, len, 1, (FILE*)userData);
|
2070
|
+
}
|
2071
|
+
|
2072
|
+
int main(int argc, char **argv) {
|
2073
|
+
void *ctxt;
|
2074
|
+
FILE *output;
|
2075
|
+
char *tstfile = NULL;
|
2076
|
+
|
2077
|
+
xmlNanoFTPInit();
|
2078
|
+
if (argc > 1) {
|
2079
|
+
ctxt = xmlNanoFTPNewCtxt(argv[1]);
|
2080
|
+
if (xmlNanoFTPConnect(ctxt) < 0) {
|
2081
|
+
xmlGenericError(xmlGenericErrorContext,
|
2082
|
+
"Couldn't connect to %s\n", argv[1]);
|
2083
|
+
exit(1);
|
2084
|
+
}
|
2085
|
+
if (argc > 2)
|
2086
|
+
tstfile = argv[2];
|
2087
|
+
} else
|
2088
|
+
ctxt = xmlNanoFTPConnectTo("localhost", 0);
|
2089
|
+
if (ctxt == NULL) {
|
2090
|
+
xmlGenericError(xmlGenericErrorContext,
|
2091
|
+
"Couldn't connect to localhost\n");
|
2092
|
+
exit(1);
|
2093
|
+
}
|
2094
|
+
xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
|
2095
|
+
output = fopen("/tmp/tstdata", "w");
|
2096
|
+
if (output != NULL) {
|
2097
|
+
if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
|
2098
|
+
xmlGenericError(xmlGenericErrorContext,
|
2099
|
+
"Failed to get file\n");
|
2100
|
+
|
2101
|
+
}
|
2102
|
+
xmlNanoFTPClose(ctxt);
|
2103
|
+
xmlMemoryDump();
|
2104
|
+
exit(0);
|
2105
|
+
}
|
2106
|
+
#endif /* STANDALONE */
|
2107
|
+
#else /* !LIBXML_FTP_ENABLED */
|
2108
|
+
#ifdef STANDALONE
|
2109
|
+
#include <stdio.h>
|
2110
|
+
int main(int argc, char **argv) {
|
2111
|
+
xmlGenericError(xmlGenericErrorContext,
|
2112
|
+
"%s : FTP support not compiled in\n", argv[0]);
|
2113
|
+
return(0);
|
2114
|
+
}
|
2115
|
+
#endif /* STANDALONE */
|
2116
|
+
#endif /* LIBXML_FTP_ENABLED */
|
2117
|
+
#define bottom_nanoftp
|
2118
|
+
#include "elfgcchack.h"
|