| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350 | //---------------------------------------------------------------------------#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/////////////////////////////////////////////////////////////////////////////// CFtpControlSocketstd::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 16384CFtpControlSocket::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 -20bool 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),      GetOptionVal(OPTION_MPEXT_MIN_TLS_VERSION),      GetOptionVal(OPTION_MPEXT_MAX_TLS_VERSION));    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;    }  }  m_ServerName = logontype?fwhost:hostname;  m_LastRecvTime = m_LastSendTime = CTime::GetCurrentTime();  m_Operation.pData = new CLogonData();}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),        GetOptionVal(OPTION_MPEXT_MIN_TLS_VERSION),        GetOptionVal(OPTION_MPEXT_MAX_TLS_VERSION));      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.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;        for (int i = 0; i < m_CurrentServer.pass.GetLength(); i++)          if (m_CurrentServer.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 "+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 "+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 4096void 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;    if (GetLastError() != WSAEWOULDBLOCK)    {      ShowStatus(IDS_STATUSMSG_DISCONNECTED, FZ_LOG_ERROR);      DoClose();    }    return;  }  if (!numread)  {    delete [] buffer;    buffer = NULL;    ShowStatus(IDS_STATUSMSG_DISCONNECTED, FZ_LOG_ERROR);    DoClose();  }  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*/){  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)      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;    if (GetOptionVal(OPTION_DEBUGSHOWLISTING))      m_pTransferSocket->m_pListResult->SendToMessageLog();    pData->pDirectoryListing->direntry = m_pTransferSocket->m_pListResult->getList(num, false);    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;    }  }  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;      int size = m_ListFile.GetLength();      char *buffer = new char[size + 1];      memmove(buffer, (LPCSTR)m_ListFile, m_ListFile.GetLength());      CFtpListResult * pListResult = new CFtpListResult(m_CurrentServer, &m_bUTF8);      pListResult->InitIntern(GetIntern());      pListResult->AddData(buffer, size);      if (GetOptionVal(OPTION_DEBUGSHOWLISTING))        pListResult->SendToMessageLog();      pData->direntry = pListResult->getList(num, true);      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::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        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;      if (GetOptionVal(OPTION_DEBUGSHOWLISTING))        m_pTransferSocket->m_pListResult->SendToMessageLog();      pData->pDirectoryListing->direntry=m_pTransferSocket->m_pListResult->getList(num, false);      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      {        delete m_pTransferSocket;        m_pTransferSocket=0;      }    }  }  //////////////////  //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 (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      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    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(){  if (!GetOptionVal(OPTION_LIMITPORTRANGE))    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);  else  {    int min=GetOptionVal(OPTION_PORTRANGELOW);    int max=GetOptionVal(OPTION_PORTRANGEHIGH);    if (min>=max)    {      ShowStatus(IDS_ERRORMSG_CANTCREATEDUETOPORTRANGE,FZ_LOG_ERROR);      return FALSE;    }    int startport = static_cast<int>(min+((double)rand()*(max-min))/(RAND_MAX+1));    int port = startport;    while (!CAsyncSocketEx::Create(port, SOCK_STREAM, FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT |  FD_CONNECT | FD_CLOSE, 0, GetOptionVal(OPTION_ENABLE_IPV6) ? AF_UNSPEC : AF_INET))    {      port++;      if (port>max)        port=min;      if (port==startport)      {        ShowStatus(IDS_ERRORMSG_CANTCREATEDUETOPORTRANGE,FZ_LOG_ERROR);        return FALSE;      }      if (!InitConnect())        return FALSE;    }  }  return TRUE;}void CFtpControlSocket::ResetOperation(int nSuccessful /*=FALSE*/){  if (nSuccessful & FZ_REPLY_CRITICALERROR)    nSuccessful |= FZ_REPLY_ERROR;  if (m_pTransferSocket)    delete m_pTransferSocket;  m_pTransferSocket=0;  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)      DebugFail();  }  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:            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 == "SIZE")    {      m_serverCapabilities.SetCapability(size_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)  {    if (GetLastError() != WSAEWOULDBLOCK)    {      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;}//---------------------------------------------------------------------------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;}
 |