123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405 |
- //---------------------------------------------------------------------------
- #include "stdafx.h"
- #include "FtpControlSocket.h"
- #include "mainthread.h"
- #include "transfersocket.h"
- #include "asyncproxysocketlayer.h"
- #include "AsyncSslSocketLayer.h"
- #ifndef MPEXT_NO_GSS
- #include "AsyncGssSocketLayer.h"
- #endif
- #include "filezillaapi.h"
- #include <WideStrUtils.hpp>
- class CFtpControlSocket::CFileTransferData : public CFtpControlSocket::t_operation::COpData
- {
- public:
- CFileTransferData()
- {
- pDirectoryListing=0;
- nGotTransferEndReply=0;
- nWaitNextOpState=0;
- nMKDOpState=-1;
- hasRemoteDate = false;
- pFileSize=0;
- bUseAbsolutePaths = FALSE;
- bTriedPortPasvOnce = FALSE;
- askOnResumeFail = false;
- };
- ~CFileTransferData()
- {
- if (pDirectoryListing)
- delete pDirectoryListing;
- pDirectoryListing=0;
- delete pFileSize;
- };
- CString rawpwd;
- t_transferfile transferfile;
- t_transferdata transferdata;
- CString host;
- int port;
- BOOL bPasv;
- int nGotTransferEndReply;
- t_directory *pDirectoryListing;
- int nWaitNextOpState;
- CServerPath MKDCurrent;
- std::list<CString> MKDSegments;
- int nMKDOpState;
- bool hasRemoteDate;
- t_directory::t_direntry::t_date remoteDate;
- //CTime *pFileTime; //Used when downloading and OPTION_PRESERVEDOWNLOADFILETIME is set or when LIST fails
- _int64 *pFileSize; //Used when LIST failes
- BOOL bUseAbsolutePaths;
- BOOL bTriedPortPasvOnce;
- #ifndef MPEXT_NO_ZLIB
- int newZlibLevel;
- #endif
- bool askOnResumeFail;
- };
- class CFtpControlSocket::CLogonData:public CFtpControlSocket::t_operation::COpData
- {
- public:
- CLogonData()
- {
- waitForAsyncRequest = false;
- gotPassword = false;
- }
- virtual ~CLogonData()
- {
- }
- bool waitForAsyncRequest;
- bool gotPassword;
- };
- class CFtpControlSocket::CListData:public CFtpControlSocket::t_operation::COpData
- {
- public:
- CListData()
- {
- pDirectoryListing = 0;
- bTriedPortPasvOnce = FALSE;
- lastCmdSentCDUP = false;
- }
- virtual ~CListData()
- {
- if (pDirectoryListing)
- delete pDirectoryListing;
- }
- CString rawpwd;
- CServerPath path;
- CString fileName;
- CString subdir;
- BOOL bPasv;
- CString host;
- UINT port;
- int nFinish;
- t_directory *pDirectoryListing;
- BOOL bTriedPortPasvOnce;
- #ifndef MPEXT_NO_ZLIB
- int newZlibLevel;
- #endif
- bool lastCmdSentCDUP;
- };
- class CFtpControlSocket::CListFileData:public CFtpControlSocket::t_operation::COpData
- {
- public:
- CListFileData()
- {
- direntry = NULL;
- }
- ~CListFileData()
- {
- delete [] direntry;
- }
- CString fileName;
- CString dir;
- CString path;
- CServerPath pwd;
- t_directory::t_direntry * direntry;
- };
- class CFtpControlSocket::CMakeDirData : public CFtpControlSocket::t_operation::COpData
- {
- public:
- CMakeDirData() {}
- virtual ~CMakeDirData() {}
- CServerPath path;
- CServerPath Current;
- std::list<CString> Segments;
- };
- #define MKD_INIT -1
- #define MKD_FINDPARENT 0
- #define MKD_MAKESUBDIRS 1
- #define MKD_CHANGETOSUBDIR 2
- /////////////////////////////////////////////////////////////////////////////
- // CFtpControlSocket
- std::list<CFtpControlSocket::t_ActiveList> CFtpControlSocket::m_InstanceList[2];
- CTime CFtpControlSocket::m_CurrentTransferTime[2] = { CTime::GetCurrentTime(), CTime::GetCurrentTime() };
- _int64 CFtpControlSocket::m_CurrentTransferLimit[2] = {0, 0};
- CCriticalSection CFtpControlSocket::m_SpeedLimitSync;
- #define BUFSIZE 16384
- CFtpControlSocket::CFtpControlSocket(CMainThread *pMainThread, CFileZillaTools * pTools)
- {
- DebugAssert(pMainThread);
- m_pOwner=pMainThread;
- m_pTools=pTools;
- m_Operation.nOpMode=0;
- m_Operation.nOpState=-1;
- m_Operation.pData=0;
- m_pProxyLayer = NULL;
- m_pSslLayer = NULL;
- #ifndef MPEXT_NO_GSS
- m_pGssLayer = NULL;
- #endif
- m_pDirectoryListing=0;
- m_pTransferSocket=0;
- m_pDataFile=0;
- srand( (unsigned)time( NULL ) );
- m_bKeepAliveActive=FALSE;
- m_bCheckForTimeout=TRUE;
- m_bDidRejectCertificate = FALSE;
- #ifndef MPEXT_NO_ZLIB
- m_useZlib = false;
- m_zlibSupported = false;
- m_zlibLevel = 8;
- #endif
- m_bUTF8 = true;
- m_hasClntCmd = false;
- m_serverCapabilities.Clear();
- m_ListFile = "";
- m_awaitsReply = false;
- m_skipReply = false;
- m_sendBuffer = 0;
- m_sendBufferLen = 0;
- m_bProtP = false;
- m_mayBeMvsFilesystem = false;
- m_mayBeBS2000Filesystem = false;
- }
- CFtpControlSocket::~CFtpControlSocket()
- {
- DoClose();
- if (m_pTransferSocket)
- {
- m_pTransferSocket->Close();
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- }
- if (m_pDataFile)
- {
- delete m_pDataFile;
- m_pDataFile=0;
- }
- Close();
- }
- void CFtpControlSocket::ShowStatus(UINT nID, int type) const
- {
- CString str;
- str.LoadString(nID);
- ShowStatus(str, type);
- }
- void CFtpControlSocket::ShowStatus(CString status, int type) const
- {
- if (!GetOptionVal(OPTION_MPEXT_LOG_SENSITIVE))
- {
- if ( status.Left(5)==L"PASS " )
- {
- int len=status.GetLength()-5;
- status=L"PASS ";
- for (int i=0;i<len;i++)
- status+=L"*";
- }
- else if ( status.Left(5)==L"ACCT " )
- {
- int len=status.GetLength()-5;
- status=L"ACCT ";
- for (int i=0;i<len;i++)
- status+=L"*";
- }
- }
- LogMessageRaw(type, (LPCTSTR)status);
- }
- void CFtpControlSocket::ShowTimeoutError(UINT nID) const
- {
- CString str1;
- str1.LoadString(IDS_ERRORMSG_TIMEOUT);
- CString str2;
- str2.LoadString(nID);
- CString message;
- message.Format(L"%s (%s)", str1, str2);
- ShowStatus(message, FZ_LOG_ERROR);
- }
- t_server CFtpControlSocket::GetCurrentServer()
- {
- return m_CurrentServer;
- }
- void CFtpControlSocket::Close()
- {
- if (m_pDirectoryListing)
- {
- delete m_pDirectoryListing;
- }
- m_pDirectoryListing=0;
- CAsyncSocketEx::Close();
- delete m_pProxyLayer;
- m_pProxyLayer = NULL;
- delete m_pSslLayer;
- m_pSslLayer = NULL;
- #ifndef MPEXT_NO_GSS
- delete m_pGssLayer;
- m_pGssLayer = NULL;
- #endif
- RemoveActiveTransfer();
- }
- BOOL CFtpControlSocket::Connect(CString hostAddress, UINT nHostPort)
- {
- hostAddress = ConvertDomainName(hostAddress);
- //Don't resolve host asynchronously when using proxies
- if (m_pProxyLayer)
- {
- return CAsyncSocketEx::Connect(hostAddress, nHostPort);
- }
- BOOL res = CAsyncSocketEx::Connect(hostAddress, nHostPort);
- int nLastError = WSAGetLastError();
- if (res || nLastError==WSAEWOULDBLOCK)
- {
- WSASetLastError(nLastError);
- }
- return res;
- }
- void CFtpControlSocket::SetDirectoryListing(t_directory *pDirectory, bool bSetWorkingDir /*=true*/)
- {
- if (m_pDirectoryListing)
- delete m_pDirectoryListing;
- m_CurrentServer=pDirectory->server;
- m_pDirectoryListing=new t_directory;
- *m_pDirectoryListing=*pDirectory;
- if (bSetWorkingDir)
- m_pOwner->SetWorkingDir(pDirectory);
- }
- /////////////////////////////////////////////////////////////////////////////
- // Member-Funktion CFtpControlSocket
- #define CONNECT_INIT -1
- #ifndef MPEXT_NO_GSS
- #define CONNECT_GSS_INIT -2
- #define CONNECT_GSS_AUTHDONE -3
- #define CONNECT_GSS_CWD -4
- #define CONNECT_GSS_FAILED -5
- #define CONNECT_GSS_NEEDPASS -6
- #define CONNECT_GSS_NEEDUSER -7
- #endif
- #define CONNECT_SSL_INIT -8
- #define CONNECT_SSL_NEGOTIATE -9
- #define CONNECT_TLS_NEGOTIATE -10
- #define CONNECT_SSL_WAITDONE -11
- #define CONNECT_SSL_PBSZ -12
- #define CONNECT_SSL_PROT -13
- #define CONNECT_FEAT -14
- #define CONNECT_SYST -15
- #define CONNECT_OPTSUTF8 -16
- #define CONNECT_CLNT -17
- #define CONNECT_OPTSMLST -18
- #define CONNECT_NEEDPASS -19
- #define CONNECT_HOST -20
- bool CFtpControlSocket::InitConnect()
- {
- USES_CONVERSION;
- // Reset detected capabilities
- m_bAnnouncesUTF8 = false;
- m_hasClntCmd = false;
- m_serverCapabilities.Clear();
- m_ListFile = "";
- m_isFileZilla = false;
- if (m_CurrentServer.nUTF8 == 2)
- m_bUTF8 = false;
- else
- m_bUTF8 = true;
- // Some sanity checks
- if (m_pOwner->IsConnected())
- {
- ShowStatus(L"Internal error: Connect called while still connected", FZ_LOG_ERROR);
- if (!m_Operation.nOpMode)
- m_Operation.nOpMode = CSMODE_CONNECT;
- DoClose(FZ_REPLY_CRITICALERROR);
- return false;
- }
- if (m_pSslLayer)
- {
- ShowStatus(L"Internal error: m_pSslLayer not zero in Connect", FZ_LOG_ERROR);
- DoClose(FZ_REPLY_CRITICALERROR);
- return false;
- }
- if (m_pProxyLayer)
- {
- ShowStatus(L"Internal error: m_pProxyLayer not zero in Connect", FZ_LOG_ERROR);
- DoClose(FZ_REPLY_CRITICALERROR);
- return false;
- }
- if (m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYER_SSL_IMPLICIT ||
- m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYER_SSL_EXPLICIT ||
- m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYER_TLS_EXPLICIT)
- {
- m_pSslLayer = new CAsyncSslSocketLayer;
- AddLayer(m_pSslLayer);
- m_pSslLayer->SetClientCertificate(m_CurrentServer.Certificate, m_CurrentServer.PrivateKey);
- TCHAR buffer[1000];
- GetModuleFileName(NULL, buffer, 1000);
- CString filename = buffer;
- int pos = filename.ReverseFind(L'\\');
- if (pos != -1)
- {
- filename = filename.Left(pos + 1);
- filename += L"cacert.pem";
- }
- else
- filename = L"cacert.pem";
- m_pSslLayer->SetCertStorage(filename);
- }
- int nProxyType = GetOptionVal(OPTION_PROXYTYPE);
- if (nProxyType != PROXYTYPE_NOPROXY)
- {
- m_pProxyLayer = new CAsyncProxySocketLayer;
- m_pProxyLayer->SetProxy(
- nProxyType, T2CA(GetOption(OPTION_PROXYHOST)), GetOptionVal(OPTION_PROXYPORT),
- GetOptionVal(OPTION_PROXYUSELOGON), T2CA(GetOption(OPTION_PROXYUSER)), T2CA(GetOption(OPTION_PROXYPASS)));
- AddLayer(m_pProxyLayer);
- }
- #ifndef MPEXT_NO_GSS
- BOOL bUseGSS = FALSE;
- if (GetOptionVal(OPTION_USEGSS) && !m_pSslLayer)
- {
- CString GssServers=GetOption(OPTION_GSSSERVERS);
- LPCSTR lpszAscii=T2CA(m_CurrentServer.host);
- hostent *fullname=gethostbyname(lpszAscii);
- CString host;
- if (fullname)
- host=fullname->h_name;
- else
- host=m_CurrentServer.host;
- host.MakeLower();
- int i;
- while ((i=GssServers.Find(L";"))!=-1)
- {
- if ((L"."+GssServers.Left(i))==host.Right(GssServers.Left(i).GetLength()+1) || GssServers.Left(i)==host)
- {
- bUseGSS=TRUE;
- break;
- }
- GssServers=GssServers.Mid(i+1);
- }
- }
- if (bUseGSS)
- {
- m_pGssLayer = new CAsyncGssSocketLayer;
- AddLayer(m_pGssLayer);
- if (!m_pGssLayer->InitGSS())
- {
- ShowStatus(L"Unable to initialize GSS api", FZ_LOG_ERROR);
- DoClose(FZ_REPLY_CRITICALERROR);
- return false;
- }
- }
- #endif
- return true;
- }
- int CFtpControlSocket::InitConnectState()
- {
- if ((m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYERMASK) & (FZ_SERVERTYPE_LAYER_SSL_EXPLICIT | FZ_SERVERTYPE_LAYER_TLS_EXPLICIT))
- return CONNECT_SSL_INIT;
- else
- #ifndef MPEXT_NO_GSS
- if (m_pGssLayer)
- return CONNECT_GSS_INIT;
- else
- #endif
- return CONNECT_INIT;
- }
- void CFtpControlSocket::Connect(t_server &server)
- {
- USES_CONVERSION;
- if (m_Operation.nOpMode)
- {
- ShowStatus(L"Internal error: m_Operation.nOpMode not zero in Connect", FZ_LOG_ERROR);
- m_Operation.nOpMode = CSMODE_CONNECT;
- DoClose(FZ_REPLY_CRITICALERROR);
- return;
- }
- m_Operation.nOpMode = CSMODE_CONNECT;
- m_CurrentServer = server;
- if (!InitConnect())
- return;
- if (!Create())
- {
- DoClose();
- return;
- }
- AsyncSelect();
- if (GetOptionVal(OPTION_MPEXT_HOST))
- {
- m_Operation.nOpState = CONNECT_HOST;
- }
- else
- {
- m_Operation.nOpState = InitConnectState();
- }
- if (server.nServerType & FZ_SERVERTYPE_LAYER_SSL_IMPLICIT)
- {
- if (!m_pSslLayer)
- {
- ShowStatus(L"Internal error: m_pSslLayer not initialized", FZ_LOG_ERROR);
- DoClose(FZ_REPLY_CRITICALERROR);
- return;
- }
- int res = m_pSslLayer->InitSSLConnection(true, NULL,
- GetOptionVal(OPTION_MPEXT_SSLSESSIONREUSE), server.host,
- m_pTools);
- if (res == SSL_FAILURE_INITSSL)
- ShowStatus(IDS_ERRORMSG_CANTINITSSL, FZ_LOG_ERROR);
- if (res)
- {
- DoClose();
- return;
- }
- }
- int logontype = GetOptionVal(OPTION_LOGONTYPE);
- int port;
- CString buf,temp;
- // are we connecting directly to the host (logon type 0) or via a firewall? (logon type>0)
- CString fwhost;
- int fwport;
- if(!logontype)
- {
- temp=server.host;
- port=server.port;
- }
- else
- {
- fwhost=GetOption(OPTION_FWHOST);
- fwport=GetOptionVal(OPTION_FWPORT);
- temp=fwhost;
- port=fwport;
- if(fwport!=21)
- fwhost.Format( L"%s:%d", fwhost, fwport); // add port to fwhost (only if port is not 21)
- }
- CString hostname = server.host;
- if(server.port!=21)
- hostname.Format( L"%s:%d", hostname, server.port); // add port to hostname (only if port is not 21)
- CString str;
- str.Format(IDS_STATUSMSG_CONNECTING, hostname);
- ShowStatus(str, FZ_LOG_STATUS);
- if (!Connect(temp, port))
- {
- if (WSAGetLastError() != WSAEWOULDBLOCK)
- {
- DoClose();
- return;
- }
- else
- {
- LogMessage(FZ_LOG_INFO, L"Connection pending");
- }
- }
- else
- {
- LogMessage(FZ_LOG_INFO, L"Connected");
- }
- m_ServerName = logontype?fwhost:hostname;
- m_LastRecvTime = m_LastSendTime = CTime::GetCurrentTime();
- m_Operation.pData = new CLogonData();
- }
- static CString NormalizePass(const CString & pass)
- {
- return CString(NormalizeString(UnicodeString(T2CW(pass))).c_str());
- }
- void CFtpControlSocket::LogOnToServer(BOOL bSkipReply /*=FALSE*/)
- {
- int logontype =
- #ifndef MPEXT_NO_GSS
- m_pGssLayer ? 0 :
- #endif
- GetOptionVal(OPTION_LOGONTYPE);
- const int LO = -2, ER = -1;
- CString buf, temp;
- const int NUMLOGIN = 9; // currently supports 9 different login sequences
- int logonseq[NUMLOGIN][20] = {
- // this array stores all of the logon sequences for the various firewalls
- // in blocks of 3 nums. 1st num is command to send, 2nd num is next point in logon sequence array
- // if 200 series response is rec'd from server as the result of the command, 3rd num is next
- // point in logon sequence if 300 series rec'd
- {0,LO,3, 1,LO,6, 12,LO,ER}, // no firewall
- {3,6,3, 4,6,ER, 5,9,9, 0,LO,12, 1,LO,15, 12,LO,ER}, // SITE hostname
- {3,6,3, 4,6,ER, 6,LO,9, 1,LO,12, 12,LO,ER}, // USER after logon
- {7,3,3, 0,LO,6, 1,LO,9, 12,LO,ER}, //proxy OPEN
- {3,6,3, 4,6,ER, 0,LO,9, 1,LO,12, 12,LO,ER}, // Transparent
- {6,LO,3, 1,LO,6, 12,LO,ER}, // USER remoteID@remotehost
- {8,6,3, 4,6,ER, 0,LO,9, 1,LO,12, 12,LO,ER}, //USER fireID@remotehost
- {9,ER,3, 1,LO,6, 2,LO,ER}, //USER remoteID@remotehost fireID
- {10,LO,3,11,LO,6,2,LO,ER} // USER remoteID@fireID@remotehost
- };
- if (m_Operation.nOpState == CONNECT_SSL_INIT)
- {
- if (m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYER_SSL_EXPLICIT)
- {
- if (!SendAuthSsl())
- {
- return;
- }
- }
- else
- {
- if (!Send("AUTH TLS"))
- return;
- m_Operation.nOpState = CONNECT_TLS_NEGOTIATE;
- }
- return;
- }
- else if ((m_Operation.nOpState == CONNECT_SSL_NEGOTIATE) ||
- (m_Operation.nOpState == CONNECT_TLS_NEGOTIATE))
- {
- int res = GetReplyCode();
- if (res!=2 && res!=3)
- {
- if (m_Operation.nOpState == CONNECT_TLS_NEGOTIATE)
- {
- // Try to fall back to AUTH SSL
- if (!SendAuthSsl())
- {
- return;
- }
- }
- else
- {
- DoClose();
- }
- return;
- }
- else
- {
- if (!m_pSslLayer)
- {
- ShowStatus(L"Internal error: m_pSslLayer not initialized", FZ_LOG_ERROR);
- DoClose(FZ_REPLY_CRITICALERROR);
- return;
- }
- int res = m_pSslLayer->InitSSLConnection(true, NULL,
- GetOptionVal(OPTION_MPEXT_SSLSESSIONREUSE), m_CurrentServer.host,
- m_pTools);
- if (res == SSL_FAILURE_INITSSL)
- ShowStatus(IDS_ERRORMSG_CANTINITSSL, FZ_LOG_ERROR);
- if (res)
- {
- DoClose();
- return;
- }
- }
- m_Operation.nOpState = CONNECT_SSL_WAITDONE;
- return;
- }
- else if (m_Operation.nOpState == CONNECT_SSL_WAITDONE)
- {
- m_Operation.nOpState = CONNECT_INIT;
- }
- else if (m_Operation.nOpState == CONNECT_SSL_PBSZ)
- {
- if (!Send(L"PROT P"))
- return;
- m_Operation.nOpState = CONNECT_SSL_PROT;
- return;
- }
- else if (m_Operation.nOpState == CONNECT_SSL_PROT)
- {
- int code = GetReplyCode();
- if (code == 2 || code == 3)
- m_bProtP = true;
- ShowStatus(IDS_STATUSMSG_CONNECTED, FZ_LOG_STATUS);
- m_pOwner->SetConnected(TRUE);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- #ifndef MPEXT_NO_GSS
- else
- if (m_Operation.nOpState==CONNECT_GSS_FAILED ||
- m_Operation.nOpState == CONNECT_GSS_NEEDPASS ||
- m_Operation.nOpState == CONNECT_GSS_NEEDUSER)
- {
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != "")
- {
- //Incoming reply from server during async is not allowed
- DoClose();
- return;
- }
- }
- #endif
- else if (m_Operation.nOpState == CONNECT_HOST)
- {
- if (Send(L"HOST " + m_CurrentServer.host))
- {
- m_Operation.nOpState = InitConnectState();
- return;
- }
- }
- else if (m_Operation.nOpState == CONNECT_OPTSMLST)
- {
- int code = GetReplyCode();
- if (code != 2 && code != 3)
- m_serverCapabilities.SetCapability(mlsd_command, no);
- ShowStatus(IDS_STATUSMSG_CONNECTED, FZ_LOG_STATUS);
- m_pOwner->SetConnected(TRUE);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- else if (m_Operation.nOpState == CONNECT_FEAT)
- {
- std::string facts;
- if (m_serverCapabilities.GetCapabilityString(mlsd_command, &facts) == yes)
- {
- ftp_capabilities_t cap = m_serverCapabilities.GetCapabilityString(opts_mlst_command);
- if (cap == unknown)
- {
- std::transform(facts.begin(), facts.end(), facts.begin(), ::tolower);
- bool had_unset = false;
- std::string opts_facts;
- // Create a list of all facts understood by both FZ and the server.
- // Check if there's any supported fact not enabled by default, should that
- // be the case we need to send OPTS MLST
- while (!facts.empty())
- {
- size_t delim = facts.find_first_of(';');
- if (delim == -1)
- break;
- if (!delim)
- {
- facts = facts.substr(1, std::string::npos);
- continue;
- }
- bool enabled = false;
- std::string fact;
- if (facts[delim - 1] == '*')
- {
- if (delim == 1)
- {
- facts = facts.substr(delim + 1, std::string::npos);
- continue;
- }
- enabled = true;
- fact = facts.substr(0, delim - 1);
- }
- else
- {
- enabled = false;
- fact = facts.substr(0, delim);
- }
- facts = facts.substr(delim + 1, std::string::npos);
- if (!strcmp(fact.c_str(), "type") ||
- !strcmp(fact.c_str(), "size") ||
- !strcmp(fact.c_str(), "modify") ||
- !strcmp(fact.c_str(), "create") ||
- !strcmp(fact.c_str(), "perm") ||
- !strcmp(fact.c_str(), "unix.mode") ||
- !strcmp(fact.c_str(), "unix.owner") ||
- !strcmp(fact.c_str(), "unix.user") ||
- !strcmp(fact.c_str(), "unix.group") ||
- !strcmp(fact.c_str(), "unix.uid") ||
- !strcmp(fact.c_str(), "unix.gid"))
- {
- had_unset |= !enabled;
- opts_facts += fact.c_str();
- opts_facts += ";";
- }
- }
- if (had_unset)
- {
- m_serverCapabilities.SetCapability(opts_mlst_command, yes, opts_facts);
- }
- else
- {
- m_serverCapabilities.SetCapability(opts_mlst_command, no);
- }
- }
- }
- GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_CAPABILITIES, 0), (LPARAM)&m_serverCapabilities);
- if (!m_bAnnouncesUTF8 && !m_CurrentServer.nUTF8)
- m_bUTF8 = false;
- if (m_hasClntCmd)
- {
- // Some servers refuse to enable UTF8 if client does not send CLNT command
- // to fix compatibility with Internet Explorer, but in the process breaking
- // compatibility with other clients.
- // Rather than forcing MS to fix Internet Explorer, letting other clients
- // suffer is a questionable decision in my opinion.
- if (Send(CString(L"CLNT ") + m_pTools->GetClientString().c_str()))
- m_Operation.nOpState = CONNECT_CLNT;
- return;
- }
- if (m_bUTF8 && !m_isFileZilla)
- {
- // Handle servers that disobey RFC 2640 that have UTF8 in the FEAT
- // response but do not use UTF8 unless OPTS UTF8 ON gets send.
- // However these servers obey a conflicting ietf draft:
- // https://tools.ietf.org/html/draft-ietf-ftpext-utf-8-option-00
- // servers are, amongst others, G6 FTP Server and RaidenFTPd.
- if (Send(L"OPTS UTF8 ON"))
- m_Operation.nOpState = CONNECT_OPTSUTF8;
- return;
- }
- if ((m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYERMASK) & (FZ_SERVERTYPE_LAYER_SSL_IMPLICIT | FZ_SERVERTYPE_LAYER_SSL_EXPLICIT | FZ_SERVERTYPE_LAYER_TLS_EXPLICIT))
- {
- m_Operation.nOpState = CONNECT_SSL_PBSZ;
- Send(L"PBSZ 0");
- return;
- }
- if (m_serverCapabilities.GetCapability(mlsd_command) == yes)
- {
- std::string args;
- // this is never true, see comment is DiscardLine
- if (m_serverCapabilities.GetCapabilityString(opts_mlst_command, &args) == yes &&
- !args.empty())
- {
- m_Operation.nOpState = CONNECT_OPTSMLST;
- Send("OPTS MLST " + CString(args.c_str()));
- return;
- }
- }
- ShowStatus(IDS_STATUSMSG_CONNECTED, FZ_LOG_STATUS);
- m_pOwner->SetConnected(TRUE);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- else if (m_Operation.nOpState == CONNECT_CLNT)
- {
- // See above why we send this command
- if (Send(L"OPTS UTF8 ON"))
- m_Operation.nOpState = CONNECT_OPTSUTF8;
- return;
- }
- else if (m_Operation.nOpState == CONNECT_OPTSUTF8)
- {
- if ((m_CurrentServer.nServerType & FZ_SERVERTYPE_LAYERMASK) & (FZ_SERVERTYPE_LAYER_SSL_IMPLICIT | FZ_SERVERTYPE_LAYER_SSL_EXPLICIT | FZ_SERVERTYPE_LAYER_TLS_EXPLICIT))
- {
- m_Operation.nOpState = CONNECT_SSL_PBSZ;
- Send(L"PBSZ 0");
- return;
- }
- ShowStatus(IDS_STATUSMSG_CONNECTED, FZ_LOG_STATUS);
- m_pOwner->SetConnected(TRUE);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- else if (m_Operation.nOpState == CONNECT_SYST)
- {
- if (GetReplyCode() == 2)
- {
- const CStringA reply = m_RecvBuffer.front();
- if (reply.GetLength() > 7 && reply.Mid(3, 4) == " MVS")
- m_mayBeMvsFilesystem = true;
- else if (reply.GetLength() >= 11 && reply.Mid(3, 8) == " BS-2000")
- m_mayBeBS2000Filesystem = true;
- if (reply.Left(4) == "VMS ")
- {
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_VMS;
- }
- if (reply.Find("FileZilla") != -1)
- m_isFileZilla = true;
- }
- if (Send(L"FEAT"))
- m_Operation.nOpState = CONNECT_FEAT;
- return;
- }
- else if (!bSkipReply)
- {
- int res = GetReplyCode();
- if (res != 2 && res != 3 && m_Operation.nOpState >= 0) // get initial connect msg off server
- {
- int nError = 0;
- if (m_bUTF8 && m_CurrentServer.nUTF8 != 1)
- {
- // Fall back to local charset for the case that the server might not
- // support UTF8 and the login data contains non-ascii characters.
- bool asciiOnly = true;
- for (int i = 0; i < m_CurrentServer.user.GetLength(); i++)
- if (m_CurrentServer.user.GetAt(i) > 127)
- asciiOnly = false;
- CString pass = NormalizePass(m_CurrentServer.pass);
- for (int i = 0; i < pass.GetLength(); i++)
- if (pass.GetAt(i) > 127)
- asciiOnly = false;
- for (int i = 0; i < m_CurrentServer.account.GetLength(); i++)
- if (m_CurrentServer.account.GetAt(i) > 127)
- asciiOnly = false;
- if (!asciiOnly)
- {
- ShowStatus(L"Login data contains non-ascii characters and server might not be UTF-8 aware. Trying local charset.", FZ_LOG_STATUS);
- m_bUTF8 = false;
- m_Operation.nOpState = CONNECT_INIT;
- }
- else
- nError = FZ_REPLY_ERROR;
- }
- else
- nError = FZ_REPLY_ERROR;
- if (nError)
- {
- if (res==5 && logonseq[logontype][m_Operation.nOpState]==1)
- nError|=FZ_REPLY_CRITICALERROR;
- DoClose(nError);
- return;
- }
- }
- }
- CString hostname = m_CurrentServer.host;
- if (m_CurrentServer.port != 21)
- hostname.Format(hostname+ L":%d", m_CurrentServer.port); // add port to hostname (only if port is not 21)
- USES_CONVERSION;
- #ifndef MPEXT_NO_GSS
- //**** GSS Authentication ****
- if (m_Operation.nOpState==CONNECT_GSS_INIT) //authenticate
- {
- int i = m_pGssLayer->GetClientAuth(T2CA(m_CurrentServer.host));
- if (i==-1)
- m_Operation.nOpState = CONNECT_GSS_AUTHDONE;
- else if (i != GSSAPI_AUTHENTICATION_SUCCEEDED)
- {
- m_Operation.nOpState = CONNECT_GSS_FAILED;
- CAsyncRequestData *pData=new CAsyncRequestData;
- pData->nRequestType=FZ_ASYNCREQUEST_GSS_AUTHFAILED;
- pData->nRequestID=m_pOwner->GetNextAsyncRequestID();
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_GSS_AUTHFAILED), (LPARAM)pData))
- {
- delete pData;
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- }
- else
- {
- // we got authentication, we need to check whether we have forwardable tickets
- if (Send(L"CWD ."))
- m_Operation.nOpState = CONNECT_GSS_CWD;
- }
- return;
- }
- else if (m_Operation.nOpState == CONNECT_GSS_AUTHDONE)
- {
- if (!m_pGssLayer->AuthSuccessful())
- {
- m_Operation.nOpState = CONNECT_GSS_FAILED;
- CAsyncRequestData *pData=new CAsyncRequestData;
- pData->nRequestType = FZ_ASYNCREQUEST_GSS_AUTHFAILED;
- pData->nRequestID = m_pOwner->GetNextAsyncRequestID();
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_GSS_AUTHFAILED), (LPARAM)pData))
- {
- delete pData;
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- return;
- }
- else
- {
- // we got authentication, we need to check whether we have forwardable tickets
- if (Send(L"CWD ."))
- m_Operation.nOpState = CONNECT_GSS_CWD;
- return;
- }
- }
- else if (m_Operation.nOpState == CONNECT_GSS_CWD)
- { // authentication succeeded, we're now get the response to the CWD command
- if (GetReplyCode() == 2) // we're logged on
- {
- if (Send(L"SYST"))
- m_Operation.nOpState = CONNECT_SYST;
- return;
- }
- else
- {
- //GSS authentication complete but we still have to go through the standard logon procedure
- m_Operation.nOpState = CONNECT_INIT;
- }
- }
- #endif
- if (m_Operation.nOpState==CONNECT_INIT)
- {
- if (logontype)
- {
- CString str;
- str.Format(IDS_STATUSMSG_FWCONNECT,hostname);
- ShowStatus(str,FZ_LOG_STATUS);
- }
- m_Operation.nOpState++;
- }
- else if (m_Operation.nOpState >= 0 && !bSkipReply)
- {
- m_Operation.nOpState=logonseq[logontype][m_Operation.nOpState+GetReplyCode()-1]; //get next command from array
- switch(m_Operation.nOpState)
- {
- case ER: // ER means summat has gone wrong
- DoClose();
- return;
- case LO: //LO means we are logged on
- if (Send(L"SYST"))
- m_Operation.nOpState = CONNECT_SYST;
- return;
- }
- }
- // go through appropriate logon procedure
- #ifndef MPEXT_NO_GSS
- int i = logonseq[logontype][m_Operation.nOpState];
- if (m_pGssLayer)
- {
- if ((i == 0 || i == 6 || i == 9 || i == 10) &&
- (m_CurrentServer.user == L"anonymous" || m_CurrentServer.user == L""))
- {
- //Extract user from kerberos ticket
- char str[256];
- if (m_pGssLayer->GetUserFromKrbTicket(str))
- m_CurrentServer.user = str;
- if (m_CurrentServer.user == L"")
- {
- CGssNeedUserRequestData *pData = new CGssNeedUserRequestData;
- pData->nRequestID = m_pOwner->GetNextAsyncRequestID();
- pData->nOldOpState = m_Operation.nOpState;
- m_Operation.nOpState = CONNECT_GSS_NEEDUSER;
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_GSS_NEEDUSER), (LPARAM)pData))
- {
- delete pData;
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- return;
- }
- }
- else if ((i == 1 || i == 11) && (m_CurrentServer.pass == GetOption(OPTION_ANONPWD) || m_CurrentServer.pass == ""))
- {
- CGssNeedPassRequestData *pData=new CGssNeedPassRequestData;
- pData->nRequestID=m_pOwner->GetNextAsyncRequestID();
- pData->nOldOpState = m_Operation.nOpState;
- m_Operation.nOpState = CONNECT_GSS_NEEDPASS;
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_GSS_NEEDPASS), (LPARAM)pData))
- {
- delete pData;
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- return;
- }
- }
- #endif
- CLogonData *pData = static_cast<CLogonData *>(m_Operation.pData);
- bool needpass = (m_CurrentServer.pass == GetOption(OPTION_ANONPWD)) || (m_CurrentServer.pass == L"");
- switch(logonseq[logontype][m_Operation.nOpState])
- {
- case 0:
- temp=L"USER "+m_CurrentServer.user;
- break;
- case 1:
- if (needpass && !pData->waitForAsyncRequest && !pData->gotPassword)
- {
- CNeedPassRequestData *pNeedPassRequestData = new CNeedPassRequestData();
- pNeedPassRequestData->nRequestID = m_pOwner->GetNextAsyncRequestID();
- pNeedPassRequestData->nOldOpState = m_Operation.nOpState;
- m_Operation.nOpState = CONNECT_NEEDPASS;
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_NEEDPASS), (LPARAM)pNeedPassRequestData))
- {
- delete pNeedPassRequestData;
- ResetOperation(FZ_REPLY_ERROR);
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- pData->waitForAsyncRequest = true;
- return;
- }
- else if (!needpass || pData->gotPassword)
- {
- temp=L"PASS "+NormalizePass(m_CurrentServer.pass);
- }
- else
- {
- return;
- }
- break;
- case 2:
- temp=L"ACCT "+GetOption(OPTION_FWPASS);
- break;
- case 3:
- temp=L"USER "+GetOption(OPTION_FWUSER);
- break;
- case 4:
- temp=L"PASS "+GetOption(OPTION_FWPASS);
- break;
- case 5:
- temp=L"SITE "+hostname;
- break;
- case 6:
- temp=L"USER "+m_CurrentServer.user+L"@"+hostname;
- break;
- case 7:
- temp=L"OPEN "+hostname;
- break;
- case 8:
- temp=L"USER "+GetOption(OPTION_FWUSER)+L"@"+hostname;
- break;
- case 9:
- temp=L"USER "+m_CurrentServer.user+L"@"+hostname+L" "+GetOption(OPTION_FWUSER);
- break;
- case 10:
- temp=L"USER "+m_CurrentServer.user+L"@"+GetOption(OPTION_FWUSER)+L"@"+hostname;
- break;
- case 11:
- if (needpass && !pData->waitForAsyncRequest && !pData->gotPassword)
- {
- CNeedPassRequestData *pNeedPassRequestData = new CNeedPassRequestData();
- pNeedPassRequestData->nRequestID = m_pOwner->GetNextAsyncRequestID();
- pNeedPassRequestData->nOldOpState = m_Operation.nOpState;
- m_Operation.nOpState = CONNECT_NEEDPASS;
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_NEEDPASS), (LPARAM)pNeedPassRequestData))
- {
- delete pNeedPassRequestData;
- ResetOperation(FZ_REPLY_ERROR);
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- pData->waitForAsyncRequest = true;
- return;
- }
- else if (!needpass || pData->gotPassword)
- {
- temp=L"PASS "+NormalizePass(m_CurrentServer.pass)+L"@"+GetOption(OPTION_FWPASS);
- }
- else
- {
- return;
- }
- break;
- case 12:
- if (m_CurrentServer.account == L"")
- temp = L"ACCT default";
- else
- temp = L"ACCT " + m_CurrentServer.account;
- break;
- }
- // send command, get response
- if(!Send(temp))
- return;
- }
- BOOL CFtpControlSocket::SendAuthSsl()
- {
- if (!Send("AUTH SSL"))
- return false;
- m_Operation.nOpState = CONNECT_SSL_NEGOTIATE;
- return true;
- }
- #define BUFFERSIZE 4096
- void CFtpControlSocket::OnReceive(int nErrorCode)
- {
- m_LastRecvTime = CTime::GetCurrentTime();
- if (!m_pOwner->IsConnected())
- {
- if (!m_Operation.nOpMode)
- {
- LogMessage(FZ_LOG_INFO, L"Socket has been closed, don't process receive" );
- return;
- }
- m_MultiLine = "";
- CString str;
- str.Format(IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
- ShowStatus(str, FZ_LOG_PROGRESS);
- m_pOwner->SetConnected(TRUE);
- }
- char *buffer = new char[BUFFERSIZE];
- int numread = Receive(buffer, BUFFERSIZE);
- if (numread == SOCKET_ERROR)
- {
- delete [] buffer;
- buffer = NULL;
- int Error = GetLastError();
- if (Error != WSAEWOULDBLOCK)
- {
- LogError(Error);
- ShowStatus(IDS_STATUSMSG_DISCONNECTED, FZ_LOG_ERROR);
- DoClose();
- }
- else
- {
- LogSocketMessageRaw(FZ_LOG_INFO, L"No data to read");
- }
- return;
- }
- if (!numread)
- {
- delete [] buffer;
- buffer = NULL;
- ShowStatus(IDS_STATUSMSG_DISCONNECTED, FZ_LOG_ERROR);
- DoClose();
- }
- if (LoggingMessageType(FZ_LOG_INFO))
- {
- CString str;
- str.Format(L"Read %d bytes", numread);
- LogSocketMessageRaw(FZ_LOG_INFO, str);
- }
- for (int i=0; i < numread; i++)
- {
- if ((buffer[i] == '\r') || (buffer[i] == '\n') || (buffer[i] == 0))
- {
- if (!m_RecvBuffer.empty() && m_RecvBuffer.back() != "")
- {
- USES_CONVERSION;
- if (m_bUTF8)
- {
- // convert from UTF-8 to ANSI
- LPCSTR utf8 = (LPCSTR)m_RecvBuffer.back();
- if (DetectUTF8Encoding(RawByteString(utf8)) == etANSI)
- {
- if (m_CurrentServer.nUTF8 != 1)
- {
- LogMessage(FZ_LOG_WARNING, L"Server does not send proper UTF-8, falling back to local charset");
- m_bUTF8 = false;
- }
- ShowStatus(A2CT(utf8), FZ_LOG_REPLY);
- }
- else
- {
- int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
- if (!len)
- m_RecvBuffer.back() = "";
- else
- {
- LPWSTR p1 = new WCHAR[len + 1];
- MultiByteToWideChar(CP_UTF8, 0, utf8, -1 , (LPWSTR)p1, len + 1);
- ShowStatus(W2CT(p1), FZ_LOG_REPLY);
- delete [] p1;
- }
- }
- }
- else
- {
- ShowStatus(A2CT(m_RecvBuffer.back()), FZ_LOG_REPLY);
- }
- // Check for multi-line responses
- // Partially duplicated in TFTPFileSystem::HandleReplyStatus
- if (m_RecvBuffer.back().GetLength() > 3)
- {
- if (m_MultiLine != "")
- {
- if (m_RecvBuffer.back().Left(4) != m_MultiLine)
- {
- CStringA line = m_RecvBuffer.back();
- if (line.Left(4) == m_MultiLine.Left(3) + '-')
- {
- line = line.Mid(4, line.GetLength() - 4);
- }
- DiscardLine(line);
- m_RecvBuffer.pop_back();
- }
- else // end of multi-line found
- {
- m_MultiLine = "";
- LPARAM lParam = 0;
- #ifdef _DEBUG
- lParam = GetTickCount();
- #endif
- m_pOwner->PostThreadMessage(m_pOwner->m_nInternalMessageID, FZAPI_THREADMSG_PROCESSREPLY, lParam);
- }
- }
- // start of new multi-line
- else if (m_RecvBuffer.back()[3] == '-')
- {
- // DDD<SP> is the end of a multi-line response
- m_MultiLine = m_RecvBuffer.back().Left(3) + ' ';
- m_RecvBuffer.pop_back();
- }
- else
- {
- LPARAM lParam = 0;
- #ifdef _DEBUG
- lParam = GetTickCount();
- #endif
- m_pOwner->PostThreadMessage(m_pOwner->m_nInternalMessageID, FZAPI_THREADMSG_PROCESSREPLY, lParam);
- }
- }
- else
- {
- m_RecvBuffer.pop_back();
- }
- m_RecvBuffer.push_back("");
- }
- }
- else
- {
- //The command may only be 2000 chars long. This ensures that a malicious user can't
- //send extremely large commands to fill the memory of the server
- if (m_RecvBuffer.empty())
- m_RecvBuffer.push_back("");
- if (m_RecvBuffer.back().GetLength() < 2000)
- m_RecvBuffer.back() += buffer[i];
- }
- }
- delete [] buffer;
- }
- void CFtpControlSocket::ProcessReply()
- {
- if (m_RecvBuffer.empty())
- return;
- if (m_awaitsReply)
- {
- if (m_sendBuffer)
- TriggerEvent(FD_WRITE);
- m_awaitsReply = false;
- }
- CString reply = GetReply();
- if ( reply == L"" )
- return;
- // After Cancel, we might have to skip a reply
- if (m_skipReply)
- {
- m_skipReply = false;
- m_RecvBuffer.pop_front();
- return;
- }
- if (m_bKeepAliveActive)
- {
- m_bKeepAliveActive = FALSE;
- m_pOwner->PostThreadMessage(m_pOwner->m_nInternalMessageID,FZAPI_THREADMSG_POSTKEEPALIVE,0);
- }
- else if (m_Operation.nOpMode&CSMODE_CONNECT)
- LogOnToServer();
- else if (m_Operation.nOpMode& (CSMODE_COMMAND|CSMODE_CHMOD) )
- {
- if (GetReplyCode()== 2 || GetReplyCode()== 3)
- ResetOperation(FZ_REPLY_OK);
- else
- ResetOperation(FZ_REPLY_ERROR);
- }
- else if (m_Operation.nOpMode&CSMODE_TRANSFER)
- {
- FileTransfer(0);
- }
- else if (m_Operation.nOpMode&CSMODE_LIST)
- List(FALSE);
- else if (m_Operation.nOpMode&CSMODE_LISTFILE)
- ListFile(L"", CServerPath());
- else if (m_Operation.nOpMode&CSMODE_DELETE)
- Delete( L"",CServerPath(), false);
- else if (m_Operation.nOpMode&CSMODE_RMDIR)
- RemoveDir( L"",CServerPath());
- else if (m_Operation.nOpMode&CSMODE_MKDIR)
- MakeDir(CServerPath());
- else if (m_Operation.nOpMode&CSMODE_RENAME)
- Rename(L"", L"", CServerPath(), CServerPath());
- if (!m_RecvBuffer.empty())
- m_RecvBuffer.pop_front();
- }
- void CFtpControlSocket::OnConnect(int nErrorCode)
- {
- if (!m_Operation.nOpMode)
- {
- if (!m_pOwner->IsConnected())
- DoClose();
- return;
- }
- if (!nErrorCode)
- {
- if (!m_pOwner->IsConnected())
- {
- m_MultiLine = "";
- m_pOwner->SetConnected(TRUE);
- CString str;
- str.Format(
- m_pSslLayer ? IDS_STATUSMSG_CONNECTEDWITHSSL : IDS_STATUSMSG_CONNECTEDWITH,
- m_ServerName);
- ShowStatus(str,FZ_LOG_PROGRESS);
- }
- }
- else
- {
- if (nErrorCode == WSAHOST_NOT_FOUND)
- {
- CString str;
- str.Format(IDS_ERRORMSG_CANTRESOLVEHOST2, m_ServerName);
- ShowStatus(str, FZ_LOG_ERROR);
- }
- else
- {
- TCHAR Buffer[255];
- int Len = FormatMessage(
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
- NULL, nErrorCode, 0, Buffer, LENOF(Buffer), NULL);
- while ((Len > 0) && ((Buffer[Len - 1] >= 0) && (Buffer[Len - 1] <= 32)))
- {
- --Len;
- }
- ShowStatus(CString(Buffer, Len), FZ_LOG_ERROR);
- }
- DoClose();
- }
- }
- BOOL CFtpControlSocket::Send(CString str)
- {
- USES_CONVERSION;
- ShowStatus(str, FZ_LOG_COMMAND);
- str += L"\r\n";
- int res = 0;
- if (m_bUTF8)
- {
- LPCWSTR unicode = T2CW(str);
- int len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, 0, 0, 0, 0);
- if (!len)
- {
- ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, FZ_LOG_ERROR);
- DoClose();
- return FALSE;
- }
- char* utf8 = new char[len + 1];
- WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len + 1, 0, 0);
- int sendLen = strlen(utf8);
- if (!m_awaitsReply && !m_sendBuffer)
- res = CAsyncSocketEx::Send(utf8, strlen(utf8));
- else
- res = -2;
- if ((res == SOCKET_ERROR && GetLastError() != WSAEWOULDBLOCK) || !res)
- {
- delete [] utf8;
- ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, FZ_LOG_ERROR);
- DoClose();
- return FALSE;
- }
- if (res != sendLen)
- {
- if (res < 0)
- res = 0;
- if (!m_sendBuffer)
- {
- m_sendBuffer = new char[sendLen - res];
- memcpy(m_sendBuffer, utf8 + res, sendLen - res);
- m_sendBufferLen = sendLen - res;
- }
- else
- {
- char* tmp = new char[m_sendBufferLen + sendLen - res];
- memcpy(tmp, m_sendBuffer, m_sendBufferLen);
- memcpy(tmp + m_sendBufferLen, utf8 + res, sendLen - res);
- delete [] m_sendBuffer;
- m_sendBuffer = tmp;
- m_sendBufferLen += sendLen - res;
- }
- }
- delete [] utf8;
- }
- else
- {
- LPCSTR lpszAsciiSend = T2CA(str);
- int sendLen = strlen(lpszAsciiSend);
- if (!m_awaitsReply && !m_sendBuffer)
- res = CAsyncSocketEx::Send(lpszAsciiSend, strlen(lpszAsciiSend));
- else
- res = -2;
- if ((res == SOCKET_ERROR && GetLastError() != WSAEWOULDBLOCK) || !res)
- {
- ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, FZ_LOG_ERROR);
- DoClose();
- return FALSE;
- }
- if (res != sendLen)
- {
- if (res < 0)
- res = 0;
- if (!m_sendBuffer)
- {
- m_sendBuffer = new char[sendLen - res];
- memcpy(m_sendBuffer, lpszAsciiSend, sendLen - res);
- m_sendBufferLen = sendLen - res;
- }
- else
- {
- char* tmp = new char[m_sendBufferLen + sendLen - res];
- memcpy(tmp, m_sendBuffer, m_sendBufferLen);
- memcpy(tmp + m_sendBufferLen, lpszAsciiSend + res, sendLen - res);
- delete [] m_sendBuffer;
- m_sendBuffer = tmp;
- m_sendBufferLen += sendLen - res;
- }
- }
- }
- if (res > 0)
- {
- m_awaitsReply = true;
- m_LastSendTime = CTime::GetCurrentTime();
- // Count timeout since the last request, not only since the last received data
- // otherwise we may happen to timeout immediately after sending request if
- // CheckForTimeout occurs in between and we haven't received any data for a while
- m_LastRecvTime = m_LastSendTime;
- }
- return TRUE;
- }
- int CFtpControlSocket::GetReplyCode()
- {
- if (m_RecvBuffer.empty())
- return 0;
- CStringA str = m_RecvBuffer.front();
- if (str == "")
- return 0;
- else
- return str[0]-'0';
- }
- void CFtpControlSocket::DoClose(int nError /*=0*/)
- {
- LogMessage(FZ_LOG_INFO, L"Connection closed");
- m_bCheckForTimeout=TRUE;
- m_pOwner->SetConnected(FALSE);
- m_bKeepAliveActive=FALSE;
- if (nError & FZ_REPLY_CRITICALERROR)
- nError |= FZ_REPLY_ERROR;
- ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_DISCONNECTED|nError);
- m_RecvBuffer.clear();
- m_MultiLine = "";
- m_bDidRejectCertificate = FALSE;
- #ifndef MPEXT_NO_ZLIB
- m_useZlib = false;
- m_zlibSupported = false;
- m_zlibLevel = 0;
- #endif
- m_bUTF8 = false;
- m_hasClntCmd = false;
- m_serverCapabilities.Clear();
- m_ListFile = "";
- m_awaitsReply = false;
- m_skipReply = false;
- delete [] m_sendBuffer;
- m_sendBuffer = 0;
- m_sendBufferLen = 0;
- m_bProtP = false;
- m_mayBeMvsFilesystem = false;
- m_mayBeBS2000Filesystem = false;
- Close();
- }
- void CFtpControlSocket::Disconnect()
- {
- DebugAssert(!m_Operation.nOpMode);
- m_Operation.nOpMode=CSMODE_DISCONNECT;
- DoClose();
- ShowStatus(IDS_STATUSMSG_DISCONNECTED,FZ_LOG_STATUS); //Send the disconnected message to the message log
- }
- void CFtpControlSocket::CheckForTimeout()
- {
- if (!m_Operation.nOpMode && !m_bKeepAliveActive)
- return;
- if (!m_bCheckForTimeout)
- return;
- int delay=GetOptionVal(OPTION_TIMEOUTLENGTH);
- if (m_pTransferSocket)
- {
- int res = m_pTransferSocket->CheckForTimeout(delay);
- if (res != 0)
- {
- if (res == 1)
- {
- // avoid trying to set keepalive command right after the transfer finishes
- m_LastSendTime = CTime::GetCurrentTime();
- }
- return;
- }
- }
- CTimeSpan span=CTime::GetCurrentTime()-m_LastRecvTime;
- if (span.GetTotalSeconds()>=delay)
- {
- ShowTimeoutError(IDS_CONTROL_CONNECTION);
- DoClose();
- }
- }
- void CFtpControlSocket::FtpCommand(LPCTSTR pCommand)
- {
- m_Operation.nOpMode=CSMODE_COMMAND;
- Send(pCommand);
- }
- bool CFtpControlSocket::UsingMlsd()
- {
- return
- // 0 = on, 1 = off, 2 = auto
- (m_CurrentServer.iUseMlsd == 0) ||
- ((m_CurrentServer.iUseMlsd != 1) &&
- (m_serverCapabilities.GetCapability(mlsd_command) == yes));
- }
- bool CFtpControlSocket::UsingUtf8()
- {
- return m_bUTF8;
- }
- std::string CFtpControlSocket::GetTlsVersionStr()
- {
- if (m_pSslLayer != NULL)
- {
- return m_pSslLayer->GetTlsVersionStr();
- }
- else
- {
- return std::string();
- }
- }
- std::string CFtpControlSocket::GetCipherName()
- {
- if (m_pSslLayer != NULL)
- {
- return m_pSslLayer->GetCipherName();
- }
- else
- {
- return std::string();
- }
- }
- CString CFtpControlSocket::GetListingCmd()
- {
- CString cmd;
- if (UsingMlsd())
- {
- cmd = L"MLSD";
- }
- else
- {
- cmd = L"LIST";
- if (GetOptionVal(OPTION_MPEXT_SHOWHIDDEN) && !(m_CurrentServer.nServerType & (FZ_SERVERTYPE_SUB_FTP_MVS | FZ_SERVERTYPE_SUB_FTP_VMS | FZ_SERVERTYPE_SUB_FTP_BS2000)))
- cmd += L" -a";
- }
- return cmd;
- }
- void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath path /*=CServerPath()*/, CString subdir /*=L""*/)
- {
- USES_CONVERSION;
- #define LIST_INIT -1
- #define LIST_PWD 0
- #define LIST_CWD 1
- #define LIST_PWD2 2
- #define LIST_CWD2 3
- #define LIST_PWD3 4
- #define LIST_MODE 5
- #define LIST_OPTS 6
- #define LIST_PORT_PASV 7
- #define LIST_TYPE 8
- #define LIST_LIST 9
- #define LIST_WAITFINISH 10
- DebugAssert(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_LIST);
- m_Operation.nOpMode|=CSMODE_LIST;
- if (!m_pOwner->IsConnected())
- {
- ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_NOTCONNECTED);
- return;
- }
- if (bFinish || nError)
- if (m_Operation.nOpMode!=CSMODE_LIST)
- return; //Old message coming in
- if (nError)
- {
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- if (nError&CSMODE_TRANSFERTIMEOUT)
- DoClose();
- else
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- CListData *pData = static_cast<CListData *>(m_Operation.pData);
- if (bFinish)
- {
- if (!m_pTransferSocket || m_pTransferSocket->m_bListening)
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing = 0;
- delete m_pTransferSocket;
- m_pTransferSocket = 0;
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- int num = 0;
- pData->pDirectoryListing = new t_directory;
- pData->pDirectoryListing->direntry = m_pTransferSocket->m_pListResult->getList(num);
- pData->pDirectoryListing->num = num;
- if (m_pTransferSocket->m_pListResult->m_server.nServerType & FZ_SERVERTYPE_SUB_FTP_VMS && m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP)
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_VMS;
- pData->pDirectoryListing->server = m_CurrentServer;
- pData->pDirectoryListing->path.SetServer(pData->pDirectoryListing->server);
- if (pData->rawpwd != L"")
- {
- if (!pData->pDirectoryListing->path.SetPath(pData->rawpwd))
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- m_pOwner->SetCurrentPath(pData->pDirectoryListing->path);
- }
- else
- pData->pDirectoryListing->path = m_pOwner->GetCurrentPath();
- if (m_Operation.nOpState!=LIST_WAITFINISH)
- {
- return;
- }
- else
- {
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- }
- }
- if (m_Operation.nOpState==LIST_WAITFINISH)
- {
- if (!bFinish)
- {
- if (pData->nFinish==-1)
- {
- int code=GetReplyCode();
- if (code== 2)
- {
- pData->nFinish=1;
- }
- else
- pData->nFinish=0;
- }
- }
- else
- {
- if (m_pTransferSocket)
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- }
- if (pData->nFinish==0)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- else if (pData->pDirectoryListing && pData->nFinish==1)
- {
- ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,FZ_LOG_PROGRESS);
- SetDirectoryListing(pData->pDirectoryListing);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- return;
- }
- else if (m_Operation.nOpState != LIST_INIT)
- {
- CString retmsg = GetReply();
- BOOL error = FALSE;
- int code = GetReplyCode();
- switch (m_Operation.nOpState)
- {
- case LIST_PWD: //Reply to PWD command
- if (code != 2 && code !=3 )
- {
- error = TRUE;
- break;
- }
- pData->rawpwd = retmsg;
- if ((m_mayBeMvsFilesystem || m_mayBeBS2000Filesystem) && m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP &&
- pData->rawpwd[0] != L'/')
- {
- m_mayBeMvsFilesystem = false;
- m_mayBeBS2000Filesystem = false;
- if (m_mayBeBS2000Filesystem)
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_BS2000;
- else
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_MVS;
- if (!pData->path.IsEmpty())
- pData->path.SetServer(m_CurrentServer);
- }
- if (!ParsePwdReply(pData->rawpwd))
- return;
- if (pData->path.IsEmpty() || pData->path == m_pOwner->GetCurrentPath())
- {
- m_Operation.nOpState = NeedModeCommand() ? LIST_MODE : (NeedOptsCommand() ? LIST_OPTS : LIST_TYPE);
- }
- else
- m_Operation.nOpState = LIST_CWD;
- break;
- case LIST_CWD:
- if (code != 2 && code != 3)
- error = TRUE;
- m_Operation.nOpState = LIST_PWD2;
- break;
- case LIST_PWD2: //Reply to PWD command
- if (code !=2 && code != 3)
- error = TRUE;
- else
- {
- pData->rawpwd = retmsg;
- if (!ParsePwdReply(pData->rawpwd))
- return;
- }
- if (pData->subdir != L"")
- {
- if (pData->path != m_pOwner->GetCurrentPath())
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- m_Operation.nOpState = LIST_CWD2;
- }
- else
- {
- m_Operation.nOpState = NeedModeCommand() ? LIST_MODE : (NeedOptsCommand() ? LIST_OPTS : LIST_TYPE);
- }
- break;
- case LIST_CWD2:
- if (pData->lastCmdSentCDUP)
- {
- CString reply = GetReply().Left(3);
- int replycode = _ttoi(reply);
- if (replycode >= 500 && replycode < 505)
- break;
- pData->lastCmdSentCDUP = false;
- }
- if (code != 2 && code != 3)
- error = TRUE;
- m_Operation.nOpState = LIST_PWD3;
- break;
- case LIST_PWD3: //Reply to PWD command
- if (code != 2 && code != 3)
- error = TRUE;
- else
- {
- pData->rawpwd = retmsg;
- if (!ParsePwdReply(pData->rawpwd))
- return;
- }
- m_Operation.nOpState = NeedModeCommand() ? LIST_MODE : (NeedOptsCommand() ? LIST_OPTS : LIST_TYPE);
- break;
- case LIST_MODE:
- #ifndef MPEXT_NO_ZLIB
- if (code == 2 || code == 3)
- m_useZlib = !m_useZlib;
- #endif
- m_Operation.nOpState = NeedOptsCommand() ? LIST_OPTS : LIST_TYPE;
- break;
- case LIST_OPTS:
- #ifndef MPEXT_NO_ZLIB
- if (code == 2 || code == 3)
- m_zlibLevel = pData->newZlibLevel;
- #endif
- m_Operation.nOpState = LIST_TYPE;
- break;
- case LIST_TYPE:
- if (code!=2 && code!=3)
- error=TRUE;
- m_Operation.nOpState = LIST_PORT_PASV;
- break;
- case LIST_PORT_PASV:
- if (code!=2 && code!=3)
- {
- error=TRUE;
- break;
- }
- if (pData->bPasv)
- {
- CString temp;
- int i,j;
- // MP EXT
- if((i=retmsg.Find(L"("))>=0&&(j=retmsg.Find(L")"))>=0)
- {
- i++;
- j--;
- }
- else
- {
- // MP EXT
- if ((i=retmsg.Mid(4).FindOneOf(L"0123456789"))>=0)
- {
- i += 4;
- j = retmsg.GetLength() - 1;
- }
- else
- {
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- error=TRUE;
- break;
- }
- }
- temp = retmsg.Mid(i,(j-i)+1);
- if (GetFamily() == AF_INET)
- {
- i=temp.ReverseFind(L',');
- pData->port=atol( T2CA( temp.Right(temp.GetLength()-(i+1)) ) ); //get ls byte of server socket
- temp=temp.Left(i);
- i=temp.ReverseFind(L',');
- pData->port+=256*atol( T2CA( temp.Right(temp.GetLength()-(i+1)) ) ); // add ms byte to server socket
- pData->host = temp.Left(i);
- pData->host.Replace(L',', L'.');
- if (!CheckForcePasvIp(pData->host))
- {
- error = TRUE;
- break;
- }
- }
- else if (GetFamily() == AF_INET6)
- {
- temp = temp.Mid(3);
- pData->port = atol( T2CA(temp.Left(temp.GetLength() - 1) ) );
- if (pData->port < 0 || pData->port > 65535)
- {
- LogMessage(FZ_LOG_WARNING, L"Port %u not valid", pData->port);
- error = TRUE;
- break;
- }
- pData->host = m_CurrentServer.host;
- }
- else
- {
- LogMessage(FZ_LOG_WARNING, L"Protocol %d not supported", GetFamily());
- error = TRUE;
- break;
- }
- }
- m_Operation.nOpState = LIST_LIST;
- break;
- case LIST_LIST:
- if (IsMisleadingListResponse())
- {
- ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
- t_directory listing;
- listing.server = m_CurrentServer;
- listing.path = m_pOwner->GetCurrentPath();
- SetDirectoryListing(&listing);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- else if (code != 1)
- error = TRUE;
- else
- m_Operation.nOpState = LIST_WAITFINISH;
- break;
- default:
- error = TRUE;
- }
- if (error)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- if (m_Operation.nOpState==LIST_INIT)
- { //Initialize some variables
- pData=new CListData;
- pData->path=path;
- pData->subdir=subdir;
- m_Operation.pData=pData;
- ShowStatus(IDS_STATUSMSG_RETRIEVINGDIRLIST, FZ_LOG_PROGRESS);
- pData->nFinish=-1;
- if (m_pDirectoryListing)
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- }
- if (GetOptionVal(OPTION_PROXYTYPE)!=PROXYTYPE_NOPROXY)
- pData->bPasv = TRUE;
- else if (m_CurrentServer.nPasv == 1)
- pData->bPasv = TRUE;
- else if (m_CurrentServer.nPasv == 2)
- pData->bPasv = FALSE;
- else
- pData->bPasv = GetOptionVal(OPTION_PASV);
- CServerPath path = pData->path;
- CServerPath realpath = m_pOwner->GetCurrentPath();
- if (!realpath.IsEmpty())
- {
- if (!pData->path.IsEmpty() && pData->path != realpath)
- m_Operation.nOpState=LIST_CWD;
- else if (!pData->path.IsEmpty() && pData->subdir!=L"")
- m_Operation.nOpState=LIST_CWD2;
- else
- {
- m_Operation.nOpState = NeedModeCommand() ? LIST_MODE : (NeedOptsCommand() ? LIST_OPTS : LIST_TYPE);;
- }
- }
- else
- m_Operation.nOpState = LIST_PWD;
- }
- CString cmd;
- if (m_Operation.nOpState == LIST_PWD)
- cmd=L"PWD";
- else if (m_Operation.nOpState==LIST_CWD)
- cmd=L"CWD " + pData->path.GetPathUnterminated(); //Command to retrieve the current directory
- else if (m_Operation.nOpState==LIST_PWD2)
- cmd=L"PWD";
- else if (m_Operation.nOpState==LIST_CWD2)
- {
- if (!pData->subdir)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- if (pData->subdir != L".." )
- {
- if (m_CurrentServer.nServerType & FZ_SERVERTYPE_SUB_FTP_VMS)
- {
- CServerPath path = m_pOwner->GetCurrentPath();
- path.AddSubdir(pData->subdir);
- cmd = L"CWD " + path.GetPathUnterminated();
- }
- else
- cmd = L"CWD " + pData->subdir;
- }
- else
- {
- if (pData->lastCmdSentCDUP)
- {
- pData->lastCmdSentCDUP = false;
- cmd = L"CWD ..";
- }
- else
- {
- pData->lastCmdSentCDUP = true;
- cmd = L"CDUP";
- }
- }
- }
- else if (m_Operation.nOpState == LIST_PWD3)
- cmd=L"PWD";
- else if (m_Operation.nOpState == LIST_MODE)
- {
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- if (m_useZlib)
- #endif
- cmd = L"MODE S";
- #ifndef MPEXT_NO_ZLIB
- else
- cmd = L"MODE Z";
- #endif
- }
- else if (m_Operation.nOpState == LIST_OPTS)
- {
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- pData->newZlibLevel = GetOptionVal(OPTION_MODEZ_LEVEL);
- cmd.Format(L"OPTS MODE Z LEVEL %d", pData->newZlibLevel);
- #endif
- }
- else if (m_Operation.nOpState == LIST_PORT_PASV)
- {
- m_pTransferSocket = new CTransferSocket(this, m_Operation.nOpMode);
- #ifndef MPEXT_NO_ZLIB
- if (m_useZlib)
- {
- if (!m_pTransferSocket->InitZlib(m_zlibLevel))
- {
- ShowStatus(L"Failed to initialize zlib", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- #endif
- m_pTransferSocket->m_nInternalMessageID = m_pOwner->m_nInternalMessageID;
- #ifndef MPEXT_NO_GSS
- if (m_pGssLayer && m_pGssLayer->AuthSuccessful())
- m_pTransferSocket->UseGSS(m_pGssLayer);
- #endif
- m_pTransferSocket->SetFamily(GetFamily());
- if (!m_pTransferSocket->Create(m_pSslLayer && m_bProtP) ||
- !m_pTransferSocket->AsyncSelect())
- {
- ShowStatus(L"Failed to create socket", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- if (pData->bPasv)
- switch (GetFamily())
- {
- case AF_INET:
- cmd = L"PASV";
- break;
- case AF_INET6:
- cmd = L"EPSV";
- break;
- default:
- LogMessage(FZ_LOG_WARNING, L"Protocol %d not supported", GetFamily());
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- else
- {
- m_pTransferSocket->m_bListening=TRUE;
- if (m_pProxyLayer)
- {
- SOCKADDR_IN addr;
- int len=sizeof(addr);
- if (!m_pProxyLayer->GetPeerName((SOCKADDR *)&addr,&len))
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- else if (!m_pTransferSocket->Listen(addr.sin_addr.S_un.S_addr))
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- else
- {
- //Set up an active file transfer
- CString tempHostname;
- UINT nPort;
- if (// create listen socket (let MFC choose the port) & start the socket listening
- !m_pTransferSocket->Listen() ||
- !m_pTransferSocket->GetSockName(tempHostname, nPort))
- {
- ShowStatus(L"Failed to create listen socket", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- CString host;
- bool bError = false;
- if (GetFamily() == AF_INET)
- {
- host = GetOption(OPTION_TRANSFERIP);
- if (host != L"")
- {
- DWORD ip = inet_addr(T2CA(host));
- if (ip != INADDR_NONE)
- host.Format(L"%d,%d,%d,%d", ip%256, (ip>>8)%256, (ip>>16)%256, ip>>24);
- else
- {
- hostent *fullname = gethostbyname(T2CA(host));
- if (!fullname)
- host = L"";
- else
- {
- DWORD ip = ((LPIN_ADDR)fullname->h_addr)->s_addr;
- if (ip != INADDR_NONE)
- host.Format(L"%d,%d,%d,%d", ip%256, (ip>>8)%256, (ip>>16)%256, ip>>24);
- else
- host = L"";
- }
- }
- }
- if (host == L"")
- {
- UINT temp;
- if (!GetSockName(host, temp))
- {
- ShowStatus(L"Failed to get socket address ", FZ_LOG_ERROR);
- bError = true;
- }
- host.Replace(L'.', L',');
- }
- if (!bError)
- {
- host.Format(host+L",%d,%d", nPort/256, nPort%256);
- cmd = L"PORT " + host; // send PORT cmd to server
- }
- }
- else if (GetFamily() == AF_INET6)
- {
- host = GetOption(OPTION_TRANSFERIP6);
- if (host != L"")
- {
- USES_CONVERSION;
- addrinfo hints, *res;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_family = AF_INET6;
- hints.ai_socktype = SOCK_STREAM;
- if (!getaddrinfo(T2CA(host), "1024", &hints, &res))
- {
- host = Inet6AddrToString(((SOCKADDR_IN6 *)res->ai_addr)->sin6_addr);
- freeaddrinfo(res);
- }
- else
- host = L"";
- }
- if (host == L"")
- {
- UINT temp;
- if(!GetSockName(host, temp))
- bError = true;
- }
- if (!bError)
- {
- // assamble EPRT command
- cmd.Format(L"EPRT |2|" + host + L"|%d|", nPort);
- }
- }
- else
- {
- LogMessage(FZ_LOG_WARNING, L"Protocol %d not supported", GetFamily());
- bError = true;
- }
- if (bError)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- }
- }
- else if (m_Operation.nOpState==LIST_TYPE)
- cmd=L"TYPE A";
- else if (m_Operation.nOpState==LIST_LIST)
- {
- if (!m_pTransferSocket)
- {
- LogMessage(FZ_LOG_APIERROR, L"Error: m_pTransferSocket==NULL" );
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- m_pTransferSocket->SetActive();
- cmd = GetListingCmd();
- if (!Send(cmd))
- return;
- if (pData->bPasv)
- {
- // if PASV create the socket & initiate outbound data channel connection
- if (!ConnectTransferSocket(pData->host, pData->port))
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- return;
- }
- if (cmd != L"")
- Send(cmd);
- }
- bool CFtpControlSocket::ConnectTransferSocket(const CString & host, UINT port)
- {
- CString hostname;
- hostname.Format(L"%s:%d", host, port);
- CString str;
- str.Format(IDS_STATUSMSG_CONNECTING, hostname);
- ShowStatus(str, FZ_LOG_PROGRESS);
- bool result = true;
- if (!m_pTransferSocket->Connect(host, port))
- {
- if (GetLastError() != WSAEWOULDBLOCK)
- {
- result = false;
- }
- else
- {
- LogMessage(FZ_LOG_INFO, L"Connection pending");
- }
- }
- else
- {
- LogMessage(FZ_LOG_INFO, L"Connected");
- }
- return result;
- }
- void CFtpControlSocket::ListFile(CString filename, const CServerPath &path)
- {
- USES_CONVERSION;
- #define LISTFILE_INIT -1
- #define LISTFILE_MLST 1
- #define LISTFILE_TYPE 2
- #define LISTFILE_SIZE 3
- #define LISTFILE_MDTM 4
- #define LISTFILE_PWD 5
- #define LISTFILE_CWD 6
- #define LISTFILE_CWD2 7
- DebugAssert(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_LISTFILE);
- m_Operation.nOpMode|=CSMODE_LISTFILE;
- if (!m_pOwner->IsConnected())
- {
- ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_NOTCONNECTED);
- return;
- }
- CListFileData * pData = static_cast<CListFileData *>(m_Operation.pData);
- BOOL error = FALSE;
- CString cmd;
- CString retmsg;
- int code = -1;
- int num = -1;
- switch (m_Operation.nOpState)
- {
- case LISTFILE_INIT:
- //Initialize some variables
- pData = new CListFileData;
- pData->fileName = filename;
- pData->dir = path.GetPath();
- // special case for listing a root folder
- pData->path = (filename == L"/") ? pData->dir : path.FormatFilename(filename);
- m_Operation.pData = pData;
- ShowStatus(IDS_STATUSMSG_RETRIEVINGLISTFILE, FZ_LOG_PROGRESS);
- if (UsingMlsd())
- {
- m_Operation.nOpState = LISTFILE_MLST;
- cmd = L"MLST " + pData->path;
- }
- else
- {
- m_Operation.nOpState = LISTFILE_PWD;
- cmd = L"PWD";
- }
- if (!Send(cmd))
- {
- error = TRUE;
- }
- break;
- case LISTFILE_MLST:
- retmsg = GetReply();
- code = GetReplyCode();
- if (IsMisleadingListResponse())
- {
- ShowStatus(IDS_STATUSMSG_LISTFILESUCCESSFUL, FZ_LOG_PROGRESS);
- num = 0;
- }
- else if (code != 2)
- {
- error = TRUE;
- }
- else
- {
- USES_CONVERSION;
- CStringA Buf = m_ListFile + '\n';
- const bool mlst = true;
- CFtpListResult * pListResult = CreateListResult(mlst);
- pListResult->AddData(static_cast<const char *>(Buf), Buf.GetLength());
- pData->direntry = pListResult->getList(num);
- if (pListResult->m_server.nServerType & FZ_SERVERTYPE_SUB_FTP_VMS && m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP)
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_VMS;
- delete pListResult;
- }
- break;
- case LISTFILE_PWD:
- code = GetReplyCode();
- retmsg = GetReply();
- if ((code == 2) &&
- ParsePwdReply(retmsg, pData->pwd) &&
- Send(L"CWD " + pData->path))
- {
- m_Operation.nOpState = LISTFILE_CWD;
- }
- else
- {
- error = TRUE;
- }
- break;
- case LISTFILE_CWD:
- code = GetReplyCode();
- pData->direntry = new t_directory::t_direntry[1];
- pData->direntry->name = pData->fileName;
- if (code == 2)
- {
- pData->direntry->dir = TRUE;
- if (Send(L"CWD " + pData->pwd.GetPathUnterminated()))
- {
- m_Operation.nOpState = LISTFILE_CWD2;
- }
- else
- {
- error = TRUE;
- }
- }
- else
- {
- // CWD failed, file is not a directory, we should not need to restore PWD.
- // Force binary mode, as according to RFC 6359,
- // SIZE command returns size as transferred over the stream.
- // Moreover ProFTPD does not even support SIZE command in ASCII mode
- if (Send(L"TYPE I"))
- {
- m_Operation.nOpState = LISTFILE_TYPE;
- }
- else
- {
- error = TRUE;
- }
- }
- break;
- case LISTFILE_CWD2:
- code = GetReplyCode();
- if (code == 2)
- {
- // No point trying SIZE on directories.
- // (More over IIS returns a multi-line response for SIZE /dir and we cannot handle that).
- // IIS fails even for MDTM, so skipping even that.
- num = 1;
- }
- // this should never really happen
- else
- {
- error = TRUE;
- }
- break;
- case LISTFILE_TYPE:
- // Do not really care if TYPE succeeded or not
- if (Send(L"SIZE " + pData->path))
- {
- m_Operation.nOpState = LISTFILE_SIZE;
- }
- else
- {
- error = TRUE;
- }
- break;
- case LISTFILE_SIZE:
- code = GetReplyCode();
- // Ignore SIZE errors for directories
- if ((HandleSize(code, pData->direntry->size) || pData->direntry->dir) &&
- Send(L"MDTM " + pData->path))
- {
- m_Operation.nOpState = LISTFILE_MDTM;
- }
- else
- {
- error = TRUE;
- }
- break;
- case LISTFILE_MDTM:
- code = GetReplyCode();
- if (HandleMdtm(code, pData->direntry->date))
- {
- num = 1;
- }
- else
- {
- error = TRUE;
- }
- break;
- default:
- error = TRUE;
- break;
- }
- if (error)
- {
- ResetOperation(FZ_REPLY_ERROR);
- }
- else if (num >= 0)
- {
- t_directory * pDirectoryListing = new t_directory;
- pDirectoryListing->direntry = pData->direntry;
- pData->direntry = NULL;
- pDirectoryListing->num = num;
- pDirectoryListing->server = m_CurrentServer;
- pDirectoryListing->path.SetServer(pDirectoryListing->server);
- pDirectoryListing->path = pData->dir;
- ShowStatus(IDS_STATUSMSG_LISTFILESUCCESSFUL,FZ_LOG_PROGRESS);
- // do not use SetDirectoryListing as that would make
- // later operations believe that there's only this one file in the folder
- m_pOwner->SendDirectoryListing(pDirectoryListing);
- ResetOperation(FZ_REPLY_OK);
- }
- }
- void CFtpControlSocket::TransferEnd(int nMode)
- {
- if (!m_Operation.nOpMode)
- {
- LogMessage(FZ_LOG_INFO, L"Ignoring old TransferEnd message");
- return;
- }
- m_LastRecvTime=CTime::GetCurrentTime();
- if (m_Operation.nOpMode&CSMODE_TRANSFER)
- FileTransfer(0,TRUE,nMode&(CSMODE_TRANSFERERROR|CSMODE_TRANSFERTIMEOUT));
- else if (m_Operation.nOpMode&CSMODE_LIST)
- List(TRUE,nMode&(CSMODE_TRANSFERERROR|CSMODE_TRANSFERTIMEOUT));
- }
- void CFtpControlSocket::OnClose(int nErrorCode)
- {
- ShowStatus(IDS_STATUSMSG_DISCONNECTED, FZ_LOG_ERROR);
- if (m_pTransferSocket)
- {
- m_pTransferSocket->OnClose(0);
- m_pTransferSocket->Close();
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- DoClose();
- return;
- }
- if (m_bDidRejectCertificate)
- DoClose(FZ_REPLY_CANCEL);
- else
- DoClose();
- }
- void CFtpControlSocket::ResetTransferSocket(int Error)
- {
- if (Error)
- {
- LogMessage(FZ_LOG_INFO, L"Destroying data socket on error");
- }
- else
- {
- LogMessage(FZ_LOG_INFO, L"Destroying data socket after transfer completed");
- }
- bool Close =
- (Error != 0) &&
- DebugAlwaysTrue(m_pTransferSocket != NULL) &&
- (m_pTransferSocket->m_uploaded > 0) &&
- FLAGCLEAR(Error, FZ_REPLY_CANCEL);
- delete m_pTransferSocket;
- m_pTransferSocket = NULL;
- if (Close)
- {
- // close the control connection too to allow reconnect => transfer resume
- LogMessage(FZ_LOG_WARNING, L"Transfer connection failed, closing");
- DoClose();
- }
- }
- void CFtpControlSocket::FileTransfer(t_transferfile *transferfile/*=0*/,BOOL bFinish/*=FALSE*/,int nError/*=0*/)
- {
- USES_CONVERSION;
- #define FILETRANSFER_INIT -1
- #define FILETRANSFER_PWD 0
- #define FILETRANSFER_CWD 1
- #define FILETRANSFER_MKD 2
- #define FILETRANSFER_CWD2 3
- #define FILETRANSFER_PWD2 4
- #define FILETRANSFER_LIST_MODE 5
- #define FILETRANSFER_LIST_OPTS 6
- #define FILETRANSFER_LIST_PORTPASV 7
- #define FILETRANSFER_LIST_TYPE 8
- #define FILETRANSFER_LIST_LIST 9
- #define FILETRANSFER_LIST_WAITFINISH 10
- #define FILETRANSFER_NOLIST_SIZE 11
- #define FILETRANSFER_NOLIST_MDTM 12
- #define FILETRANSFER_TYPE 13
- #define FILETRANSFER_REST 14
- #define FILETRANSFER_MODE 15
- #define FILETRANSFER_OPTS 16
- #define FILETRANSFER_PORTPASV 17
- #define FILETRANSFER_RETRSTOR 18
- #define FILETRANSFER_WAITFINISH 19
- #define FILETRANSFER_WAIT 20
- #define FILETRANSFER_MFMT 21
- //Partial flowchart of FileTransfer
- //
- // +----+
- // /------|Init|--------\
- // | +----+ |
- // | | |
- // | /---+ |
- // | | | |
- // | | +---+ |
- // | | |PWD| |
- // | | +---+ |
- // | | | |
- // | \---+ |
- // | | |
- // | +---+ |
- // | |CWD|--\ |
- // | +---+ | |
- // | | | |
- // | | | |
- // | | +---+ |
- // | | |MKD| |
- // | | +---+ |
- // | | | |
- // | | | |
- // | | +----+ |
- // | | |CWD2| |
- // | | +----+ |
- // | | | |
- // | +----/ |
- // | | |
- // | +---+ |
- // +-------|PWD| |
- // | +---+ |
- // | | |
- // | +----------/
- // | |
- // | +---------+
- // | |LIST_TYPE|
- // | +---------+
- // | |
- // | |
- // | +-------------+
- // | |LIST_PORTPASV|
- // | +-------------+
- // | |
- // | |
- // | +---------+
- // | |LIST_LIST|-----\ //List fails, maybe folder is list protected
- // | +---------+ | //Use SIZE and MDTM to get file information
- // | | +----+
- // | | |SIZE|
- // | | +----+
- // | | |
- // | | +----+
- // | | |MDTM|
- // | | +----+
- // | | |
- // | | |
- // | +---------------+ |
- // | |LIST_WAITFINISH| |
- // | +---------------+ |
- // | | |
- // | | |
- // | +----------/
- // | |
- // \---------+
- // |
- // +----+
- // |TYPE|
- // +----+
- // |
- // |
- // +--------+
- // |PORTPASV|--\
- // +--------+ |
- // | |
- // | |
- // | +----+
- // | |REST|
- // | +----+
- // | |
- // +------/
- // |
- // +--------+
- // |RETRSTOR|
- // +--------+
- // |
- // |
- // +----------+
- // |WAITFINISH|
- // +----------+
- DebugAssert(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_TRANSFER);
- if (!m_pOwner->IsConnected())
- {
- m_Operation.nOpMode=CSMODE_TRANSFER|(transferfile->get?CSMODE_DOWNLOAD:CSMODE_UPLOAD);
- ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_DISCONNECTED);
- return;
- }
- CFileTransferData *pData=static_cast<CFileTransferData *>(m_Operation.pData);
- //Process finish and error messages
- if (bFinish || nError)
- {
- DebugAssert(m_Operation.nOpMode&CSMODE_TRANSFER);
- // APPE failed, ignore this reply
- if (m_Operation.nOpMode == FILETRANSFER_WAIT && bFinish)
- return;
- if (!(m_Operation.nOpMode&CSMODE_TRANSFER))
- return;
- if (nError)
- {
- if (m_Operation.nOpState == FILETRANSFER_LIST_LIST && nError & CSMODE_TRANSFERERROR)
- { //Don't abort operation, use fallback to SIZE and MDTM (when actual LIST reply comes in)
- if (m_pTransferSocket)
- m_pTransferSocket=0;
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- }
- else if (nError&CSMODE_TRANSFERTIMEOUT)
- DoClose();
- else
- {
- // we may get here when connection was closed, when the closure
- // was first detected while reading/writing,
- // when we abort file transfer with regular error,
- // possibly preventing automatic reconnect
- LogMessage(FZ_LOG_INFO, L"Transfer error (%x)", nError);
- ResetOperation(FZ_REPLY_ERROR);
- }
- return;
- }
- if (m_Operation.nOpState <= FILETRANSFER_LIST_PORTPASV)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- else if (m_Operation.nOpState<=FILETRANSFER_LIST_WAITFINISH)
- {
- if (!m_pTransferSocket || m_pTransferSocket->m_bListening)
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- int num=0;
- pData->pDirectoryListing=new t_directory;
- pData->pDirectoryListing->direntry=m_pTransferSocket->m_pListResult->getList(num);
- pData->pDirectoryListing->num=num;
- if (m_pTransferSocket->m_pListResult->m_server.nServerType&FZ_SERVERTYPE_SUB_FTP_VMS && m_CurrentServer.nServerType&FZ_SERVERTYPE_FTP)
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_VMS;
- pData->pDirectoryListing->server = m_CurrentServer;
- pData->pDirectoryListing->path.SetServer(m_CurrentServer);
- pData->pDirectoryListing->path = pData->transferfile.remotepath;
- if (pData->rawpwd!=L"")
- {
- if (!pData->pDirectoryListing->path.SetPath(pData->rawpwd))
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- else
- pData->pDirectoryListing->path=pData->transferfile.remotepath;
- if (m_Operation.nOpState!=FILETRANSFER_LIST_WAITFINISH)
- return;
- }
- else if (m_Operation.nOpState <= FILETRANSFER_PORTPASV)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- else if (m_Operation.nOpState<=FILETRANSFER_WAITFINISH)
- {
- if (m_pTransferSocket->m_bListening)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- pData->nGotTransferEndReply |= 2;
- if (m_Operation.nOpState!=FILETRANSFER_WAITFINISH)
- return;
- else
- {
- ResetTransferSocket(nError);
- }
- }
- }
- //////////////////
- //Initialization//
- //////////////////
- int nReplyError = 0;
- if (m_Operation.nOpState == FILETRANSFER_INIT)
- {
- DebugAssert(transferfile);
- DebugAssert(!m_Operation.nOpMode);
- DebugAssert(!m_Operation.pData);
- CString str;
- str.Format(transferfile->get?IDS_STATUSMSG_DOWNLOADSTART:IDS_STATUSMSG_UPLOADSTART,
- transferfile->get ? transferfile->remotepath.FormatFilename(transferfile->remotefile) : transferfile->localfile);
- ShowStatus(str,FZ_LOG_STATUS);
- m_Operation.nOpMode=CSMODE_TRANSFER|(transferfile->get?CSMODE_DOWNLOAD:CSMODE_UPLOAD);
- m_Operation.pData=new CFileTransferData;
- pData=static_cast<CFileTransferData *>(m_Operation.pData);
- if (GetOptionVal(OPTION_PROXYTYPE)!=PROXYTYPE_NOPROXY)
- pData->bPasv = TRUE;
- else if (m_CurrentServer.nPasv == 1)
- pData->bPasv = TRUE;
- else if (m_CurrentServer.nPasv == 2)
- pData->bPasv = FALSE;
- else
- pData->bPasv = GetOptionVal(OPTION_PASV);
- //Replace invalid characters in the local filename
- int pos=transferfile->localfile.ReverseFind(L'\\');
- for (int i=(pos+1);i<transferfile->localfile.GetLength();i++)
- if (transferfile->localfile[i]==L':')
- transferfile->localfile.SetAt(i, L'_');
- pData->transferfile=*transferfile;
- pData->transferdata.transfersize=pData->transferfile.size;
- pData->transferdata.transferleft=pData->transferfile.size;
- pData->transferdata.bResume = FALSE;
- pData->transferdata.bResumeAppend = FALSE;
- pData->transferdata.bType = (pData->transferfile.nType == 1) ? TRUE : FALSE;
- CServerPath path;
- DebugCheck(m_pOwner->GetCurrentPath(path));
- if (path == pData->transferfile.remotepath)
- {
- if (m_pDirectoryListing)
- {
- m_Operation.nOpState=FILETRANSFER_TYPE;
- CString remotefile=pData->transferfile.remotefile;
- int i;
- for (i=0; i<m_pDirectoryListing->num; i++)
- {
- if (m_pDirectoryListing->direntry[i].name==remotefile &&
- ( m_pDirectoryListing->direntry[i].bUnsure || m_pDirectoryListing->direntry[i].size==-1 ))
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- m_Operation.nOpState = FileTransferListState(transferfile->get);
- break;
- }
- }
- if (m_pDirectoryListing && i==m_pDirectoryListing->num)
- {
- nReplyError = CheckOverwriteFile();
- if (!nReplyError)
- {
- if (pData->transferfile.get)
- {
- CString path=pData->transferfile.localfile;
- if (path.ReverseFind(L'\\')!=-1)
- {
- path=path.Left(path.ReverseFind(L'\\')+1);
- CString path2;
- while (path!=L"")
- {
- path2+=path.Left(path.Find( L"\\" )+1);
- path=path.Mid(path.Find( L"\\" )+1);
- CreateDirectory(path2, 0);
- }
- }
- }
- }
- }
- }
- else
- {
- m_Operation.nOpState = FileTransferListState(transferfile->get);
- }
- }
- else
- {
- if (path.IsEmpty())
- m_Operation.nOpState = FILETRANSFER_PWD;
- else
- m_Operation.nOpState = FILETRANSFER_CWD;
- }
- }
- else
- {
- ///////////
- //Replies//
- ///////////
- int code = GetReplyCode();
- switch(m_Operation.nOpState)
- {
- case FILETRANSFER_PWD:
- if (code != 2 && code != 3)
- {
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- pData->rawpwd = GetReply();
- if ((m_mayBeMvsFilesystem || m_mayBeBS2000Filesystem) && m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP &&
- pData->rawpwd[0] != L'/')
- {
- m_mayBeMvsFilesystem = false;
- m_mayBeBS2000Filesystem = false;
- if (m_mayBeBS2000Filesystem)
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_BS2000;
- else
- m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_MVS;
- pData->transferfile.remotepath.SetServer(m_CurrentServer);
- }
- if (!ParsePwdReply(pData->rawpwd))
- return;
- if (m_pOwner->GetCurrentPath() == pData->transferfile.remotepath)
- {
- m_Operation.nOpState = FileTransferListState(pData->transferfile.get);
- }
- else
- m_Operation.nOpState = LIST_CWD;
- break;
- case FILETRANSFER_CWD:
- if (code != 2 && code != 3)
- if (pData->transferfile.get)
- {
- pData->bUseAbsolutePaths = TRUE;
- m_Operation.nOpState = FILETRANSFER_NOLIST_SIZE;
- }
- else
- m_Operation.nOpState = FILETRANSFER_MKD;
- else
- m_Operation.nOpState = FILETRANSFER_PWD2;
- break;
- case FILETRANSFER_MKD:
- switch(pData->nMKDOpState)
- {
- case MKD_FINDPARENT:
- {
- if (code == 2 || code == 3)
- {
- m_pOwner->SetCurrentPath(pData->MKDCurrent);
- pData->nMKDOpState=MKD_CHANGETOSUBDIR;
- pData->MKDCurrent.AddSubdir(pData->MKDSegments.front());
- CString Segment=pData->MKDSegments.front();
- pData->MKDSegments.pop_front();
- if (!Send( L"MKD " + Segment))
- return;
- }
- else
- {
- if (!pData->MKDCurrent.HasParent())
- nReplyError = FZ_REPLY_ERROR | ((code == 5) ? FZ_REPLY_CRITICALERROR : 0);
- else
- {
- pData->MKDSegments.push_front(pData->MKDCurrent.GetLastSegment());
- pData->MKDCurrent=pData->MKDCurrent.GetParent();
- if (!Send(L"CWD "+pData->MKDCurrent.GetPathUnterminated()))
- return;
- }
- }
- }
- break;
- case MKD_MAKESUBDIRS:
- {
- if (code == 2 || code == 3)
- { //Create dir entry in parent dir
- DebugAssert(!pData->MKDSegments.empty());
- pData->MKDCurrent.AddSubdir(pData->MKDSegments.front());
- CString Segment=pData->MKDSegments.front();
- pData->MKDSegments.pop_front();
- if (Send( L"MKD " + Segment))
- pData->nMKDOpState=MKD_CHANGETOSUBDIR;
- else
- return;
- }
- else
- nReplyError=FZ_REPLY_ERROR;
- }
- break;
- case MKD_CHANGETOSUBDIR:
- {
- if (code == 2 || code == 3 || //Creation successful
- m_RecvBuffer.front() == "550 Directory already exists") //Creation was successful, although someone else did the work for us
- {
- CServerPath path2 = pData->MKDCurrent;
- if (path2.HasParent())
- {
- CString name=path2.GetLastSegment();
- path2=path2.GetParent();
- t_directory dir;
- BOOL res=FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path==path2)
- {
- dir=*m_pDirectoryListing;
- res=TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound=m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path==path2)
- {
- dir=WorkingDir;
- res=TRUE;
- }
- if (!res)
- {
- dir.path=path2;
- dir.server=m_CurrentServer;
- }
- int i;
- for (i=0; i<dir.num; i++)
- if (dir.direntry[i].name == name)
- {
- LogMessage(FZ_LOG_WARNING, L"Dir already exists in cache!");
- break;
- }
- if (i==dir.num)
- {
- t_directory::t_direntry *entries = new t_directory::t_direntry[dir.num+1];
- for (i=0;i<dir.num;i++)
- entries[i]=dir.direntry[i];
- entries[i].name=name;
- entries[i].dir=TRUE;
- entries[i].date.hasdate=FALSE;
- entries[i].size=-1;
- entries[i].bUnsure=FALSE;
- delete [] dir.direntry;
- dir.direntry=entries;
- dir.num++;
- BOOL updated=FALSE;
- if (m_pDirectoryListing && m_pDirectoryListing->path==dir.path)
- {
- updated=TRUE;
- SetDirectoryListing(&dir);
- }
- if (!updated)
- if (WorkingDir.path==dir.path)
- {
- updated=TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- }
- }
- //Continue operation even if MKD failed, maybe another thread did create this directory for us
- if (pData->MKDSegments.empty())
- m_Operation.nOpState=FILETRANSFER_CWD2;
- else
- {
- if (Send( L"CWD " + pData->MKDCurrent.GetPathUnterminated()))
- pData->nMKDOpState=MKD_MAKESUBDIRS;
- else
- return;
- }
- }
- break;
- default:
- DebugFail();
- }
- break;
- case FILETRANSFER_CWD2:
- if (code != 2 && code != 3)
- if (code == 4)
- nReplyError=FZ_REPLY_ERROR;
- else
- nReplyError=FZ_REPLY_CRITICALERROR;
- else
- m_Operation.nOpState=FILETRANSFER_PWD2;
- break;
- case FILETRANSFER_PWD2:
- if (code != 2 && code != 3)
- nReplyError = FZ_REPLY_ERROR;
- else
- {
- pData->rawpwd = GetReply();
- if (!ParsePwdReply(pData->rawpwd))
- return;
- m_Operation.nOpState = FileTransferListState(pData->transferfile.get);
- }
- break;
- case FILETRANSFER_LIST_MODE:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- m_Operation.nOpState = FILETRANSFER_LIST_TYPE;
- #else
- if (code == 2 || code == 3)
- m_useZlib = !m_useZlib;
- m_Operation.nOpState = NeedOptsCommand() ? FILETRANSFER_LIST_OPTS : FILETRANSFER_LIST_TYPE;
- #endif
- break;
- case FILETRANSFER_LIST_OPTS:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- if (code == 2 || code == 3)
- m_zlibLevel = pData->newZlibLevel;
- m_Operation.nOpState = FILETRANSFER_LIST_TYPE;
- #endif
- break;
- case FILETRANSFER_LIST_TYPE:
- if (code != 2 && code != 3)
- nReplyError = FZ_REPLY_ERROR;
- else
- m_Operation.nOpState = FILETRANSFER_LIST_PORTPASV;
- break;
- case FILETRANSFER_LIST_PORTPASV:
- if (code!=3 && code!=2)
- {
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- nReplyError=FZ_REPLY_ERROR;
- break;
- }
- if (pData->bPasv)
- {
- CString reply = GetReply();
- int i,j;
- // MP EXT
- if((i=reply.Find(L"("))>=0&&(j=reply.Find(L")"))>=0)
- {
- i++;
- j--;
- }
- else
- {
- // MP EXT
- if ((i=reply.Mid(4).FindOneOf(L"0123456789"))>=0)
- {
- i += 4;
- j = reply.GetLength() - 1;
- }
- else
- {
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- }
- CString temp = reply.Mid(i,(j-i)+1);
- if (GetFamily() == AF_INET)
- {
- int count=0;
- int pos=0;
- //Convert commas to dots
- temp.Replace( L",", L"." );
- while(1)
- {
- pos=temp.Find(L".",pos);
- if (pos!=-1)
- count++;
- else
- break;
- pos++;
- }
- if (count!=5)
- {
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- i=temp.ReverseFind(L'.');
- pData->port=atol( T2CA( temp.Right(temp.GetLength()-(i+1)) ) ); //get ls byte of server socket
- temp=temp.Left(i);
- i=temp.ReverseFind(L'.');
- pData->port+=256*atol( T2CA( temp.Right(temp.GetLength()-(i+1)) ) ); // add ms byte to server socket
- pData->host=temp.Left(i);
- if (!CheckForcePasvIp(pData->host))
- {
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- }
- else if (GetFamily() == AF_INET6)
- {
- temp = temp.Mid(3);
- pData->port = atol( T2CA(temp.Left(temp.GetLength() - 1) ) );
- if (pData->port < 0 || pData->port > 65535)
- {
- LogMessage(FZ_LOG_WARNING, L"Port %u not valid", pData->port);
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- pData->host = m_CurrentServer.host;
- }
- m_pTransferSocket = new CTransferSocket(this, CSMODE_LIST);
- #ifndef MPEXT_NO_ZLIB
- if (m_useZlib)
- {
- if (!m_pTransferSocket->InitZlib(m_zlibLevel))
- {
- ShowStatus(L"Failed to initialize zlib", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- #endif
- #ifndef MPEXT_NO_GSS
- if (m_pGssLayer && m_pGssLayer->AuthSuccessful())
- m_pTransferSocket->UseGSS(m_pGssLayer);
- #endif
- m_pTransferSocket->m_nInternalMessageID = m_pOwner->m_nInternalMessageID;
- m_pTransferSocket->SetFamily(GetFamily());
- if (!m_pTransferSocket->Create(m_pSslLayer && m_bProtP))
- {
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- DebugCheck(m_pTransferSocket->AsyncSelect());
- }
- m_Operation.nOpState=FILETRANSFER_LIST_LIST;
- break;
- case FILETRANSFER_LIST_LIST:
- if (IsMisleadingListResponse())
- {
- ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, FZ_LOG_PROGRESS);
- t_directory listing;
- listing.server = m_CurrentServer;
- listing.path.SetServer(m_CurrentServer);
- if (pData->rawpwd != L"")
- {
- if (!listing.path.SetPath(pData->rawpwd))
- {
- delete m_pDirectoryListing;
- m_pDirectoryListing = 0;
- delete m_pTransferSocket;
- m_pTransferSocket = 0;
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- else
- listing.path = pData->transferfile.remotepath;
- SetDirectoryListing(&listing);
- m_Operation.nOpState = FILETRANSFER_TYPE;
- delete m_pTransferSocket;
- m_pTransferSocket = 0;
- nReplyError = CheckOverwriteFile();
- if (!nReplyError)
- {
- if (pData->transferfile.get)
- {
- CString path=pData->transferfile.localfile;
- if (path.ReverseFind(L'\\')!=-1)
- {
- path=path.Left(path.ReverseFind(L'\\')+1);
- CString path2;
- while (path!=L"")
- {
- path2+=path.Left(path.Find( L"\\" )+1);
- path=path.Mid(path.Find( L"\\" )+1);
- CreateDirectory(path2, 0);
- }
- }
- }
- }
- }
- else if (code==4 || code==5) //LIST failed, try getting file information using SIZE and MDTM
- {
- TransferHandleListError();
- }
- else if (code!=1)
- nReplyError=FZ_REPLY_ERROR;
- else
- m_Operation.nOpState=FILETRANSFER_LIST_WAITFINISH;
- break;
- case FILETRANSFER_LIST_WAITFINISH:
- if (!bFinish)
- {
- if (code!=2 && code!=3)
- {
- if (code==4 || code==5)
- {
- TransferHandleListError();
- }
- else
- {
- nReplyError=FZ_REPLY_ERROR;
- }
- }
- else
- pData->nGotTransferEndReply = 1;
- }
- if (pData->nGotTransferEndReply && pData->pDirectoryListing)
- {
- SetDirectoryListing(pData->pDirectoryListing);
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- m_Operation.nOpState=FILETRANSFER_TYPE;
- nReplyError = CheckOverwriteFile();
- if (!nReplyError)
- {
- if (pData->transferfile.get)
- {
- CString path=pData->transferfile.localfile;
- if (path.ReverseFind(L'\\')!=-1)
- {
- path=path.Left(path.ReverseFind(L'\\')+1);
- CString path2;
- while (path!=L"")
- {
- path2+=path.Left(path.Find( L"\\" )+1);
- path=path.Mid(path.Find( L"\\" )+1);
- CreateDirectory(path2, 0);
- }
- }
- }
- }
- pData->nGotTransferEndReply=0;
- }
- break;
- case FILETRANSFER_NOLIST_SIZE:
- {
- __int64 size;
- if (HandleSize(code, size))
- {
- DebugAssert(!pData->pFileSize);
- pData->pFileSize=new _int64;
- *pData->pFileSize=size;
- }
- }
- m_Operation.nOpState=FILETRANSFER_NOLIST_MDTM;
- break;
- case FILETRANSFER_NOLIST_MDTM:
- if (HandleMdtm(code, pData->remoteDate))
- {
- pData->hasRemoteDate = true;
- }
- m_Operation.nOpState=FILETRANSFER_TYPE;
- nReplyError=CheckOverwriteFile();
- break;
- case FILETRANSFER_TYPE:
- if (code!=2 && code!=3)
- nReplyError = FZ_REPLY_ERROR;
- m_Operation.nOpState = NeedModeCommand() ? FILETRANSFER_MODE : (NeedOptsCommand() ? FILETRANSFER_OPTS : FILETRANSFER_PORTPASV);
- break;
- case FILETRANSFER_WAIT:
- if (!pData->nWaitNextOpState)
- nReplyError=FZ_REPLY_ERROR;
- else
- m_Operation.nOpState=pData->nWaitNextOpState;
- break;
- case FILETRANSFER_MODE:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- m_Operation.nOpState = FILETRANSFER_PORTPASV;
- #else
- if (code == 2 || code == 3)
- m_useZlib = !m_useZlib;
- m_Operation.nOpState = NeedOptsCommand() ? FILETRANSFER_OPTS : FILETRANSFER_PORTPASV;
- #endif
- break;
- case FILETRANSFER_OPTS:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- if (code == 2 || code == 3)
- m_zlibLevel = pData->newZlibLevel;
- #endif
- m_Operation.nOpState = FILETRANSFER_PORTPASV;
- break;
- case FILETRANSFER_PORTPASV:
- if (code == 3 || code == 2)
- {
- if (pData->bPasv)
- {
- CString reply = GetReply();
- int i,j;
- // MP EXT
- if((i=reply.Find(L"("))>=0&&(j=reply.Find(L")"))>=0)
- {
- i++;
- j--;
- }
- else
- {
- // MP EXT
- if ((i=reply.Mid(4).FindOneOf(L"0123456789"))>=0)
- {
- i += 4;
- j = reply.GetLength() - 1;
- }
- else
- {
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- }
- CString temp = reply.Mid(i,(j-i)+1);
- if (GetFamily() == AF_INET)
- {
- int count=0;
- int pos=0;
- //Convert commas to dots
- temp.Replace( L",", L"." );
- while(1)
- {
- pos=temp.Find( L".", pos);
- if (pos!=-1)
- count++;
- else
- break;
- pos++;
- }
- if (count!=5)
- {
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- i=temp.ReverseFind(L'.');
- pData->port=atol( T2CA( temp.Right(temp.GetLength()-(i+1)) ) ); //get ls byte of server socket
- temp=temp.Left(i);
- i=temp.ReverseFind(L'.');
- pData->port+=256*atol( T2CA( temp.Right(temp.GetLength()-(i+1)) ) ); // add ms byte to server socket
- pData->host=temp.Left(i);
- if (!CheckForcePasvIp(pData->host))
- {
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- }
- else if (GetFamily() == AF_INET6)
- {
- temp = temp.Mid(3);
- pData->port = atol( T2CA(temp.Left(temp.GetLength() - 1) ) );
- if (pData->port < 0 || pData->port > 65535)
- {
- LogMessage(FZ_LOG_WARNING, L"Port %u not valid", pData->port);
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- pData->host = m_CurrentServer.host;
- }
- else
- {
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- m_pTransferSocket = new CTransferSocket(this, m_Operation.nOpMode);
- #ifndef MPEXT_NO_ZLIB
- if (m_useZlib)
- {
- if (!m_pTransferSocket->InitZlib(m_zlibLevel))
- {
- ShowStatus(L"Failed to initialize zlib", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- #endif
- #ifndef MPEXT_NO_GSS
- if (m_pGssLayer && m_pGssLayer->AuthSuccessful())
- m_pTransferSocket->UseGSS(m_pGssLayer);
- #endif
- m_pTransferSocket->m_nInternalMessageID = m_pOwner->m_nInternalMessageID;
- m_pTransferSocket->SetFamily(GetFamily());
- if (!m_pTransferSocket->Create(m_pSslLayer && m_bProtP))
- {
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- DebugCheck(m_pTransferSocket->AsyncSelect());
- }
- if (pData->transferdata.bResume)
- m_Operation.nOpState = FILETRANSFER_REST;
- else
- m_Operation.nOpState = FILETRANSFER_RETRSTOR;
- BOOL res = FALSE;
- if (!m_pDataFile)
- m_pDataFile = new CFile;
- if (pData->transferfile.get)
- {
- if (pData->transferdata.bResume)
- res = m_pDataFile->Open(pData->transferfile.localfile,CFile::modeCreate|CFile::modeWrite|CFile::modeNoTruncate|CFile::shareDenyWrite);
- else
- res = m_pDataFile->Open(pData->transferfile.localfile,CFile::modeWrite|CFile::modeCreate|CFile::shareDenyWrite);
- }
- else
- res = m_pDataFile->Open(pData->transferfile.localfile,CFile::modeRead|CFile::shareDenyNone);
- if (!res)
- {
- wchar_t * Error = m_pTools->LastSysErrorMessage();
- //Error opening the file
- CString str;
- str.Format(IDS_ERRORMSG_FILEOPENFAILED,pData->transferfile.localfile);
- str += L"\n";
- str += Error;
- free(Error);
- ShowStatus(str,FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_ERROR;
- break;
- }
- if (!m_pTransferSocket)
- {
- nReplyError=FZ_REPLY_ERROR;
- break;
- }
- m_pTransferSocket->m_pFile = m_pDataFile;
- if (!pData->transferfile.get)
- {
- // See comment in !get branch below
- pData->transferdata.transfersize=GetLength64(*m_pDataFile);
- pData->transferdata.transferleft=pData->transferdata.transfersize;
- if (pData->transferdata.bResume)
- {
- CString remotefile=pData->transferfile.remotefile;
- if (m_pDirectoryListing)
- for (int i = 0; i < m_pDirectoryListing->num; i++)
- {
- if (m_pDirectoryListing->direntry[i].name == remotefile)
- {
- pData->transferdata.transferleft -= m_pDirectoryListing->direntry[i].size;
- break;
- }
- }
- _int64 size = pData->transferdata.transfersize-pData->transferdata.transferleft;
- LONG low = static_cast<LONG>(size&0xFFFFFFFF);
- LONG high = static_cast<LONG>(size>>32);
- if (SetFilePointer((HANDLE)m_pDataFile->m_hFile, low, &high, FILE_BEGIN)==0xFFFFFFFF && GetLastError()!=NO_ERROR)
- {
- ShowStatus(IDS_ERRORMSG_SETFILEPOINTER, FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_ERROR;
- }
- }
- }
- else
- {
- // Resetting transfersize here is pointless as we
- // always provide valid size in call to FileTransfer.
- // We unnecessary reply on the file being in the directory listing.
- pData->transferdata.transfersize=-1;
- CString remotefile=pData->transferfile.remotefile;
- if (m_pDirectoryListing)
- for (int i=0; i<m_pDirectoryListing->num; i++)
- {
- if (m_pDirectoryListing->direntry[i].name==remotefile)
- {
- pData->hasRemoteDate = true;
- pData->remoteDate = m_pDirectoryListing->direntry[i].date;
- pData->transferdata.transfersize=m_pDirectoryListing->direntry[i].size;
- }
- }
- else if (pData->pFileSize)
- pData->transferdata.transfersize=*pData->pFileSize;
- pData->transferdata.transferleft=pData->transferdata.transfersize;
- }
- }
- else
- if (!pData->bTriedPortPasvOnce)
- {
- pData->bTriedPortPasvOnce = TRUE;
- pData->bPasv = !pData->bPasv;
- }
- else
- nReplyError = FZ_REPLY_ERROR;
- break;
- case FILETRANSFER_REST:
- { //Resume
- if (code==3 || code==2)
- {
- LONG high = 0;
- if (pData->transferfile.get)
- {
- pData->transferdata.transferleft = pData->transferdata.transfersize - GetLength64(*m_pDataFile);
- if (SetFilePointer((HANDLE)m_pDataFile->m_hFile, 0, &high, FILE_END)==0xFFFFFFFF && GetLastError()!=NO_ERROR)
- {
- ShowStatus(IDS_ERRORMSG_SETFILEPOINTER, FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_ERROR;
- }
- else
- m_Operation.nOpState = FILETRANSFER_RETRSTOR;
- }
- else
- {
- m_Operation.nOpState = FILETRANSFER_RETRSTOR;
- }
- }
- else
- {
- if (code==5 && GetReply()[1]==L'0')
- {
- if (pData->transferfile.get)
- {
- if (pData->transferdata.transfersize!=-1)
- {
- DebugAssert(m_pDataFile);
- if (GetLength64(*m_pDataFile) == pData->transferdata.transfersize)
- {
- ShowStatus(IDS_ERRORMSG_CANTRESUME_FINISH, FZ_LOG_STATUS);
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- }
- ShowStatus(IDS_ERRORMSG_CANTRESUME, FZ_LOG_ERROR);
- pData->transferdata.transferleft=pData->transferdata.transfersize;
- pData->transferdata.bResume=FALSE;
- m_Operation.nOpState=FILETRANSFER_RETRSTOR;
- }
- else
- {
- ShowStatus(L"Resume command not supported by server, trying append.", FZ_LOG_PROGRESS);
- pData->transferdata.bResumeAppend=TRUE;
- m_Operation.nOpState=FILETRANSFER_RETRSTOR;
- }
- }
- else
- nReplyError=FZ_REPLY_ERROR;
- }
- }
- break;
- case FILETRANSFER_RETRSTOR:
- // A '1xy opening data connection' reply is expected if RETR/STOR/APPE
- // is successful.
- // On failure, it's a 4xy or 5xy reply.
- // However, some servers send a 2xy transfer complete reply without opening a data
- // connection if there's no data to send.
- if (code==2)
- {
- //Transfer successful, however server did not open data connection
- ResetOperation(FZ_REPLY_OK);
- return;
- }
- else if (code!=1)
- {
- if (!pData->transferfile.get && pData->transferdata.bResume && pData->askOnResumeFail)
- {
- pData->askOnResumeFail = false;
- delete m_pTransferSocket;
- m_pTransferSocket = 0;
- delete m_pDataFile;
- m_pDataFile = 0;
- pData->nGotTransferEndReply = 0;
- nReplyError = CheckOverwriteFile();
- }
- else
- {
- nReplyError = FZ_REPLY_ERROR;
- if (code == 5)
- nReplyError |= FZ_REPLY_CRITICALERROR;
- }
- }
- else
- {
- m_Operation.nOpState=FILETRANSFER_WAITFINISH;
- //Look if we can find any information about the resume offset
- if (!pData->transferfile.get && pData->transferdata.bResumeAppend)
- {
- _int64 nOffset = -1;
- CString reply = GetReply();
- reply.MakeLower();
- int pos = reply.Find(L"restarting at offset ");
- if (pos != -1)
- pos += _tcslen(L"restarting at offset ");
- reply = reply.Mid(pos);
- int i;
- for (i=0; i<reply.GetLength(); i++)
- {
- if (reply[i] < L'0' || reply[i] > L'9')
- break;
- }
- if (i == reply.GetLength())
- nOffset = _ttoi64(reply);
- if (nOffset != -1 && m_pDataFile)
- {
- LONG low = 0;
- LONG high = 0;
- if (nOffset >= GetLength64(*m_pDataFile))
- {
- if (SetFilePointer((HANDLE)m_pDataFile->m_hFile, 0, &high, FILE_END)==0xFFFFFFFF && GetLastError()!=NO_ERROR)
- {
- ShowStatus(IDS_ERRORMSG_SETFILEPOINTER, FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_ERROR;
- }
- }
- else
- {
- low=static_cast<LONG>(nOffset&0xFFFFFFFF);
- high=static_cast<LONG>(nOffset>>32);
- if (SetFilePointer((HANDLE)m_pDataFile->m_hFile, low, &high, FILE_BEGIN)==0xFFFFFFFF && GetLastError()!=NO_ERROR)
- {
- ShowStatus(IDS_ERRORMSG_SETFILEPOINTER, FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_ERROR;
- }
- }
- }
- if (!nReplyError && !GetOptionVal(OPTION_MPEXT_TRANSFER_ACTIVE_IMMEDIATELY))
- {
- m_pTransferSocket->SetActive();
- }
- }
- else if (pData->bPasv && !GetOptionVal(OPTION_MPEXT_TRANSFER_ACTIVE_IMMEDIATELY))
- {
- m_pTransferSocket->SetActive();
- }
- }
- break;
- case FILETRANSFER_WAITFINISH:
- if (bFinish)
- {
- if (nError)
- {
- LogMessage(FZ_LOG_INFO, L"Transfer completed");
- }
- else
- {
- LogMessage(FZ_LOG_INFO, L"Transfer failed");
- }
- }
- if (!bFinish)
- {
- if (code == 1)
- {
- /* Some non-rfc959 compatible servers send more than one code 1yz reply, especially if using APPE.
- * Just ignore the additional ones.
- */
- LogMessage(FZ_LOG_WARNING, L"Server sent more than one code 1yz reply, ignoring additional reply");
- break;
- }
- else if (code!=2 && code!=3)
- nReplyError = FZ_REPLY_ERROR;
- else
- {
- pData->nGotTransferEndReply |= 1;
- }
- }
- if (pData->nGotTransferEndReply==3)
- {
- // Not really sure about a reason for the m_pDataFile condition here
- TransferFinished(m_pDataFile != NULL);
- return;
- }
- break;
- case FILETRANSFER_MFMT:
- //Transfer successful
- ResetOperation(FZ_REPLY_OK);
- break;
- }
- if (nReplyError)
- { //Error transferring the file
- LogMessage(FZ_LOG_INFO, L"Transfer response error (%x)", nReplyError);
- ResetOperation(nReplyError);
- return;
- }
- }
- /////////////////
- //Send commands//
- /////////////////
- BOOL bError=FALSE;
- switch(m_Operation.nOpState)
- {
- case FILETRANSFER_PWD:
- if (!Send(L"PWD"))
- bError = TRUE;
- break;
- case FILETRANSFER_CWD:
- if (!Send(L"CWD "+pData->transferfile.remotepath.GetPathUnterminated()))
- bError=TRUE;
- break;
- case FILETRANSFER_MKD:
- if (pData->nMKDOpState==MKD_INIT)
- {
- if (!pData->transferfile.remotepath.HasParent())
- {
- LogMessage(FZ_LOG_WARNING, L"Can't create root dir");
- ResetOperation(FZ_REPLY_CRITICALERROR);
- return;
- }
- if (!Send(L"CWD "+pData->transferfile.remotepath.GetParent().GetPathUnterminated()))
- bError=TRUE;
- pData->MKDCurrent=pData->transferfile.remotepath.GetParent();
- pData->MKDSegments.push_front(pData->transferfile.remotepath.GetLastSegment());
- pData->nMKDOpState=MKD_FINDPARENT;
- }
- break;
- case FILETRANSFER_CWD2:
- if (!Send(L"CWD "+pData->transferfile.remotepath.GetPathUnterminated()))
- bError=TRUE;
- break;
- case FILETRANSFER_PWD2:
- if (!Send(L"PWD"))
- bError=TRUE;
- break;
- case FILETRANSFER_LIST_MODE:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- if (m_useZlib)
- {
- if (!Send(L"MODE S"))
- bError = TRUE;
- }
- else
- if (!Send(L"MODE Z"))
- bError = TRUE;
- #endif
- break;
- case FILETRANSFER_LIST_OPTS:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- {
- pData->newZlibLevel = GetOptionVal(OPTION_MODEZ_LEVEL);
- CString str;
- str.Format(L"OPTS MODE Z LEVEL %d", pData->newZlibLevel);
- if (!Send(str))
- bError = TRUE;
- }
- #endif
- break;
- case FILETRANSFER_LIST_PORTPASV:
- delete m_pDirectoryListing;
- m_pDirectoryListing=0;
- if (pData->bPasv)
- {
- if (!Send((GetFamily() == AF_INET) ? L"PASV" : L"EPSV"))
- bError=TRUE;
- }
- else
- {
- if (m_pTransferSocket)
- {
- delete m_pTransferSocket;
- }
- m_pTransferSocket = new CTransferSocket(this, CSMODE_LIST);
- #ifndef MPEXT_NO_ZLIB
- if (m_useZlib)
- {
- if (!m_pTransferSocket->InitZlib(m_zlibLevel))
- {
- ShowStatus(L"Failed to initialize zlib", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- #endif
- #ifndef MPEXT_NO_GSS
- if (m_pGssLayer && m_pGssLayer->AuthSuccessful())
- m_pTransferSocket->UseGSS(m_pGssLayer);
- #endif
- m_pTransferSocket->m_nInternalMessageID = m_pOwner->m_nInternalMessageID;
- m_pTransferSocket->m_bListening = TRUE;
- m_pTransferSocket->SetFamily(GetFamily());
- if(!m_pTransferSocket->Create(m_pSslLayer && m_bProtP) || !m_pTransferSocket->AsyncSelect())
- bError=TRUE;
- else if (m_pProxyLayer)
- {
- SOCKADDR_IN addr;
- int len=sizeof(addr);
- if (!m_pProxyLayer->GetPeerName((SOCKADDR *)&addr,&len))
- {
- ShowStatus(IDS_ERRORMSG_CANTGETLIST,FZ_LOG_ERROR);
- bError=TRUE;
- }
- else if (!m_pTransferSocket->Listen(addr.sin_addr.S_un.S_addr))
- {
- ShowStatus(IDS_ERRORMSG_CANTGETLIST,FZ_LOG_ERROR);
- bError=TRUE;
- }
- //Don't send PORT command yet, params are unknown.
- //will be sent in TransfersocketListenFinished
- }
- else
- {
- //Set up an active file transfer
- CString temp;
- UINT nPort;
- if (//create listen socket (let Windows choose the port) & start listening
- !m_pTransferSocket->Listen() ||
- !m_pTransferSocket->GetSockName(temp, nPort))
- {
- bError = TRUE;
- break;
- }
- CString host;
- if (GetFamily() == AF_INET)
- {
- host = GetOption(OPTION_TRANSFERIP);
- if (host != L"")
- {
- DWORD ip = inet_addr(T2CA(host));
- if (ip != INADDR_NONE)
- host.Format(L"%d,%d,%d,%d", ip%256, (ip>>8)%256, (ip>>16)%256, ip>>24);
- else
- {
- hostent *fullname = gethostbyname(T2CA(host));
- if (!fullname)
- host = L"";
- else
- {
- DWORD ip = ((LPIN_ADDR)fullname->h_addr)->s_addr;
- if (ip != INADDR_NONE)
- host.Format(L"%d,%d,%d,%d", ip%256, (ip>>8)%256, (ip>>16)%256, ip>>24);
- else
- host = L"";
- }
- }
- }
- if (host == L"")
- {
- UINT temp;
- if (!GetSockName(host, temp))
- {
- bError = true;
- break;
- }
- host.Replace(L'.', L',');
- }
- if (!bError)
- {
- host.Format(host+L",%d,%d", nPort/256, nPort%256);
- if (!Send(L"PORT " + host)) // send PORT cmd to server
- bError = TRUE;
- }
- }
- else if (GetFamily() == AF_INET6)
- {
- host = GetOption(OPTION_TRANSFERIP6);
- if (host != L"")
- {
- USES_CONVERSION;
- addrinfo hints, *res;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_family = AF_INET6;
- hints.ai_socktype = SOCK_STREAM;
- if (!getaddrinfo(T2CA(host), "1024", &hints, &res))
- {
- host = Inet6AddrToString(((SOCKADDR_IN6 *)res->ai_addr)->sin6_addr);
- freeaddrinfo(res);
- }
- else
- host = L"";
- }
- if (host == L"")
- {
- UINT temp;
- if(!GetSockName(host, temp))
- bError = true;
- }
- if (!bError)
- {
- // assamble EPRT command
- CString cmd;
- cmd.Format(L"EPRT |2|" + host + L"|%d|", nPort);
- if (!Send(cmd))
- bError = TRUE;
- }
- }
- else
- {
- LogMessage(FZ_LOG_WARNING, L"Protocol %d not supported", GetFamily());
- bError = true;
- }
- }
- }
- break;
- case FILETRANSFER_LIST_TYPE:
- if (!Send(L"TYPE A"))
- bError=TRUE;
- break;
- case FILETRANSFER_LIST_LIST:
- {
- if (!m_pTransferSocket)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- m_pTransferSocket->SetActive();
- CString cmd = GetListingCmd();
- if(!Send(cmd))
- bError=TRUE;
- else if(pData->bPasv)
- {
- if (!ConnectTransferSocket(pData->host, pData->port))
- {
- bError=TRUE;
- ShowStatus(IDS_ERRORMSG_CANTGETLIST,FZ_LOG_ERROR);
- }
- }
- }
- break;
- case FILETRANSFER_NOLIST_SIZE:
- {
- CString command = L"SIZE ";
- command += pData->transferfile.remotepath.FormatFilename(pData->transferfile.remotefile, !pData->bUseAbsolutePaths);
- if (!Send(command))
- bError=TRUE;
- }
- break;
- case FILETRANSFER_NOLIST_MDTM:
- {
- CString command = L"MDTM ";
- command += pData->transferfile.remotepath.FormatFilename(pData->transferfile.remotefile, !pData->bUseAbsolutePaths);
- if (!Send(command))
- bError=TRUE;
- }
- break;
- case FILETRANSFER_TYPE:
- if (pData->transferfile.nType==1)
- {
- if (!Send(L"TYPE A"))
- bError=TRUE;
- }
- else
- if (!Send(L"TYPE I"))
- bError=TRUE;
- break;
- case FILETRANSFER_MODE:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- if (m_useZlib)
- {
- if (!Send(L"MODE S"))
- bError = TRUE;
- }
- else
- if (!Send(L"MODE Z"))
- bError = TRUE;
- #endif
- break;
- case FILETRANSFER_OPTS:
- #ifdef MPEXT_NO_ZLIB
- DebugFail();
- #else
- {
- pData->newZlibLevel = GetOptionVal(OPTION_MODEZ_LEVEL);
- CString str;
- str.Format(L"OPTS MODE Z LEVEL %d", pData->newZlibLevel);
- if (!Send(str))
- bError = TRUE;
- }
- #endif
- break;
- case FILETRANSFER_PORTPASV:
- if (pData->bPasv)
- {
- if (!Send((GetFamily() == AF_INET) ? L"PASV" : L"EPSV"))
- bError=TRUE;
- }
- else
- {
- if (m_pTransferSocket)
- {
- delete m_pTransferSocket;
- }
- m_pTransferSocket=new CTransferSocket(this, m_Operation.nOpMode);
- #ifndef MPEXT_NO_ZLIB
- if (m_useZlib)
- {
- if (!m_pTransferSocket->InitZlib(m_zlibLevel))
- {
- ShowStatus(L"Failed to initialize zlib", FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- #endif
- #ifndef MPEXT_NO_GSS
- if (m_pGssLayer && m_pGssLayer->AuthSuccessful())
- m_pTransferSocket->UseGSS(m_pGssLayer);
- #endif
- m_pTransferSocket->m_nInternalMessageID=m_pOwner->m_nInternalMessageID;
- m_pTransferSocket->m_bListening = TRUE;
- m_pTransferSocket->SetFamily(GetFamily());
- if(!m_pTransferSocket->Create(m_pSslLayer && m_bProtP) || !m_pTransferSocket->AsyncSelect())
- bError = TRUE;
- else if (m_pProxyLayer)
- {
- SOCKADDR_IN addr;
- int len=sizeof(addr);
- if (!m_pProxyLayer->GetPeerName((SOCKADDR *)&addr,&len))
- {
- ShowStatus(IDS_ERRORMSG_CANTGETLIST,FZ_LOG_ERROR);
- bError=TRUE;
- }
- else if (!m_pTransferSocket->Listen(addr.sin_addr.S_un.S_addr))
- {
- ShowStatus(IDS_ERRORMSG_CANTGETLIST,FZ_LOG_ERROR);
- bError=TRUE;
- }
- //Don't send PORT command yet, params are unknown.
- //will be sent in TransfersocketListenFinished
- }
- else
- {
- //Set up an active file transfer
- CString temp;
- UINT nPort;
- if (//create listen socket (let Windows choose the port) & start listening
- !m_pTransferSocket->Listen() ||
- !m_pTransferSocket->GetSockName(temp, nPort))
- {
- bError = TRUE;
- break;
- }
- CString host;
- if (GetFamily() == AF_INET)
- {
- host = GetOption(OPTION_TRANSFERIP);
- if (host != L"")
- {
- DWORD ip = inet_addr(T2CA(host));
- if (ip != INADDR_NONE)
- host.Format(L"%d,%d,%d,%d", ip%256, (ip>>8)%256, (ip>>16)%256, ip>>24);
- else
- {
- hostent *fullname = gethostbyname(T2CA(host));
- if (!fullname)
- host = L"";
- else
- {
- DWORD ip = ((LPIN_ADDR)fullname->h_addr)->s_addr;
- if (ip != INADDR_NONE)
- host.Format(L"%d,%d,%d,%d", ip%256, (ip>>8)%256, (ip>>16)%256, ip>>24);
- else
- host = L"";
- }
- }
- }
- if (host == L"")
- {
- UINT temp;
- if (!GetSockName(host, temp))
- bError = true;
- host.Replace(L'.', L',');
- }
- if (!bError)
- {
- host.Format(host+L",%d,%d", nPort/256, nPort%256);
- if (!Send(L"PORT " + host)) // send PORT cmd to server
- bError = TRUE;
- }
- }
- else if (GetFamily() == AF_INET6)
- {
- host = GetOption(OPTION_TRANSFERIP6);
- if (host != L"")
- {
- USES_CONVERSION;
- addrinfo hints, *res;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_family = AF_INET6;
- hints.ai_socktype = SOCK_STREAM;
- if (!getaddrinfo(T2CA(host), "1024", &hints, &res))
- {
- host = Inet6AddrToString(((SOCKADDR_IN6 *)res->ai_addr)->sin6_addr);
- freeaddrinfo(res);
- }
- else
- host = L"";
- }
- if (host == L"")
- {
- UINT temp;
- if(!GetSockName(host, temp))
- bError = true;
- }
- if (!bError)
- {
- // assamble EPRT command
- CString cmd;
- cmd.Format(L"EPRT |2|" + host + L"|%d|", nPort);
- if (!Send(cmd))
- bError = TRUE;
- }
- }
- else
- {
- LogMessage(FZ_LOG_WARNING, L"Protocol %d not supported", GetFamily());
- bError = true;
- }
- if (bError)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- }
- break;
- case FILETRANSFER_REST:
- DebugAssert(m_pDataFile);
- {
- CString command;
- __int64 transferoffset =
- pData->transferfile.get ?
- GetLength64(*m_pDataFile) :
- pData->transferdata.transfersize-pData->transferdata.transferleft;
- command.Format(L"REST %I64d", transferoffset);
- if (!Send(command))
- bError=TRUE;
- }
- break;
- case FILETRANSFER_RETRSTOR:
- // send RETR/STOR command to server
- if (!m_pTransferSocket)
- {
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- m_pTransferSocket->m_transferdata=pData->transferdata;
- if (GetOptionVal(OPTION_MPEXT_TRANSFER_ACTIVE_IMMEDIATELY) || !pData->bPasv)
- {
- m_pTransferSocket->SetActive();
- }
- CString filename;
- filename = pData->transferfile.remotepath.FormatFilename(pData->transferfile.remotefile, !pData->bUseAbsolutePaths);
- if(!Send((pData->transferfile.get?L"RETR ":(pData->transferdata.bResumeAppend)?L"APPE ":L"STOR ")+ filename))
- bError = TRUE;
- else
- {
- if (pData->bPasv)
- {
- // if PASV create the socket & initiate outbound data channel connection
- if (!ConnectTransferSocket(pData->host, pData->port))
- {
- bError=TRUE;
- }
- }
- }
- break;
- }
- if (bError)
- { //Error transferring the file
- LogMessage(FZ_LOG_INFO, L"Transfer error");
- ResetOperation(FZ_REPLY_ERROR);
- return;
- }
- }
- void CFtpControlSocket::TransferHandleListError()
- {
- if (m_pTransferSocket)
- delete m_pTransferSocket;
- m_pTransferSocket=0;
- m_Operation.nOpState = FILETRANSFER_NOLIST_SIZE;
- }
- static int atoui(const wchar_t * s)
- {
- wchar_t * endptr;
- int result = wcstol(s, &endptr, 10);
- if ((*s == L'\0') || (*endptr != L'\0'))
- {
- result = -1;
- }
- return result;
- }
- bool CFtpControlSocket::HandleMdtm(int code, t_directory::t_direntry::t_date & date)
- {
- bool result = false;
- if (code==2)
- {
- CString line = GetReply();
- if ( line.GetLength()>4 && line.Left(4) == L"213 " )
- {
- int y=0, M=0, d=0, h=0, m=0, s=0;
- bool hasseconds = false;
- line=line.Mid(4);
- y=atoui(line.Left(4));
- if ((y >= 0) && (line.GetLength() > 4))
- {
- line=line.Mid(4);
- M=atoui(line.Left(2));
- if ((M >= 0) && (line.GetLength() > 2))
- {
- line=line.Mid(2);
- d=atoui(line.Left(2));
- if ((d >= 0) && (line.GetLength() > 2))
- {
- line=line.Mid(2);
- h=atoui(line.Left(2));
- if ((h >= 0) && (line.GetLength() > 2))
- {
- line=line.Mid(2);
- m=atoui(line.Left(2));
- if ((m >= 0) && (line.GetLength() > 2))
- {
- line=line.Mid(2);
- s=_ttoi(line.Left(2));
- hasseconds = true;
- }
- }
- }
- if (M>0 && M<=12 && d>0 && d<=31 && h>=0 && h<24 && m>=0 && m<60 && s>=0 && s<60)
- {
- result = true;
- date.year = y;
- date.month = M;
- date.day = d;
- date.hour = h;
- date.minute = m;
- date.second = s;
- date.hastime = true;
- date.hasseconds = hasseconds;
- date.hasdate = true;
- date.utc = true;
- }
- }
- }
- }
- }
- return result;
- }
- bool CFtpControlSocket::HandleSize(int code, __int64 & size)
- {
- bool result = false;
- if (code == 2)
- {
- CString line = GetReply();
- if ((line.GetLength() > 4) && (line.Left(4) == L"213 "))
- {
- size = _ttoi64(line.Mid(4));
- result = true;
- }
- }
- return result;
- }
- void CFtpControlSocket::TransferFinished(bool preserveFileTimeForUploads)
- {
- CFileTransferData *pData=static_cast<CFileTransferData *>(m_Operation.pData);
- if (GetOptionVal(OPTION_PRESERVEDOWNLOADFILETIME) && m_pDataFile &&
- pData->transferfile.get)
- {
- m_pTools->PreserveDownloadFileTime(
- (HANDLE)m_pDataFile->m_hFile, reinterpret_cast<void *>(pData->transferfile.nUserData));
- }
- if (!pData->transferfile.get &&
- GetOptionVal(OPTION_MPEXT_PRESERVEUPLOADFILETIME) && preserveFileTimeForUploads &&
- ((m_serverCapabilities.GetCapability(mfmt_command) == yes) ||
- (m_serverCapabilities.GetCapability(mdtm_command) == yes)))
- {
- CString filename =
- pData->transferfile.remotepath.FormatFilename(pData->transferfile.remotefile, !pData->bUseAbsolutePaths);
- struct tm tm;
- if (m_pTools->GetFileModificationTimeInUtc((LPCTSTR)pData->transferfile.localfile, tm))
- {
- CString timestr;
- timestr.Format(L"%02d%02d%02d%02d%02d%02d",
- 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
- CString command;
- if (m_serverCapabilities.GetCapability(mfmt_command) == yes)
- {
- command = L"MFMT";
- }
- else
- {
- // Support for MDTM does not necessarily mean
- // that the server supports non-standard hack
- // of setting timestamp using
- // MFMT-like (two argument) call to MDTM.
- // IIS definitelly does.
- command = L"MDTM";
- }
- if (Send( command + L" " + timestr + L" " + filename))
- {
- m_Operation.nOpState = FILETRANSFER_MFMT;
- return;
- }
- }
- }
- //Transfer successful
- ResetOperation(FZ_REPLY_OK);
- }
- void CFtpControlSocket::Cancel(BOOL bQuit/*=FALSE*/)
- {
- const int nOpMode = m_Operation.nOpMode;
- if (nOpMode==CSMODE_CONNECT)
- DoClose(FZ_REPLY_CANCEL);
- else if (nOpMode & CSMODE_LIST)
- {
- if (m_Operation.nOpState == LIST_WAITFINISH)
- m_skipReply = true;
- ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_CANCEL);
- }
- else if (nOpMode & CSMODE_TRANSFER)
- {
- if (m_Operation.nOpState == FILETRANSFER_WAITFINISH || m_Operation.nOpState == FILETRANSFER_LIST_WAITFINISH)
- m_skipReply = true;
- ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_CANCEL | FZ_REPLY_ABORTED);
- }
- else if (nOpMode != CSMODE_NONE)
- ResetOperation(FZ_REPLY_ERROR | FZ_REPLY_CANCEL);
- if (nOpMode != CSMODE_NONE && !bQuit)
- ShowStatus(IDS_ERRORMSG_INTERRUPTED, FZ_LOG_ERROR);
- if (m_awaitsReply)
- m_skipReply = true;
- }
- void CFtpControlSocket::TransfersocketListenFinished(unsigned int ip, unsigned short port)
- {
- if (m_Operation.nOpMode&CSMODE_TRANSFER || m_Operation.nOpMode&CSMODE_LIST)
- {
- CString host;
- host.Format(L"%d,%d,%d,%d,%d,%d",ip%256,(ip>>8)%256,(ip>>16)%256,(ip>>24)%256,port%256,port>>8);
- Send(L"PORT "+host);
- }
- }
- void CFtpControlSocket::ResumeTransfer()
- {
- if (m_pTransferSocket && (m_Operation.nOpMode&CSMODE_TRANSFER || m_Operation.nOpMode&CSMODE_LIST))
- {
- m_pTransferSocket->OnSend(0);
- m_pTransferSocket->OnReceive(0);
- }
- }
- BOOL CFtpControlSocket::Create()
- {
- return CAsyncSocketEx::Create(0, SOCK_STREAM, FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE, 0, GetOptionVal(OPTION_ENABLE_IPV6) ? AF_UNSPEC : AF_INET);
- }
- void CFtpControlSocket::ResetOperation(int nSuccessful /*=FALSE*/)
- {
- if (nSuccessful & FZ_REPLY_CRITICALERROR)
- nSuccessful |= FZ_REPLY_ERROR;
- if (m_pTransferSocket)
- {
- ResetTransferSocket(nSuccessful & (FZ_REPLY_ERROR | FZ_REPLY_CANCEL));
- }
- if (m_pDataFile)
- delete m_pDataFile;
- m_pDataFile=0;
- if (m_Operation.nOpMode)
- {
- //Unset busy attribute so that new commands can be executed
- m_pOwner->SetBusy(FALSE);
- if (m_Operation.nOpMode&CSMODE_CONNECT && nSuccessful&FZ_REPLY_ERROR)
- {
- nSuccessful|=FZ_REPLY_DISCONNECTED;
- ShowStatus(IDS_ERRORMSG_CANTCONNECT, FZ_LOG_ERROR);
- }
- if (m_Operation.nOpMode & (CSMODE_LIST|CSMODE_LISTFILE|CSMODE_TRANSFER) && nSuccessful==FZ_REPLY_OK)
- m_LastSendTime=CTime::GetCurrentTime();
- //Update remote file entry
- if (m_Operation.pData &&
- m_Operation.nOpMode&CSMODE_TRANSFER &&
- (!((CFileTransferData*)m_Operation.pData)->transferfile.get) &&
- m_pDirectoryListing &&
- m_Operation.nOpState>=FILETRANSFER_RETRSTOR)
- {
- CString filename=((CFileTransferData*)m_Operation.pData)->transferfile.remotefile;
- CServerPath path=((CFileTransferData*)m_Operation.pData)->transferfile.remotepath;
- t_directory dir;
- BOOL res=FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path==path)
- {
- dir=*m_pDirectoryListing;
- res=TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound=m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path==path)
- {
- dir=WorkingDir;
- res=TRUE;
- }
- if (res)
- {
- int i;
- for (i=0; i<dir.num; i++)
- if (dir.direntry[i].name==filename)
- {
- dir.direntry[i].bUnsure = TRUE;
- if (nSuccessful & FZ_REPLY_ERROR)
- {
- dir.direntry[i].bUnsure = TRUE;
- if (!((CFileTransferData *)m_Operation.pData)->transferfile.get)
- dir.direntry[i].size = -1;
- if (!GetLength64(((CFileTransferData *)m_Operation.pData)->transferfile.localfile, dir.direntry[i].size))
- dir.direntry[i].size = -1;
- }
- dir.direntry[i].date.hasdate = false;
- break;
- }
- if (i==dir.num)
- {
- t_directory::t_direntry *entries=new t_directory::t_direntry[dir.num+1];
- int i;
- for (i=0; i<dir.num; i++)
- entries[i]=dir.direntry[i];
- entries[i].name=filename;
- entries[i].dir=FALSE;
- entries[i].date.hasdate=FALSE;
- entries[i].size=-1;
- if (nSuccessful&FZ_REPLY_OK)
- entries[i].bUnsure=FALSE;
- else
- entries[i].bUnsure=TRUE;
- delete [] dir.direntry;
- dir.direntry=entries;
- dir.num++;
- }
- BOOL updated=FALSE;
- if (m_pDirectoryListing && m_pDirectoryListing->path==dir.path)
- {
- updated=TRUE;
- SetDirectoryListing(&dir, bFound && WorkingDir.path == dir.path);
- }
- if (!updated)
- if (bFound && WorkingDir.path==dir.path)
- {
- updated = TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- }
- if (m_Operation.pData && nSuccessful&FZ_REPLY_ERROR)
- {
- if (m_Operation.nOpMode&CSMODE_TRANSFER)
- if (nSuccessful&FZ_REPLY_ABORTED)
- //Transfer aborted by user
- ShowStatus((m_Operation.nOpMode&CSMODE_DOWNLOAD)?IDS_ERRORMSG_DOWNLOADABORTED:IDS_ERRORMSG_UPLOADABORTED,FZ_LOG_ERROR);
- else
- ShowStatus(((CFileTransferData*)m_Operation.pData)->transferfile.get?IDS_ERRORMSG_DOWNLOADFAILED:IDS_ERRORMSG_UPLOADFAILED,FZ_LOG_ERROR);
- else if (m_Operation.nOpMode&CSMODE_LIST)
- ShowStatus(IDS_ERRORMSG_CANTGETLIST,FZ_LOG_ERROR);
- else if (m_Operation.nOpMode&CSMODE_LISTFILE)
- ShowStatus(IDS_ERRORMSG_CANTGETLISTFILE,FZ_LOG_ERROR);
- }
- else if (m_Operation.pData && m_Operation.nOpMode&CSMODE_TRANSFER && nSuccessful==FZ_REPLY_OK)
- ShowStatus(((CFileTransferData*)m_Operation.pData)->transferfile.get?IDS_STATUSMSG_DOWNLOADSUCCESSFUL:IDS_STATUSMSG_UPLOADSUCCESSFUL,FZ_LOG_STATUS);
- }
- else
- {
- // When control socket is waiting for reply
- // to keepalive (!IsReady), while new command comes,
- // its execution is postponed
- // (CMainThread::m_pPostKeepAliveCommand),
- // but the main thread
- // is set to busy state already (CMainThread::Command).
- // if connection is closed before without receiving reply,
- // main thread would stay busy forever.
- m_pOwner->SetBusy(FALSE);
- //No operation in progress
- nSuccessful&=FZ_REPLY_DISCONNECTED|FZ_REPLY_CANCEL;
- }
- if (nSuccessful&FZ_REPLY_DISCONNECTED)
- m_pOwner->SetWorkingDir(0); //Disconnected, reset working dir
- if (m_Operation.nOpMode)
- GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_REPLY, m_pOwner->m_LastCommand.id), nSuccessful);
- else
- GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_REPLY, 0), nSuccessful);
- m_Operation.nOpMode=0;
- m_Operation.nOpState=-1;
- if (m_Operation.pData)
- delete m_Operation.pData;
- m_Operation.pData=0;
- }
- void CFtpControlSocket::Delete(CString filename, const CServerPath &path, bool filenameOnly)
- {
- class CDeleteData : public CFtpControlSocket::t_operation::COpData
- {
- public:
- CDeleteData() {}
- virtual ~CDeleteData() {}
- CString m_FileName;
- CServerPath path;
- };
- if (filename!=L"")
- {
- DebugAssert(!path.IsEmpty());
- DebugAssert(m_Operation.nOpMode==CSMODE_NONE);
- DebugAssert(m_Operation.nOpState==-1);
- DebugAssert(!m_Operation.pData);
- m_Operation.nOpMode=CSMODE_DELETE;
- CString command = L"DELE ";
- if (!filenameOnly)
- {
- command += path.FormatFilename(filename);
- }
- else
- {
- command += filename;
- }
- if (!Send(command))
- return;
- CDeleteData *data=new CDeleteData;
- data->m_FileName=filename;
- data->path=path;
- m_Operation.pData=data;
- }
- else
- {
- DebugAssert(path.IsEmpty());
- DebugAssert(m_Operation.nOpMode==CSMODE_DELETE);
- DebugAssert(m_Operation.nOpState==-1);
- DebugAssert(m_Operation.pData);
- int res=GetReplyCode();
- if (res==2 || res==3)
- { //Remove file from cached dirs
- CDeleteData *pData=(CDeleteData *)m_Operation.pData;
- t_directory dir;
- BOOL res=FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path==pData->path)
- {
- dir=*m_pDirectoryListing;
- res=TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound=m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path==pData->path)
- {
- dir=WorkingDir;
- res=TRUE;
- }
- if (res)
- {
- BOOL found=FALSE;
- for (int i=0;i<dir.num;i++)
- {
- if (dir.direntry[i].name==pData->m_FileName)
- {
- DebugAssert(!dir.direntry[i].dir || dir.direntry[i].bLink);
- found=TRUE;
- break;
- }
- }
- if (found)
- {
- t_directory::t_direntry *direntry=new t_directory::t_direntry[dir.num-1];
- int j=0;
- int i;
- for (i=0; i<dir.num; i++)
- {
- if (dir.direntry[i].name==pData->m_FileName)
- continue;
- direntry[j]=dir.direntry[i];
- j++;
- }
- delete [] dir.direntry;
- dir.direntry=direntry;
- dir.num--;
- BOOL updated=FALSE;
- if (m_pDirectoryListing)
- if (m_pDirectoryListing->path==dir.path)
- {
- updated=TRUE;
- SetDirectoryListing(&dir);
- }
- if (!updated)
- if (WorkingDir.path==dir.path)
- {
- updated=TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- }
- }
- ResetOperation(FZ_REPLY_OK);
- }
- }
- void CFtpControlSocket::RemoveDir(CString dirname, const CServerPath &path)
- {
- class CRemoveDirData : public CFtpControlSocket::t_operation::COpData
- {
- public:
- CRemoveDirData() {}
- virtual ~CRemoveDirData() {}
- CString m_DirName;
- CServerPath path;
- };
- if (dirname != L"")
- {
- DebugAssert(!path.IsEmpty());
- DebugAssert(m_Operation.nOpMode == CSMODE_NONE);
- DebugAssert(m_Operation.nOpState == -1);
- DebugAssert(!m_Operation.pData);
- m_Operation.nOpMode = CSMODE_RMDIR;
- CServerPath newPath = path;
- if (!newPath.AddSubdir(dirname))
- {
- ShowStatus(L"Unable to concatenate path", FZ_LOG_ERROR);
- return;
- }
- if (!Send(L"RMD "+ newPath.GetPathUnterminated()))
- return;
- CRemoveDirData *data = new CRemoveDirData;
- data->m_DirName = dirname;
- data->path = path;
- m_Operation.pData = data;
- }
- else
- {
- DebugAssert(path.IsEmpty());
- DebugAssert(m_Operation.nOpMode == CSMODE_RMDIR);
- DebugAssert(m_Operation.nOpState == -1);
- DebugAssert(m_Operation.pData);
- int res = GetReplyCode();
- if (res == 2 || res == 3)
- { //Remove dir from cached dirs
- CRemoveDirData *pData= (CRemoveDirData *)m_Operation.pData;
- t_directory dir;
- BOOL res = FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path == pData->path)
- {
- dir = *m_pDirectoryListing;
- res = TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound = m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path == pData->path)
- {
- dir = WorkingDir;
- res = TRUE;
- }
- if (res)
- {
- BOOL found = FALSE;
- for (int i = 0; i < dir.num; i++)
- {
- if (dir.direntry[i].name == pData->m_DirName)
- {
- DebugAssert(dir.direntry[i].dir);
- found = TRUE;
- break;
- }
- }
- if (found)
- {
- t_directory::t_direntry *direntry = new t_directory::t_direntry[dir.num-1];
- int j = 0;
- int i;
- for (i = 0; i < dir.num; i++)
- {
- if (dir.direntry[i].name == pData->m_DirName)
- continue;
- direntry[j] = dir.direntry[i];
- j++;
- }
- delete [] dir.direntry;
- dir.direntry = direntry;
- dir.num--;
- BOOL updated = FALSE;
- if (m_pDirectoryListing)
- if (m_pDirectoryListing->path == dir.path)
- {
- updated = TRUE;
- SetDirectoryListing(&dir);
- }
- if (!updated)
- if (WorkingDir.path == dir.path)
- {
- updated = TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- }
- ResetOperation(FZ_REPLY_OK);
- }
- else
- ResetOperation(FZ_REPLY_ERROR);
- }
- }
- int CFtpControlSocket::CheckOverwriteFile()
- {
- if (!m_Operation.pData)
- {
- return FZ_REPLY_ERROR;
- }
- CFileTransferData *pData = reinterpret_cast<CFileTransferData *>(m_Operation.pData);
- int nReplyError = 0;
- CFileStatus64 status;
- BOOL res = GetStatus64(pData->transferfile.localfile, status);
- if (!res)
- {
- if (!pData->transferfile.get)
- {
- ShowStatus(IDS_ERRORMSG_CANTGETLISTFILE,FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_CRITICALERROR; //File has to exist when uploading
- }
- else
- {
- m_Operation.nOpState = FILETRANSFER_TYPE;
- }
- }
- else
- {
- if (status.m_attribute & 0x10)
- {
- nReplyError = FZ_REPLY_CRITICALERROR; //Can't transfer to/from dirs
- }
- else
- {
- _int64 localsize;
- if (!GetLength64(pData->transferfile.localfile, localsize))
- if (!pData->transferfile.get)
- nReplyError = FZ_REPLY_CRITICALERROR;
- else
- m_Operation.nOpState = FILETRANSFER_TYPE;
- CTime *localtime = NULL;
- TRY
- {
- if (status.m_has_mtime && status.m_mtime != -1)
- localtime = new CTime(status.m_mtime);
- }
- CATCH_ALL(e)
- {
- TCHAR buffer[1024];
- CString str =L"Exception creating CTime object: ";
- if (e->GetErrorMessage(buffer, 1024, NULL))
- str += buffer;
- else
- str += L"Unknown exception";
- LogMessageRaw(FZ_LOG_WARNING, str);
- localtime = NULL;
- }
- END_CATCH_ALL;
- BOOL bRemoteFileExists = FALSE;
- __int64 remotesize = -1;
- t_directory::t_direntry::t_date remotetime;
- if (m_pDirectoryListing)
- {
- for (int i=0; i<m_pDirectoryListing->num; i++)
- {
- CString remotefile = pData->transferfile.remotefile;
- if (m_pDirectoryListing->direntry[i].name == remotefile)
- {
- remotesize = m_pDirectoryListing->direntry[i].size;
- remotetime = m_pDirectoryListing->direntry[i].date;
- bRemoteFileExists = TRUE;
- break;
- }
- }
- }
- if (!bRemoteFileExists && pData->hasRemoteDate)
- {
- remotetime = pData->remoteDate;
- bRemoteFileExists = TRUE;
- }
- if (remotesize == -1 && pData->pFileSize)
- {
- remotesize = *pData->pFileSize;
- bRemoteFileExists = TRUE;
- }
- if (bRemoteFileExists || pData->transferfile.get )
- {
- COverwriteRequestData *pOverwriteData = new COverwriteRequestData;
- t_transferfile *pTransferFile = new t_transferfile;
- *pTransferFile = pData->transferfile;
- pOverwriteData->pTransferFile = pTransferFile;
- if (pData->transferfile.get)
- {
- int pos = pData->transferfile.localfile.ReverseFind(L'\\');
- // pos can be -1 here, e.g. in scripting, the code below still works then
- pOverwriteData->FileName1 = pData->transferfile.localfile.Mid(pos+1);
- pOverwriteData->FileName2 = pData->transferfile.remotefile;
- pOverwriteData->path1 = pData->transferfile.localfile.Left(pos+1);
- pOverwriteData->path2 = pData->transferfile.remotepath.GetPath();
- pOverwriteData->size1 = localsize;
- pOverwriteData->size2 = remotesize;
- }
- else
- {
- int pos = pData->transferfile.localfile.ReverseFind(L'\\');
- // pos can be -1 here, e.g. in scripting, the code below still works then
- pOverwriteData->FileName1 = pData->transferfile.remotefile;
- pOverwriteData->FileName2 = pData->transferfile.localfile.Mid(pos+1);
- pOverwriteData->path1 = pData->transferfile.remotepath.GetPath();
- pOverwriteData->path2 = pData->transferfile.localfile.Left(pos+1);
- pOverwriteData->size1 = remotesize;
- pOverwriteData->size2 = localsize;
- }
- pOverwriteData->localtime = localtime;
- pOverwriteData->remotetime = remotetime;
- pOverwriteData->nRequestID = m_pOwner->GetNextAsyncRequestID();
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_OVERWRITE), (LPARAM)pOverwriteData))
- {
- delete pOverwriteData;
- nReplyError = FZ_REPLY_ERROR;
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- m_Operation.nOpState = FILETRANSFER_WAIT;
- }
- }
- else
- {
- m_Operation.nOpState = FILETRANSFER_TYPE;
- delete localtime;
- }
- }
- }
- return nReplyError;
- }
- void CFtpControlSocket::SetFileExistsAction(int nAction, COverwriteRequestData *pData)
- {
- if (!pData)
- return;
- if (!(m_Operation.nOpMode & CSMODE_TRANSFER))
- return;
- if (m_Operation.nOpState != FILETRANSFER_WAIT)
- return;
- CFileTransferData* pTransferData = reinterpret_cast<CFileTransferData*>(m_Operation.pData);
- if (!pTransferData)
- return;
- pTransferData->transferdata.bResume = false;
- m_bCheckForTimeout = TRUE;
- int nReplyError = 0;
- switch (nAction)
- {
- case FILEEXISTS_SKIP:
- nReplyError = FZ_REPLY_OK;
- break;
- case FILEEXISTS_OVERWRITE:
- pTransferData->nWaitNextOpState = FILETRANSFER_TYPE;
- break;
- case FILEEXISTS_RENAME:
- if (pTransferData->transferfile.get)
- {
- CFileStatus64 status;
- if (GetStatus64(pData->FileName1, status))
- {
- ShowStatus(IDS_ERRORMSG_NAMEINUSE, FZ_LOG_ERROR);
- nReplyError= FZ_REPLY_CRITICALERROR;
- }
- else
- {
- pTransferData->transferfile.localfile = pData->path1+pData->FileName1;
- //Replace invalid characters in the local filename
- int pos = pTransferData->transferfile.localfile.ReverseFind(L'\\');
- for (int i = (pos+1); i < pTransferData->transferfile.localfile.GetLength(); i++)
- if (pTransferData->transferfile.localfile[i] == L':')
- pTransferData->transferfile.localfile.SetAt(i, L'_');
- pTransferData->nWaitNextOpState= FILETRANSFER_TYPE;
- }
- }
- else
- {
- DebugAssert(m_pDirectoryListing);
- int i;
- for (i = 0; i < m_pDirectoryListing->num; i++)
- {
- if (m_pDirectoryListing->direntry[i].name == pData->FileName1)
- {
- ShowStatus(IDS_ERRORMSG_NAMEINUSE, FZ_LOG_ERROR);
- nReplyError = FZ_REPLY_CRITICALERROR;
- break;
- }
- }
- if (i==m_pDirectoryListing->num)
- {
- pTransferData->transferfile.remotefile = pData->FileName1;
- pTransferData->nWaitNextOpState = FILETRANSFER_TYPE;
- }
- }
- break;
- case FILEEXISTS_RESUME:
- if (pData->size1 >= 0)
- {
- pTransferData->transferdata.bResume = TRUE;
- }
- pTransferData->nWaitNextOpState = FILETRANSFER_TYPE;
- break;
- case FILEEXISTS_COMPLETE:
- // Simulating transfer finish
- m_Operation.nOpState=FILETRANSFER_WAITFINISH;
- TransferFinished(true);
- return; // Avoid call to FileTransfer below
- }
- if (nReplyError == FZ_REPLY_OK)
- ResetOperation(FZ_REPLY_OK);
- else if (nReplyError)
- ResetOperation(FZ_REPLY_ERROR | nReplyError); //Error transferring the file
- else
- FileTransfer();
- }
- void CFtpControlSocket::SendKeepAliveCommand()
- {
- ShowStatus(L"Sending dummy command to keep session alive.", FZ_LOG_PROGRESS);
- m_bKeepAliveActive=TRUE;
- //Choose a random command from the list
- TCHAR commands[4][7]={L"PWD",L"REST 0",L"TYPE A",L"TYPE I"};
- int choice=(rand()*4)/(RAND_MAX+1);
- Send(commands[choice]);
- }
- void CFtpControlSocket::MakeDir(const CServerPath &path)
- {
- //Directory creation works like this:
- //Find existing parent and create subdirs one by one
- if (m_Operation.nOpState == MKD_INIT)
- {
- DebugAssert(!path.IsEmpty());
- DebugAssert(m_Operation.nOpMode==CSMODE_NONE);
- DebugAssert(!m_Operation.pData);
- m_Operation.nOpMode = CSMODE_MKDIR;
- if (!Send(L"CWD "+path.GetParent().GetPathUnterminated()))
- return;
- CMakeDirData *data = new CMakeDirData;
- data->path = path;
- data->Current = path.GetParent();
- data->Segments.push_front(path.GetLastSegment());
- m_Operation.pData = data;
- m_Operation.nOpState = MKD_FINDPARENT;
- }
- else if (m_Operation.nOpState==MKD_FINDPARENT)
- {
- DebugAssert(m_Operation.nOpMode==CSMODE_MKDIR);
- DebugAssert(path.IsEmpty());
- DebugAssert(m_Operation.pData);
- CMakeDirData *pData=(CMakeDirData *)m_Operation.pData;
- int res=GetReplyCode();
- if (res==2 || res==3)
- {
- m_pOwner->SetCurrentPath(pData->Current);
- m_Operation.nOpState=MKD_MAKESUBDIRS;
- pData->Current.AddSubdir(pData->Segments.front());
- CString Segment=pData->Segments.front();
- pData->Segments.pop_front();
- if (Send( L"MKD " + Segment))
- m_Operation.nOpState = MKD_CHANGETOSUBDIR;
- else
- return;
- }
- else
- {
- if (!pData->Current.HasParent())
- ResetOperation(FZ_REPLY_ERROR);
- else
- {
- pData->Segments.push_front(pData->Current.GetLastSegment());
- pData->Current=pData->Current.GetParent();
- if (!Send(L"CWD "+pData->Current.GetPathUnterminated()))
- return;
- }
- }
- }
- else if (m_Operation.nOpState==MKD_MAKESUBDIRS)
- {
- int res=GetReplyCode();
- if (res==2 || res==3)
- { //Create dir entry in parent dir
- CMakeDirData *pData=(CMakeDirData *)m_Operation.pData;
- DebugAssert(!pData->Segments.empty());
- m_pOwner->SetCurrentPath(pData->Current);
- pData->Current.AddSubdir(pData->Segments.front());
- CString Segment=pData->Segments.front();
- pData->Segments.pop_front();
- if (Send( L"MKD " + Segment))
- m_Operation.nOpState=MKD_CHANGETOSUBDIR;
- else
- return;
- }
- else
- ResetOperation(FZ_REPLY_ERROR);
- }
- else if (m_Operation.nOpState==MKD_CHANGETOSUBDIR)
- {
- CMakeDirData *pData=(CMakeDirData *)m_Operation.pData;
- int res=GetReplyCode();
- if (res==2 || res==3 || //Creation successful
- GetReply() == L"550 Directory already exists")//Creation was successful, although someone else did the work for us
- { //Create dir entry in parent dir
- CServerPath path2=pData->Current;
- if (path2.HasParent())
- {
- CString name=path2.GetLastSegment();
- path2=path2.GetParent();
- t_directory dir;
- BOOL res = FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path == path2)
- {
- dir = *m_pDirectoryListing;
- res = TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound = m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path == path2)
- {
- dir = WorkingDir;
- res = TRUE;
- }
- if (!res)
- {
- dir.path = path2;
- dir.server = m_CurrentServer;
- }
- int i;
- for (i=0; i<dir.num; i++)
- if (dir.direntry[i].name==name)
- {
- LogMessage(FZ_LOG_WARNING, L"Dir already exists in cache!");
- break;
- }
- if (i==dir.num)
- {
- t_directory::t_direntry *entries=new t_directory::t_direntry[dir.num+1];
- for (i=0;i<dir.num;i++)
- entries[i]=dir.direntry[i];
- entries[i].name=name;
- entries[i].dir=TRUE;
- entries[i].date.hasdate=FALSE;
- entries[i].size=-1;
- entries[i].bUnsure=FALSE;
- delete [] dir.direntry;
- dir.direntry=entries;
- dir.num++;
- BOOL updated = FALSE;
- if (m_pDirectoryListing && m_pDirectoryListing->path == dir.path)
- {
- updated = TRUE;
- SetDirectoryListing(&dir, bFound && WorkingDir.path == dir.path);
- }
- if (!updated)
- if (bFound && WorkingDir.path == dir.path)
- {
- updated = TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- }
- }
- //Continue operation even if MKD failed, maybe another thread did create this directory for us
- if (pData->Segments.empty())
- ResetOperation(FZ_REPLY_OK);
- else
- {
- if (Send( L"CWD " + pData->Current.GetPathUnterminated()))
- m_Operation.nOpState=MKD_MAKESUBDIRS;
- else
- return;
- }
- }
- else
- DebugFail();
- }
- void CFtpControlSocket::Rename(CString oldName, CString newName, const CServerPath &path, const CServerPath &newPath)
- {
- class CRenameData : public CFtpControlSocket::t_operation::COpData
- {
- public:
- CRenameData() {}
- virtual ~CRenameData() {}
- CString oldName, newName;
- CServerPath path;
- CServerPath newPath;
- };
- if (oldName != L"")
- {
- DebugAssert(newName != L"");
- DebugAssert(!path.IsEmpty());
- DebugAssert(m_Operation.nOpMode == CSMODE_NONE);
- DebugAssert(m_Operation.nOpState == -1);
- DebugAssert(!m_Operation.pData);
- m_Operation.nOpMode = CSMODE_RENAME;
- if (!Send(L"RNFR " + path.FormatFilename(oldName)))
- return;
- CRenameData *data = new CRenameData;
- data->oldName = oldName;
- data->newName = newName;
- data->path = path;
- data->newPath = newPath;
- m_Operation.pData = data;
- }
- else
- {
- DebugAssert(oldName == L"");
- DebugAssert(path.IsEmpty());
- DebugAssert(m_Operation.nOpMode == CSMODE_RENAME);
- DebugAssert(m_Operation.pData);
- CRenameData *pData = reinterpret_cast<CRenameData *>(m_Operation.pData);
- if (m_Operation.nOpState == -1)
- {
- int res = GetReplyCode();
- if (res == 2 || res == 3)
- {
- m_Operation.nOpState++;
- if (pData->newPath.IsEmpty())
- {
- if (!Send(L"RNTO " + pData->path.FormatFilename(((CRenameData *)m_Operation.pData)->newName)))
- return;
- }
- else
- if (!Send(L"RNTO " + pData->newPath.FormatFilename(((CRenameData *)m_Operation.pData)->newName)))
- return;
- }
- else
- ResetOperation(FZ_REPLY_ERROR);
- }
- else
- {
- int res = GetReplyCode();
- if (res == 2 || res == 3)
- { //Rename entry in cached directory
- CRenameData *pData = reinterpret_cast<CRenameData *>(m_Operation.pData);
- t_directory dir;
- BOOL res = FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path == pData->path)
- {
- dir = *m_pDirectoryListing;
- res = TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound = m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path == pData->path)
- {
- dir = WorkingDir;
- res = TRUE;
- }
- if (res)
- {
- for (int i=0; i<dir.num; i++)
- if (dir.direntry[i].name == pData->oldName)
- {
- if (pData->newPath.IsEmpty())
- {
- dir.direntry[i].name = pData->newName;
- BOOL updated = FALSE;
- if (m_pDirectoryListing && m_pDirectoryListing->path == dir.path)
- {
- updated = TRUE;
- SetDirectoryListing(&dir, WorkingDir.path == dir.path);
- }
- if (!updated)
- if (WorkingDir.path == dir.path)
- {
- updated = TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- else
- {
- t_directory::t_direntry oldentry = dir.direntry[i];
- for (int j = i+1; j < dir.num; j++)
- {
- dir.direntry[j-1] = dir.direntry[j];
- }
- dir.num--;
- BOOL updated = FALSE;
- if (m_pDirectoryListing && m_pDirectoryListing->path == dir.path)
- {
- updated = TRUE;
- SetDirectoryListing(&dir, WorkingDir.path == dir.path);
- }
- if (!updated)
- if (WorkingDir.path == dir.path)
- {
- updated = TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- BOOL res = FALSE;
- if (m_pDirectoryListing)
- {
- if (m_pDirectoryListing->path == pData->newPath)
- {
- dir = *m_pDirectoryListing;
- res = TRUE;
- }
- }
- t_directory WorkingDir;
- BOOL bFound = m_pOwner->GetWorkingDir(&WorkingDir);
- if (!res && bFound)
- if (WorkingDir.path == pData->newPath)
- {
- dir = WorkingDir;
- res = TRUE;
- }
- if (res)
- {
- t_directory::t_direntry *direntry = new t_directory::t_direntry[dir.num + 1];
- for (int i = 0; i < dir.num; i++)
- direntry[i] = dir.direntry[i];
- direntry[dir.num] = oldentry;
- direntry[dir.num].name = pData->newName;
- dir.num++;
- delete [] dir.direntry;
- dir.direntry = direntry;
- BOOL updated = FALSE;
- if (m_pDirectoryListing && m_pDirectoryListing->path == dir.path)
- {
- updated = TRUE;
- SetDirectoryListing(&dir, bFound && WorkingDir.path == dir.path);
- }
- if (!updated)
- if (bFound && WorkingDir.path == dir.path)
- {
- updated = TRUE;
- m_pOwner->SetWorkingDir(&dir);
- }
- }
- }
- break;
- }
- }
- ResetOperation(FZ_REPLY_OK);
- }
- else
- ResetOperation(FZ_REPLY_ERROR);
- }
- }
- }
- void CFtpControlSocket::SetVerifyCertResult(int nResult, t_SslCertData *pData)
- {
- DebugAssert(pData);
- if (!m_pSslLayer)
- return;
- if (!m_Operation.nOpMode == CSMODE_CONNECT)
- return;
- m_bCheckForTimeout = TRUE;
- m_pSslLayer->SetNotifyReply(pData->priv_data, SSL_VERIFY_CERT, nResult);
- m_LastRecvTime = CTime::GetCurrentTime();
- }
- void CFtpControlSocket::OnTimer()
- {
- CheckForTimeout();
- ResumeTransfer();
- if (GetOptionVal(OPTION_KEEPALIVE))
- {
- if (!m_pOwner->IsBusy() && m_pOwner->IsConnected() && !m_bKeepAliveActive)
- {
- //Getting intervals for the Keep Alive feature
- int low=GetOptionVal(OPTION_INTERVALLOW);
- int diff=GetOptionVal(OPTION_INTERVALHIGH)-low;
- //Choose a new delay
- int delay=low+(rand()*diff)/RAND_MAX;
- CTimeSpan span=CTime::GetCurrentTime()-m_LastSendTime;
- if (span.GetTotalSeconds()>=delay)
- SendKeepAliveCommand();
- }
- }
- }
- BOOL CFtpControlSocket::IsReady()
- {
- return !m_bKeepAliveActive;
- }
- void CFtpControlSocket::Chmod(CString filename, const CServerPath &path, int nValue)
- {
- m_Operation.nOpMode=CSMODE_CHMOD;
- CString str;
- str.Format( L"SITE CHMOD %03d %s", nValue, path.FormatFilename(filename));
- Send(str);
- }
- void CFtpControlSocket::SetAsyncRequestResult(int nAction, CAsyncRequestData *pData)
- {
- switch (pData->nRequestType)
- {
- case FZ_ASYNCREQUEST_OVERWRITE:
- SetFileExistsAction(nAction, (COverwriteRequestData *)pData);
- break;
- case FZ_ASYNCREQUEST_VERIFYCERT:
- SetVerifyCertResult(nAction, ((CVerifyCertRequestData *)pData)->pCertData );
- break;
- case FZ_ASYNCREQUEST_NEEDPASS:
- if (m_Operation.nOpMode!=CSMODE_CONNECT ||
- m_Operation.nOpState != CONNECT_NEEDPASS)
- break;
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != "")
- {
- DoClose();
- break;
- }
- if (!nAction)
- {
- DoClose(FZ_REPLY_CRITICALERROR|FZ_REPLY_CANCEL);
- ShowStatus(IDS_ERRORMSG_INTERRUPTED,FZ_LOG_ERROR);
- break;
- }
- else
- {
- m_bCheckForTimeout = TRUE;
- m_CurrentServer.pass=((CNeedPassRequestData *)pData)->Password;
- m_Operation.nOpState=((CNeedPassRequestData *)pData)->nOldOpState;
- CLogonData *pLogonData = static_cast<CLogonData *>(m_Operation.pData);
- pLogonData->waitForAsyncRequest = false;
- pLogonData->gotPassword = true;
- LogOnToServer(TRUE);
- }
- break;
- #ifndef MPEXT_NO_GSS
- case FZ_ASYNCREQUEST_GSS_AUTHFAILED:
- if (m_Operation.nOpMode!=CSMODE_CONNECT || m_Operation.nOpState!=CONNECT_GSS_FAILED)
- break;
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != "")
- {
- DoClose();
- break;
- }
- if (!nAction)
- {
- DoClose(FZ_REPLY_CRITICALERROR|FZ_REPLY_CANCEL);
- ShowStatus(IDS_ERRORMSG_INTERRUPTED,FZ_LOG_ERROR);
- break;
- }
- m_bCheckForTimeout = TRUE;
- m_Operation.nOpState=-1;
- LogOnToServer(TRUE);
- break;
- case FZ_ASYNCREQUEST_GSS_NEEDPASS:
- if (m_Operation.nOpMode!=CSMODE_CONNECT ||
- m_Operation.nOpState != CONNECT_GSS_NEEDPASS)
- break;
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != "")
- {
- DoClose();
- break;
- }
- if (!nAction)
- {
- DoClose(FZ_REPLY_CRITICALERROR|FZ_REPLY_CANCEL);
- ShowStatus(IDS_ERRORMSG_INTERRUPTED,FZ_LOG_ERROR);
- break;
- }
- else
- {
- m_bCheckForTimeout = TRUE;
- m_CurrentServer.pass=((CGssNeedPassRequestData *)pData)->pass;
- m_Operation.nOpState=((CGssNeedPassRequestData *)pData)->nOldOpState;
- LogOnToServer(TRUE);
- }
- break;
- case FZ_ASYNCREQUEST_GSS_NEEDUSER:
- if (m_Operation.nOpMode != CSMODE_CONNECT ||
- m_Operation.nOpState != CONNECT_GSS_NEEDUSER)
- break;
- if (!m_RecvBuffer.empty() && m_RecvBuffer.front() != "")
- {
- DoClose();
- break;
- }
- if (!nAction)
- {
- DoClose(FZ_REPLY_CRITICALERROR | FZ_REPLY_CANCEL);
- ShowStatus(IDS_ERRORMSG_INTERRUPTED, FZ_LOG_ERROR);
- break;
- }
- else
- {
- m_bCheckForTimeout = TRUE;
- m_CurrentServer.user = ((CGssNeedUserRequestData *)pData)->user;
- m_Operation.nOpState=((CGssNeedUserRequestData *)pData)->nOldOpState;
- LogOnToServer(TRUE);
- }
- break;
- #endif
- default:
- LogMessage(FZ_LOG_WARNING, L"Unknown request reply %d", pData->nRequestType);
- break;
- }
- }
- int CFtpControlSocket::OnLayerCallback(std::list<t_callbackMsg>& callbacks)
- {
- for (std::list<t_callbackMsg>::iterator iter = callbacks.begin(); iter != callbacks.end(); iter++)
- {
- if (iter->nType == LAYERCALLBACK_STATECHANGE)
- {
- if (CAsyncSocketEx::LogStateChange(iter->nParam1, iter->nParam2))
- {
- const TCHAR * state2Desc = CAsyncSocketEx::GetStateDesc(iter->nParam2);
- const TCHAR * state1Desc = CAsyncSocketEx::GetStateDesc(iter->nParam1);
- if (iter->pLayer == m_pProxyLayer)
- LogMessage(FZ_LOG_INFO, L"Proxy layer changed state from %s to %s", state2Desc, state1Desc);
- #ifndef MPEXT_NO_GSS
- else if (iter->pLayer == m_pGssLayer)
- LogMessage(FZ_LOG_INFO, L"m_pGssLayer changed state from %s to %s", state2Desc, state1Desc);
- #endif
- else if (iter->pLayer == m_pSslLayer)
- {
- delete [] iter->str;
- LogMessage(FZ_LOG_INFO, L"TLS layer changed state from %s to %s", state2Desc, state1Desc);
- }
- else
- LogMessage(FZ_LOG_INFO, L"Layer @ %d changed state from %s to %s", iter->pLayer, state2Desc, state1Desc);
- }
- }
- else if (iter->nType == LAYERCALLBACK_LAYERSPECIFIC)
- {
- USES_CONVERSION;
- if (iter->pLayer == m_pProxyLayer)
- {
- switch (iter->nParam1)
- {
- case PROXYERROR_NOERROR:
- ShowStatus(IDS_PROXY_CONNECTED, FZ_LOG_STATUS);
- break;
- case PROXYERROR_NOCONN:
- ShowStatus(IDS_ERRORMSG_PROXY_NOCONN, FZ_LOG_ERROR);
- break;
- case PROXYERROR_REQUESTFAILED:
- ShowStatus(IDS_ERRORMSG_PROXY_REQUESTFAILED, FZ_LOG_ERROR);
- if (iter->str)
- ShowStatus(A2T(iter->str), FZ_LOG_ERROR);
- break;
- case PROXYERROR_AUTHTYPEUNKNOWN:
- ShowStatus(IDS_ERRORMSG_PROXY_AUTHTYPEUNKNOWN, FZ_LOG_ERROR);
- break;
- case PROXYERROR_AUTHFAILED:
- ShowStatus(IDS_ERRORMSG_PROXY_AUTHFAILED, FZ_LOG_ERROR);
- break;
- case PROXYERROR_AUTHNOLOGON:
- ShowStatus(IDS_ERRORMSG_PROXY_AUTHNOLOGON, FZ_LOG_ERROR);
- break;
- case PROXYERROR_CANTRESOLVEHOST:
- ShowStatus(IDS_ERRORMSG_PROXY_CANTRESOLVEHOST, FZ_LOG_ERROR);
- break;
- default:
- LogMessage(FZ_LOG_WARNING, L"Unknown proxy error" );
- }
- }
- #ifndef MPEXT_NO_GSS
- else if (iter->pLayer == m_pGssLayer)
- {
- switch (iter->nParam1)
- {
- case GSS_INFO:
- LogMessageRaw(FZ_LOG_INFO, A2CT(iter->str));
- break;
- case GSS_ERROR:
- LogMessageRaw(FZ_LOG_APIERROR, A2CT(iter->str));
- break;
- case GSS_COMMAND:
- ShowStatus(A2CT(iter->str), FZ_LOG_COMMAND);
- break;
- case GSS_REPLY:
- ShowStatus(A2CT(iter->str), FZ_LOG_REPLY);
- break;
- }
- }
- #endif
- else if (iter->pLayer == m_pSslLayer)
- {
- USES_CONVERSION;
- switch (iter->nParam1)
- {
- case SSL_INFO:
- switch (iter->nParam2)
- {
- case SSL_INFO_ESTABLISHED:
- ShowStatus(IDS_STATUSMSG_SSLESTABLISHED, FZ_LOG_STATUS);
- if (m_Operation.nOpState == CONNECT_SSL_WAITDONE)
- {
- LogOnToServer();
- }
- break;
- }
- break;
- case SSL_FAILURE:
- switch (iter->nParam2)
- {
- case SSL_FAILURE_UNKNOWN:
- // CTransferSocket has a special treatment of SSL_FAILURE_UNKNOWN,
- // as an indication of a re-key failure.
- ShowStatus(IDS_ERRORMSG_UNKNOWNSSLERROR, FZ_LOG_ERROR);
- break;
- case SSL_FAILURE_ESTABLISH:
- ShowStatus(IDS_ERRORMSG_CANTESTABLISHSSLCONNECTION, FZ_LOG_ERROR);
- break;
- case SSL_FAILURE_INITSSL:
- ShowStatus(IDS_ERRORMSG_CANTINITSSL, FZ_LOG_ERROR);
- break;
- case SSL_FAILURE_VERIFYCERT:
- ShowStatus(IDS_ERRORMSG_SSLCERTIFICATEERROR, FZ_LOG_ERROR);
- break;
- case SSL_FAILURE_CERTREJECTED:
- ShowStatus(IDS_ERRORMSG_CERTREJECTED, FZ_LOG_ERROR);
- m_bDidRejectCertificate = TRUE;
- break;
- }
- TriggerEvent(FD_CLOSE);
- break;
- case SSL_VERIFY_CERT:
- t_SslCertData *pData = new t_SslCertData;
- LPTSTR CertError = NULL;
- if (m_pSslLayer->GetPeerCertificateData(*pData, CertError))
- {
- CVerifyCertRequestData *pRequestData = new CVerifyCertRequestData;
- pRequestData->nRequestID=m_pOwner->GetNextAsyncRequestID();
- pRequestData->pCertData = pData;
- if (!GetIntern()->PostMessage(FZ_MSG_MAKEMSG(FZ_MSG_ASYNCREQUEST, FZ_ASYNCREQUEST_VERIFYCERT), (LPARAM)pRequestData))
- {
- delete pRequestData->pCertData;
- delete pRequestData;
- ResetOperation(FZ_REPLY_ERROR);
- }
- else
- {
- m_bCheckForTimeout = FALSE;
- }
- delete [] iter->str;
- continue;
- }
- else
- {
- delete pData;
- delete [] iter->str;
- CString str;
- str.Format(TLS_CERT_DECODE_ERROR, CertError);
- ShowStatus(str, FZ_LOG_ERROR);
- ResetOperation(FZ_REPLY_ERROR);
- continue;
- }
- break;
- }
- delete [] iter->str;
- continue;
- }
- #ifndef MPEXT_NO_GSS
- else
- if (iter->pLayer == m_pGssLayer)
- {
- if (iter->nParam1 == GSS_AUTHCOMPLETE ||
- iter->nParam1 == GSS_AUTHFAILED)
- {
- LogOnToServer(TRUE);
- delete [] iter->str;
- continue;
- }
- }
- #endif
- }
- delete [] iter->str;
- }
- return 0;
- }
- _int64 CFtpControlSocket::GetSpeedLimit(CTime &time, int valType, int valValue)
- {
- int type = GetOptionVal(valType);
- if ( type == 1)
- return ( _int64)GetOptionVal(valValue) * 1024;
- return ( _int64)1000000000000; // I hope that when there will be something with 1000GB/s then I'll change it :)
- }
- _int64 CFtpControlSocket::GetSpeedLimit(enum transferDirection direction, CTime &time)
- {
- if (direction == download)
- return GetSpeedLimit(time, OPTION_SPEEDLIMIT_DOWNLOAD_TYPE, OPTION_SPEEDLIMIT_DOWNLOAD_VALUE);
- else
- return GetSpeedLimit(time, OPTION_SPEEDLIMIT_UPLOAD_TYPE, OPTION_SPEEDLIMIT_UPLOAD_VALUE);
- return ( _int64)1000000000000;
- }
- _int64 CFtpControlSocket::GetAbleToUDSize( bool &beenWaiting, CTime &curTime, _int64 &curLimit, std::list<CFtpControlSocket::t_ActiveList>::iterator &iter, enum transferDirection direction, int nBufSize)
- {
- beenWaiting = false;
- CTime nowTime = CTime::GetCurrentTime();
- _int64 ableToRead = BUFSIZE;
- if ( nowTime == curTime)
- {
- ableToRead = iter->nBytesAvailable;
- if (ableToRead <= 0)
- {
- // we should wait till next second
- nowTime = CTime::GetCurrentTime();
- while (nowTime == curTime && !iter->nBytesAvailable)
- {
- if (beenWaiting)
- {
- //Check if there are other commands in the command queue.
- MSG msg;
- if (PeekMessage(&msg, 0, m_pOwner->m_nInternalMessageID, m_pOwner->m_nInternalMessageID, PM_NOREMOVE))
- {
- LogMessage(FZ_LOG_INFO, L"Message waiting in queue, resuming later");
- return 0;
- }
- }
- m_SpeedLimitSync.Unlock();
- Sleep(100);
- m_SpeedLimitSync.Lock();
- nowTime = CTime::GetCurrentTime();
- beenWaiting = true;
- // Since we didn't hold the critical section for some time, we have to renew the iterator
- for (iter = m_InstanceList[direction].begin(); iter != m_InstanceList[direction].end(); iter++)
- if (iter->pOwner == this)
- break;
- if (iter == m_InstanceList[direction].end())
- return 0;
- }
- }
- ableToRead = iter->nBytesAvailable;
- }
- if (nowTime != curTime)
- {
- if (ableToRead > 0)
- ableToRead = 0;
- curLimit = GetSpeedLimit(direction, curTime);
- __int64 nMax = curLimit / m_InstanceList[direction].size();
- _int64 nLeft = 0;
- int nCount = 0;
- std::list<t_ActiveList>::iterator iter2;
- for (iter2 = m_InstanceList[direction].begin(); iter2 != m_InstanceList[direction].end(); iter2++)
- {
- if (iter2->nBytesAvailable>0)
- {
- nLeft += iter2->nBytesAvailable;
- iter2->nBytesTransferred = 1;
- }
- else
- {
- nCount++;
- iter2->nBytesTransferred = 0;
- }
- iter2->nBytesAvailable = nMax;
- }
- if (nLeft && nCount)
- {
- nMax = nLeft / nCount;
- for (iter2 = m_InstanceList[direction].begin(); iter2 != m_InstanceList[direction].end(); iter2++)
- {
- if (!iter2->nBytesTransferred)
- iter2->nBytesAvailable += nMax;
- else
- iter2->nBytesTransferred = 0;
- }
- }
- ableToRead = iter->nBytesAvailable;
- }
- curTime = nowTime;
- if (!nBufSize)
- nBufSize = BUFSIZE;
- if (ableToRead > nBufSize)
- ableToRead = nBufSize;
- return ableToRead;
- }
- _int64 CFtpControlSocket::GetAbleToTransferSize(enum transferDirection direction, bool &beenWaiting, int nBufSize)
- {
- m_SpeedLimitSync.Lock();
- std::list<t_ActiveList>::iterator iter;
- for (iter = m_InstanceList[direction].begin(); iter != m_InstanceList[direction].end(); iter++)
- if (iter->pOwner == this)
- break;
- if (iter == m_InstanceList[direction].end())
- {
- t_ActiveList item;
- CTime time = CTime::GetCurrentTime();
- item.nBytesAvailable = GetSpeedLimit(direction, time) / (m_InstanceList[direction].size() + 1);
- item.nBytesTransferred = 0;
- item.pOwner = this;
- m_InstanceList[direction].push_back(item);
- iter = m_InstanceList[direction].end();
- iter--;
- }
- _int64 limit = GetAbleToUDSize(beenWaiting, m_CurrentTransferTime[direction], m_CurrentTransferLimit[direction], iter, direction, nBufSize);
- m_SpeedLimitSync.Unlock();
- return limit;
- }
- BOOL CFtpControlSocket::RemoveActiveTransfer()
- {
- BOOL bFound = FALSE;
- m_SpeedLimitSync.Lock();
- std::list<t_ActiveList>::iterator iter;
- for (int i = 0; i < 2; i++)
- {
- for (iter = m_InstanceList[i].begin(); iter != m_InstanceList[i].end(); iter++)
- if (iter->pOwner == this)
- {
- m_InstanceList[i].erase(iter);
- bFound = TRUE;
- break;
- }
- }
- m_SpeedLimitSync.Unlock();
- return bFound;
- }
- BOOL CFtpControlSocket::SpeedLimitAddTransferredBytes(enum transferDirection direction, _int64 nBytesTransferred)
- {
- m_SpeedLimitSync.Lock();
- std::list<t_ActiveList>::iterator iter;
- for (iter = m_InstanceList[direction].begin(); iter != m_InstanceList[direction].end(); iter++)
- if (iter->pOwner == this)
- {
- if (iter->nBytesAvailable > nBytesTransferred)
- iter->nBytesAvailable -= nBytesTransferred;
- else
- iter->nBytesAvailable = 0;
- iter->nBytesTransferred += nBytesTransferred;
- m_SpeedLimitSync.Unlock();
- return TRUE;
- }
- m_SpeedLimitSync.Unlock();
- return FALSE;
- }
- CString CFtpControlSocket::ConvertDomainName(CString domain)
- {
- USES_CONVERSION;
- LPCWSTR buffer = T2CW(domain);
- char *utf8 = new char[wcslen(buffer) * 2 + 2];
- if (!WideCharToMultiByte(CP_UTF8, 0, buffer, -1, utf8, wcslen(buffer) * 2 + 2, 0, 0))
- {
- delete [] utf8;
- LogMessage(FZ_LOG_WARNING, L"Could not convert domain name");
- return domain;
- }
- char *output = 0;
- output = strdup(utf8);
- delete [] utf8;
- CString result = A2T(output);
- free(output);
- return result;
- }
- void CFtpControlSocket::LogSocketMessageRaw(int nMessageType, LPCTSTR pMsg)
- {
- LogMessageRaw(nMessageType, pMsg);
- }
- bool CFtpControlSocket::LoggingSocketMessage(int nMessageType)
- {
- return LoggingMessageType(nMessageType);
- }
- BOOL CFtpControlSocket::ParsePwdReply(CString& rawpwd)
- {
- CServerPath realPath;
- BOOL Result = ParsePwdReply(rawpwd, realPath);
- if (Result)
- {
- m_pOwner->SetCurrentPath(realPath);
- }
- return Result;
- }
- BOOL CFtpControlSocket::ParsePwdReply(CString& rawpwd, CServerPath & realPath)
- {
- CListData *pData = static_cast<CListData *>(m_Operation.pData);
- DebugAssert(pData);
- int pos1 = rawpwd.Find(L'"');
- int pos2 = rawpwd.ReverseFind(L'"');
- if (pos1 == -1 || pos2 == -1 || pos1 >= pos2)
- {
- LogMessage(FZ_LOG_WARNING, L"No quoted path found, try using first token as path");
- pos1 = rawpwd.Find(L' ');
- if (pos1 != -1)
- {
- pos2 = rawpwd.Find(L' ', pos1 + 1);
- if (pos2 == -1)
- pos2 = rawpwd.GetLength();
- }
- if (pos1 == -1)
- {
- LogMessage(FZ_LOG_WARNING, L"Can't parse path!");
- ResetOperation(FZ_REPLY_ERROR);
- return FALSE;
- }
- }
- rawpwd = rawpwd.Mid(pos1 + 1, pos2 - pos1 - 1);
- realPath = m_pOwner->GetCurrentPath();
- realPath.SetServer(m_CurrentServer);
- if (!realPath.SetPath(rawpwd))
- {
- LogMessage(FZ_LOG_WARNING, L"Can't parse path!");
- ResetOperation(FZ_REPLY_ERROR);
- return FALSE;
- }
- return TRUE;
- }
- void CFtpControlSocket::DiscardLine(CStringA line)
- {
- if (m_Operation.nOpMode == CSMODE_CONNECT && m_Operation.nOpState == CONNECT_FEAT)
- {
- line.MakeUpper();
- while (line.Left(1) == " ")
- {
- line = line.Mid(1, line.GetLength() - 1);
- }
- #ifndef MPEXT_NO_ZLIB
- if (line == "MODE Z" || line.Left(7) == "MODE Z ")
- m_zlibSupported = true;
- else
- #endif
- if (line == "UTF8" && m_CurrentServer.nUTF8 != 2)
- m_bAnnouncesUTF8 = true;
- else if (line == "CLNT" || line.Left(5) == "CLNT ")
- m_hasClntCmd = true;
- else if (line == "MLSD")
- {
- m_serverCapabilities.SetCapability(mlsd_command, yes);
- }
- else if (line == "MDTM")
- {
- m_serverCapabilities.SetCapability(mdtm_command, yes);
- }
- else if (line.Left(4) == "MLST")
- {
- USES_CONVERSION;
- std::string facts;
- if (line.GetLength() > 5)
- {
- facts = (LPCSTR)line.Mid(5, line.GetLength() - 5);
- }
- m_serverCapabilities.SetCapability(mlsd_command, yes, facts);
- }
- else if (line == "MFMT")
- {
- m_serverCapabilities.SetCapability(mfmt_command, yes);
- }
- }
- else if (m_Operation.nOpMode == CSMODE_LISTFILE)
- {
- m_ListFile = line;
- }
- }
- int CFtpControlSocket::FileTransferListState(bool get)
- {
- int Result;
- if (GetOptionVal(OPTION_MPEXT_NOLIST) && !get)
- {
- Result = FILETRANSFER_TYPE;
- }
- else
- {
- Result = NeedModeCommand() ? FILETRANSFER_LIST_MODE : (NeedOptsCommand() ? FILETRANSFER_LIST_OPTS : FILETRANSFER_LIST_TYPE);
- }
- return Result;
- }
- bool CFtpControlSocket::NeedModeCommand()
- {
- #ifdef MPEXT_NO_ZLIB
- return false;
- #else
- bool useZlib;
- if (m_Operation.nOpMode == CSMODE_LIST || (m_Operation.nOpMode == CSMODE_TRANSFER && m_Operation.nOpMode <= FILETRANSFER_TYPE))
- useZlib = GetOptionVal(OPTION_MODEZ_USE) != 0;
- else
- useZlib = GetOptionVal(OPTION_MODEZ_USE) > 1;
- if (!m_useZlib && !m_zlibSupported)
- return false;
- return m_useZlib != useZlib;
- #endif
- }
- bool CFtpControlSocket::NeedOptsCommand()
- {
- #ifndef MPEXT_NO_ZLIB
- if (!m_useZlib)
- #endif
- return false;
- #ifndef MPEXT_NO_ZLIB
- return m_zlibLevel != GetOptionVal(OPTION_MODEZ_LEVEL);
- #endif
- }
- CString CFtpControlSocket::GetReply()
- {
- if (m_RecvBuffer.empty())
- return L"";
- USES_CONVERSION;
- LPCSTR line;
- if ((m_Operation.nOpMode&CSMODE_LISTFILE) && (m_Operation.nOpState==LISTFILE_MLST) &&
- (GetReplyCode() == 2))
- {
- // this is probably never used anyway
- line = (LPCSTR)m_ListFile;
- }
- else
- {
- line = (LPCSTR)m_RecvBuffer.front();
- }
- if (m_bUTF8)
- {
- // convert from UTF-8 to ANSI
- if (DetectUTF8Encoding(RawByteString(line)) == etANSI)
- {
- if (m_CurrentServer.nUTF8 != 1)
- {
- LogMessage(FZ_LOG_WARNING, L"Server does not send proper UTF-8, falling back to local charset");
- m_bUTF8 = false;
- }
- return A2CT(line);
- }
- // convert from UTF-8 to ANSI
- int len = MultiByteToWideChar(CP_UTF8, 0, line, -1, NULL, 0);
- if (!len)
- {
- m_RecvBuffer.pop_front();
- if (m_RecvBuffer.empty())
- m_RecvBuffer.push_back("");
- return L"";
- }
- else
- {
- LPWSTR p1 = new WCHAR[len + 1];
- MultiByteToWideChar(CP_UTF8, 0, line, -1 , (LPWSTR)p1, len + 1);
- CString reply = W2CT(p1);
- delete [] p1;
- return reply;
- }
- }
- else
- return A2CT(line);
- }
- void CFtpControlSocket::OnSend(int nErrorCode)
- {
- if (!m_sendBufferLen || !m_sendBuffer || m_awaitsReply)
- return;
- int res = CAsyncSocketEx::Send(m_sendBuffer, m_sendBufferLen);
- if (res == -1)
- {
- int Error = GetLastError();
- if (Error != WSAEWOULDBLOCK)
- {
- LogError(Error);
- ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, FZ_LOG_ERROR);
- DoClose();
- }
- return;
- }
- if (!res)
- {
- ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, FZ_LOG_ERROR);
- DoClose();
- }
- m_awaitsReply = true;
- m_LastSendTime = CTime::GetCurrentTime();
- if (res == m_sendBufferLen)
- {
- delete [] m_sendBuffer;
- m_sendBuffer = 0;
- m_sendBufferLen = 0;
- }
- else
- {
- char* tmp = new char[m_sendBufferLen - res];
- memcpy(tmp, m_sendBuffer + res, m_sendBufferLen - res);
- delete [] m_sendBuffer;
- m_sendBuffer = tmp;
- m_sendBufferLen -= res;
- }
- }
- bool CFtpControlSocket::IsMisleadingListResponse()
- {
- // Some servers are broken. Instead of an empty listing, some MVS servers
- // for example they return something "550 no members found"
- // Other servers return "550 No files found."
- CString retmsg = GetReply();
- if (!retmsg.CompareNoCase(L"550 No members found."))
- return true;
- if (!retmsg.CompareNoCase(L"550 No data sets found."))
- return true;
- if (!retmsg.CompareNoCase(L"550 No files found."))
- return true;
- return false;
- }
- bool CFtpControlSocket::IsRoutableAddress(const CString & host)
- {
- USES_CONVERSION;
- if (host.Left(3) == L"127" ||
- host.Left(3) == L"10." ||
- host.Left(7) == L"192.168" ||
- host.Left(7) == L"169.254")
- {
- return false;
- }
- else if (host.Left(3) == L"172")
- {
- CString middle = host.Mid(4);
- int pos = middle.Find(L".");
- long part = atol(T2CA(middle.Left(pos)));
- if ((part >= 16) && (part <= 31))
- {
- return false;
- }
- }
- return true;
- }
- bool CFtpControlSocket::CheckForcePasvIp(CString & host)
- {
- bool result = true;
- unsigned int tmpPort;
- CString ahost;
- switch (m_CurrentServer.iForcePasvIp)
- {
- case 0: // on
- if (!GetPeerName(ahost, tmpPort))
- {
- // this should happen with proxy server only
- int logontype = GetOptionVal(OPTION_LOGONTYPE);
- // do not know what to do, if there's FTP proxy
- if (!logontype)
- {
- // this is a host name, not an IP, but it should not be a problem
- ahost = m_CurrentServer.host;
- }
- }
- if (ahost != host)
- {
- LogMessage(FZ_LOG_WARNING, L"Using host address %s instead of the one suggested by the server: %s", ahost, host);
- host = ahost;
- }
- break;
- case 1: // off
- // noop
- break;
- default: // auto
- if (!GetPeerName(ahost, tmpPort))
- {
- LogMessage(FZ_LOG_PROGRESS, L"Error retrieving server address, cannot test if address is routable");
- }
- else if (!IsRoutableAddress(host) && IsRoutableAddress(ahost))
- {
- LogMessage(FZ_LOG_WARNING, L"Server sent passive reply with unroutable address %s, using host address instead.", host, ahost);
- host = ahost;
- }
- break;
- }
- return result;
- }
- CFtpListResult * CFtpControlSocket::CreateListResult(bool mlst)
- {
- CFtpListResult * Result =
- new CFtpListResult(
- m_CurrentServer, mlst, &m_bUTF8, GetOptionVal(OPTION_VMSALLREVISIONS), GetOptionVal(OPTION_DEBUGSHOWLISTING));
- Result->InitIntern(GetIntern());
- return Result;
- }
- //---------------------------------------------------------------------------
- ftp_capabilities_t TFTPServerCapabilities::GetCapability(ftp_capability_names_t Name)
- {
- t_cap tcap = FCapabilityMap[Name];
- return tcap.cap;
- }
- ftp_capabilities_t TFTPServerCapabilities::GetCapabilityString(ftp_capability_names_t Name, std::string * Option)
- {
- t_cap tcap = FCapabilityMap[Name];
- if (Option)
- *Option = tcap.option;
- return tcap.cap;
- }
- void TFTPServerCapabilities::SetCapability(ftp_capability_names_t Name, ftp_capabilities_t Cap)
- {
- t_cap tcap = FCapabilityMap[Name];
- tcap.cap = Cap;
- tcap.number = 1;
- FCapabilityMap[Name] = tcap;
- }
- void TFTPServerCapabilities::SetCapability(ftp_capability_names_t Name, ftp_capabilities_t Cap, const std::string & Option)
- {
- t_cap tcap = FCapabilityMap[Name];
- tcap.cap = Cap;
- tcap.option = Option;
- tcap.number = 0;
- FCapabilityMap[Name] = tcap;
- }
|