nanoftp.c 52 KB

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