nanoftp.c 50 KB

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