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