1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585 |
- #include "curl_setup.h"
- #ifndef CURL_DISABLE_FTP
- #ifdef HAVE_NETINET_IN_H
- #include <netinet/in.h>
- #endif
- #ifdef HAVE_ARPA_INET_H
- #include <arpa/inet.h>
- #endif
- #ifdef HAVE_UTSNAME_H
- #include <sys/utsname.h>
- #endif
- #ifdef HAVE_NETDB_H
- #include <netdb.h>
- #endif
- #ifdef __VMS
- #include <in.h>
- #include <inet.h>
- #endif
- #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
- #undef in_addr_t
- #define in_addr_t unsigned long
- #endif
- #include <curl/curl.h>
- #include "urldata.h"
- #include "sendf.h"
- #include "if2ip.h"
- #include "hostip.h"
- #include "progress.h"
- #include "transfer.h"
- #include "escape.h"
- #include "http.h"
- #include "socks.h"
- #include "ftp.h"
- #include "fileinfo.h"
- #include "ftplistparser.h"
- #include "curl_sec.h"
- #include "strtoofft.h"
- #include "strequal.h"
- #include "vtls/vtls.h"
- #include "connect.h"
- #include "strerror.h"
- #include "inet_ntop.h"
- #include "inet_pton.h"
- #include "select.h"
- #include "parsedate.h"
- #include "sockaddr.h"
- #include "multiif.h"
- #include "url.h"
- #include "rawstr.h"
- #include "speedcheck.h"
- #include "warnless.h"
- #include "http_proxy.h"
- #include "non-ascii.h"
- #define _MPRINTF_REPLACE
- #include <curl/mprintf.h>
- #include "curl_memory.h"
- #include "memdebug.h"
- #ifndef NI_MAXHOST
- #define NI_MAXHOST 1025
- #endif
- #ifndef INET_ADDRSTRLEN
- #define INET_ADDRSTRLEN 16
- #endif
- #ifdef CURL_DISABLE_VERBOSE_STRINGS
- #define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
- #endif
- #ifndef DEBUGBUILD
- static void _state(struct connectdata *conn,
- ftpstate newstate);
- #define state(x,y) _state(x,y)
- #else
- static void _state(struct connectdata *conn,
- ftpstate newstate,
- int lineno);
- #define state(x,y) _state(x,y,__LINE__)
- #endif
- static CURLcode ftp_sendquote(struct connectdata *conn,
- struct curl_slist *quote);
- static CURLcode ftp_quit(struct connectdata *conn);
- static CURLcode ftp_parse_url_path(struct connectdata *conn);
- static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
- #ifndef CURL_DISABLE_VERBOSE_STRINGS
- static void ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
- char *newhost,
- int port);
- #endif
- static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
- static CURLcode ftp_state_mdtm(struct connectdata *conn);
- static CURLcode ftp_state_quote(struct connectdata *conn,
- bool init, ftpstate instate);
- static CURLcode ftp_nb_type(struct connectdata *conn,
- bool ascii, ftpstate newstate);
- static int ftp_need_type(struct connectdata *conn,
- bool ascii);
- static CURLcode ftp_do(struct connectdata *conn, bool *done);
- static CURLcode ftp_done(struct connectdata *conn,
- CURLcode, bool premature);
- static CURLcode ftp_connect(struct connectdata *conn, bool *done);
- static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
- static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
- static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
- static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
- int numsocks);
- static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
- int numsocks);
- static CURLcode ftp_doing(struct connectdata *conn,
- bool *dophase_done);
- static CURLcode ftp_setup_connection(struct connectdata * conn);
- static CURLcode init_wc_data(struct connectdata *conn);
- static CURLcode wc_statemach(struct connectdata *conn);
- static void wc_data_dtor(void *ptr);
- static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
- static CURLcode ftp_readresp(curl_socket_t sockfd,
- struct pingpong *pp,
- int *ftpcode,
- size_t *size);
- static CURLcode ftp_dophase_done(struct connectdata *conn,
- bool connected);
- #define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
- return result
- const struct Curl_handler Curl_handler_ftp = {
- "FTP",
- ftp_setup_connection,
- ftp_do,
- ftp_done,
- ftp_do_more,
- ftp_connect,
- ftp_multi_statemach,
- ftp_doing,
- ftp_getsock,
- ftp_getsock,
- ftp_domore_getsock,
- ZERO_NULL,
- ftp_disconnect,
- ZERO_NULL,
- PORT_FTP,
- CURLPROTO_FTP,
- PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
- | PROTOPT_NOURLQUERY
- };
- #ifdef USE_SSL
- const struct Curl_handler Curl_handler_ftps = {
- "FTPS",
- ftp_setup_connection,
- ftp_do,
- ftp_done,
- ftp_do_more,
- ftp_connect,
- ftp_multi_statemach,
- ftp_doing,
- ftp_getsock,
- ftp_getsock,
- ftp_domore_getsock,
- ZERO_NULL,
- ftp_disconnect,
- ZERO_NULL,
- PORT_FTPS,
- CURLPROTO_FTPS,
- PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
- PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY
- };
- #endif
- #ifndef CURL_DISABLE_HTTP
- static const struct Curl_handler Curl_handler_ftp_proxy = {
- "FTP",
- Curl_http_setup_conn,
- Curl_http,
- Curl_http_done,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- PORT_FTP,
- CURLPROTO_HTTP,
- PROTOPT_NONE
- };
- #ifdef USE_SSL
- static const struct Curl_handler Curl_handler_ftps_proxy = {
- "FTPS",
- Curl_http_setup_conn,
- Curl_http,
- Curl_http_done,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- ZERO_NULL,
- PORT_FTPS,
- CURLPROTO_HTTP,
- PROTOPT_NONE
- };
- #endif
- #endif
- #define CURL_FTP_HTTPSTYLE_HEAD 1
- static void freedirs(struct ftp_conn *ftpc)
- {
- int i;
- if(ftpc->dirs) {
- for(i=0; i < ftpc->dirdepth; i++) {
- if(ftpc->dirs[i]) {
- free(ftpc->dirs[i]);
- ftpc->dirs[i]=NULL;
- }
- }
- free(ftpc->dirs);
- ftpc->dirs = NULL;
- ftpc->dirdepth = 0;
- }
- if(ftpc->file) {
- free(ftpc->file);
- ftpc->file = NULL;
- }
- }
- static bool isBadFtpString(const char *string)
- {
- return ((NULL != strchr(string, '\r')) ||
- (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
- }
- static CURLcode AcceptServerConnect(struct connectdata *conn)
- {
- struct SessionHandle *data = conn->data;
- curl_socket_t sock = conn->sock[SECONDARYSOCKET];
- curl_socket_t s = CURL_SOCKET_BAD;
- #ifdef ENABLE_IPV6
- struct Curl_sockaddr_storage add;
- #else
- struct sockaddr_in add;
- #endif
- curl_socklen_t size = (curl_socklen_t) sizeof(add);
- if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
- size = sizeof(add);
- s=accept(sock, (struct sockaddr *) &add, &size);
- }
- Curl_closesocket(conn, sock);
- if(CURL_SOCKET_BAD == s) {
- failf(data, "Error accept()ing server connect");
- return CURLE_FTP_PORT_FAILED;
- }
- infof(data, "Connection accepted from server\n");
- conn->sock[SECONDARYSOCKET] = s;
- curlx_nonblock(s, TRUE);
- conn->sock_accepted[SECONDARYSOCKET] = TRUE;
- if(data->set.fsockopt) {
- int error = 0;
-
- error = data->set.fsockopt(data->set.sockopt_client,
- s,
- CURLSOCKTYPE_ACCEPT);
- if(error) {
- Curl_closesocket(conn, s);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- return CURLE_ABORTED_BY_CALLBACK;
- }
- }
- return CURLE_OK;
- }
- static long ftp_timeleft_accept(struct SessionHandle *data)
- {
- long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
- long other;
- struct timeval now;
- if(data->set.accepttimeout > 0)
- timeout_ms = data->set.accepttimeout;
- now = Curl_tvnow();
-
- other = Curl_timeleft(data, &now, FALSE);
- if(other && (other < timeout_ms))
-
- timeout_ms = other;
- else {
-
- timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
- if(!timeout_ms)
-
- return -1;
- }
- return timeout_ms;
- }
- static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
- {
- struct SessionHandle *data = conn->data;
- curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
- curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- int result;
- long timeout_ms;
- ssize_t nread;
- int ftpcode;
- *received = FALSE;
- timeout_ms = ftp_timeleft_accept(data);
- infof(data, "Checking for server connect\n");
- if(timeout_ms < 0) {
-
- failf(data, "Accept timeout occurred while waiting server connect");
- return CURLE_FTP_ACCEPT_TIMEOUT;
- }
-
- if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
-
- infof(data, "There is negative response in cache while serv connect\n");
- Curl_GetFTPResponse(&nread, conn, &ftpcode);
- return CURLE_FTP_ACCEPT_FAILED;
- }
- result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
-
- switch (result) {
- case -1:
-
- failf(data, "Error while waiting for server connect");
- return CURLE_FTP_ACCEPT_FAILED;
- case 0:
- break;
- default:
- if(result & CURL_CSELECT_IN2) {
- infof(data, "Ready to accept data connection from server\n");
- *received = TRUE;
- }
- else if(result & CURL_CSELECT_IN) {
- infof(data, "Ctrl conn has data while waiting for data conn\n");
- Curl_GetFTPResponse(&nread, conn, &ftpcode);
- if(ftpcode/100 > 3)
- return CURLE_FTP_ACCEPT_FAILED;
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
- break;
- }
- return CURLE_OK;
- }
- static CURLcode InitiateTransfer(struct connectdata *conn)
- {
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->req.protop;
- CURLcode result = CURLE_OK;
- if(conn->ssl[SECONDARYSOCKET].use) {
-
- infof(data, "Doing the SSL/TLS handshake on the data stream\n");
- result = Curl_ssl_connect(conn, SECONDARYSOCKET);
- if(result)
- return result;
- }
- if(conn->proto.ftpc.state_saved == FTP_STOR) {
- *(ftp->bytecountp)=0;
-
- Curl_pgrsSetUploadSize(data, data->state.infilesize);
-
- Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
- SECONDARYSOCKET, ftp->bytecountp);
- }
- else {
-
- Curl_setup_transfer(conn, SECONDARYSOCKET,
- conn->proto.ftpc.retr_size_saved, FALSE,
- ftp->bytecountp, -1, NULL);
- }
- conn->proto.ftpc.pp.pending_resp = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
- {
- struct SessionHandle *data = conn->data;
- long timeout_ms;
- CURLcode ret = CURLE_OK;
- *connected = FALSE;
- infof(data, "Preparing for accepting server on data port\n");
-
- Curl_pgrsTime(data, TIMER_STARTACCEPT);
- timeout_ms = ftp_timeleft_accept(data);
- if(timeout_ms < 0) {
-
- failf(data, "Accept timeout occurred while waiting server connect");
- return CURLE_FTP_ACCEPT_TIMEOUT;
- }
-
- ret = ReceivedServerConnect(conn, connected);
- if(ret)
- return ret;
- if(*connected) {
- ret = AcceptServerConnect(conn);
- if(ret)
- return ret;
- ret = InitiateTransfer(conn);
- if(ret)
- return ret;
- }
- else {
-
- if(ret == CURLE_OK && *connected == FALSE) {
- if(data->set.accepttimeout > 0)
- Curl_expire(data, data->set.accepttimeout);
- else
- Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
- }
- }
- return ret;
- }
- #define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
- ISDIGIT(line[2]))
- #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
- static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
- int *code)
- {
- (void)conn;
- if((len > 3) && LASTLINE(line)) {
- *code = curlx_sltosi(strtol(line, NULL, 10));
- return TRUE;
- }
- return FALSE;
- }
- static CURLcode ftp_readresp(curl_socket_t sockfd,
- struct pingpong *pp,
- int *ftpcode,
- size_t *size)
- {
- struct connectdata *conn = pp->conn;
- struct SessionHandle *data = conn->data;
- #ifdef HAVE_GSSAPI
- char * const buf = data->state.buffer;
- #endif
- CURLcode result = CURLE_OK;
- int code;
- result = Curl_pp_readresp(sockfd, pp, &code, size);
- #if defined(HAVE_GSSAPI)
-
-
- switch(code) {
- case 631:
- code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
- break;
- case 632:
- code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
- break;
- case 633:
- code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
- break;
- default:
-
- break;
- }
- #endif
-
- data->info.httpcode=code;
- if(ftpcode)
- *ftpcode = code;
- if(421 == code) {
-
- infof(data, "We got a 421 - timeout!\n");
- state(conn, FTP_STOP);
- return CURLE_OPERATION_TIMEDOUT;
- }
- return result;
- }
- CURLcode Curl_GetFTPResponse(ssize_t *nreadp,
- struct connectdata *conn,
- int *ftpcode)
- {
-
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
- long timeout;
- long interval_ms;
- struct SessionHandle *data = conn->data;
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- size_t nread;
- int cache_skip=0;
- int value_to_be_ignored=0;
- if(ftpcode)
- *ftpcode = 0;
- else
-
- ftpcode = &value_to_be_ignored;
- *nreadp=0;
- while(!*ftpcode && !result) {
-
- timeout = Curl_pp_state_timeout(pp);
- if(timeout <=0 ) {
- failf(data, "FTP response timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- interval_ms = 1000;
- if(timeout < interval_ms)
- interval_ms = timeout;
-
- if(pp->cache && (cache_skip < 2)) {
-
- }
- else {
- switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
- case -1:
- failf(data, "FTP response aborted due to select/poll error: %d",
- SOCKERRNO);
- return CURLE_RECV_ERROR;
- case 0:
- if(Curl_pgrsUpdate(conn))
- return CURLE_ABORTED_BY_CALLBACK;
- continue;
- default:
- break;
- }
- }
- result = ftp_readresp(sockfd, pp, ftpcode, &nread);
- if(result)
- break;
- if(!nread && pp->cache)
-
- cache_skip++;
- else
-
- cache_skip=0;
- *nreadp += nread;
- }
- pp->pending_resp = FALSE;
- return result;
- }
- #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-
- static const char * const ftp_state_names[]={
- "STOP",
- "WAIT220",
- "AUTH",
- "USER",
- "PASS",
- "ACCT",
- "PBSZ",
- "PROT",
- "CCC",
- "PWD",
- "SYST",
- "NAMEFMT",
- "QUOTE",
- "RETR_PREQUOTE",
- "STOR_PREQUOTE",
- "POSTQUOTE",
- "CWD",
- "MKD",
- "MDTM",
- "TYPE",
- "LIST_TYPE",
- "RETR_TYPE",
- "STOR_TYPE",
- "SIZE",
- "RETR_SIZE",
- "STOR_SIZE",
- "REST",
- "RETR_REST",
- "PORT",
- "PRET",
- "PASV",
- "LIST",
- "RETR",
- "STOR",
- "QUIT"
- };
- #endif
- static void _state(struct connectdata *conn,
- ftpstate newstate
- #ifdef DEBUGBUILD
- , int lineno
- #endif
- )
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
- if(ftpc->state != newstate)
- infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
- (void *)ftpc, lineno, ftp_state_names[ftpc->state],
- ftp_state_names[newstate]);
- #endif
- ftpc->state = newstate;
- }
- static CURLcode ftp_state_user(struct connectdata *conn)
- {
- CURLcode result;
- struct FTP *ftp = conn->data->req.protop;
-
- PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
- state(conn, FTP_USER);
- conn->data->state.ftp_trying_alternative = FALSE;
- return CURLE_OK;
- }
- static CURLcode ftp_state_pwd(struct connectdata *conn)
- {
- CURLcode result;
-
- PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
- state(conn, FTP_PWD);
- return CURLE_OK;
- }
- static int ftp_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
- {
- return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
- }
- static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
- int numsocks)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(!numsocks)
- return GETSOCK_BLANK;
-
- if(FTP_STOP == ftpc->state) {
- int bits = GETSOCK_READSOCK(0);
-
- socks[0] = conn->sock[FIRSTSOCKET];
- if(!conn->data->set.ftp_use_port) {
- int s;
- int i;
-
- for(s=1, i=0; i<2; i++) {
- if(conn->tempsock[i] != CURL_SOCKET_BAD) {
- socks[s] = conn->tempsock[i];
- bits |= GETSOCK_WRITESOCK(s++);
- }
- }
- }
- else {
- socks[1] = conn->sock[SECONDARYSOCKET];
- bits |= GETSOCK_WRITESOCK(1);
- }
- return bits;
- }
- else
- return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
- }
- static CURLcode ftp_state_cwd(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(ftpc->cwddone)
-
- result = ftp_state_mdtm(conn);
- else {
- ftpc->count2 = 0;
-
- ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
- if(conn->bits.reuse && ftpc->entrypath) {
-
- ftpc->count1 = 0;
- PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
- state(conn, FTP_CWD);
- }
- else {
- if(ftpc->dirdepth) {
- ftpc->count1 = 1;
-
- PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
- state(conn, FTP_CWD);
- }
- else {
-
- result = ftp_state_mdtm(conn);
- }
- }
- }
- return result;
- }
- typedef enum {
- EPRT,
- PORT,
- DONE
- } ftpport;
- static CURLcode ftp_state_use_port(struct connectdata *conn,
- ftpport fcmd)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct SessionHandle *data=conn->data;
- curl_socket_t portsock= CURL_SOCKET_BAD;
- char myhost[256] = "";
- struct Curl_sockaddr_storage ss;
- Curl_addrinfo *res, *ai;
- curl_socklen_t sslen;
- char hbuf[NI_MAXHOST];
- struct sockaddr *sa=(struct sockaddr *)&ss;
- struct sockaddr_in * const sa4 = (void *)sa;
- #ifdef ENABLE_IPV6
- struct sockaddr_in6 * const sa6 = (void *)sa;
- #endif
- char tmp[1024];
- static const char mode[][5] = { "EPRT", "PORT" };
- int rc;
- int error;
- char *host = NULL;
- char *string_ftpport = data->set.str[STRING_FTPPORT];
- struct Curl_dns_entry *h=NULL;
- unsigned short port_min = 0;
- unsigned short port_max = 0;
- unsigned short port;
- bool possibly_non_local = TRUE;
- char *addr = NULL;
-
- if(data->set.str[STRING_FTPPORT] &&
- (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
- #ifdef ENABLE_IPV6
- size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
- INET6_ADDRSTRLEN : strlen(string_ftpport);
- #else
- size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
- INET_ADDRSTRLEN : strlen(string_ftpport);
- #endif
- char *ip_start = string_ftpport;
- char *ip_end = NULL;
- char *port_start = NULL;
- char *port_sep = NULL;
- addr = calloc(addrlen+1, 1);
- if(!addr)
- return CURLE_OUT_OF_MEMORY;
- #ifdef ENABLE_IPV6
- if(*string_ftpport == '[') {
-
- ip_start = string_ftpport + 1;
- if((ip_end = strchr(string_ftpport, ']')) != NULL )
- strncpy(addr, ip_start, ip_end - ip_start);
- }
- else
- #endif
- if(*string_ftpport == ':') {
-
- ip_end = string_ftpport;
- }
- else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
-
- #ifdef ENABLE_IPV6
- if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
-
- port_min = port_max = 0;
- strcpy(addr, string_ftpport);
- ip_end = NULL;
- }
- else
- #endif
-
- strncpy(addr, string_ftpport, ip_end - ip_start );
- }
- else
-
- strcpy(addr, string_ftpport);
-
- if(ip_end != NULL) {
- if((port_start = strchr(ip_end, ':')) != NULL) {
- port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
- if((port_sep = strchr(port_start, '-')) != NULL) {
- port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
- }
- else
- port_max = port_min;
- }
- }
-
- if(port_min > port_max )
- port_min = port_max = 0;
- if(*addr != '\0') {
-
- switch(Curl_if2ip(conn->ip_addr->ai_family, conn->scope, addr,
- hbuf, sizeof(hbuf))) {
- case IF2IP_NOT_FOUND:
-
- host = addr;
- break;
- case IF2IP_AF_NOT_SUPPORTED:
- return CURLE_FTP_PORT_FAILED;
- case IF2IP_FOUND:
- host = hbuf;
- }
- }
- else
-
- host = NULL;
- }
- if(!host) {
-
- sslen = sizeof(ss);
- if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
- Curl_safefree(addr);
- return CURLE_FTP_PORT_FAILED;
- }
- switch(sa->sa_family) {
- #ifdef ENABLE_IPV6
- case AF_INET6:
- Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
- break;
- #endif
- default:
- Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
- break;
- }
- host = hbuf;
- possibly_non_local = FALSE;
- }
-
- rc = Curl_resolv(conn, host, 0, &h);
- if(rc == CURLRESOLV_PENDING)
- (void)Curl_resolver_wait_resolv(conn, &h);
- if(h) {
- res = h->addr;
-
- Curl_resolv_unlock(data, h);
- }
- else
- res = NULL;
- if(res == NULL) {
- failf(data, "failed to resolve the address provided to PORT: %s", host);
- Curl_safefree(addr);
- return CURLE_FTP_PORT_FAILED;
- }
- Curl_safefree(addr);
- host = NULL;
-
- portsock = CURL_SOCKET_BAD;
- error = 0;
- for(ai = res; ai; ai = ai->ai_next) {
- result = Curl_socket(conn, ai, NULL, &portsock);
- if(result) {
- error = SOCKERRNO;
- continue;
- }
- break;
- }
- if(!ai) {
- failf(data, "socket failure: %s", Curl_strerror(conn, error));
- return CURLE_FTP_PORT_FAILED;
- }
-
- memcpy(sa, ai->ai_addr, ai->ai_addrlen);
- sslen = ai->ai_addrlen;
- for(port = port_min; port <= port_max;) {
- if(sa->sa_family == AF_INET)
- sa4->sin_port = htons(port);
- #ifdef ENABLE_IPV6
- else
- sa6->sin6_port = htons(port);
- #endif
-
- if(bind(portsock, sa, sslen) ) {
-
- error = SOCKERRNO;
- if(possibly_non_local && (error == EADDRNOTAVAIL)) {
-
- infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
- Curl_strerror(conn, error) );
- sslen = sizeof(ss);
- if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
- port = port_min;
- possibly_non_local = FALSE;
- continue;
- }
- else if(error != EADDRINUSE && error != EACCES) {
- failf(data, "bind(port=%hu) failed: %s", port,
- Curl_strerror(conn, error) );
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
- }
- else
- break;
- port++;
- }
-
- if(port > port_max) {
- failf(data, "bind() failed, we ran out of ports!");
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- sslen = sizeof(ss);
- if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, SOCKERRNO) );
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- if(listen(portsock, 1)) {
- failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
- Curl_closesocket(conn, portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
-
- Curl_printable_address(ai, myhost, sizeof(myhost));
- #ifdef ENABLE_IPV6
- if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
-
- conn->bits.ftp_use_eprt = TRUE;
- #endif
- for(; fcmd != DONE; fcmd++) {
- if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
-
- continue;
- if((PORT == fcmd) && sa->sa_family != AF_INET)
-
- continue;
- switch (sa->sa_family) {
- case AF_INET:
- port = ntohs(sa4->sin_port);
- break;
- #ifdef ENABLE_IPV6
- case AF_INET6:
- port = ntohs(sa6->sin6_port);
- break;
- #endif
- default:
- continue;
- }
- if(EPRT == fcmd) {
-
- result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
- sa->sa_family == AF_INET?1:2,
- myhost, port);
- if(result) {
- failf(data, "Failure sending EPRT command: %s",
- curl_easy_strerror(result));
- Curl_closesocket(conn, portsock);
-
- ftpc->count1 = PORT;
-
- state(conn, FTP_STOP);
- return result;
- }
- break;
- }
- else if(PORT == fcmd) {
- char *source = myhost;
- char *dest = tmp;
-
- while(source && *source) {
- if(*source == '.')
- *dest=',';
- else
- *dest = *source;
- dest++;
- source++;
- }
- *dest = 0;
- snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
- result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
- if(result) {
- failf(data, "Failure sending PORT command: %s",
- curl_easy_strerror(result));
- Curl_closesocket(conn, portsock);
-
- state(conn, FTP_STOP);
- return result;
- }
- break;
- }
- }
-
- ftpc->count1 = fcmd;
-
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = portsock;
-
- conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
- state(conn, FTP_PORT);
- return result;
- }
- static CURLcode ftp_state_use_pasv(struct connectdata *conn)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
-
- static const char mode[][5] = { "EPSV", "PASV" };
- int modeoff;
- #ifdef PF_INET6
- if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
-
- conn->bits.ftp_use_epsv = TRUE;
- #endif
- modeoff = conn->bits.ftp_use_epsv?0:1;
- PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
- ftpc->count1 = modeoff;
- state(conn, FTP_PASV);
- infof(conn->data, "Connect data stream passively\n");
- return result;
- }
- static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct SessionHandle *data = conn->data;
- if(ftp->transfer != FTPTRANSFER_BODY) {
-
-
- state(conn, FTP_RETR_PREQUOTE);
- result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
- }
- else if(data->set.ftp_use_port) {
-
- result = ftp_state_use_port(conn, EPRT);
- }
- else {
-
- if(data->set.ftp_use_pret) {
-
- if(!conn->proto.ftpc.file) {
- PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
- data->set.str[STRING_CUSTOMREQUEST]?
- data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"));
- }
- else if(data->set.upload) {
- PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
- }
- else {
- PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
- }
- state(conn, FTP_PRET);
- }
- else {
- result = ftp_state_use_pasv(conn);
- }
- }
- return result;
- }
- static CURLcode ftp_state_rest(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
-
-
- PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
- state(conn, FTP_REST);
- }
- else
- result = ftp_state_prepare_transfer(conn);
- return result;
- }
- static CURLcode ftp_state_size(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
-
-
- PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
- state(conn, FTP_SIZE);
- }
- else
- result = ftp_state_rest(conn);
- return result;
- }
- static CURLcode ftp_state_list(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
-
-
- char *cmd,*lstArg,*slashPos;
- lstArg = NULL;
- if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
- data->state.path &&
- data->state.path[0] &&
- strchr(data->state.path,'/')) {
- lstArg = strdup(data->state.path);
- if(!lstArg)
- return CURLE_OUT_OF_MEMORY;
-
- if(lstArg[strlen(lstArg) - 1] != '/') {
-
- slashPos = strrchr(lstArg,'/');
- if(slashPos)
- *(slashPos+1) = '\0';
- }
- }
- cmd = aprintf( "%s%s%s",
- data->set.str[STRING_CUSTOMREQUEST]?
- data->set.str[STRING_CUSTOMREQUEST]:
- (data->set.ftp_list_only?"NLST":"LIST"),
- lstArg? " ": "",
- lstArg? lstArg: "" );
- if(!cmd) {
- if(lstArg)
- free(lstArg);
- return CURLE_OUT_OF_MEMORY;
- }
- result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
- if(lstArg)
- free(lstArg);
- free(cmd);
- if(result != CURLE_OK)
- return result;
- state(conn, FTP_LIST);
- return result;
- }
- static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
-
- result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
- return result;
- }
- static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
-
- result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
- return result;
- }
- static CURLcode ftp_state_type(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if(data->set.opt_no_body && ftpc->file &&
- ftp_need_type(conn, data->set.prefer_ascii)) {
-
- ftp->transfer = FTPTRANSFER_INFO;
-
-
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
- if(result)
- return result;
- }
- else
- result = ftp_state_size(conn);
- return result;
- }
- static CURLcode ftp_state_mdtm(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
-
- PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
- state(conn, FTP_MDTM);
- }
- else
- result = ftp_state_type(conn);
- return result;
- }
- static CURLcode ftp_state_ul_setup(struct connectdata *conn,
- bool sizechecked)
- {
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->req.protop;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- int seekerr = CURL_SEEKFUNC_OK;
- if((data->state.resume_from && !sizechecked) ||
- ((data->state.resume_from > 0) && sizechecked)) {
-
-
-
-
-
-
- if(data->state.resume_from < 0 ) {
-
- PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
- state(conn, FTP_STOR_SIZE);
- return result;
- }
-
- data->set.ftp_append = TRUE;
-
- if(conn->seek_func) {
- seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
- SEEK_SET);
- }
- if(seekerr != CURL_SEEKFUNC_OK) {
- if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
- failf(data, "Could not seek stream");
- return CURLE_FTP_COULDNT_USE_REST;
- }
-
- else {
- curl_off_t passed=0;
- do {
- size_t readthisamountnow =
- (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
- BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
- size_t actuallyread =
- conn->fread_func(data->state.buffer, 1, readthisamountnow,
- conn->fread_in);
- passed += actuallyread;
- if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
-
- failf(data, "Failed to read data");
- return CURLE_FTP_COULDNT_USE_REST;
- }
- } while(passed < data->state.resume_from);
- }
- }
-
- if(data->state.infilesize>0) {
- data->state.infilesize -= data->state.resume_from;
- if(data->state.infilesize <= 0) {
- infof(data, "File already completely uploaded\n");
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
- ftp->transfer = FTPTRANSFER_NONE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- }
-
- }
- PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
- ftpc->file);
- state(conn, FTP_STOR);
- return result;
- }
- static CURLcode ftp_state_quote(struct connectdata *conn,
- bool init,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- bool quote=FALSE;
- struct curl_slist *item;
- switch(instate) {
- case FTP_QUOTE:
- default:
- item = data->set.quote;
- break;
- case FTP_RETR_PREQUOTE:
- case FTP_STOR_PREQUOTE:
- item = data->set.prequote;
- break;
- case FTP_POSTQUOTE:
- item = data->set.postquote;
- break;
- }
-
- if(init)
- ftpc->count1 = 0;
- else
- ftpc->count1++;
- if(item) {
- int i = 0;
-
- while((i< ftpc->count1) && item) {
- item = item->next;
- i++;
- }
- if(item) {
- char *cmd = item->data;
- if(cmd[0] == '*') {
- cmd++;
- ftpc->count2 = 1;
- }
- else
- ftpc->count2 = 0;
- PPSENDF(&ftpc->pp, "%s", cmd);
- state(conn, instate);
- quote = TRUE;
- }
- }
- if(!quote) {
-
- switch(instate) {
- case FTP_QUOTE:
- default:
- result = ftp_state_cwd(conn);
- break;
- case FTP_RETR_PREQUOTE:
- if(ftp->transfer != FTPTRANSFER_BODY)
- state(conn, FTP_STOP);
- else {
- if(ftpc->known_filesize != -1) {
- Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
- result = ftp_state_retr(conn, ftpc->known_filesize);
- }
- else {
- PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
- state(conn, FTP_RETR_SIZE);
- }
- }
- break;
- case FTP_STOR_PREQUOTE:
- result = ftp_state_ul_setup(conn, FALSE);
- break;
- case FTP_POSTQUOTE:
- break;
- }
- }
- return result;
- }
- static CURLcode ftp_epsv_disable(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
-
- conn->bits.ftp_use_epsv = FALSE;
- conn->data->state.errorbuf = FALSE;
- PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
- conn->proto.ftpc.count1++;
-
- state(conn, FTP_PASV);
- return result;
- }
- static CURLcode proxy_magic(struct connectdata *conn,
- char *newhost, unsigned short newport,
- bool *magicdone)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- *magicdone = FALSE;
- switch(conn->proxytype) {
- case CURLPROXY_SOCKS5:
- case CURLPROXY_SOCKS5_HOSTNAME:
- result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost,
- newport, SECONDARYSOCKET, conn);
- *magicdone = TRUE;
- break;
- case CURLPROXY_SOCKS4:
- result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
- SECONDARYSOCKET, conn, FALSE);
- *magicdone = TRUE;
- break;
- case CURLPROXY_SOCKS4A:
- result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
- SECONDARYSOCKET, conn, TRUE);
- *magicdone = TRUE;
- break;
- case CURLPROXY_HTTP:
- case CURLPROXY_HTTP_1_0:
-
- break;
- default:
- failf(data, "unknown proxytype option given");
- result = CURLE_COULDNT_CONNECT;
- break;
- }
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
-
-
-
- struct HTTP http_proxy;
- struct FTP *ftp_save = data->req.protop;
- memset(&http_proxy, 0, sizeof(http_proxy));
- data->req.protop = &http_proxy;
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
- data->req.protop = ftp_save;
- if(result)
- return result;
- if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
-
- state(conn, FTP_STOP);
- return result;
- }
- else
- *magicdone = TRUE;
- }
- return result;
- }
- static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
- int ftpcode)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result;
- struct SessionHandle *data=conn->data;
- struct Curl_dns_entry *addr=NULL;
- int rc;
- unsigned short connectport;
- char *str=&data->state.buffer[4];
- if((ftpc->count1 == 0) &&
- (ftpcode == 229)) {
-
- char *ptr = strchr(str, '(');
- if(ptr) {
- unsigned int num;
- char separator[4];
- ptr++;
- if(5 == sscanf(ptr, "%c%c%c%u%c",
- &separator[0],
- &separator[1],
- &separator[2],
- &num,
- &separator[3])) {
- const char sep1 = separator[0];
- int i;
-
- for(i=1; i<4; i++) {
- if(separator[i] != sep1) {
- ptr=NULL;
- break;
- }
- }
- if(num > 0xffff) {
- failf(data, "Illegal port number in EPSV reply");
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- if(ptr) {
- ftpc->newport = (unsigned short)(num & 0xffff);
- if(conn->bits.tunnel_proxy ||
- conn->proxytype == CURLPROXY_SOCKS5 ||
- conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
- conn->proxytype == CURLPROXY_SOCKS4 ||
- conn->proxytype == CURLPROXY_SOCKS4A)
-
- snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
- conn->host.name);
- else
-
- snprintf(ftpc->newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
- }
- }
- else
- ptr=NULL;
- }
- if(!ptr) {
- failf(data, "Weirdly formatted EPSV reply");
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- }
- else if((ftpc->count1 == 1) &&
- (ftpcode == 227)) {
-
- int ip[4];
- int port[2];
-
- while(*str) {
- if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
- &ip[0], &ip[1], &ip[2], &ip[3],
- &port[0], &port[1]))
- break;
- str++;
- }
- if(!*str) {
- failf(data, "Couldn't interpret the 227-response");
- return CURLE_FTP_WEIRD_227_FORMAT;
- }
-
- if(data->set.ftp_skip_ip) {
-
- infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
- ip[0], ip[1], ip[2], ip[3],
- conn->ip_addr_str);
- if(conn->bits.tunnel_proxy ||
- conn->proxytype == CURLPROXY_SOCKS5 ||
- conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
- conn->proxytype == CURLPROXY_SOCKS4 ||
- conn->proxytype == CURLPROXY_SOCKS4A)
-
- snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s", conn->host.name);
- else
- snprintf(ftpc->newhost, sizeof(ftpc->newhost), "%s",
- conn->ip_addr_str);
- }
- else
- snprintf(ftpc->newhost, sizeof(ftpc->newhost),
- "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
- ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
- }
- else if(ftpc->count1 == 0) {
-
- return ftp_epsv_disable(conn);
- }
- else {
- failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- if(conn->bits.proxy) {
-
- rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
- if(rc == CURLRESOLV_PENDING)
-
- (void)Curl_resolver_wait_resolv(conn, &addr);
- connectport =
- (unsigned short)conn->port;
- if(!addr) {
- failf(data, "Can't resolve proxy host %s:%hu",
- conn->proxy.name, connectport);
- return CURLE_FTP_CANT_GET_HOST;
- }
- }
- else {
-
- rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
- if(rc == CURLRESOLV_PENDING)
-
- (void)Curl_resolver_wait_resolv(conn, &addr);
- connectport = ftpc->newport;
- if(!addr) {
- failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
- return CURLE_FTP_CANT_GET_HOST;
- }
- }
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
- result = Curl_connecthost(conn, addr);
- Curl_resolv_unlock(data, addr);
- if(result) {
- if(ftpc->count1 == 0 && ftpcode == 229)
- return ftp_epsv_disable(conn);
- return result;
- }
-
- if(data->set.verbose)
-
- ftp_pasv_verbose(conn, conn->ip_addr, ftpc->newhost, connectport);
- conn->bits.do_more = TRUE;
- state(conn, FTP_STOP);
- return result;
- }
- static CURLcode ftp_state_port_resp(struct connectdata *conn,
- int ftpcode)
- {
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- ftpport fcmd = (ftpport)ftpc->count1;
- CURLcode result = CURLE_OK;
- if(ftpcode != 200) {
-
- if(EPRT == fcmd) {
- infof(data, "disabling EPRT usage\n");
- conn->bits.ftp_use_eprt = FALSE;
- }
- fcmd++;
- if(fcmd == DONE) {
- failf(data, "Failed to do PORT");
- result = CURLE_FTP_PORT_FAILED;
- }
- else
-
- result = ftp_state_use_port(conn, fcmd);
- }
- else {
- infof(data, "Connect data stream actively\n");
- state(conn, FTP_STOP);
- result = ftp_dophase_done(conn, FALSE);
- }
- return result;
- }
- static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
- int ftpcode)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- switch(ftpcode) {
- case 213:
- {
-
- int year, month, day, hour, minute, second;
- char *buf = data->state.buffer;
- if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
- &year, &month, &day, &hour, &minute, &second)) {
-
- time_t secs=time(NULL);
-
- snprintf(buf, sizeof(conn->data->state.buffer),
- "%04d%02d%02d %02d:%02d:%02d GMT",
- year, month, day, hour, minute, second);
-
- data->info.filetime = (long)curl_getdate(buf, &secs);
- }
- #ifdef CURL_FTP_HTTPSTYLE_HEAD
-
- if(data->set.opt_no_body &&
- ftpc->file &&
- data->set.get_filetime &&
- (data->info.filetime>=0) ) {
- time_t filetime = (time_t)data->info.filetime;
- struct tm buffer;
- const struct tm *tm = &buffer;
- result = Curl_gmtime(filetime, &buffer);
- if(result)
- return result;
-
- snprintf(buf, BUFSIZE-1,
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
- if(result)
- return result;
- }
- #endif
- }
- break;
- default:
- infof(data, "unsupported MDTM reply format\n");
- break;
- case 550:
- failf(data, "Given file does not exist");
- result = CURLE_FTP_COULDNT_RETR_FILE;
- break;
- }
- if(data->set.timecondition) {
- if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
- switch(data->set.timecondition) {
- case CURL_TIMECOND_IFMODSINCE:
- default:
- if(data->info.filetime <= data->set.timevalue) {
- infof(data, "The requested document is not new enough\n");
- ftp->transfer = FTPTRANSFER_NONE;
- data->info.timecond = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- break;
- case CURL_TIMECOND_IFUNMODSINCE:
- if(data->info.filetime > data->set.timevalue) {
- infof(data, "The requested document is not old enough\n");
- ftp->transfer = FTPTRANSFER_NONE;
- data->info.timecond = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- break;
- }
- }
- else {
- infof(data, "Skipping time comparison\n");
- }
- }
- if(!result)
- result = ftp_state_type(conn);
- return result;
- }
- static CURLcode ftp_state_type_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- if(ftpcode/100 != 2) {
-
- failf(data, "Couldn't set desired mode");
- return CURLE_FTP_COULDNT_SET_TYPE;
- }
- if(ftpcode != 200)
- infof(data, "Got a %03d response code instead of the assumed 200\n",
- ftpcode);
- if(instate == FTP_TYPE)
- result = ftp_state_size(conn);
- else if(instate == FTP_LIST_TYPE)
- result = ftp_state_list(conn);
- else if(instate == FTP_RETR_TYPE)
- result = ftp_state_retr_prequote(conn);
- else if(instate == FTP_STOR_TYPE)
- result = ftp_state_stor_prequote(conn);
- return result;
- }
- static CURLcode ftp_state_retr(struct connectdata *conn,
- curl_off_t filesize)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- ftp->downloadsize = filesize;
- if(data->state.resume_from) {
-
- if(filesize == -1) {
- infof(data, "ftp server doesn't support SIZE\n");
-
- }
- else {
-
- if(data->state.resume_from< 0) {
-
- if(filesize < -data->state.resume_from) {
- failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
- ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
- data->state.resume_from, filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
-
- ftp->downloadsize = -data->state.resume_from;
-
- data->state.resume_from = filesize - ftp->downloadsize;
- }
- else {
- if(filesize < data->state.resume_from) {
- failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
- ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
- data->state.resume_from, filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
-
- ftp->downloadsize = filesize-data->state.resume_from;
- }
- }
- if(ftp->downloadsize == 0) {
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- infof(data, "File already completely downloaded\n");
-
- ftp->transfer = FTPTRANSFER_NONE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
-
- infof(data, "Instructs server to resume from offset %"
- CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
- PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
- data->state.resume_from);
- state(conn, FTP_RETR_REST);
- }
- else {
-
- PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
- state(conn, FTP_RETR);
- }
- return result;
- }
- static CURLcode ftp_state_size_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- curl_off_t filesize;
- char *buf = data->state.buffer;
-
- filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
- if(instate == FTP_SIZE) {
- #ifdef CURL_FTP_HTTPSTYLE_HEAD
- if(-1 != filesize) {
- snprintf(buf, sizeof(data->state.buffer),
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
- if(result)
- return result;
- }
- #endif
- Curl_pgrsSetDownloadSize(data, filesize);
- result = ftp_state_rest(conn);
- }
- else if(instate == FTP_RETR_SIZE) {
- Curl_pgrsSetDownloadSize(data, filesize);
- result = ftp_state_retr(conn, filesize);
- }
- else if(instate == FTP_STOR_SIZE) {
- data->state.resume_from = filesize;
- result = ftp_state_ul_setup(conn, TRUE);
- }
- return result;
- }
- static CURLcode ftp_state_rest_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- switch(instate) {
- case FTP_REST:
- default:
- #ifdef CURL_FTP_HTTPSTYLE_HEAD
- if(ftpcode == 350) {
- char buffer[24]= { "Accept-ranges: bytes\r\n" };
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
- if(result)
- return result;
- }
- #endif
- result = ftp_state_prepare_transfer(conn);
- break;
- case FTP_RETR_REST:
- if(ftpcode != 350) {
- failf(conn->data, "Couldn't use REST");
- result = CURLE_FTP_COULDNT_USE_REST;
- }
- else {
- PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
- state(conn, FTP_RETR);
- }
- break;
- }
- return result;
- }
- static CURLcode ftp_state_stor_resp(struct connectdata *conn,
- int ftpcode, ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- if(ftpcode>=400) {
- failf(data, "Failed FTP upload: %0d", ftpcode);
- state(conn, FTP_STOP);
-
- return CURLE_UPLOAD_FAILED;
- }
- conn->proto.ftpc.state_saved = instate;
-
- if(data->set.ftp_use_port) {
- bool connected;
- state(conn, FTP_STOP);
- result = AllowServerConnect(conn, &connected);
- if(result)
- return result;
- if(!connected) {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- infof(data, "Data conn was not available immediately\n");
- ftpc->wait_data_conn = TRUE;
- }
- return CURLE_OK;
- }
- else
- return InitiateTransfer(conn);
- }
- static CURLcode ftp_state_get_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->req.protop;
- char *buf = data->state.buffer;
- if((ftpcode == 150) || (ftpcode == 125)) {
-
- curl_off_t size=-1;
-
- if((instate != FTP_LIST) &&
- !data->set.prefer_ascii &&
- (ftp->downloadsize < 1)) {
-
- char *bytes;
- bytes=strstr(buf, " bytes");
- if(bytes--) {
- long in=(long)(bytes-buf);
-
- while(--in) {
-
- if('(' == *bytes)
- break;
-
- if(!ISDIGIT(*bytes)) {
- bytes=NULL;
- break;
- }
-
- bytes--;
- }
-
- if(bytes++) {
-
- size = curlx_strtoofft(bytes, NULL, 0);
- }
- }
- }
- else if(ftp->downloadsize > -1)
- size = ftp->downloadsize;
- if(size > data->req.maxdownload && data->req.maxdownload > 0)
- size = data->req.size = data->req.maxdownload;
- else if((instate != FTP_LIST) && (data->set.prefer_ascii))
- size = -1;
- infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
- data->req.maxdownload);
- if(instate != FTP_LIST)
- infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
- size);
-
- conn->proto.ftpc.state_saved = instate;
- conn->proto.ftpc.retr_size_saved = size;
- if(data->set.ftp_use_port) {
- bool connected;
- result = AllowServerConnect(conn, &connected);
- if(result)
- return result;
- if(!connected) {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- infof(data, "Data conn was not available immediately\n");
- state(conn, FTP_STOP);
- ftpc->wait_data_conn = TRUE;
- }
- }
- else
- return InitiateTransfer(conn);
- }
- else {
- if((instate == FTP_LIST) && (ftpcode == 450)) {
-
- ftp->transfer = FTPTRANSFER_NONE;
- state(conn, FTP_STOP);
- }
- else {
- failf(data, "RETR response: %03d", ftpcode);
- return instate == FTP_RETR && ftpcode == 550?
- CURLE_REMOTE_FILE_NOT_FOUND:
- CURLE_FTP_COULDNT_RETR_FILE;
- }
- }
- return result;
- }
- static CURLcode ftp_state_loggedin(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- if(conn->ssl[FIRSTSOCKET].use) {
-
- PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
- state(conn, FTP_PBSZ);
- }
- else {
- result = ftp_state_pwd(conn);
- }
- return result;
- }
- static CURLcode ftp_state_user_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- (void)instate;
-
- if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
-
- PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
- state(conn, FTP_PASS);
- }
- else if(ftpcode/100 == 2) {
-
- result = ftp_state_loggedin(conn);
- }
- else if(ftpcode == 332) {
- if(data->set.str[STRING_FTP_ACCOUNT]) {
- PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
- state(conn, FTP_ACCT);
- }
- else {
- failf(data, "ACCT requested but none available");
- result = CURLE_LOGIN_DENIED;
- }
- }
- else {
-
- if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
- !conn->data->state.ftp_trying_alternative) {
-
- PPSENDF(&conn->proto.ftpc.pp, "%s",
- conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
- conn->data->state.ftp_trying_alternative = TRUE;
- state(conn, FTP_USER);
- result = CURLE_OK;
- }
- else {
- failf(data, "Access denied: %03d", ftpcode);
- result = CURLE_LOGIN_DENIED;
- }
- }
- return result;
- }
- static CURLcode ftp_state_acct_resp(struct connectdata *conn,
- int ftpcode)
- {
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- if(ftpcode != 230) {
- failf(data, "ACCT rejected by server: %03d", ftpcode);
- result = CURLE_FTP_WEIRD_PASS_REPLY;
- }
- else
- result = ftp_state_loggedin(conn);
- return result;
- }
- static CURLcode ftp_statemach_act(struct connectdata *conn)
- {
- CURLcode result;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- struct SessionHandle *data=conn->data;
- int ftpcode;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- static const char ftpauth[][4] = { "SSL", "TLS" };
- size_t nread = 0;
- if(pp->sendleft)
- return Curl_pp_flushsend(pp);
- result = ftp_readresp(sock, pp, &ftpcode, &nread);
- if(result)
- return result;
- if(ftpcode) {
-
- switch(ftpc->state) {
- case FTP_WAIT220:
- if(ftpcode == 230)
-
- return ftp_state_user_resp(conn, ftpcode, ftpc->state);
- else if(ftpcode != 220) {
- failf(data, "Got a %03d ftp-server response when 220 was expected",
- ftpcode);
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
-
- #ifdef HAVE_GSSAPI
- if(data->set.krb) {
-
- Curl_sec_request_prot(conn, "private");
-
- Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
- if(Curl_sec_login(conn) != CURLE_OK)
- infof(data, "Logging in with password in cleartext!\n");
- else
- infof(data, "Authentication successful\n");
- }
- #endif
- if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
-
- ftpc->count3=0;
- switch(data->set.ftpsslauth) {
- case CURLFTPAUTH_DEFAULT:
- case CURLFTPAUTH_SSL:
- ftpc->count2 = 1;
- ftpc->count1 = 0;
- break;
- case CURLFTPAUTH_TLS:
- ftpc->count2 = -1;
- ftpc->count1 = 1;
- break;
- default:
- failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
- (int)data->set.ftpsslauth);
- return CURLE_UNKNOWN_OPTION;
- }
- PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
- state(conn, FTP_AUTH);
- }
- else {
- result = ftp_state_user(conn);
- if(result)
- return result;
- }
- break;
- case FTP_AUTH:
-
-
- if((ftpcode == 234) || (ftpcode == 334)) {
-
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(CURLE_OK == result) {
- conn->ssl[SECONDARYSOCKET].use = FALSE;
- result = ftp_state_user(conn);
- }
- }
- else if(ftpc->count3 < 1) {
- ftpc->count3++;
- ftpc->count1 += ftpc->count2;
- result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
-
- }
- else {
- if(data->set.use_ssl > CURLUSESSL_TRY)
-
- result = CURLE_USE_SSL_FAILED;
- else
-
- result = ftp_state_user(conn);
- }
- if(result)
- return result;
- break;
- case FTP_USER:
- case FTP_PASS:
- result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_ACCT:
- result = ftp_state_acct_resp(conn, ftpcode);
- break;
- case FTP_PBSZ:
- PPSENDF(&ftpc->pp, "PROT %c",
- data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
- state(conn, FTP_PROT);
- break;
- case FTP_PROT:
- if(ftpcode/100 == 2)
-
- conn->ssl[SECONDARYSOCKET].use =
- (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
-
- else if(data->set.use_ssl > CURLUSESSL_CONTROL)
-
- return CURLE_USE_SSL_FAILED;
- if(data->set.ftp_ccc) {
-
- PPSENDF(&ftpc->pp, "%s", "CCC");
- state(conn, FTP_CCC);
- }
- else {
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- }
- break;
- case FTP_CCC:
- if(ftpcode < 500) {
-
- result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
- if(result) {
- failf(conn->data, "Failed to clear the command channel (CCC)");
- return result;
- }
- }
-
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- break;
- case FTP_PWD:
- if(ftpcode == 257) {
- char *ptr=&data->state.buffer[4];
- char *dir;
- char *store;
- dir = malloc(nread + 1);
- if(!dir)
- return CURLE_OUT_OF_MEMORY;
-
-
- while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
- && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
- ptr++;
- if('\"' == *ptr) {
-
- ptr++;
- for(store = dir; *ptr;) {
- if('\"' == *ptr) {
- if('\"' == ptr[1]) {
-
- *store = ptr[1];
- ptr++;
- }
- else {
-
- *store = '\0';
- break;
- }
- }
- else
- *store = *ptr;
- store++;
- ptr++;
- }
-
- if(!ftpc->server_os && dir[0] != '/') {
- result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
- if(result != CURLE_OK) {
- free(dir);
- return result;
- }
- Curl_safefree(ftpc->entrypath);
- ftpc->entrypath = dir;
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
-
- data->state.most_recent_ftp_entrypath = ftpc->entrypath;
- state(conn, FTP_SYST);
- break;
- }
- Curl_safefree(ftpc->entrypath);
- ftpc->entrypath = dir;
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
-
- data->state.most_recent_ftp_entrypath = ftpc->entrypath;
- }
- else {
-
- free(dir);
- infof(data, "Failed to figure out path\n");
- }
- }
- state(conn, FTP_STOP);
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
- case FTP_SYST:
- if(ftpcode == 215) {
- char *ptr=&data->state.buffer[4];
- char *os;
- char *store;
- os = malloc(nread + 1);
- if(!os)
- return CURLE_OUT_OF_MEMORY;
-
- while(*ptr == ' ')
- ptr++;
- for(store = os; *ptr && *ptr != ' ';)
- *store++ = *ptr++;
- *store = '\0';
-
- if(strequal(os, "OS/400")) {
-
- result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
- if(result != CURLE_OK) {
- free(os);
- return result;
- }
-
- Curl_safefree(ftpc->server_os);
- ftpc->server_os = os;
- state(conn, FTP_NAMEFMT);
- break;
- }
- else {
-
-
- Curl_safefree(ftpc->server_os);
- ftpc->server_os = os;
- }
- }
- else {
-
- }
- state(conn, FTP_STOP);
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
- case FTP_NAMEFMT:
- if(ftpcode == 250) {
-
- ftp_state_pwd(conn);
- break;
- }
- state(conn, FTP_STOP);
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
- case FTP_QUOTE:
- case FTP_POSTQUOTE:
- case FTP_RETR_PREQUOTE:
- case FTP_STOR_PREQUOTE:
- if((ftpcode >= 400) && !ftpc->count2) {
-
- failf(conn->data, "QUOT command failed with %03d", ftpcode);
- return CURLE_QUOTE_ERROR;
- }
- result = ftp_state_quote(conn, FALSE, ftpc->state);
- if(result)
- return result;
- break;
- case FTP_CWD:
- if(ftpcode/100 != 2) {
-
- if(conn->data->set.ftp_create_missing_dirs &&
- ftpc->count1 && !ftpc->count2) {
-
- ftpc->count2++;
- PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
- state(conn, FTP_MKD);
- }
- else {
-
- failf(data, "Server denied you to change to the given directory");
- ftpc->cwdfail = TRUE;
- return CURLE_REMOTE_ACCESS_DENIED;
- }
- }
- else {
-
- ftpc->count2=0;
- if(++ftpc->count1 <= ftpc->dirdepth) {
-
- PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
- }
- else {
- result = ftp_state_mdtm(conn);
- if(result)
- return result;
- }
- }
- break;
- case FTP_MKD:
- if((ftpcode/100 != 2) && !ftpc->count3--) {
-
- failf(data, "Failed to MKD dir: %03d", ftpcode);
- return CURLE_REMOTE_ACCESS_DENIED;
- }
- state(conn, FTP_CWD);
-
- PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
- break;
- case FTP_MDTM:
- result = ftp_state_mdtm_resp(conn, ftpcode);
- break;
- case FTP_TYPE:
- case FTP_LIST_TYPE:
- case FTP_RETR_TYPE:
- case FTP_STOR_TYPE:
- result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_SIZE:
- case FTP_RETR_SIZE:
- case FTP_STOR_SIZE:
- result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_REST:
- case FTP_RETR_REST:
- result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_PRET:
- if(ftpcode != 200) {
-
- failf(data, "PRET command not accepted: %03d", ftpcode);
- return CURLE_FTP_PRET_FAILED;
- }
- result = ftp_state_use_pasv(conn);
- break;
- case FTP_PASV:
- result = ftp_state_pasv_resp(conn, ftpcode);
- break;
- case FTP_PORT:
- result = ftp_state_port_resp(conn, ftpcode);
- break;
- case FTP_LIST:
- case FTP_RETR:
- result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_STOR:
- result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
- break;
- case FTP_QUIT:
-
- default:
-
- state(conn, FTP_STOP);
- break;
- }
- }
- return result;
- }
- static CURLcode ftp_multi_statemach(struct connectdata *conn,
- bool *done)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
-
- *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
- return result;
- }
- static CURLcode ftp_block_statemach(struct connectdata *conn)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- CURLcode result = CURLE_OK;
- while(ftpc->state != FTP_STOP) {
- result = Curl_pp_statemach(pp, TRUE);
- if(result)
- break;
- }
- return result;
- }
- static CURLcode ftp_connect(struct connectdata *conn,
- bool *done)
- {
- CURLcode result;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- *done = FALSE;
-
- connkeep(conn, "FTP default");
- pp->response_time = RESP_TIMEOUT;
- pp->statemach_act = ftp_statemach_act;
- pp->endofresp = ftp_endofresp;
- pp->conn = conn;
- if(conn->handler->flags & PROTOPT_SSL) {
-
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(result)
- return result;
- }
- Curl_pp_init(pp);
-
- state(conn, FTP_WAIT220);
- result = ftp_multi_statemach(conn, done);
- return result;
- }
- static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
- bool premature)
- {
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- ssize_t nread;
- int ftpcode;
- CURLcode result = CURLE_OK;
- bool was_ctl_valid = ftpc->ctl_valid;
- char *path;
- const char *path_to_use = data->state.path;
- if(!ftp)
-
- return CURLE_OK;
- switch(status) {
- case CURLE_BAD_DOWNLOAD_RESUME:
- case CURLE_FTP_WEIRD_PASV_REPLY:
- case CURLE_FTP_PORT_FAILED:
- case CURLE_FTP_ACCEPT_FAILED:
- case CURLE_FTP_ACCEPT_TIMEOUT:
- case CURLE_FTP_COULDNT_SET_TYPE:
- case CURLE_FTP_COULDNT_RETR_FILE:
- case CURLE_PARTIAL_FILE:
- case CURLE_UPLOAD_FAILED:
- case CURLE_REMOTE_ACCESS_DENIED:
- case CURLE_FILESIZE_EXCEEDED:
- case CURLE_REMOTE_FILE_NOT_FOUND:
- case CURLE_WRITE_ERROR:
-
-
- case CURLE_OK:
- if(!premature) {
- ftpc->ctl_valid = was_ctl_valid;
- break;
- }
-
- default:
- ftpc->ctl_valid = FALSE;
- ftpc->cwdfail = TRUE;
- connclose(conn, "FTP ended with bad error code");
- result = status;
- break;
- }
-
- if(ftpc->prevpath)
- free(ftpc->prevpath);
- if(data->set.wildcardmatch) {
- if(data->set.chunk_end && ftpc->file) {
- data->set.chunk_end(data->wildcard.customptr);
- }
- ftpc->known_filesize = -1;
- }
-
- path = curl_easy_unescape(data, path_to_use, 0, NULL);
- if(!path) {
-
- if(!result)
- result = CURLE_OUT_OF_MEMORY;
- ftpc->ctl_valid = FALSE;
- connclose(conn, "FTP: out of memory!");
- ftpc->prevpath = NULL;
- }
- else {
- size_t flen = ftpc->file?strlen(ftpc->file):0;
- size_t dlen = strlen(path)-flen;
- if(!ftpc->cwdfail) {
- if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
- ftpc->prevpath = path;
- if(flen)
-
- ftpc->prevpath[dlen]=0;
- }
- else {
-
- ftpc->prevpath=strdup("");
- free(path);
- }
- if(ftpc->prevpath)
- infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
- }
- else {
- ftpc->prevpath = NULL;
- free(path);
- }
- }
-
- freedirs(ftpc);
-
- #ifdef _WIN32_WCE
- shutdown(conn->sock[SECONDARYSOCKET],2);
- #endif
- if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
- if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
-
- result = Curl_pp_sendf(pp, "%s", "ABOR");
- if(result) {
- failf(data, "Failure sending ABOR command: %s",
- curl_easy_strerror(result));
- ftpc->ctl_valid = FALSE;
- connclose(conn, "ABOR command failed");
- }
- }
- if(conn->ssl[SECONDARYSOCKET].use) {
-
- Curl_ssl_close(conn, SECONDARYSOCKET);
-
- }
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
- Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
- }
- }
- if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
- pp->pending_resp && !premature) {
-
- long old_time = pp->response_time;
- pp->response_time = 60*1000;
- pp->response = Curl_tvnow();
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
- pp->response_time = old_time;
- if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
- failf(data, "control connection looks dead");
- ftpc->ctl_valid = FALSE;
- connclose(conn, "Timeout or similar in FTP DONE operation");
- }
- if(result)
- return result;
- if(ftpc->dont_check && data->req.maxdownload > 0) {
-
- infof(data, "partial download completed, closing connection\n");
- connclose(conn, "Partial download with no ability to check");
- return result;
- }
- if(!ftpc->dont_check) {
-
- if((ftpcode != 226) && (ftpcode != 250)) {
- failf(data, "server did not report OK, got %d", ftpcode);
- result = CURLE_PARTIAL_FILE;
- }
- }
- }
- if(result || premature)
-
- ;
- else if(data->set.upload) {
- if((-1 != data->state.infilesize) &&
- (data->state.infilesize != *ftp->bytecountp) &&
- !data->set.crlf &&
- (ftp->transfer == FTPTRANSFER_BODY)) {
- failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
- " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
- *ftp->bytecountp, data->state.infilesize);
- result = CURLE_PARTIAL_FILE;
- }
- }
- else {
- if((-1 != data->req.size) &&
- (data->req.size != *ftp->bytecountp) &&
- #ifdef CURL_DO_LINEEND_CONV
-
- ((data->req.size + data->state.crlf_conversions) !=
- *ftp->bytecountp) &&
- #endif
- (data->req.maxdownload != *ftp->bytecountp)) {
- failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
- " bytes", *ftp->bytecountp);
- result = CURLE_PARTIAL_FILE;
- }
- else if(!ftpc->dont_check &&
- !*ftp->bytecountp &&
- (data->req.size>0)) {
- failf(data, "No data was received!");
- result = CURLE_FTP_COULDNT_RETR_FILE;
- }
- }
-
- ftp->transfer = FTPTRANSFER_BODY;
- ftpc->dont_check = FALSE;
-
- if(!status && !result && !premature && data->set.postquote)
- result = ftp_sendquote(conn, data->set.postquote);
- return result;
- }
- static
- CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
- {
- struct curl_slist *item;
- ssize_t nread;
- int ftpcode;
- CURLcode result;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
- item = quote;
- while(item) {
- if(item->data) {
- char *cmd = item->data;
- bool acceptfail = FALSE;
-
- if(cmd[0] == '*') {
- cmd++;
- acceptfail = TRUE;
- }
- PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
- pp->response = Curl_tvnow();
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
- if(result)
- return result;
- if(!acceptfail && (ftpcode >= 400)) {
- failf(conn->data, "QUOT string not accepted: %s", cmd);
- return CURLE_QUOTE_ERROR;
- }
- }
- item = item->next;
- }
- return CURLE_OK;
- }
- static int ftp_need_type(struct connectdata *conn,
- bool ascii_wanted)
- {
- return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
- }
- static CURLcode ftp_nb_type(struct connectdata *conn,
- bool ascii, ftpstate newstate)
- {
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result;
- char want = (char)(ascii?'A':'I');
- if(ftpc->transfertype == want) {
- state(conn, newstate);
- return ftp_state_type_resp(conn, 200, newstate);
- }
- PPSENDF(&ftpc->pp, "TYPE %c", want);
- state(conn, newstate);
-
- ftpc->transfertype = want;
- return CURLE_OK;
- }
- #ifndef CURL_DISABLE_VERBOSE_STRINGS
- static void
- ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
- char *newhost,
- int port)
- {
- char buf[256];
- Curl_printable_address(ai, buf, sizeof(buf));
- infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
- }
- #endif
- static CURLcode ftp_range(struct connectdata *conn)
- {
- curl_off_t from, to;
- char *ptr;
- char *ptr2;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(data->state.use_range && data->state.range) {
- from=curlx_strtoofft(data->state.range, &ptr, 0);
- while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
- ptr++;
- to=curlx_strtoofft(ptr, &ptr2, 0);
- if(ptr == ptr2) {
-
- to=-1;
- }
- if((-1 == to) && (from>=0)) {
-
- data->state.resume_from = from;
- DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
- " to end of file\n", from));
- }
- else if(from < 0) {
-
- data->req.maxdownload = -from;
- data->state.resume_from = from;
- DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
- " bytes\n", -from));
- }
- else {
-
- data->req.maxdownload = (to-from)+1;
- data->state.resume_from = from;
- DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
- " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
- from, data->req.maxdownload));
- }
- DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
- " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
- CURL_FORMAT_CURL_OFF_T " bytes\n",
- from, to, data->req.maxdownload));
- ftpc->dont_check = TRUE;
- }
- else
- data->req.maxdownload = -1;
- return CURLE_OK;
- }
- static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
- {
- struct SessionHandle *data=conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
- bool connected = FALSE;
- bool complete = FALSE;
-
- struct FTP *ftp = data->req.protop;
-
- if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
- if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
-
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
- return result;
- }
- result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
-
- if(connected) {
- DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
- if(conn->bits.proxy) {
- infof(data, "Connection to proxy confirmed\n");
- result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected);
- }
- }
- else {
- if(result && (ftpc->count1 == 0)) {
- *completep = -1;
-
- return ftp_epsv_disable(conn);
- }
- return result;
- }
- }
- if(ftpc->state) {
-
- result = ftp_multi_statemach(conn, &complete);
- *completep = (int)complete;
-
- if(result || (ftpc->wait_data_conn != TRUE))
- return result;
- if(ftpc->wait_data_conn)
-
- *completep = 0;
- }
- if(ftp->transfer <= FTPTRANSFER_INFO) {
-
- if(ftpc->wait_data_conn == TRUE) {
- bool serv_conned;
- result = ReceivedServerConnect(conn, &serv_conned);
- if(result)
- return result;
- if(serv_conned) {
-
- result = AcceptServerConnect(conn);
- ftpc->wait_data_conn = FALSE;
- if(!result)
- result = InitiateTransfer(conn);
- if(result)
- return result;
- *completep = 1;
- }
- }
- else if(data->set.upload) {
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
- if(result)
- return result;
- result = ftp_multi_statemach(conn, &complete);
- *completep = (int)complete;
- }
- else {
-
- ftp->downloadsize = -1;
- result = ftp_range(conn);
- if(result)
- ;
- else if(data->set.ftp_list_only || !ftpc->file) {
-
-
- if(ftp->transfer == FTPTRANSFER_BODY) {
- result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
- if(result)
- return result;
- }
-
- }
- else {
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
- if(result)
- return result;
- }
- result = ftp_multi_statemach(conn, &complete);
- *completep = (int)complete;
- }
- return result;
- }
- if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- if(!ftpc->wait_data_conn) {
-
- *completep = 1;
- DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
- }
- return result;
- }
- static
- CURLcode ftp_perform(struct connectdata *conn,
- bool *connected,
- bool *dophase_done)
- {
-
- CURLcode result=CURLE_OK;
- DEBUGF(infof(conn->data, "DO phase starts\n"));
- if(conn->data->set.opt_no_body) {
-
- struct FTP *ftp = conn->data->req.protop;
- ftp->transfer = FTPTRANSFER_INFO;
- }
- *dophase_done = FALSE;
-
- result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
- if(result)
- return result;
-
- result = ftp_multi_statemach(conn, dophase_done);
- *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
- infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
- if(*dophase_done)
- DEBUGF(infof(conn->data, "DO phase is complete1\n"));
- return result;
- }
- static void wc_data_dtor(void *ptr)
- {
- struct ftp_wc_tmpdata *tmp = ptr;
- if(tmp)
- Curl_ftp_parselist_data_free(&tmp->parser);
- Curl_safefree(tmp);
- }
- static CURLcode init_wc_data(struct connectdata *conn)
- {
- char *last_slash;
- char *path = conn->data->state.path;
- struct WildcardData *wildcard = &(conn->data->wildcard);
- CURLcode ret = CURLE_OK;
- struct ftp_wc_tmpdata *ftp_tmp;
- last_slash = strrchr(conn->data->state.path, '/');
- if(last_slash) {
- last_slash++;
- if(last_slash[0] == '\0') {
- wildcard->state = CURLWC_CLEAN;
- ret = ftp_parse_url_path(conn);
- return ret;
- }
- else {
- wildcard->pattern = strdup(last_slash);
- if(!wildcard->pattern)
- return CURLE_OUT_OF_MEMORY;
- last_slash[0] = '\0';
- }
- }
- else {
- if(path[0]) {
- wildcard->pattern = strdup(path);
- if(!wildcard->pattern)
- return CURLE_OUT_OF_MEMORY;
- path[0] = '\0';
- }
- else {
- wildcard->state = CURLWC_CLEAN;
- ret = ftp_parse_url_path(conn);
- return ret;
- }
- }
-
-
- ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
- if(!ftp_tmp) {
- Curl_safefree(wildcard->pattern);
- return CURLE_OUT_OF_MEMORY;
- }
-
- ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
- if(!ftp_tmp->parser) {
- Curl_safefree(wildcard->pattern);
- Curl_safefree(ftp_tmp);
- return CURLE_OUT_OF_MEMORY;
- }
- wildcard->tmp = ftp_tmp;
- wildcard->tmp_dtor = wc_data_dtor;
-
- if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
- conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
-
- ret = ftp_parse_url_path(conn);
- if(ret) {
- Curl_safefree(wildcard->pattern);
- wildcard->tmp_dtor(wildcard->tmp);
- wildcard->tmp_dtor = ZERO_NULL;
- wildcard->tmp = NULL;
- return ret;
- }
- wildcard->path = strdup(conn->data->state.path);
- if(!wildcard->path) {
- Curl_safefree(wildcard->pattern);
- wildcard->tmp_dtor(wildcard->tmp);
- wildcard->tmp_dtor = ZERO_NULL;
- wildcard->tmp = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
-
- ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
-
- conn->data->set.fwrite_func = Curl_ftp_parselist;
-
- ftp_tmp->backup.file_descriptor = conn->data->set.out;
-
- conn->data->set.out = conn;
- infof(conn->data, "Wildcard - Parsing started\n");
- return CURLE_OK;
- }
- static CURLcode wc_statemach(struct connectdata *conn)
- {
- struct WildcardData * const wildcard = &(conn->data->wildcard);
- CURLcode ret = CURLE_OK;
- switch (wildcard->state) {
- case CURLWC_INIT:
- ret = init_wc_data(conn);
- if(wildcard->state == CURLWC_CLEAN)
-
- break;
- else
- wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
- break;
- case CURLWC_MATCHING: {
-
- struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
- conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
- conn->data->set.out = ftp_tmp->backup.file_descriptor;
- ftp_tmp->backup.write_function = ZERO_NULL;
- ftp_tmp->backup.file_descriptor = NULL;
- wildcard->state = CURLWC_DOWNLOADING;
- if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
-
- wildcard->state = CURLWC_CLEAN;
- return wc_statemach(conn);
- }
- else if(wildcard->filelist->size == 0) {
-
- wildcard->state = CURLWC_CLEAN;
- return CURLE_REMOTE_FILE_NOT_FOUND;
- }
- return wc_statemach(conn);
- }
- case CURLWC_DOWNLOADING: {
-
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
- char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
- if(!tmp_path)
- return CURLE_OUT_OF_MEMORY;
-
- Curl_safefree(conn->data->state.pathbuffer);
- conn->data->state.pathbuffer = tmp_path;
- conn->data->state.path = tmp_path;
- infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
- if(conn->data->set.chunk_bgn) {
- long userresponse = conn->data->set.chunk_bgn(
- finfo, wildcard->customptr, (int)wildcard->filelist->size);
- switch(userresponse) {
- case CURL_CHUNK_BGN_FUNC_SKIP:
- infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
- finfo->filename);
- wildcard->state = CURLWC_SKIP;
- return wc_statemach(conn);
- case CURL_CHUNK_BGN_FUNC_FAIL:
- return CURLE_CHUNK_FAILED;
- }
- }
- if(finfo->filetype != CURLFILETYPE_FILE) {
- wildcard->state = CURLWC_SKIP;
- return wc_statemach(conn);
- }
- if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
- ftpc->known_filesize = finfo->size;
- ret = ftp_parse_url_path(conn);
- if(ret) {
- return ret;
- }
-
- Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
- if(wildcard->filelist->size == 0) {
- wildcard->state = CURLWC_CLEAN;
-
- return CURLE_OK;
- }
- } break;
- case CURLWC_SKIP: {
- if(conn->data->set.chunk_end)
- conn->data->set.chunk_end(conn->data->wildcard.customptr);
- Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
- wildcard->state = (wildcard->filelist->size == 0) ?
- CURLWC_CLEAN : CURLWC_DOWNLOADING;
- return wc_statemach(conn);
- }
- case CURLWC_CLEAN: {
- struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
- ret = CURLE_OK;
- if(ftp_tmp) {
- ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
- }
- wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
- } break;
- case CURLWC_DONE:
- case CURLWC_ERROR:
- break;
- }
- return ret;
- }
- static CURLcode ftp_do(struct connectdata *conn, bool *done)
- {
- CURLcode retcode = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- *done = FALSE;
- ftpc->wait_data_conn = FALSE;
- if(conn->data->set.wildcardmatch) {
- retcode = wc_statemach(conn);
- if(conn->data->wildcard.state == CURLWC_SKIP ||
- conn->data->wildcard.state == CURLWC_DONE) {
-
- return CURLE_OK;
- }
- if(retcode)
- return retcode;
- }
- else {
- retcode = ftp_parse_url_path(conn);
- if(retcode)
- return retcode;
- }
- retcode = ftp_regular_transfer(conn, done);
- return retcode;
- }
- CURLcode Curl_ftpsendf(struct connectdata *conn,
- const char *fmt, ...)
- {
- ssize_t bytes_written;
- #define SBUF_SIZE 1024
- char s[SBUF_SIZE];
- size_t write_len;
- char *sptr=s;
- CURLcode res = CURLE_OK;
- #ifdef HAVE_GSSAPI
- enum protection_level data_sec = conn->data_prot;
- #endif
- va_list ap;
- va_start(ap, fmt);
- write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
- va_end(ap);
- strcpy(&s[write_len], "\r\n");
- write_len +=2;
- bytes_written=0;
- res = Curl_convert_to_network(conn->data, s, write_len);
-
- if(res)
- return(res);
- for(;;) {
- #ifdef HAVE_GSSAPI
- conn->data_prot = PROT_CMD;
- #endif
- res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
- &bytes_written);
- #ifdef HAVE_GSSAPI
- DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
- conn->data_prot = data_sec;
- #endif
- if(CURLE_OK != res)
- break;
- if(conn->data->set.verbose)
- Curl_debug(conn->data, CURLINFO_HEADER_OUT,
- sptr, (size_t)bytes_written, conn);
- if(bytes_written != (ssize_t)write_len) {
- write_len -= bytes_written;
- sptr += bytes_written;
- }
- else
- break;
- }
- return res;
- }
- static CURLcode ftp_quit(struct connectdata *conn)
- {
- CURLcode result = CURLE_OK;
- if(conn->proto.ftpc.ctl_valid) {
- result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
- if(result) {
- failf(conn->data, "Failure sending QUIT command: %s",
- curl_easy_strerror(result));
- conn->proto.ftpc.ctl_valid = FALSE;
- connclose(conn, "QUIT command failed");
- state(conn, FTP_STOP);
- return result;
- }
- state(conn, FTP_QUIT);
- result = ftp_block_statemach(conn);
- }
- return result;
- }
- static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
- {
- struct ftp_conn *ftpc= &conn->proto.ftpc;
- struct pingpong *pp = &ftpc->pp;
-
- if(dead_connection)
- ftpc->ctl_valid = FALSE;
-
- (void)ftp_quit(conn);
- if(ftpc->entrypath) {
- struct SessionHandle *data = conn->data;
- if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
- data->state.most_recent_ftp_entrypath = NULL;
- }
- free(ftpc->entrypath);
- ftpc->entrypath = NULL;
- }
- freedirs(ftpc);
- if(ftpc->prevpath) {
- free(ftpc->prevpath);
- ftpc->prevpath = NULL;
- }
- if(ftpc->server_os) {
- free(ftpc->server_os);
- ftpc->server_os = NULL;
- }
- Curl_pp_disconnect(pp);
- #ifdef HAVE_GSSAPI
- Curl_sec_end(conn);
- #endif
- return CURLE_OK;
- }
- static
- CURLcode ftp_parse_url_path(struct connectdata *conn)
- {
- struct SessionHandle *data = conn->data;
-
- struct FTP *ftp = data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- const char *slash_pos;
- const char *path_to_use = data->state.path;
- const char *cur_pos;
- const char *filename = NULL;
- cur_pos = path_to_use;
- ftpc->ctl_valid = FALSE;
- ftpc->cwdfail = FALSE;
- switch(data->set.ftp_filemethod) {
- case FTPFILE_NOCWD:
-
-
- if(data->state.path &&
- data->state.path[0] &&
- (data->state.path[strlen(data->state.path) - 1] != '/') )
- filename = data->state.path;
-
- break;
- case FTPFILE_SINGLECWD:
-
- if(!path_to_use[0]) {
-
- ftpc->dirdepth = 0;
- break;
- }
- slash_pos=strrchr(cur_pos, '/');
- if(slash_pos || !*cur_pos) {
- size_t dirlen = slash_pos-cur_pos;
- ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
- if(!ftpc->dirs)
- return CURLE_OUT_OF_MEMORY;
- if(!dirlen)
- dirlen++;
- ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
- slash_pos ? curlx_uztosi(dirlen) : 1,
- NULL);
- if(!ftpc->dirs[0]) {
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- ftpc->dirdepth = 1;
- filename = slash_pos ? slash_pos+1 : cur_pos;
- }
- else
- filename = cur_pos;
- break;
- default:
- case FTPFILE_MULTICWD:
- ftpc->dirdepth = 0;
- ftpc->diralloc = 5;
- ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
- if(!ftpc->dirs)
- return CURLE_OUT_OF_MEMORY;
-
- if(strequal(path_to_use, "/")) {
- cur_pos++;
- ftpc->dirs[0] = strdup("/");
- ftpc->dirdepth++;
- }
- else {
-
- while((slash_pos = strchr(cur_pos, '/')) != NULL) {
-
- ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
- (ftpc->dirdepth == 0))?1:0;
-
- if(slash_pos-cur_pos) {
-
- int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
- ftpc->dirs[ftpc->dirdepth] =
- curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
- if(!ftpc->dirs[ftpc->dirdepth]) {
- failf(data, "no memory");
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
- free(ftpc->dirs[ftpc->dirdepth]);
- freedirs(ftpc);
- return CURLE_URL_MALFORMAT;
- }
- }
- else {
- cur_pos = slash_pos + 1;
- if(!ftpc->dirdepth) {
-
- ftpc->dirs[ftpc->dirdepth] = strdup("/");
- if(!ftpc->dirs[ftpc->dirdepth++]) {
- failf(data, "no memory");
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- }
- continue;
- }
- cur_pos = slash_pos + 1;
- if(++ftpc->dirdepth >= ftpc->diralloc) {
-
- char **bigger;
- ftpc->diralloc *= 2;
- bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
- if(!bigger) {
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- ftpc->dirs = bigger;
- }
- }
- }
- filename = cur_pos;
- break;
- }
- if(filename && *filename) {
- ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
- if(NULL == ftpc->file) {
- freedirs(ftpc);
- failf(data, "no memory");
- return CURLE_OUT_OF_MEMORY;
- }
- if(isBadFtpString(ftpc->file)) {
- freedirs(ftpc);
- return CURLE_URL_MALFORMAT;
- }
- }
- else
- ftpc->file=NULL;
- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
-
- failf(data, "Uploading to a URL without a file name!");
- return CURLE_URL_MALFORMAT;
- }
- ftpc->cwddone = FALSE;
- if(ftpc->prevpath) {
-
- int dlen;
- char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
- if(!path) {
- freedirs(ftpc);
- return CURLE_OUT_OF_MEMORY;
- }
- dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
- if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
- strnequal(path, ftpc->prevpath, dlen)) {
- infof(data, "Request has same path as previous transfer\n");
- ftpc->cwddone = TRUE;
- }
- free(path);
- }
- return CURLE_OK;
- }
- static CURLcode ftp_dophase_done(struct connectdata *conn,
- bool connected)
- {
- struct FTP *ftp = conn->data->req.protop;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- if(connected) {
- int completed;
- CURLcode result = ftp_do_more(conn, &completed);
- if(result) {
- if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
-
- Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- }
- return result;
- }
- }
- if(ftp->transfer != FTPTRANSFER_BODY)
-
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- else if(!connected)
-
- conn->bits.do_more = TRUE;
- ftpc->ctl_valid = TRUE;
- return CURLE_OK;
- }
- static CURLcode ftp_doing(struct connectdata *conn,
- bool *dophase_done)
- {
- CURLcode result = ftp_multi_statemach(conn, dophase_done);
- if(result)
- DEBUGF(infof(conn->data, "DO phase failed\n"));
- else if(*dophase_done) {
- result = ftp_dophase_done(conn, FALSE );
- DEBUGF(infof(conn->data, "DO phase is complete2\n"));
- }
- return result;
- }
- static
- CURLcode ftp_regular_transfer(struct connectdata *conn,
- bool *dophase_done)
- {
- CURLcode result=CURLE_OK;
- bool connected=FALSE;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- data->req.size = -1;
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
- Curl_pgrsSetUploadSize(data, 0);
- Curl_pgrsSetDownloadSize(data, 0);
- ftpc->ctl_valid = TRUE;
- result = ftp_perform(conn,
- &connected,
- dophase_done);
- if(CURLE_OK == result) {
- if(!*dophase_done)
-
- return CURLE_OK;
- result = ftp_dophase_done(conn, connected);
- if(result)
- return result;
- }
- else
- freedirs(ftpc);
- return result;
- }
- static CURLcode ftp_setup_connection(struct connectdata *conn)
- {
- struct SessionHandle *data = conn->data;
- char *type;
- char command;
- struct FTP *ftp;
- if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
-
- #ifndef CURL_DISABLE_HTTP
- if(conn->handler == &Curl_handler_ftp)
- conn->handler = &Curl_handler_ftp_proxy;
- else {
- #ifdef USE_SSL
- conn->handler = &Curl_handler_ftps_proxy;
- #else
- failf(data, "FTPS not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
- #endif
- }
-
- return conn->handler->setup_connection(conn);
- #else
- failf(data, "FTP over http proxy requires HTTP support built-in!");
- return CURLE_UNSUPPORTED_PROTOCOL;
- #endif
- }
- conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
- if(NULL == ftp)
- return CURLE_OUT_OF_MEMORY;
- data->state.path++;
- data->state.slash_removed = TRUE;
-
- type = strstr(data->state.path, ";type=");
- if(!type)
- type = strstr(conn->host.rawalloc, ";type=");
- if(type) {
- *type = 0;
- command = Curl_raw_toupper(type[6]);
- conn->bits.type_set = TRUE;
- switch (command) {
- case 'A':
- data->set.prefer_ascii = TRUE;
- break;
- case 'D':
- data->set.ftp_list_only = TRUE;
- break;
- case 'I':
- default:
-
- data->set.prefer_ascii = FALSE;
- break;
- }
- }
-
- ftp->bytecountp = &conn->data->req.bytecount;
- ftp->transfer = FTPTRANSFER_BODY;
- ftp->downloadsize = 0;
-
- ftp->user = conn->user;
- ftp->passwd = conn->passwd;
- if(isBadFtpString(ftp->user))
- return CURLE_URL_MALFORMAT;
- if(isBadFtpString(ftp->passwd))
- return CURLE_URL_MALFORMAT;
- conn->proto.ftpc.known_filesize = -1;
- return CURLE_OK;
- }
- #endif
|