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.

Files changed (160) hide show
  1. package/LICENSE +19 -0
  2. package/Makefile +18 -0
  3. package/README.md +52 -0
  4. package/binding.gyp +81 -0
  5. package/index.d.ts +273 -0
  6. package/index.js +45 -0
  7. package/lib/bindings.js +1 -0
  8. package/lib/document.js +122 -0
  9. package/lib/element.js +82 -0
  10. package/lib/sax_parser.js +38 -0
  11. package/package.json +70 -0
  12. package/src/html_document.cc +7 -0
  13. package/src/html_document.h +18 -0
  14. package/src/libxmljs.cc +252 -0
  15. package/src/libxmljs.h +53 -0
  16. package/src/xml_attribute.cc +173 -0
  17. package/src/xml_attribute.h +40 -0
  18. package/src/xml_comment.cc +117 -0
  19. package/src/xml_comment.h +30 -0
  20. package/src/xml_document.cc +810 -0
  21. package/src/xml_document.h +67 -0
  22. package/src/xml_element.cc +565 -0
  23. package/src/xml_element.h +61 -0
  24. package/src/xml_namespace.cc +158 -0
  25. package/src/xml_namespace.h +39 -0
  26. package/src/xml_node.cc +761 -0
  27. package/src/xml_node.h +73 -0
  28. package/src/xml_pi.cc +161 -0
  29. package/src/xml_pi.h +34 -0
  30. package/src/xml_sax_parser.cc +424 -0
  31. package/src/xml_sax_parser.h +73 -0
  32. package/src/xml_syntax_error.cc +66 -0
  33. package/src/xml_syntax_error.h +25 -0
  34. package/src/xml_text.cc +320 -0
  35. package/src/xml_text.h +48 -0
  36. package/src/xml_textwriter.cc +315 -0
  37. package/src/xml_textwriter.h +62 -0
  38. package/src/xml_xpath_context.cc +70 -0
  39. package/src/xml_xpath_context.h +23 -0
  40. package/vendor/libxml/Copyright +23 -0
  41. package/vendor/libxml/DOCBparser.c +305 -0
  42. package/vendor/libxml/HTMLparser.c +7287 -0
  43. package/vendor/libxml/HTMLtree.c +1200 -0
  44. package/vendor/libxml/Makefile +2983 -0
  45. package/vendor/libxml/SAX.c +180 -0
  46. package/vendor/libxml/SAX2.c +3036 -0
  47. package/vendor/libxml/buf.c +1351 -0
  48. package/vendor/libxml/buf.h +72 -0
  49. package/vendor/libxml/c14n.c +2234 -0
  50. package/vendor/libxml/catalog.c +3828 -0
  51. package/vendor/libxml/chvalid.c +336 -0
  52. package/vendor/libxml/config.h +294 -0
  53. package/vendor/libxml/config.h.gch +0 -0
  54. package/vendor/libxml/debugXML.c +3423 -0
  55. package/vendor/libxml/dict.c +1298 -0
  56. package/vendor/libxml/elfgcchack.h +17818 -0
  57. package/vendor/libxml/enc.h +32 -0
  58. package/vendor/libxml/encoding.c +3975 -0
  59. package/vendor/libxml/entities.c +1163 -0
  60. package/vendor/libxml/error.c +998 -0
  61. package/vendor/libxml/globals.c +1126 -0
  62. package/vendor/libxml/hash.c +1146 -0
  63. package/vendor/libxml/include/libxml/DOCBparser.h +96 -0
  64. package/vendor/libxml/include/libxml/HTMLparser.h +306 -0
  65. package/vendor/libxml/include/libxml/HTMLtree.h +147 -0
  66. package/vendor/libxml/include/libxml/Makefile +725 -0
  67. package/vendor/libxml/include/libxml/Makefile.am +54 -0
  68. package/vendor/libxml/include/libxml/Makefile.in +725 -0
  69. package/vendor/libxml/include/libxml/SAX.h +173 -0
  70. package/vendor/libxml/include/libxml/SAX2.h +178 -0
  71. package/vendor/libxml/include/libxml/c14n.h +128 -0
  72. package/vendor/libxml/include/libxml/catalog.h +182 -0
  73. package/vendor/libxml/include/libxml/chvalid.h +230 -0
  74. package/vendor/libxml/include/libxml/debugXML.h +217 -0
  75. package/vendor/libxml/include/libxml/dict.h +79 -0
  76. package/vendor/libxml/include/libxml/encoding.h +245 -0
  77. package/vendor/libxml/include/libxml/entities.h +151 -0
  78. package/vendor/libxml/include/libxml/globals.h +508 -0
  79. package/vendor/libxml/include/libxml/hash.h +236 -0
  80. package/vendor/libxml/include/libxml/list.h +137 -0
  81. package/vendor/libxml/include/libxml/nanoftp.h +163 -0
  82. package/vendor/libxml/include/libxml/nanohttp.h +81 -0
  83. package/vendor/libxml/include/libxml/parser.h +1243 -0
  84. package/vendor/libxml/include/libxml/parserInternals.h +644 -0
  85. package/vendor/libxml/include/libxml/pattern.h +100 -0
  86. package/vendor/libxml/include/libxml/relaxng.h +217 -0
  87. package/vendor/libxml/include/libxml/schemasInternals.h +958 -0
  88. package/vendor/libxml/include/libxml/schematron.h +142 -0
  89. package/vendor/libxml/include/libxml/threads.h +89 -0
  90. package/vendor/libxml/include/libxml/tree.h +1311 -0
  91. package/vendor/libxml/include/libxml/uri.h +94 -0
  92. package/vendor/libxml/include/libxml/valid.h +458 -0
  93. package/vendor/libxml/include/libxml/xinclude.h +129 -0
  94. package/vendor/libxml/include/libxml/xlink.h +189 -0
  95. package/vendor/libxml/include/libxml/xmlIO.h +368 -0
  96. package/vendor/libxml/include/libxml/xmlautomata.h +146 -0
  97. package/vendor/libxml/include/libxml/xmlerror.h +945 -0
  98. package/vendor/libxml/include/libxml/xmlexports.h +77 -0
  99. package/vendor/libxml/include/libxml/xmlmemory.h +224 -0
  100. package/vendor/libxml/include/libxml/xmlmodule.h +57 -0
  101. package/vendor/libxml/include/libxml/xmlreader.h +428 -0
  102. package/vendor/libxml/include/libxml/xmlregexp.h +222 -0
  103. package/vendor/libxml/include/libxml/xmlsave.h +88 -0
  104. package/vendor/libxml/include/libxml/xmlschemas.h +246 -0
  105. package/vendor/libxml/include/libxml/xmlschemastypes.h +151 -0
  106. package/vendor/libxml/include/libxml/xmlstring.h +140 -0
  107. package/vendor/libxml/include/libxml/xmlunicode.h +202 -0
  108. package/vendor/libxml/include/libxml/xmlversion.h +484 -0
  109. package/vendor/libxml/include/libxml/xmlwin32version.h +239 -0
  110. package/vendor/libxml/include/libxml/xmlwriter.h +488 -0
  111. package/vendor/libxml/include/libxml/xpath.h +564 -0
  112. package/vendor/libxml/include/libxml/xpathInternals.h +632 -0
  113. package/vendor/libxml/include/libxml/xpointer.h +114 -0
  114. package/vendor/libxml/include/win32config.h +122 -0
  115. package/vendor/libxml/include/wsockcompat.h +54 -0
  116. package/vendor/libxml/legacy.c +1343 -0
  117. package/vendor/libxml/libxml.h +134 -0
  118. package/vendor/libxml/list.c +779 -0
  119. package/vendor/libxml/nanoftp.c +2118 -0
  120. package/vendor/libxml/nanohttp.c +1899 -0
  121. package/vendor/libxml/parser.c +15553 -0
  122. package/vendor/libxml/parserInternals.c +2164 -0
  123. package/vendor/libxml/pattern.c +2621 -0
  124. package/vendor/libxml/relaxng.c +11101 -0
  125. package/vendor/libxml/rngparser.c +1595 -0
  126. package/vendor/libxml/runsuite.c +1157 -0
  127. package/vendor/libxml/save.h +36 -0
  128. package/vendor/libxml/schematron.c +1787 -0
  129. package/vendor/libxml/threads.c +1049 -0
  130. package/vendor/libxml/timsort.h +601 -0
  131. package/vendor/libxml/tree.c +10183 -0
  132. package/vendor/libxml/trio.c +6895 -0
  133. package/vendor/libxml/trio.h +230 -0
  134. package/vendor/libxml/triodef.h +228 -0
  135. package/vendor/libxml/trionan.c +914 -0
  136. package/vendor/libxml/trionan.h +84 -0
  137. package/vendor/libxml/triop.h +150 -0
  138. package/vendor/libxml/triostr.c +2112 -0
  139. package/vendor/libxml/triostr.h +144 -0
  140. package/vendor/libxml/uri.c +2561 -0
  141. package/vendor/libxml/valid.c +7138 -0
  142. package/vendor/libxml/xinclude.c +2657 -0
  143. package/vendor/libxml/xlink.c +183 -0
  144. package/vendor/libxml/xmlIO.c +4135 -0
  145. package/vendor/libxml/xmlcatalog.c +624 -0
  146. package/vendor/libxml/xmllint.c +3796 -0
  147. package/vendor/libxml/xmlmemory.c +1163 -0
  148. package/vendor/libxml/xmlmodule.c +468 -0
  149. package/vendor/libxml/xmlreader.c +6033 -0
  150. package/vendor/libxml/xmlregexp.c +8271 -0
  151. package/vendor/libxml/xmlsave.c +2735 -0
  152. package/vendor/libxml/xmlschemas.c +29173 -0
  153. package/vendor/libxml/xmlschemastypes.c +6276 -0
  154. package/vendor/libxml/xmlstring.c +1050 -0
  155. package/vendor/libxml/xmlunicode.c +3179 -0
  156. package/vendor/libxml/xmlwriter.c +4738 -0
  157. package/vendor/libxml/xpath.c +14734 -0
  158. package/vendor/libxml/xpointer.c +2969 -0
  159. package/vendor/libxml/xzlib.c +815 -0
  160. 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"