nanoftp.c 52 KB

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