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