Experimental IRC client, daemon and bot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

degesch.c 383KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950
  1. /*
  2. * degesch.c: the experimental IRC client
  3. *
  4. * Copyright (c) 2015 - 2018, Přemysl Janouch <p@janouch.name>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any
  7. * purpose with or without fee is hereby granted.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  12. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  14. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  15. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. *
  17. */
  18. // A table of all attributes we use for output
  19. #define ATTR_TABLE(XX) \
  20. XX( PROMPT, "prompt", "Terminal attrs for the prompt" ) \
  21. XX( RESET, "reset", "String to reset terminal attributes" ) \
  22. XX( DATE_CHANGE, "date_change", "Terminal attrs for date change" ) \
  23. XX( READ_MARKER, "read_marker", "Terminal attrs for the read marker" ) \
  24. XX( WARNING, "warning", "Terminal attrs for warnings" ) \
  25. XX( ERROR, "error", "Terminal attrs for errors" ) \
  26. XX( EXTERNAL, "external", "Terminal attrs for external lines" ) \
  27. XX( TIMESTAMP, "timestamp", "Terminal attrs for timestamps" ) \
  28. XX( HIGHLIGHT, "highlight", "Terminal attrs for highlights" ) \
  29. XX( ACTION, "action", "Terminal attrs for user actions" ) \
  30. XX( USERHOST, "userhost", "Terminal attrs for user@host" ) \
  31. XX( JOIN, "join", "Terminal attrs for joins" ) \
  32. XX( PART, "part", "Terminal attrs for parts" )
  33. enum
  34. {
  35. #define XX(x, y, z) ATTR_ ## x,
  36. ATTR_TABLE (XX)
  37. #undef XX
  38. ATTR_COUNT
  39. };
  40. // User data for logger functions to enable formatted logging
  41. #define print_fatal_data ((void *) ATTR_ERROR)
  42. #define print_error_data ((void *) ATTR_ERROR)
  43. #define print_warning_data ((void *) ATTR_WARNING)
  44. #include "config.h"
  45. #define PROGRAM_NAME "degesch"
  46. #include "common.c"
  47. #include "kike-replies.c"
  48. #include <langinfo.h>
  49. #include <locale.h>
  50. #include <pwd.h>
  51. #include <sys/utsname.h>
  52. #include <wchar.h>
  53. #include <termios.h>
  54. #include <sys/ioctl.h>
  55. #include <curses.h>
  56. #include <term.h>
  57. // Literally cancer
  58. #undef lines
  59. #undef columns
  60. #include <ffi.h>
  61. #ifdef HAVE_LUA
  62. #include <lua.h>
  63. #include <lualib.h>
  64. #include <lauxlib.h>
  65. #endif // HAVE_LUA
  66. // --- Terminal information ----------------------------------------------------
  67. static struct
  68. {
  69. bool initialized; ///< Terminal is available
  70. bool stdout_is_tty; ///< `stdout' is a terminal
  71. bool stderr_is_tty; ///< `stderr' is a terminal
  72. struct termios termios; ///< Terminal attributes
  73. char *color_set_fg[256]; ///< Codes to set the foreground colour
  74. char *color_set_bg[256]; ///< Codes to set the background colour
  75. int lines; ///< Number of lines
  76. int columns; ///< Number of columns
  77. }
  78. g_terminal;
  79. static void
  80. update_screen_size (void)
  81. {
  82. #ifdef TIOCGWINSZ
  83. if (!g_terminal.stdout_is_tty)
  84. return;
  85. struct winsize size;
  86. if (!ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &size))
  87. {
  88. char *row = getenv ("LINES");
  89. char *col = getenv ("COLUMNS");
  90. unsigned long tmp;
  91. g_terminal.lines =
  92. (row && xstrtoul (&tmp, row, 10)) ? tmp : size.ws_row;
  93. g_terminal.columns =
  94. (col && xstrtoul (&tmp, col, 10)) ? tmp : size.ws_col;
  95. }
  96. #endif // TIOCGWINSZ
  97. }
  98. static bool
  99. init_terminal (void)
  100. {
  101. int tty_fd = -1;
  102. if ((g_terminal.stderr_is_tty = isatty (STDERR_FILENO)))
  103. tty_fd = STDERR_FILENO;
  104. if ((g_terminal.stdout_is_tty = isatty (STDOUT_FILENO)))
  105. tty_fd = STDOUT_FILENO;
  106. int err;
  107. if (tty_fd == -1 || setupterm (NULL, tty_fd, &err) == ERR)
  108. return false;
  109. // Make sure all terminal features used by us are supported
  110. if (!set_a_foreground || !set_a_background
  111. || !enter_bold_mode || !exit_attribute_mode
  112. || tcgetattr (tty_fd, &g_terminal.termios))
  113. {
  114. del_curterm (cur_term);
  115. return false;
  116. }
  117. // Make sure newlines are output correctly
  118. g_terminal.termios.c_oflag |= ONLCR;
  119. (void) tcsetattr (tty_fd, TCSADRAIN, &g_terminal.termios);
  120. g_terminal.lines = tigetnum ("lines");
  121. g_terminal.columns = tigetnum ("cols");
  122. update_screen_size ();
  123. int max = MIN (256, max_colors);
  124. for (int i = 0; i < max; i++)
  125. {
  126. g_terminal.color_set_fg[i] = xstrdup (tparm (set_a_foreground,
  127. i, 0, 0, 0, 0, 0, 0, 0, 0));
  128. g_terminal.color_set_bg[i] = xstrdup (tparm (set_a_background,
  129. i, 0, 0, 0, 0, 0, 0, 0, 0));
  130. }
  131. return g_terminal.initialized = true;
  132. }
  133. static void
  134. free_terminal (void)
  135. {
  136. if (!g_terminal.initialized)
  137. return;
  138. for (int i = 0; i < 256; i++)
  139. {
  140. free (g_terminal.color_set_fg[i]);
  141. free (g_terminal.color_set_bg[i]);
  142. }
  143. del_curterm (cur_term);
  144. }
  145. // --- User interface ----------------------------------------------------------
  146. // I'm not sure which one of these backends is worse: whether it's GNU Readline
  147. // or BSD Editline. They both have their own annoying problems. We use lots
  148. // of hacks to get the results we want and need.
  149. //
  150. // The abstraction is a necessary evil. It's still not 100%, though.
  151. /// Some arbitrary limit for the history
  152. #define HISTORY_LIMIT 10000
  153. /// Characters that separate words
  154. #define WORD_BREAKING_CHARS " \f\n\r\t\v"
  155. struct input
  156. {
  157. struct input_vtable *vtable; ///< Virtual methods
  158. void (*add_functions) (void *); ///< Define functions for binding
  159. void *user_data; ///< User data for callbacks
  160. };
  161. typedef void *input_buffer_t; ///< Pointer alias for input buffers
  162. /// Named function that can be bound to a sequence of characters
  163. typedef bool (*input_fn) (int count, int key, void *user_data);
  164. // A little bit better than tons of forwarder functions in our case
  165. #define CALL(self, name) ((self)->vtable->name ((self)))
  166. #define CALL_(self, name, ...) ((self)->vtable->name ((self), __VA_ARGS__))
  167. struct input_vtable
  168. {
  169. /// Start the interface under the given program name
  170. void (*start) (void *input, const char *program_name);
  171. /// Stop the interface
  172. void (*stop) (void *input);
  173. /// Prepare or unprepare terminal for our needs
  174. void (*prepare) (void *input, bool enabled);
  175. /// Destroy the object
  176. void (*destroy) (void *input);
  177. /// Hide the prompt if shown
  178. void (*hide) (void *input);
  179. /// Show the prompt if hidden
  180. void (*show) (void *input);
  181. /// Retrieve current prompt string
  182. const char *(*get_prompt) (void *input);
  183. /// Change the prompt string; takes ownership
  184. void (*set_prompt) (void *input, char *prompt);
  185. /// Ring the terminal bell
  186. void (*ding) (void *input);
  187. /// Create a new input buffer
  188. input_buffer_t (*buffer_new) (void *input);
  189. /// Destroy an input buffer
  190. void (*buffer_destroy) (void *input, input_buffer_t buffer);
  191. /// Switch to a different input buffer
  192. void (*buffer_switch) (void *input, input_buffer_t buffer);
  193. /// Register a function that can be bound to character sequences
  194. void (*register_fn) (void *input,
  195. const char *name, const char *help, input_fn fn, void *user_data);
  196. /// Bind an arbitrary sequence of characters to the given named function
  197. void (*bind) (void *input, const char *seq, const char *fn);
  198. /// Bind Ctrl+key to the given named function
  199. void (*bind_control) (void *input, char key, const char *fn);
  200. /// Bind Alt+key to the given named function
  201. void (*bind_meta) (void *input, char key, const char *fn);
  202. /// Get the current line input
  203. char *(*get_line) (void *input);
  204. /// Clear the current line input
  205. void (*clear_line) (void *input);
  206. /// Insert text at current position
  207. bool (*insert) (void *input, const char *text);
  208. /// Handle terminal resize
  209. void (*on_tty_resized) (void *input);
  210. /// Handle terminal input
  211. void (*on_tty_readable) (void *input);
  212. };
  213. #define INPUT_VTABLE(XX) \
  214. XX (start) XX (stop) XX (prepare) XX (destroy) \
  215. XX (hide) XX (show) XX (get_prompt) XX (set_prompt) XX (ding) \
  216. XX (buffer_new) XX (buffer_destroy) XX (buffer_switch) \
  217. XX (register_fn) XX (bind) XX (bind_control) XX (bind_meta) \
  218. XX (get_line) XX (clear_line) XX (insert) \
  219. XX (on_tty_resized) XX (on_tty_readable)
  220. // --- GNU Readline ------------------------------------------------------------
  221. #ifdef HAVE_READLINE
  222. #include <readline/readline.h>
  223. #include <readline/history.h>
  224. #define INPUT_START_IGNORE RL_PROMPT_START_IGNORE
  225. #define INPUT_END_IGNORE RL_PROMPT_END_IGNORE
  226. struct input_rl_fn
  227. {
  228. ffi_closure closure; ///< Closure
  229. LIST_HEADER (struct input_rl_fn)
  230. input_fn callback; ///< Real callback
  231. void *user_data; ///< Real callback user data
  232. };
  233. struct input_rl_buffer
  234. {
  235. HISTORY_STATE *history; ///< Saved history state
  236. char *saved_line; ///< Saved line content
  237. int saved_point; ///< Saved cursor position
  238. int saved_mark; ///< Saved mark
  239. };
  240. struct input_rl
  241. {
  242. struct input super; ///< Parent class
  243. bool active; ///< Interface has been started
  244. char *prompt; ///< The prompt we use
  245. int prompt_shown; ///< Whether the prompt is shown now
  246. char *saved_line; ///< Saved line content
  247. int saved_point; ///< Saved cursor position
  248. int saved_mark; ///< Saved mark
  249. struct input_rl_fn *fns; ///< Named functions
  250. struct input_rl_buffer *current; ///< Current input buffer
  251. };
  252. static void
  253. input_rl_ding (void *input)
  254. {
  255. (void) input;
  256. rl_ding ();
  257. }
  258. static const char *
  259. input_rl_get_prompt (void *input)
  260. {
  261. struct input_rl *self = input;
  262. return self->prompt;
  263. }
  264. static void
  265. input_rl_set_prompt (void *input, char *prompt)
  266. {
  267. struct input_rl *self = input;
  268. cstr_set (&self->prompt, prompt);
  269. if (!self->active)
  270. return;
  271. // First reset the prompt to work around a bug in readline
  272. rl_set_prompt ("");
  273. if (self->prompt_shown > 0)
  274. rl_redisplay ();
  275. rl_set_prompt (self->prompt);
  276. if (self->prompt_shown > 0)
  277. rl_redisplay ();
  278. }
  279. static void
  280. input_rl_clear_line (void *input)
  281. {
  282. (void) input;
  283. rl_replace_line ("", false);
  284. rl_redisplay ();
  285. }
  286. static void
  287. input_rl__erase (struct input_rl *self)
  288. {
  289. rl_set_prompt ("");
  290. input_rl_clear_line (self);
  291. }
  292. static bool
  293. input_rl_insert (void *input, const char *s)
  294. {
  295. struct input_rl *self = input;
  296. rl_insert_text (s);
  297. if (self->prompt_shown > 0)
  298. rl_redisplay ();
  299. // GNU Readline, contrary to Editline, doesn't care about validity
  300. return true;
  301. }
  302. static char *
  303. input_rl_get_line (void *input)
  304. {
  305. (void) input;
  306. return rl_copy_text (0, rl_end);
  307. }
  308. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  309. static void
  310. input_rl_bind (void *input, const char *seq, const char *function_name)
  311. {
  312. (void) input;
  313. rl_bind_keyseq (seq, rl_named_function (function_name));
  314. }
  315. static void
  316. input_rl_bind_meta (void *input, char key, const char *function_name)
  317. {
  318. // This one seems to actually work
  319. char keyseq[] = { '\\', 'e', key, 0 };
  320. input_rl_bind (input, keyseq, function_name);
  321. #if 0
  322. // While this one only fucks up UTF-8
  323. // Tested with urxvt and xterm, on Debian Jessie/Arch, default settings
  324. // \M-<key> behaves exactly the same
  325. rl_bind_key (META (key), rl_named_function (function_name));
  326. #endif
  327. }
  328. static void
  329. input_rl_bind_control (void *input, char key, const char *function_name)
  330. {
  331. char keyseq[] = { '\\', 'C', '-', key, 0 };
  332. input_rl_bind (input, keyseq, function_name);
  333. }
  334. static void
  335. input_rl__forward (ffi_cif *cif, void *ret, void **args, void *user_data)
  336. {
  337. (void) cif;
  338. struct input_rl_fn *data = user_data;
  339. if (!data->callback
  340. (*(int *) args[0], UNMETA (*(int *) args[1]), data->user_data))
  341. rl_ding ();
  342. *(int *) ret = 0;
  343. }
  344. static void
  345. input_rl_register_fn (void *input,
  346. const char *name, const char *help, input_fn callback, void *user_data)
  347. {
  348. struct input_rl *self = input;
  349. (void) help;
  350. void *bound_fn = NULL;
  351. struct input_rl_fn *data = ffi_closure_alloc (sizeof *data, &bound_fn);
  352. hard_assert (data);
  353. static ffi_cif cif;
  354. static ffi_type *args[2] = { &ffi_type_sint, &ffi_type_sint };
  355. hard_assert (ffi_prep_cif
  356. (&cif, FFI_DEFAULT_ABI, 2, &ffi_type_sint, args) == FFI_OK);
  357. data->prev = data->next = NULL;
  358. data->callback = callback;
  359. data->user_data = user_data;
  360. hard_assert (ffi_prep_closure_loc (&data->closure,
  361. &cif, input_rl__forward, data, bound_fn) == FFI_OK);
  362. rl_add_defun (name, (rl_command_func_t *) bound_fn, -1);
  363. LIST_PREPEND (self->fns, data);
  364. }
  365. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  366. static int app_readline_init (void);
  367. static void on_readline_input (char *line);
  368. static char **app_readline_completion (const char *text, int start, int end);
  369. static void
  370. input_rl_start (void *input, const char *program_name)
  371. {
  372. struct input_rl *self = input;
  373. using_history ();
  374. // This can cause memory leaks, or maybe even a segfault. Funny, eh?
  375. stifle_history (HISTORY_LIMIT);
  376. const char *slash = strrchr (program_name, '/');
  377. rl_readline_name = slash ? ++slash : program_name;
  378. rl_startup_hook = app_readline_init;
  379. rl_catch_sigwinch = false;
  380. rl_basic_word_break_characters = WORD_BREAKING_CHARS;
  381. rl_completer_word_break_characters = NULL;
  382. rl_attempted_completion_function = app_readline_completion;
  383. hard_assert (self->prompt != NULL);
  384. // The inputrc is read before any callbacks are called, so we need to
  385. // register all functions that our user may want to map up front
  386. self->super.add_functions (self->super.user_data);
  387. rl_callback_handler_install (self->prompt, on_readline_input);
  388. self->prompt_shown = 1;
  389. self->active = true;
  390. }
  391. static void
  392. input_rl_stop (void *input)
  393. {
  394. struct input_rl *self = input;
  395. if (self->prompt_shown > 0)
  396. input_rl__erase (self);
  397. // This is okay as long as we're not called from within readline
  398. rl_callback_handler_remove ();
  399. self->active = false;
  400. self->prompt_shown = false;
  401. }
  402. static void
  403. input_rl_prepare (void *input, bool enabled)
  404. {
  405. (void) input;
  406. if (enabled)
  407. rl_prep_terminal (true);
  408. else
  409. rl_deprep_terminal ();
  410. }
  411. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  412. // The following part shows you why it's not a good idea to use
  413. // GNU Readline for this kind of software. Or for anything else, really.
  414. static void
  415. input_rl__save_buffer (struct input_rl *self, struct input_rl_buffer *buffer)
  416. {
  417. (void) self;
  418. buffer->history = history_get_history_state ();
  419. buffer->saved_line = rl_copy_text (0, rl_end);
  420. buffer->saved_point = rl_point;
  421. buffer->saved_mark = rl_mark;
  422. rl_replace_line ("", true);
  423. if (self->prompt_shown > 0)
  424. rl_redisplay ();
  425. }
  426. static void
  427. input_rl__restore_buffer (struct input_rl *self, struct input_rl_buffer *buffer)
  428. {
  429. if (buffer->history)
  430. {
  431. // history_get_history_state() just allocates a new HISTORY_STATE
  432. // and fills it with its current internal data. We don't need that
  433. // shell anymore after reviving it.
  434. history_set_history_state (buffer->history);
  435. free (buffer->history);
  436. buffer->history = NULL;
  437. }
  438. else
  439. {
  440. // This should get us a clean history while keeping the flags.
  441. // Note that we've either saved the previous history entries, or we've
  442. // cleared them altogether, so there should be nothing to leak.
  443. HISTORY_STATE *state = history_get_history_state ();
  444. state->offset = state->length = state->size = 0;
  445. state->entries = NULL;
  446. history_set_history_state (state);
  447. free (state);
  448. }
  449. if (buffer->saved_line)
  450. {
  451. rl_replace_line (buffer->saved_line, true);
  452. rl_point = buffer->saved_point;
  453. rl_mark = buffer->saved_mark;
  454. cstr_set (&buffer->saved_line, NULL);
  455. if (self->prompt_shown > 0)
  456. rl_redisplay ();
  457. }
  458. }
  459. static void
  460. input_rl_buffer_switch (void *input, input_buffer_t input_buffer)
  461. {
  462. struct input_rl *self = input;
  463. struct input_rl_buffer *buffer = input_buffer;
  464. // There could possibly be occurences of the current undo list in some
  465. // history entry. We either need to free the undo list, or move it
  466. // somewhere else to load back later, as the buffer we're switching to
  467. // has its own history state.
  468. rl_free_undo_list ();
  469. // Save this buffer's history so that it's independent for each buffer
  470. if (self->current)
  471. input_rl__save_buffer (self, self->current);
  472. else
  473. // Just throw it away; there should always be an active buffer however
  474. #if RL_READLINE_VERSION >= 0x0603
  475. rl_clear_history ();
  476. #else // RL_READLINE_VERSION < 0x0603
  477. // At least something... this may leak undo entries
  478. clear_history ();
  479. #endif // RL_READLINE_VERSION < 0x0603
  480. input_rl__restore_buffer (self, buffer);
  481. self->current = buffer;
  482. }
  483. static void
  484. input_rl__buffer_destroy_wo_history (struct input_rl_buffer *self)
  485. {
  486. free (self->history);
  487. free (self->saved_line);
  488. free (self);
  489. }
  490. static void
  491. input_rl_buffer_destroy (void *input, input_buffer_t input_buffer)
  492. {
  493. (void) input;
  494. struct input_rl_buffer *buffer = input_buffer;
  495. // rl_clear_history, being the only way I know of to get rid of the complete
  496. // history including attached data, is a pretty recent addition. *sigh*
  497. #if RL_READLINE_VERSION >= 0x0603
  498. if (buffer->history)
  499. {
  500. // See input_rl_buffer_switch() for why we need to do this BS
  501. rl_free_undo_list ();
  502. // This is probably the only way we can free the history fully
  503. HISTORY_STATE *state = history_get_history_state ();
  504. history_set_history_state (buffer->history);
  505. rl_clear_history ();
  506. // rl_clear_history just removes history entries,
  507. // we have to reclaim memory for their actual container ourselves
  508. free (buffer->history->entries);
  509. free (buffer->history);
  510. buffer->history = NULL;
  511. history_set_history_state (state);
  512. free (state);
  513. }
  514. #endif // RL_READLINE_VERSION
  515. input_rl__buffer_destroy_wo_history (buffer);
  516. }
  517. static input_buffer_t
  518. input_rl_buffer_new (void *input)
  519. {
  520. (void) input;
  521. struct input_rl_buffer *self = xcalloc (1, sizeof *self);
  522. return self;
  523. }
  524. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  525. // Since {save,restore}_buffer() store history, we can't use them here like we
  526. // do with libedit, because then buffer_destroy() can free memory that's still
  527. // being used by readline. This situation is bound to happen on quit.
  528. static void
  529. input_rl__save (struct input_rl *self)
  530. {
  531. hard_assert (!self->saved_line);
  532. self->saved_point = rl_point;
  533. self->saved_mark = rl_mark;
  534. self->saved_line = rl_copy_text (0, rl_end);
  535. }
  536. static void
  537. input_rl__restore (struct input_rl *self)
  538. {
  539. hard_assert (self->saved_line);
  540. rl_set_prompt (self->prompt);
  541. rl_replace_line (self->saved_line, false);
  542. rl_point = self->saved_point;
  543. rl_mark = self->saved_mark;
  544. cstr_set (&self->saved_line, NULL);
  545. }
  546. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  547. static void
  548. input_rl_hide (void *input)
  549. {
  550. struct input_rl *self = input;
  551. if (!self->active || self->prompt_shown-- < 1)
  552. return;
  553. input_rl__save (self);
  554. input_rl__erase (self);
  555. }
  556. static void
  557. input_rl_show (void *input)
  558. {
  559. struct input_rl *self = input;
  560. if (!self->active || ++self->prompt_shown < 1)
  561. return;
  562. input_rl__restore (self);
  563. rl_redisplay ();
  564. }
  565. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  566. static void
  567. input_rl_on_tty_resized (void *input)
  568. {
  569. (void) input;
  570. // This fucks up big time on terminals with automatic wrapping such as
  571. // rxvt-unicode or newer VTE when the current line overflows, however we
  572. // can't do much about that
  573. rl_resize_terminal ();
  574. }
  575. static void
  576. input_rl_on_tty_readable (void *input)
  577. {
  578. (void) input;
  579. rl_callback_read_char ();
  580. }
  581. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  582. static void
  583. input_rl_destroy (void *input)
  584. {
  585. struct input_rl *self = input;
  586. free (self->saved_line);
  587. LIST_FOR_EACH (struct input_rl_fn, iter, self->fns)
  588. ffi_closure_free (iter);
  589. free (self->prompt);
  590. free (self);
  591. }
  592. #define XX(a) .a = input_rl_ ## a,
  593. static struct input_vtable input_rl_vtable = { INPUT_VTABLE (XX) };
  594. #undef XX
  595. static struct input *
  596. input_rl_new (void)
  597. {
  598. struct input_rl *self = xcalloc (1, sizeof *self);
  599. self->super.vtable = &input_rl_vtable;
  600. return &self->super;
  601. }
  602. #define input_new input_rl_new
  603. #endif // HAVE_READLINE
  604. // --- BSD Editline ------------------------------------------------------------
  605. #ifdef HAVE_EDITLINE
  606. #include <histedit.h>
  607. #define INPUT_START_IGNORE '\x01'
  608. #define INPUT_END_IGNORE '\x01'
  609. struct input_el_fn
  610. {
  611. ffi_closure closure; ///< Closure
  612. LIST_HEADER (struct input_el_fn)
  613. input_fn callback; ///< Real callback
  614. void *user_data; ///< Real callback user data
  615. wchar_t *name; ///< Function name
  616. wchar_t *help; ///< Function help
  617. };
  618. struct input_el_buffer
  619. {
  620. HistoryW *history; ///< The history object
  621. wchar_t *saved_line; ///< Saved line content
  622. int saved_len; ///< Length of the saved line
  623. int saved_point; ///< Saved cursor position
  624. };
  625. struct input_el
  626. {
  627. struct input super; ///< Parent class
  628. EditLine *editline; ///< The EditLine object
  629. bool active; ///< Are we a thing?
  630. char *prompt; ///< The prompt we use
  631. int prompt_shown; ///< Whether the prompt is shown now
  632. struct input_el_fn *fns; ///< Named functions
  633. struct input_el_buffer *current; ///< Current input buffer
  634. };
  635. static void app_editline_init (struct input_el *self);
  636. static int
  637. input_el__get_termios (int character, int fallback)
  638. {
  639. if (!g_terminal.initialized)
  640. return fallback;
  641. cc_t value = g_terminal.termios.c_cc[character];
  642. if (value == _POSIX_VDISABLE)
  643. return fallback;
  644. return value;
  645. }
  646. static void
  647. input_el__redisplay (void *input)
  648. {
  649. // See rl_redisplay()
  650. struct input_el *self = input;
  651. char x[] = { input_el__get_termios (VREPRINT, 'R' - 0x40), 0 };
  652. el_push (self->editline, x);
  653. // We have to do this or it gets stuck and nothing is done
  654. (void) el_gets (self->editline, NULL);
  655. }
  656. static char *
  657. input_el__make_prompt (EditLine *editline)
  658. {
  659. struct input_el *self;
  660. el_get (editline, EL_CLIENTDATA, &self);
  661. if (!self->prompt)
  662. return "";
  663. return self->prompt;
  664. }
  665. static char *
  666. input_el__make_empty_prompt (EditLine *editline)
  667. {
  668. (void) editline;
  669. return "";
  670. }
  671. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  672. static void
  673. input_el_ding (void *input)
  674. {
  675. // XXX: this isn't probably very portable;
  676. // we could use "bell" from terminfo but that creates a dependency
  677. (void) input;
  678. write (STDOUT_FILENO, "\a", 1);
  679. }
  680. static const char *
  681. input_el_get_prompt (void *input)
  682. {
  683. struct input_el *self = input;
  684. return self->prompt;
  685. }
  686. static void
  687. input_el_set_prompt (void *input, char *prompt)
  688. {
  689. struct input_el *self = input;
  690. cstr_set (&self->prompt, prompt);
  691. if (self->prompt_shown > 0)
  692. input_el__redisplay (self);
  693. }
  694. static void
  695. input_el_clear_line (void *input)
  696. {
  697. struct input_el *self = input;
  698. const LineInfoW *info = el_wline (self->editline);
  699. int len = info->lastchar - info->buffer;
  700. int point = info->cursor - info->buffer;
  701. el_cursor (self->editline, len - point);
  702. el_wdeletestr (self->editline, len);
  703. input_el__redisplay (self);
  704. }
  705. static void
  706. input_el__erase (struct input_el *self)
  707. {
  708. el_set (self->editline, EL_PROMPT, input_el__make_empty_prompt);
  709. input_el_clear_line (self);
  710. }
  711. static bool
  712. input_el_insert (void *input, const char *s)
  713. {
  714. struct input_el *self = input;
  715. bool success = !*s || !el_insertstr (self->editline, s);
  716. if (self->prompt_shown > 0)
  717. input_el__redisplay (self);
  718. return success;
  719. }
  720. static char *
  721. input_el_get_line (void *input)
  722. {
  723. struct input_el *self = input;
  724. const LineInfo *info = el_line (self->editline);
  725. return xstrndup (info->buffer, info->lastchar - info->buffer);
  726. }
  727. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  728. static void
  729. input_el_bind (void *input, const char *seq, const char *function_name)
  730. {
  731. struct input_el *self = input;
  732. el_set (self->editline, EL_BIND, seq, function_name, NULL);
  733. }
  734. static void
  735. input_el_bind_meta (void *input, char key, const char *function_name)
  736. {
  737. char keyseq[] = { 'M', '-', key, 0 };
  738. input_el_bind (input, keyseq, function_name);
  739. }
  740. static void
  741. input_el_bind_control (void *input, char key, const char *function_name)
  742. {
  743. char keyseq[] = { '^', key, 0 };
  744. input_el_bind (input, keyseq, function_name);
  745. }
  746. static void
  747. input_el__forward (ffi_cif *cif, void *ret, void **args, void *user_data)
  748. {
  749. (void) cif;
  750. struct input_el_fn *data = user_data;
  751. *(unsigned char *) ret = data->callback
  752. (1, *(int *) args[1], data->user_data) ? CC_NORM : CC_ERROR;
  753. }
  754. static wchar_t *
  755. ascii_to_wide (const char *ascii)
  756. {
  757. size_t len = strlen (ascii) + 1;
  758. wchar_t *wide = xcalloc (sizeof *wide, len);
  759. while (len--)
  760. hard_assert ((wide[len] = (unsigned char) ascii[len]) < 0x80);
  761. return wide;
  762. }
  763. static void
  764. input_el_register_fn (void *input,
  765. const char *name, const char *help, input_fn callback, void *user_data)
  766. {
  767. void *bound_fn = NULL;
  768. struct input_el_fn *data = ffi_closure_alloc (sizeof *data, &bound_fn);
  769. hard_assert (data);
  770. static ffi_cif cif;
  771. static ffi_type *args[2] = { &ffi_type_pointer, &ffi_type_sint };
  772. hard_assert (ffi_prep_cif
  773. (&cif, FFI_DEFAULT_ABI, 2, &ffi_type_uchar, args) == FFI_OK);
  774. data->user_data = user_data;
  775. data->callback = callback;
  776. data->name = ascii_to_wide (name);
  777. data->help = ascii_to_wide (help);
  778. hard_assert (ffi_prep_closure_loc (&data->closure,
  779. &cif, input_el__forward, data, bound_fn) == FFI_OK);
  780. struct input_el *self = input;
  781. el_wset (self->editline, EL_ADDFN, data->name, data->help, bound_fn);
  782. LIST_PREPEND (self->fns, data);
  783. }
  784. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  785. static void
  786. input_el_start (void *input, const char *program_name)
  787. {
  788. struct input_el *self = input;
  789. self->editline = el_init (program_name, stdin, stdout, stderr);
  790. el_set (self->editline, EL_CLIENTDATA, self);
  791. el_set (self->editline, EL_PROMPT_ESC,
  792. input_el__make_prompt, INPUT_START_IGNORE);
  793. el_set (self->editline, EL_SIGNAL, false);
  794. el_set (self->editline, EL_UNBUFFERED, true);
  795. el_set (self->editline, EL_EDITOR, "emacs");
  796. app_editline_init (self);
  797. self->prompt_shown = 1;
  798. self->active = true;
  799. }
  800. static void
  801. input_el_stop (void *input)
  802. {
  803. struct input_el *self = input;
  804. if (self->prompt_shown > 0)
  805. input_el__erase (self);
  806. el_end (self->editline);
  807. self->editline = NULL;
  808. self->active = false;
  809. self->prompt_shown = false;
  810. }
  811. static void
  812. input_el_prepare (void *input, bool enabled)
  813. {
  814. struct input_el *self = input;
  815. el_set (self->editline, EL_PREP_TERM, enabled);
  816. }
  817. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  818. static void
  819. input_el__save_buffer (struct input_el *self, struct input_el_buffer *buffer)
  820. {
  821. const LineInfoW *info = el_wline (self->editline);
  822. int len = info->lastchar - info->buffer;
  823. int point = info->cursor - info->buffer;
  824. wchar_t *line = calloc (sizeof *info->buffer, len + 1);
  825. memcpy (line, info->buffer, sizeof *info->buffer * len);
  826. el_cursor (self->editline, len - point);
  827. el_wdeletestr (self->editline, len);
  828. buffer->saved_line = line;
  829. buffer->saved_point = point;
  830. buffer->saved_len = len;
  831. }
  832. static void
  833. input_el__save (struct input_el *self)
  834. {
  835. if (self->current)
  836. input_el__save_buffer (self, self->current);
  837. }
  838. static void
  839. input_el__restore_buffer (struct input_el *self, struct input_el_buffer *buffer)
  840. {
  841. if (buffer->saved_line)
  842. {
  843. el_winsertstr (self->editline, buffer->saved_line);
  844. el_cursor (self->editline,
  845. -(buffer->saved_len - buffer->saved_point));
  846. cstr_set (&buffer->saved_line, NULL);
  847. }
  848. }
  849. static void
  850. input_el__restore (struct input_el *self)
  851. {
  852. if (self->current)
  853. input_el__restore_buffer (self, self->current);
  854. }
  855. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  856. static void
  857. input_el_buffer_switch (void *input, input_buffer_t input_buffer)
  858. {
  859. struct input_el *self = input;
  860. struct input_el_buffer *buffer = input_buffer;
  861. if (self->current)
  862. input_el__save_buffer (self, self->current);
  863. input_el__restore_buffer (self, buffer);
  864. el_wset (self->editline, EL_HIST, history, buffer->history);
  865. self->current = buffer;
  866. }
  867. static void
  868. input_el_buffer_destroy (void *input, input_buffer_t input_buffer)
  869. {
  870. (void) input;
  871. struct input_el_buffer *buffer = input_buffer;
  872. history_wend (buffer->history);
  873. free (buffer->saved_line);
  874. free (buffer);
  875. }
  876. static input_buffer_t
  877. input_el_buffer_new (void *input)
  878. {
  879. (void) input;
  880. struct input_el_buffer *self = xcalloc (1, sizeof *self);
  881. self->history = history_winit ();
  882. HistEventW ev;
  883. history_w (self->history, &ev, H_SETSIZE, HISTORY_LIMIT);
  884. return self;
  885. }
  886. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  887. static void
  888. input_el_hide (void *input)
  889. {
  890. struct input_el *self = input;
  891. if (!self->active || self->prompt_shown-- < 1)
  892. return;
  893. input_el__save (self);
  894. input_el__erase (self);
  895. }
  896. static void
  897. input_el_show (void *input)
  898. {
  899. struct input_el *self = input;
  900. if (!self->active || ++self->prompt_shown < 1)
  901. return;
  902. input_el__restore (self);
  903. // XXX: the ignore doesn't quite work, see https://gnats.netbsd.org/47539
  904. el_set (self->editline,
  905. EL_PROMPT_ESC, input_el__make_prompt, INPUT_START_IGNORE);
  906. input_el__redisplay (self);
  907. }
  908. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  909. static void
  910. input_el_on_tty_resized (void *input)
  911. {
  912. struct input_el *self = input;
  913. el_resize (self->editline);
  914. }
  915. static void
  916. input_el_on_tty_readable (void *input)
  917. {
  918. // We bind the return key to process it how we need to
  919. struct input_el *self = input;
  920. // el_gets() with EL_UNBUFFERED doesn't work with UTF-8,
  921. // we must use the wide-character interface
  922. int count = 0;
  923. const wchar_t *buf = el_wgets (self->editline, &count);
  924. if (!buf || count-- <= 0)
  925. return;
  926. if (count == 0 && buf[0] == ('D' - 0x40) /* hardcoded VEOF in editline */)
  927. {
  928. el_deletestr (self->editline, 1);
  929. input_el__redisplay (self);
  930. input_el_ding (self);
  931. }
  932. }
  933. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  934. static void
  935. input_el_destroy (void *input)
  936. {
  937. struct input_el *self = input;
  938. LIST_FOR_EACH (struct input_el_fn, iter, self->fns)
  939. {
  940. free (iter->name);
  941. free (iter->help);
  942. ffi_closure_free (iter);
  943. }
  944. free (self->prompt);
  945. free (self);
  946. }
  947. #define XX(a) .a = input_el_ ## a,
  948. static struct input_vtable input_el_vtable = { INPUT_VTABLE (XX) };
  949. #undef XX
  950. static struct input *
  951. input_el_new (void)
  952. {
  953. struct input_el *self = xcalloc (1, sizeof *self);
  954. self->super.vtable = &input_el_vtable;
  955. return &self->super;
  956. }
  957. #define input_new input_el_new
  958. #endif // HAVE_EDITLINE
  959. // --- Application data --------------------------------------------------------
  960. // All text stored in our data structures is encoded in UTF-8.
  961. // Or at least should be. The exception is IRC identifiers.
  962. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  963. // We need a few reference countable objects with support for both strong
  964. // and weak references (mainly used for scripted plugins).
  965. //
  966. // Beware that if you don't own the object, you will most probably want
  967. // to keep the weak reference link so that you can get rid of it later.
  968. // Also note that you have to make sure the user_data don't leak resources.
  969. //
  970. // Having a callback is more versatile than just nulling out a pointer.
  971. /// Callback just before a reference counted object is destroyed
  972. typedef void (*destroy_cb_fn) (void *object, void *user_data);
  973. struct weak_ref_link
  974. {
  975. LIST_HEADER (struct weak_ref_link)
  976. destroy_cb_fn on_destroy; ///< Called when object is destroyed
  977. void *user_data; ///< User data
  978. };
  979. static struct weak_ref_link *
  980. weak_ref (struct weak_ref_link **list, destroy_cb_fn cb, void *user_data)
  981. {
  982. struct weak_ref_link *link = xcalloc (1, sizeof *link);
  983. link->on_destroy = cb;
  984. link->user_data = user_data;
  985. LIST_PREPEND (*list, link);
  986. return link;
  987. }
  988. static void
  989. weak_unref (struct weak_ref_link **list, struct weak_ref_link **link)
  990. {
  991. if (*link)
  992. LIST_UNLINK (*list, *link);
  993. free (*link);
  994. *link = NULL;
  995. }
  996. #define REF_COUNTABLE_HEADER \
  997. size_t ref_count; /**< Reference count */ \
  998. struct weak_ref_link *weak_refs; /**< To remove any weak references */
  999. #define REF_COUNTABLE_METHODS(name) \
  1000. static struct name * \
  1001. name ## _ref (struct name *self) \
  1002. { \
  1003. self->ref_count++; \
  1004. return self; \
  1005. } \
  1006. \
  1007. static void \
  1008. name ## _unref (struct name *self) \
  1009. { \
  1010. if (--self->ref_count) \
  1011. return; \
  1012. LIST_FOR_EACH (struct weak_ref_link, iter, self->weak_refs) \
  1013. { \
  1014. iter->on_destroy (self, iter->user_data); \
  1015. free (iter); \
  1016. } \
  1017. name ## _destroy (self); \
  1018. } \
  1019. \
  1020. static struct weak_ref_link * \
  1021. name ## _weak_ref (struct name *self, destroy_cb_fn cb, void *user_data) \
  1022. { return weak_ref (&self->weak_refs, cb, user_data); } \
  1023. \
  1024. static void \
  1025. name ## _weak_unref (struct name *self, struct weak_ref_link **link) \
  1026. { weak_unref (&self->weak_refs, link); }
  1027. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1028. // Simple introspection framework to simplify exporting stuff to Lua, since
  1029. // there is a lot of it. While not fully automated, at least we have control
  1030. // over which fields are exported.
  1031. enum ispect_type
  1032. {
  1033. ISPECT_BOOL, ISPECT_INT, ISPECT_UINT, ISPECT_SIZE, ISPECT_STRING,
  1034. ISPECT_STR, ///< "struct str"
  1035. ISPECT_STR_MAP, ///< "struct str_map"
  1036. ISPECT_REF ///< Weakly referenced object
  1037. };
  1038. struct ispect_field
  1039. {
  1040. const char *name; ///< Name of the field
  1041. size_t offset; ///< Offset in the structure
  1042. enum ispect_type type; ///< Type of the field
  1043. enum ispect_type subtype; ///< STR_MAP subtype
  1044. struct ispect_field *fields; ///< REF target fields
  1045. bool is_list; ///< REF target is a list
  1046. };
  1047. #define ISPECT(object, field, type) \
  1048. { #field, offsetof (struct object, field), ISPECT_##type, 0, NULL, false },
  1049. #define ISPECT_REF(object, field, is_list, ref_type) \
  1050. { #field, offsetof (struct object, field), ISPECT_REF, 0, \
  1051. g_##ref_type##_ispect, is_list },
  1052. #define ISPECT_MAP(object, field, subtype) \
  1053. { #field, offsetof (struct object, field), ISPECT_STR_MAP, \
  1054. ISPECT_##subtype, NULL, false },
  1055. #define ISPECT_MAP_REF(object, field, is_list, ref_type) \
  1056. { #field, offsetof (struct object, field), ISPECT_STR_MAP, \
  1057. ISPECT_REF, g_##ref_type##_ispect, is_list },
  1058. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1059. struct user_channel
  1060. {
  1061. LIST_HEADER (struct user_channel)
  1062. struct channel *channel; ///< Reference to channel
  1063. };
  1064. static struct user_channel *
  1065. user_channel_new (void)
  1066. {
  1067. struct user_channel *self = xcalloc (1, sizeof *self);
  1068. return self;
  1069. }
  1070. static void
  1071. user_channel_destroy (struct user_channel *self)
  1072. {
  1073. // The "channel" reference is weak and this object should get
  1074. // destroyed whenever the user stops being in the channel.
  1075. free (self);
  1076. }
  1077. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1078. // We keep references to user information in channels and buffers,
  1079. // and weak references in the name lookup table.
  1080. struct user
  1081. {
  1082. REF_COUNTABLE_HEADER
  1083. char *nickname; ///< Literal nickname
  1084. // TODO: write code to poll for the away status
  1085. bool away; ///< User is away
  1086. struct user_channel *channels; ///< Channels the user is on
  1087. };
  1088. static struct ispect_field g_user_ispect[] =
  1089. {
  1090. ISPECT( user, nickname, STRING )
  1091. ISPECT( user, away, BOOL )
  1092. {}
  1093. };
  1094. static struct user *
  1095. user_new (void)
  1096. {
  1097. struct user *self = xcalloc (1, sizeof *self);
  1098. self->ref_count = 1;
  1099. return self;
  1100. }
  1101. static void
  1102. user_destroy (struct user *self)
  1103. {
  1104. free (self->nickname);
  1105. LIST_FOR_EACH (struct user_channel, iter, self->channels)
  1106. user_channel_destroy (iter);
  1107. free (self);
  1108. }
  1109. REF_COUNTABLE_METHODS (user)
  1110. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1111. struct channel_user
  1112. {
  1113. LIST_HEADER (struct channel_user)
  1114. struct user *user; ///< Reference to user
  1115. struct str prefixes; ///< Ordered @+... characters
  1116. };
  1117. static struct channel_user *
  1118. channel_user_new (void)
  1119. {
  1120. struct channel_user *self = xcalloc (1, sizeof *self);
  1121. self->prefixes = str_make ();
  1122. return self;
  1123. }
  1124. static void
  1125. channel_user_destroy (struct channel_user *self)
  1126. {
  1127. user_unref (self->user);
  1128. str_free (&self->prefixes);
  1129. free (self);
  1130. }
  1131. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1132. // We keep references to channels in their buffers,
  1133. // and weak references in their users and the name lookup table.
  1134. struct channel
  1135. {
  1136. REF_COUNTABLE_HEADER
  1137. char *name; ///< Channel name
  1138. char *topic; ///< Channel topic
  1139. // XXX: write something like an ordered set of characters object?
  1140. struct str no_param_modes; ///< No parameter channel modes
  1141. struct str_map param_modes; ///< Parametrized channel modes
  1142. struct channel_user *users; ///< Channel users
  1143. struct strv names_buf; ///< Buffer for RPL_NAMREPLY
  1144. size_t users_len; ///< User count
  1145. bool left_manually; ///< Don't rejoin on reconnect
  1146. };
  1147. static struct ispect_field g_channel_ispect[] =
  1148. {
  1149. ISPECT( channel, name, STRING )
  1150. ISPECT( channel, topic, STRING )
  1151. ISPECT( channel, no_param_modes, STR )
  1152. ISPECT_MAP( channel, param_modes, STRING )
  1153. ISPECT( channel, users_len, SIZE )
  1154. ISPECT( channel, left_manually, BOOL )
  1155. {}
  1156. };
  1157. static struct channel *
  1158. channel_new (void)
  1159. {
  1160. struct channel *self = xcalloc (1, sizeof *self);
  1161. self->ref_count = 1;
  1162. self->no_param_modes = str_make ();
  1163. self->param_modes = str_map_make (free);
  1164. self->names_buf = strv_make ();
  1165. return self;
  1166. }
  1167. static void
  1168. channel_destroy (struct channel *self)
  1169. {
  1170. free (self->name);
  1171. free (self->topic);
  1172. str_free (&self->no_param_modes);
  1173. str_map_free (&self->param_modes);
  1174. // Owner has to make sure we have no users by now
  1175. hard_assert (!self->users && !self->users_len);
  1176. strv_free (&self->names_buf);
  1177. free (self);
  1178. }
  1179. REF_COUNTABLE_METHODS (channel)
  1180. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1181. enum formatter_item_type
  1182. {
  1183. FORMATTER_ITEM_END, ///< Sentinel value for arrays
  1184. FORMATTER_ITEM_TEXT, ///< Text
  1185. FORMATTER_ITEM_ATTR, ///< Formatting attributes
  1186. FORMATTER_ITEM_FG_COLOR, ///< Foreground color
  1187. FORMATTER_ITEM_BG_COLOR, ///< Background color
  1188. FORMATTER_ITEM_SIMPLE, ///< Toggle mIRC formatting
  1189. FORMATTER_ITEM_IGNORE_ATTR ///< Un/set attribute ignoration
  1190. };
  1191. struct formatter_item
  1192. {
  1193. enum formatter_item_type type : 16; ///< Type of this item
  1194. int attribute : 16; ///< Attribute ID
  1195. int color; ///< Color
  1196. char *text; ///< String
  1197. };
  1198. static void
  1199. formatter_item_free (struct formatter_item *self)
  1200. {
  1201. free (self->text);
  1202. }
  1203. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1204. struct formatter
  1205. {
  1206. struct app_context *ctx; ///< Application context
  1207. struct server *s; ///< Server
  1208. struct formatter_item *items; ///< Items
  1209. size_t items_len; ///< Items used
  1210. size_t items_alloc; ///< Items allocated
  1211. };
  1212. static struct formatter
  1213. formatter_make (struct app_context *ctx, struct server *s)
  1214. {
  1215. struct formatter self = { .ctx = ctx, .s = s };
  1216. self.items = xcalloc (sizeof *self.items, (self.items_alloc = 16));
  1217. return self;
  1218. }
  1219. static void
  1220. formatter_free (struct formatter *self)
  1221. {
  1222. for (size_t i = 0; i < self->items_len; i++)
  1223. formatter_item_free (&self->items[i]);
  1224. free (self->items);
  1225. }
  1226. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1227. enum buffer_line_flags
  1228. {
  1229. BUFFER_LINE_STATUS = 1 << 0, ///< Status message
  1230. BUFFER_LINE_ERROR = 1 << 1, ///< Error message
  1231. BUFFER_LINE_HIGHLIGHT = 1 << 2, ///< The user was highlighted by this
  1232. BUFFER_LINE_SKIP_FILE = 1 << 3, ///< Don't log this to file
  1233. BUFFER_LINE_INDENT = 1 << 4, ///< Just indent the line
  1234. BUFFER_LINE_UNIMPORTANT = 1 << 5 ///< Joins, parts, similar spam
  1235. };
  1236. struct buffer_line
  1237. {
  1238. LIST_HEADER (struct buffer_line)
  1239. int flags; ///< Flags
  1240. time_t when; ///< Time of the event
  1241. struct formatter_item items[]; ///< Line data
  1242. };
  1243. /// Create a new buffer line stealing all data from the provided formatter
  1244. struct buffer_line *
  1245. buffer_line_new (struct formatter *f)
  1246. {
  1247. // We make space for one more item that gets initialized to all zeros,
  1248. // meaning FORMATTER_ITEM_END (because it's the first value in the enum)
  1249. size_t items_size = f->items_len * sizeof *f->items;
  1250. struct buffer_line *self =
  1251. xcalloc (1, sizeof *self + items_size + sizeof *self->items);
  1252. memcpy (self->items, f->items, items_size);
  1253. // We've stolen pointers from the formatter, let's destroy it altogether
  1254. free (f->items);
  1255. memset (f, 0, sizeof *f);
  1256. return self;
  1257. }
  1258. static void
  1259. buffer_line_destroy (struct buffer_line *self)
  1260. {
  1261. for (struct formatter_item *iter = self->items; iter->type; iter++)
  1262. formatter_item_free (iter);
  1263. free (self);
  1264. }
  1265. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1266. enum buffer_type
  1267. {
  1268. BUFFER_GLOBAL, ///< Global information
  1269. BUFFER_SERVER, ///< Server-related messages
  1270. BUFFER_CHANNEL, ///< Channels
  1271. BUFFER_PM ///< Private messages (query)
  1272. };
  1273. struct buffer
  1274. {
  1275. LIST_HEADER (struct buffer)
  1276. REF_COUNTABLE_HEADER
  1277. enum buffer_type type; ///< Type of the buffer
  1278. char *name; ///< The name of the buffer
  1279. struct input *input; ///< API for "input_data"
  1280. input_buffer_t input_data; ///< User interface data
  1281. // Buffer contents:
  1282. struct buffer_line *lines; ///< All lines in this buffer
  1283. struct buffer_line *lines_tail; ///< The tail of buffer lines
  1284. unsigned lines_count; ///< How many lines we have
  1285. unsigned new_messages_count; ///< # messages since last left
  1286. unsigned new_unimportant_count; ///< How much of that is unimportant
  1287. bool highlighted; ///< We've been highlighted
  1288. bool hide_unimportant; ///< Hide unimportant messages
  1289. FILE *log_file; ///< Log file
  1290. // Origin information:
  1291. struct server *server; ///< Reference to server
  1292. struct channel *channel; ///< Reference to channel
  1293. struct user *user; ///< Reference to user
  1294. };
  1295. static struct ispect_field g_server_ispect[];
  1296. static struct ispect_field g_buffer_ispect[] =
  1297. {
  1298. ISPECT( buffer, name, STRING )
  1299. ISPECT( buffer, new_messages_count, UINT )
  1300. ISPECT( buffer, new_unimportant_count, UINT )
  1301. ISPECT( buffer, highlighted, BOOL )
  1302. ISPECT( buffer, hide_unimportant, BOOL )
  1303. ISPECT_REF( buffer, server, false, server )
  1304. ISPECT_REF( buffer, channel, false, channel )
  1305. ISPECT_REF( buffer, user, false, user )
  1306. {}
  1307. };
  1308. static struct buffer *
  1309. buffer_new (struct input *input)
  1310. {
  1311. struct buffer *self = xcalloc (1, sizeof *self);
  1312. self->ref_count = 1;
  1313. self->input = input;
  1314. self->input_data = CALL (input, buffer_new);
  1315. return self;
  1316. }
  1317. static void
  1318. buffer_destroy (struct buffer *self)
  1319. {
  1320. free (self->name);
  1321. if (self->input_data)
  1322. {
  1323. #ifdef HAVE_READLINE
  1324. // FIXME: can't really free "history" contents from here, as we cannot
  1325. // be sure that the user interface pointer is valid and usable
  1326. input_rl__buffer_destroy_wo_history (self->input_data);
  1327. #else // ! HAVE_READLINE
  1328. CALL_ (self->input, buffer_destroy, self->input_data);
  1329. #endif // ! HAVE_READLINE
  1330. }
  1331. LIST_FOR_EACH (struct buffer_line, iter, self->lines)
  1332. buffer_line_destroy (iter);
  1333. if (self->log_file)
  1334. (void) fclose (self->log_file);
  1335. if (self->user)
  1336. user_unref (self->user);
  1337. if (self->channel)
  1338. channel_unref (self->channel);
  1339. free (self);
  1340. }
  1341. REF_COUNTABLE_METHODS (buffer)
  1342. #define buffer_ref do_not_use_dangerous
  1343. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1344. // The only real purpose of this is to abstract away TLS
  1345. struct transport
  1346. {
  1347. /// Initialize the transport
  1348. bool (*init) (struct server *s, const char *hostname, struct error **e);
  1349. /// Destroy the user data pointer
  1350. void (*cleanup) (struct server *s);
  1351. /// The underlying socket may have become readable, update `read_buffer'
  1352. enum socket_io_result (*try_read) (struct server *s);
  1353. /// The underlying socket may have become writeable, flush `write_buffer'
  1354. enum socket_io_result (*try_write) (struct server *s);
  1355. /// Return event mask to use in the poller
  1356. int (*get_poll_events) (struct server *s);
  1357. /// Called just before closing the connection from our side
  1358. void (*in_before_shutdown) (struct server *s);
  1359. };
  1360. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1361. enum server_state
  1362. {
  1363. IRC_DISCONNECTED, ///< Not connected
  1364. IRC_CONNECTING, ///< Connecting to the server
  1365. IRC_CONNECTED, ///< Trying to register
  1366. IRC_REGISTERED, ///< We can chat now
  1367. IRC_CLOSING, ///< Flushing output before shutdown
  1368. IRC_HALF_CLOSED ///< Connection shutdown from our side
  1369. };
  1370. /// Convert an IRC identifier character to lower-case
  1371. typedef int (*irc_tolower_fn) (int);
  1372. /// Key conversion function for hashmap lookups
  1373. typedef size_t (*irc_strxfrm_fn) (char *, const char *, size_t);
  1374. struct server
  1375. {
  1376. REF_COUNTABLE_HEADER
  1377. struct app_context *ctx; ///< Application context
  1378. char *name; ///< Server identifier
  1379. struct buffer *buffer; ///< The buffer for this server
  1380. struct config_item *config; ///< Configuration root
  1381. // Connection:
  1382. enum server_state state; ///< Connection state
  1383. struct connector *connector; ///< Connection establisher
  1384. struct socks_connector *socks_conn; ///< SOCKS connection establisher
  1385. unsigned reconnect_attempt; ///< Number of reconnect attempt
  1386. bool manual_disconnect; ///< Don't reconnect after disconnect
  1387. int socket; ///< Socket FD of the server
  1388. struct str read_buffer; ///< Input yet to be processed
  1389. struct str write_buffer; ///< Outut yet to be be sent out
  1390. struct poller_fd socket_event; ///< We can read from the socket
  1391. struct transport *transport; ///< Transport method
  1392. void *transport_data; ///< Transport data
  1393. // Events:
  1394. struct poller_timer ping_tmr; ///< We should send a ping
  1395. struct poller_timer timeout_tmr; ///< Connection seems to be dead
  1396. struct poller_timer reconnect_tmr; ///< We should reconnect now
  1397. struct poller_timer autojoin_tmr; ///< Re/join channels as appropriate
  1398. // IRC:
  1399. // TODO: an output queue to prevent excess floods (this will be needed
  1400. // especially for away status polling)
  1401. bool rehashing; ///< Rehashing IRC identifiers
  1402. struct str_map irc_users; ///< IRC user data
  1403. struct str_map irc_channels; ///< IRC channel data
  1404. struct str_map irc_buffer_map; ///< Maps IRC identifiers to buffers
  1405. struct user *irc_user; ///< Our own user
  1406. int nick_counter; ///< Iterates "nicks" when registering
  1407. struct str irc_user_mode; ///< Our current user modes
  1408. char *irc_user_host; ///< Our current user@host
  1409. bool autoaway_active; ///< Autoaway is currently active
  1410. bool cap_echo_message; ///< Whether the server echos messages
  1411. // Server-specific information (from RPL_ISUPPORT):
  1412. irc_tolower_fn irc_tolower; ///< Server tolower()
  1413. irc_strxfrm_fn irc_strxfrm; ///< Server strxfrm()
  1414. char *irc_chantypes; ///< Channel types (name prefixes)
  1415. char *irc_idchan_prefixes; ///< Prefixes for "safe channels"
  1416. char *irc_statusmsg; ///< Prefixes for channel targets
  1417. char *irc_chanmodes_list; ///< Channel modes for lists
  1418. char *irc_chanmodes_param_always; ///< Channel modes with mandatory param
  1419. char *irc_chanmodes_param_when_set; ///< Channel modes with param when set
  1420. char *irc_chanmodes_param_never; ///< Channel modes without param
  1421. char *irc_chanuser_prefixes; ///< Channel user prefixes
  1422. char *irc_chanuser_modes; ///< Channel user modes
  1423. unsigned irc_max_modes; ///< Max parametrized modes per command
  1424. };
  1425. static struct ispect_field g_server_ispect[] =
  1426. {
  1427. ISPECT( server, name, STRING )
  1428. ISPECT( server, state, INT )
  1429. ISPECT( server, reconnect_attempt, UINT )
  1430. ISPECT( server, manual_disconnect, BOOL )
  1431. ISPECT( server, irc_user_host, STRING )
  1432. ISPECT( server, autoaway_active, BOOL )
  1433. ISPECT( server, cap_echo_message, BOOL )
  1434. ISPECT_REF( server, buffer, false, buffer )
  1435. // TODO: either rename the underlying field or fix the plugins
  1436. { "user", offsetof (struct server, irc_user),
  1437. ISPECT_REF, 0, g_user_ispect, false },
  1438. { "user_mode", offsetof (struct server, irc_user_mode),
  1439. ISPECT_STR, 0, NULL, false },
  1440. {}
  1441. };
  1442. static void on_irc_timeout (void *user_data);
  1443. static void on_irc_ping_timeout (void *user_data);
  1444. static void on_irc_autojoin_timeout (void *user_data);
  1445. static void irc_initiate_connect (struct server *s);
  1446. static void
  1447. server_init_specifics (struct server *self)
  1448. {
  1449. // Defaults as per the RPL_ISUPPORT drafts, or RFC 1459
  1450. self->irc_tolower = irc_tolower;
  1451. self->irc_strxfrm = irc_strxfrm;
  1452. self->irc_chantypes = xstrdup ("#&");
  1453. self->irc_idchan_prefixes = xstrdup ("");
  1454. self->irc_statusmsg = xstrdup ("");
  1455. self->irc_chanmodes_list = xstrdup ("b");
  1456. self->irc_chanmodes_param_always = xstrdup ("k");
  1457. self->irc_chanmodes_param_when_set = xstrdup ("l");
  1458. self->irc_chanmodes_param_never = xstrdup ("imnpst");
  1459. self->irc_chanuser_prefixes = xstrdup ("@+");
  1460. self->irc_chanuser_modes = xstrdup ("ov");
  1461. self->irc_max_modes = 3;
  1462. }
  1463. static void
  1464. server_free_specifics (struct server *self)
  1465. {
  1466. free (self->irc_chantypes);
  1467. free (self->irc_idchan_prefixes);
  1468. free (self->irc_statusmsg);
  1469. free (self->irc_chanmodes_list);
  1470. free (self->irc_chanmodes_param_always);
  1471. free (self->irc_chanmodes_param_when_set);
  1472. free (self->irc_chanmodes_param_never);
  1473. free (self->irc_chanuser_prefixes);
  1474. free (self->irc_chanuser_modes);
  1475. }
  1476. static struct server *
  1477. server_new (struct poller *poller)
  1478. {
  1479. struct server *self = xcalloc (1, sizeof *self);
  1480. self->ref_count = 1;
  1481. self->socket = -1;
  1482. self->read_buffer = str_make ();
  1483. self->write_buffer = str_make ();
  1484. self->state = IRC_DISCONNECTED;
  1485. self->timeout_tmr = poller_timer_make (poller);
  1486. self->timeout_tmr.dispatcher = on_irc_timeout;
  1487. self->timeout_tmr.user_data = self;
  1488. self->ping_tmr = poller_timer_make (poller);
  1489. self->ping_tmr.dispatcher = on_irc_ping_timeout;
  1490. self->ping_tmr.user_data = self;
  1491. self->reconnect_tmr = poller_timer_make (poller);
  1492. self->reconnect_tmr.dispatcher = (poller_timer_fn) irc_initiate_connect;
  1493. self->reconnect_tmr.user_data = self;
  1494. self->autojoin_tmr = poller_timer_make (poller);
  1495. self->autojoin_tmr.dispatcher = on_irc_autojoin_timeout;
  1496. self->autojoin_tmr.user_data = self;
  1497. self->irc_users = str_map_make (NULL);
  1498. self->irc_users.key_xfrm = irc_strxfrm;
  1499. self->irc_channels = str_map_make (NULL);
  1500. self->irc_channels.key_xfrm = irc_strxfrm;
  1501. self->irc_buffer_map = str_map_make (NULL);
  1502. self->irc_buffer_map.key_xfrm = irc_strxfrm;
  1503. self->irc_user_mode = str_make ();
  1504. server_init_specifics (self);
  1505. return self;
  1506. }
  1507. static void
  1508. server_destroy (struct server *self)
  1509. {
  1510. free (self->name);
  1511. if (self->connector)
  1512. {
  1513. connector_free (self->connector);
  1514. free (self->connector);
  1515. }
  1516. if (self->socks_conn)
  1517. {
  1518. socks_connector_free (self->socks_conn);
  1519. free (self->socks_conn);
  1520. }
  1521. if (self->transport
  1522. && self->transport->cleanup)
  1523. self->transport->cleanup (self);
  1524. if (self->socket != -1)
  1525. {
  1526. poller_fd_reset (&self->socket_event);
  1527. xclose (self->socket);
  1528. }
  1529. str_free (&self->read_buffer);
  1530. str_free (&self->write_buffer);
  1531. poller_timer_reset (&self->ping_tmr);
  1532. poller_timer_reset (&self->timeout_tmr);
  1533. poller_timer_reset (&self->reconnect_tmr);
  1534. poller_timer_reset (&self->autojoin_tmr);
  1535. str_map_free (&self->irc_users);
  1536. str_map_free (&self->irc_channels);
  1537. str_map_free (&self->irc_buffer_map);
  1538. if (self->irc_user)
  1539. user_unref (self->irc_user);
  1540. str_free (&self->irc_user_mode);
  1541. free (self->irc_user_host);
  1542. server_free_specifics (self);
  1543. free (self);
  1544. }
  1545. REF_COUNTABLE_METHODS (server)
  1546. #define server_ref do_not_use_dangerous
  1547. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1548. struct plugin
  1549. {
  1550. LIST_HEADER (struct plugin)
  1551. char *name; ///< Name of the plugin
  1552. struct plugin_vtable *vtable; ///< Methods
  1553. };
  1554. struct plugin_vtable
  1555. {
  1556. /// Unregister and free the plugin including all relevant resources
  1557. void (*free) (struct plugin *self);
  1558. };
  1559. static void
  1560. plugin_destroy (struct plugin *self)
  1561. {
  1562. self->vtable->free (self);
  1563. free (self->name);
  1564. free (self);
  1565. }
  1566. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1567. // This is a bit ugly since insertion is O(n) and the need to get rid of the
  1568. // specific type because of list macros, however I don't currently posses any
  1569. // strictly better, ordered data structure
  1570. struct hook
  1571. {
  1572. LIST_HEADER (struct hook)
  1573. int priority; ///< The lesser the sooner
  1574. };
  1575. static struct hook *
  1576. hook_insert (struct hook *list, struct hook *item)
  1577. {
  1578. // Corner cases: list is empty or we precede everything
  1579. if (!list || item->priority < list->priority)
  1580. {
  1581. LIST_PREPEND (list, item);
  1582. return list;
  1583. }
  1584. // Otherwise fast-forward to the last entry that precedes us
  1585. struct hook *before = list;
  1586. while (before->next && before->next->priority < item->priority)
  1587. before = before->next;
  1588. // And link ourselves in between it and its successor
  1589. if ((item->next = before->next))
  1590. item->next->prev = item;
  1591. before->next = item;
  1592. item->prev = before;
  1593. return list;
  1594. }
  1595. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1596. struct input_hook
  1597. {
  1598. struct hook super; ///< Common hook fields
  1599. /// Takes over the ownership of "input", returns either NULL if input
  1600. /// was thrown away, or a possibly modified version of it
  1601. char *(*filter) (struct input_hook *self,
  1602. struct buffer *buffer, char *input);
  1603. };
  1604. struct irc_hook
  1605. {
  1606. struct hook super; ///< Common hook fields
  1607. /// Takes over the ownership of "message", returns either NULL if message
  1608. /// was thrown away, or a possibly modified version of it
  1609. char *(*filter) (struct irc_hook *self,
  1610. struct server *server, char *message);
  1611. };
  1612. struct prompt_hook
  1613. {
  1614. struct hook super; ///< Common hook fields
  1615. /// Returns what the prompt should look like right now based on other state
  1616. char *(*make) (struct prompt_hook *self);
  1617. };
  1618. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1619. struct completion_word
  1620. {
  1621. size_t start; ///< Offset to start of word
  1622. size_t end; ///< Offset to end of word
  1623. };
  1624. struct completion
  1625. {
  1626. char *line; ///< The line which is being completed
  1627. struct completion_word *words; ///< Word locations
  1628. size_t words_len; ///< Number of words
  1629. size_t words_alloc; ///< Number of words allocated
  1630. size_t location; ///< Which word is being completed
  1631. };
  1632. struct completion_hook
  1633. {
  1634. struct hook super; ///< Common hook fields
  1635. /// Tries to add possible completions of "word" to "output"
  1636. void (*complete) (struct completion_hook *self,
  1637. struct completion *data, const char *word, struct strv *output);
  1638. };
  1639. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1640. struct app_context
  1641. {
  1642. char *attrs_defaults[ATTR_COUNT]; ///< Default terminal attributes
  1643. // Configuration:
  1644. struct config config; ///< Program configuration
  1645. char *attrs[ATTR_COUNT]; ///< Terminal attributes
  1646. bool isolate_buffers; ///< Isolate global/server buffers
  1647. bool beep_on_highlight; ///< Beep on highlight
  1648. bool logging; ///< Logging to file enabled
  1649. bool show_all_prefixes; ///< Show all prefixes before nicks
  1650. bool word_wrapping; ///< Enable simple word wrapping
  1651. struct str_map servers; ///< Our servers
  1652. // Events:
  1653. struct poller_fd tty_event; ///< Terminal input event
  1654. struct poller_fd signal_event; ///< Signal FD event
  1655. struct poller_timer flush_timer; ///< Flush all open files (e.g. logs)
  1656. struct poller_timer date_chg_tmr; ///< Print a date change
  1657. struct poller_timer autoaway_tmr; ///< Autoaway timer
  1658. struct poller poller; ///< Manages polled descriptors
  1659. bool quitting; ///< User requested quitting
  1660. bool polling; ///< The event loop is running
  1661. // Buffers:
  1662. struct buffer *buffers; ///< All our buffers in order
  1663. struct buffer *buffers_tail; ///< The tail of our buffers
  1664. struct buffer *global_buffer; ///< The global buffer
  1665. struct buffer *current_buffer; ///< The current buffer
  1666. struct buffer *last_buffer; ///< Last used buffer
  1667. struct str_map buffers_by_name; ///< Buffers by name
  1668. unsigned backlog_limit; ///< Limit for buffer lines
  1669. time_t last_displayed_msg_time; ///< Time of last displayed message
  1670. // Terminal:
  1671. iconv_t term_to_utf8; ///< Terminal encoding to UTF-8
  1672. iconv_t term_from_utf8; ///< UTF-8 to terminal encoding
  1673. struct input *input; ///< User interface
  1674. struct poller_idle prompt_event; ///< Deferred prompt refresh
  1675. struct poller_idle input_event; ///< Pending input event
  1676. struct strv pending_input; ///< Pending input lines
  1677. int *nick_palette; ///< A 256-color palette for nicknames
  1678. size_t nick_palette_len; ///< Number of entries in nick_palette
  1679. bool awaiting_mirc_escape; ///< Awaiting a mIRC attribute escape
  1680. bool in_bracketed_paste; ///< User is pasting some content
  1681. struct str input_buffer; ///< Buffered pasted content
  1682. bool running_backlog_helper; ///< Running a backlog helper
  1683. bool running_editor; ///< Running editor for the input
  1684. char *editor_filename; ///< The file being edited by user
  1685. int terminal_suspended; ///< Terminal suspension level
  1686. struct plugin *plugins; ///< Loaded plugins
  1687. struct hook *input_hooks; ///< Input hooks
  1688. struct hook *irc_hooks; ///< IRC hooks
  1689. struct hook *prompt_hooks; ///< Prompt hooks
  1690. struct hook *completion_hooks; ///< Autocomplete hooks
  1691. }
  1692. *g_ctx;
  1693. static struct ispect_field g_ctx_ispect[] =
  1694. {
  1695. ISPECT_MAP_REF( app_context, servers, false, server )
  1696. ISPECT_REF( app_context, buffers, true, buffer )
  1697. ISPECT_REF( app_context, global_buffer, false, buffer )
  1698. ISPECT_REF( app_context, current_buffer, false, buffer )
  1699. {}
  1700. };
  1701. static int *
  1702. filter_color_cube_for_acceptable_nick_colors (size_t *len)
  1703. {
  1704. // This is a pure function and we don't use threads, static storage is fine
  1705. static int table[6 * 6 * 6];
  1706. size_t len_counter = 0;
  1707. for (int x = 0; x < 6 * 6 * 6; x++)
  1708. {
  1709. // FIXME this isn't exactly right, the values aren't linear
  1710. int r = x / 36;
  1711. int g = (x / 6) % 6;
  1712. int b = (x % 6);
  1713. // Use the luma value of colours within the cube to filter colours that
  1714. // look okay-ish on terminals with both black and white backgrounds
  1715. double luma = 0.2126 * r / 6. + 0.7152 * g / 6. + 0.0722 * b / 6.;
  1716. if (luma >= .3 && luma <= .5)
  1717. table[len_counter++] = 16 + x;
  1718. }
  1719. *len = len_counter;
  1720. return table;
  1721. }
  1722. static bool
  1723. app_iconv_open (iconv_t *target, const char *to, const char *from)
  1724. {
  1725. if (ICONV_ACCEPTS_TRANSLIT)
  1726. {
  1727. char *to_real = xstrdup_printf ("%s//TRANSLIT", to);
  1728. *target = iconv_open (to_real, from);
  1729. free (to_real);
  1730. }
  1731. else
  1732. *target = iconv_open (to, from);
  1733. return *target != (iconv_t) -1;
  1734. }
  1735. static void
  1736. app_context_init (struct app_context *self)
  1737. {
  1738. memset (self, 0, sizeof *self);
  1739. self->config = config_make ();
  1740. poller_init (&self->poller);
  1741. self->servers = str_map_make ((str_map_free_fn) server_unref);
  1742. self->servers.key_xfrm = tolower_ascii_strxfrm;
  1743. self->buffers_by_name = str_map_make (NULL);
  1744. self->buffers_by_name.key_xfrm = tolower_ascii_strxfrm;
  1745. // So that we don't lose the logo shortly after startup
  1746. self->backlog_limit = 1000;
  1747. self->last_displayed_msg_time = time (NULL);
  1748. char *native = nl_langinfo (CODESET);
  1749. if (!app_iconv_open (&self->term_from_utf8, native, "UTF-8")
  1750. || !app_iconv_open (&self->term_to_utf8, "UTF-8", native))
  1751. exit_fatal ("creating the UTF-8 conversion object failed: %s",
  1752. strerror (errno));
  1753. self->input = input_new ();
  1754. self->input->user_data = self;
  1755. self->pending_input = strv_make ();
  1756. self->input_buffer = str_make ();
  1757. self->nick_palette =
  1758. filter_color_cube_for_acceptable_nick_colors (&self->nick_palette_len);
  1759. }
  1760. static void
  1761. app_context_free (struct app_context *self)
  1762. {
  1763. // Plugins can try to use of the other fields when destroyed
  1764. LIST_FOR_EACH (struct plugin, iter, self->plugins)
  1765. plugin_destroy (iter);
  1766. config_free (&self->config);
  1767. for (size_t i = 0; i < ATTR_COUNT; i++)
  1768. {
  1769. free (self->attrs_defaults[i]);
  1770. free (self->attrs[i]);
  1771. }
  1772. LIST_FOR_EACH (struct buffer, iter, self->buffers)
  1773. {
  1774. #ifdef HAVE_READLINE
  1775. // We can use the user interface here; see buffer_destroy()
  1776. CALL_ (self->input, buffer_destroy, iter->input_data);
  1777. iter->input_data = NULL;
  1778. #endif // HAVE_READLINE
  1779. buffer_unref (iter);
  1780. }
  1781. str_map_free (&self->buffers_by_name);
  1782. str_map_free (&self->servers);
  1783. poller_free (&self->poller);
  1784. iconv_close (self->term_from_utf8);
  1785. iconv_close (self->term_to_utf8);
  1786. CALL (self->input, destroy);
  1787. strv_free (&self->pending_input);
  1788. str_free (&self->input_buffer);
  1789. free (self->editor_filename);
  1790. }
  1791. static void
  1792. refresh_prompt (struct app_context *ctx)
  1793. {
  1794. // XXX: the need for this conditional could probably be resolved
  1795. // by some clever reordering
  1796. if (ctx->prompt_event.poller)
  1797. poller_idle_set (&ctx->prompt_event);
  1798. }
  1799. // --- Configuration -----------------------------------------------------------
  1800. static void
  1801. on_config_debug_mode_change (struct config_item *item)
  1802. {
  1803. g_debug_mode = item->value.boolean;
  1804. }
  1805. static void
  1806. on_config_show_all_prefixes_change (struct config_item *item)
  1807. {
  1808. struct app_context *ctx = item->user_data;
  1809. ctx->show_all_prefixes = item->value.boolean;
  1810. refresh_prompt (ctx);
  1811. }
  1812. static void on_config_backlog_limit_change (struct config_item *item);
  1813. static void on_config_attribute_change (struct config_item *item);
  1814. static void on_config_logging_change (struct config_item *item);
  1815. #define TRIVIAL_BOOLEAN_ON_CHANGE(name) \
  1816. static void \
  1817. on_config_ ## name ## _change (struct config_item *item) \
  1818. { \
  1819. struct app_context *ctx = item->user_data; \
  1820. ctx->name = item->value.boolean; \
  1821. }
  1822. TRIVIAL_BOOLEAN_ON_CHANGE (isolate_buffers)
  1823. TRIVIAL_BOOLEAN_ON_CHANGE (beep_on_highlight)
  1824. TRIVIAL_BOOLEAN_ON_CHANGE (word_wrapping)
  1825. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  1826. static bool
  1827. config_validate_nonjunk_string
  1828. (const struct config_item *item, struct error **e)
  1829. {
  1830. if (item->type == CONFIG_ITEM_NULL)
  1831. return true;
  1832. hard_assert (config_item_type_is_string (item->type));
  1833. for (size_t i = 0; i < item->value.string.len; i++)
  1834. {
  1835. // Not even a tabulator
  1836. unsigned char c = item->value.string.str[i];
  1837. if (c < 32)
  1838. {
  1839. error_set (e, "control characters are not allowed");
  1840. return false;
  1841. }
  1842. }
  1843. return true;
  1844. }
  1845. static bool
  1846. config_validate_addresses
  1847. (const struct config_item *item, struct error **e)
  1848. {
  1849. if (item->type == CONFIG_ITEM_NULL)
  1850. return true;
  1851. if (!config_validate_nonjunk_string (item, e))
  1852. return false;
  1853. // Comma-separated list of "host[:port]" pairs
  1854. regex_t re;
  1855. int err = regcomp (&re, "^([^/:,]+(:[^/:,]+)?)?"
  1856. "(,([^/:,]+(:[^/:,]+)?)?)*$", REG_EXTENDED | REG_NOSUB);
  1857. hard_assert (!err);
  1858. bool result = !regexec (&re, item->value.string.str, 0, NULL, 0);
  1859. if (!result)
  1860. error_set (e, "invalid address list string");
  1861. regfree (&re);
  1862. return result;
  1863. }
  1864. static bool
  1865. config_validate_nonnegative
  1866. (const struct config_item *item, struct error **e)
  1867. {
  1868. if (item->type == CONFIG_ITEM_NULL)
  1869. return true;
  1870. hard_assert (item->type == CONFIG_ITEM_INTEGER);
  1871. if (item->value.integer >= 0)
  1872. return true;
  1873. error_set (e, "must be non-negative");
  1874. return false;
  1875. }
  1876. static struct config_schema g_config_server[] =
  1877. {
  1878. { .name = "nicks",
  1879. .comment = "IRC nickname",
  1880. .type = CONFIG_ITEM_STRING_ARRAY,
  1881. .validate = config_validate_nonjunk_string },
  1882. { .name = "username",
  1883. .comment = "IRC user name",
  1884. .type = CONFIG_ITEM_STRING,
  1885. .validate = config_validate_nonjunk_string },
  1886. { .name = "realname",
  1887. .comment = "IRC real name/e-mail",
  1888. .type = CONFIG_ITEM_STRING,
  1889. .validate = config_validate_nonjunk_string },
  1890. { .name = "addresses",
  1891. .comment = "Addresses of the IRC network (e.g. \"irc.net:6667\")",
  1892. .type = CONFIG_ITEM_STRING_ARRAY,
  1893. .validate = config_validate_addresses },
  1894. { .name = "password",
  1895. .comment = "Password to connect to the server, if any",
  1896. .type = CONFIG_ITEM_STRING,
  1897. .validate = config_validate_nonjunk_string },
  1898. // XXX: if we add support for new capabilities, the value stays unchanged
  1899. { .name = "capabilities",
  1900. .comment = "Capabilities to use if supported by server",
  1901. .type = CONFIG_ITEM_STRING_ARRAY,
  1902. .validate = config_validate_nonjunk_string,
  1903. .default_ = "\"multi-prefix,invite-notify,server-time,echo-message\"" },
  1904. { .name = "tls",
  1905. .comment = "Whether to use TLS",
  1906. .type = CONFIG_ITEM_BOOLEAN,
  1907. .default_ = "off" },
  1908. { .name = "tls_cert",
  1909. .comment = "Client TLS certificate (PEM)",
  1910. .type = CONFIG_ITEM_STRING },
  1911. { .name = "tls_verify",
  1912. .comment = "Whether to verify certificates",
  1913. .type = CONFIG_ITEM_BOOLEAN,
  1914. .default_ = "on" },
  1915. { .name = "tls_ca_file",
  1916. .comment = "OpenSSL CA bundle file",
  1917. .type = CONFIG_ITEM_STRING },
  1918. { .name = "tls_ca_path",
  1919. .comment = "OpenSSL CA bundle path",
  1920. .type = CONFIG_ITEM_STRING },
  1921. { .name = "tls_ciphers",
  1922. .comment = "OpenSSL cipher preference list",
  1923. .type = CONFIG_ITEM_STRING,
  1924. .default_ = "\"DEFAULT:!MEDIUM:!LOW\"" },
  1925. { .name = "autoconnect",
  1926. .comment = "Connect automatically on startup",
  1927. .type = CONFIG_ITEM_BOOLEAN,
  1928. .default_ = "on" },
  1929. { .name = "autojoin",
  1930. .comment = "Channels to join on start (e.g. \"#abc,#def key,#ghi\")",
  1931. .type = CONFIG_ITEM_STRING_ARRAY,
  1932. .validate = config_validate_nonjunk_string },
  1933. { .name = "command",
  1934. .comment = "Command to execute after a successful connect",
  1935. .type = CONFIG_ITEM_STRING },
  1936. { .name = "command_delay",
  1937. .comment = "Delay between executing \"command\" and joining channels",
  1938. .type = CONFIG_ITEM_INTEGER,
  1939. .validate = config_validate_nonnegative,
  1940. .default_ = "0" },
  1941. { .name = "reconnect",
  1942. .comment = "Whether to reconnect on error",
  1943. .type = CONFIG_ITEM_BOOLEAN,
  1944. .default_ = "on" },
  1945. { .name = "reconnect_delay",
  1946. .comment = "Time between reconnecting",
  1947. .type = CONFIG_ITEM_INTEGER,
  1948. .validate = config_validate_nonnegative,
  1949. .default_ = "5" },
  1950. { .name = "socks_host",
  1951. .comment = "Address of a SOCKS 4a/5 proxy",
  1952. .type = CONFIG_ITEM_STRING,
  1953. .validate = config_validate_nonjunk_string },
  1954. { .name = "socks_port",
  1955. .comment = "SOCKS port number",
  1956. .type = CONFIG_ITEM_INTEGER,
  1957. .validate = config_validate_nonnegative,
  1958. .default_ = "1080" },
  1959. { .name = "socks_username",
  1960. .comment = "SOCKS auth. username",
  1961. .type = CONFIG_ITEM_STRING },
  1962. { .name = "socks_password",
  1963. .comment = "SOCKS auth. password",
  1964. .type = CONFIG_ITEM_STRING },
  1965. {}
  1966. };
  1967. static struct config_schema g_config_behaviour[] =
  1968. {
  1969. { .name = "isolate_buffers",
  1970. .comment = "Don't leak messages from the server and global buffers",
  1971. .type = CONFIG_ITEM_BOOLEAN,
  1972. .default_ = "off",
  1973. .on_change = on_config_isolate_buffers_change },
  1974. { .name = "beep_on_highlight",
  1975. .comment = "Beep when highlighted or on a new invisible PM",
  1976. .type = CONFIG_ITEM_BOOLEAN,
  1977. .default_ = "on",
  1978. .on_change = on_config_beep_on_highlight_change },
  1979. { .name = "show_all_prefixes",
  1980. .comment = "Show all prefixes in front of nicknames",
  1981. .type = CONFIG_ITEM_BOOLEAN,
  1982. .default_ = "off",
  1983. .on_change = on_config_show_all_prefixes_change },
  1984. { .name = "word_wrapping",
  1985. .comment = "Enable simple word wrapping in buffers",
  1986. .type = CONFIG_ITEM_BOOLEAN,
  1987. .default_ = "on",
  1988. .on_change = on_config_word_wrapping_change },
  1989. { .name = "date_change_line",
  1990. .comment = "Input to strftime(3) for the date change line",
  1991. .type = CONFIG_ITEM_STRING,
  1992. .default_ = "\"%F\"" },
  1993. { .name = "logging",
  1994. .comment = "Log buffer contents to file",
  1995. .type = CONFIG_ITEM_BOOLEAN,
  1996. .default_ = "off",
  1997. .on_change = on_config_logging_change },
  1998. { .name = "save_on_quit",
  1999. .comment = "Save configuration before quitting",
  2000. .type = CONFIG_ITEM_BOOLEAN,
  2001. .default_ = "on" },
  2002. { .name = "debug_mode",
  2003. .comment = "Produce some debugging output",
  2004. .type = CONFIG_ITEM_BOOLEAN,
  2005. .default_ = "off",
  2006. .on_change = on_config_debug_mode_change },
  2007. // GNU screen has an ^O in its formatting attributes reset string,
  2008. // therefore we can't just pipe raw formatting to `less -R`.
  2009. // You can use the -r switch, however that makes `less` very confused
  2010. // about line wrapping, and the result is suboptimal.
  2011. { .name = "backlog_limit",
  2012. .comment = "Maximum number of lines stored in the backlog",
  2013. .type = CONFIG_ITEM_INTEGER,
  2014. .validate = config_validate_nonnegative,
  2015. .default_ = "1000",
  2016. .on_change = on_config_backlog_limit_change },
  2017. { .name = "backlog_helper",
  2018. .comment = "Shell command to display a buffer's history",
  2019. .type = CONFIG_ITEM_STRING,
  2020. .default_ = "\"LESSSECURE=1 less -M -R +G\"" },
  2021. { .name = "backlog_helper_strip_formatting",
  2022. .comment = "Strip formatting from backlog helper input",
  2023. .type = CONFIG_ITEM_BOOLEAN,
  2024. .default_ = "on" },
  2025. { .name = "reconnect_delay_growing",
  2026. .comment = "Growing factor for reconnect delay",
  2027. .type = CONFIG_ITEM_INTEGER,
  2028. .validate = config_validate_nonnegative,
  2029. .default_ = "2" },
  2030. { .name = "reconnect_delay_max",
  2031. .comment = "Maximum reconnect delay in seconds",
  2032. .type = CONFIG_ITEM_INTEGER,
  2033. .validate = config_validate_nonnegative,
  2034. .default_ = "600" },
  2035. { .name = "autoaway_message",
  2036. .comment = "Automated away message",
  2037. .type = CONFIG_ITEM_STRING,
  2038. .default_ = "\"I'm not here right now\"" },
  2039. { .name = "autoaway_delay",
  2040. .comment = "Delay from the last keypress in seconds",
  2041. .type = CONFIG_ITEM_INTEGER,
  2042. .validate = config_validate_nonnegative,
  2043. .default_ = "1800" },
  2044. { .name = "plugin_autoload",
  2045. .comment = "Plugins to automatically load on start",
  2046. .type = CONFIG_ITEM_STRING_ARRAY,
  2047. .validate = config_validate_nonjunk_string },
  2048. {}
  2049. };
  2050. static struct config_schema g_config_attributes[] =
  2051. {
  2052. #define XX(x, y, z) { .name = y, .comment = z, .type = CONFIG_ITEM_STRING, \
  2053. .on_change = on_config_attribute_change },
  2054. ATTR_TABLE (XX)
  2055. #undef XX
  2056. {}
  2057. };
  2058. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2059. static void
  2060. load_config_behaviour (struct config_item *subtree, void *user_data)
  2061. {
  2062. config_schema_apply_to_object (g_config_behaviour, subtree, user_data);
  2063. }
  2064. static void
  2065. load_config_attributes (struct config_item *subtree, void *user_data)
  2066. {
  2067. config_schema_apply_to_object (g_config_attributes, subtree, user_data);
  2068. }
  2069. static void
  2070. register_config_modules (struct app_context *ctx)
  2071. {
  2072. struct config *config = &ctx->config;
  2073. // The servers are loaded later when we can create buffers for them
  2074. config_register_module (config, "servers", NULL, NULL);
  2075. config_register_module (config, "aliases", NULL, NULL);
  2076. config_register_module (config, "plugins", NULL, NULL);
  2077. config_register_module (config, "behaviour", load_config_behaviour, ctx);
  2078. config_register_module (config, "attributes", load_config_attributes, ctx);
  2079. }
  2080. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2081. static const char *
  2082. get_config_string (struct config_item *root, const char *key)
  2083. {
  2084. struct config_item *item = config_item_get (root, key, NULL);
  2085. hard_assert (item);
  2086. if (item->type == CONFIG_ITEM_NULL)
  2087. return NULL;
  2088. hard_assert (config_item_type_is_string (item->type));
  2089. return item->value.string.str;
  2090. }
  2091. static bool
  2092. set_config_string
  2093. (struct config_item *root, const char *key, const char *value)
  2094. {
  2095. struct config_item *item = config_item_get (root, key, NULL);
  2096. hard_assert (item);
  2097. struct config_item *new_ = config_item_string_from_cstr (value);
  2098. struct error *e = NULL;
  2099. if (config_item_set_from (item, new_, &e))
  2100. return true;
  2101. config_item_destroy (new_);
  2102. print_error ("couldn't set `%s' in configuration: %s", key, e->message);
  2103. error_free (e);
  2104. return false;
  2105. }
  2106. static int64_t
  2107. get_config_integer (struct config_item *root, const char *key)
  2108. {
  2109. struct config_item *item = config_item_get (root, key, NULL);
  2110. hard_assert (item && item->type == CONFIG_ITEM_INTEGER);
  2111. return item->value.integer;
  2112. }
  2113. static bool
  2114. get_config_boolean (struct config_item *root, const char *key)
  2115. {
  2116. struct config_item *item = config_item_get (root, key, NULL);
  2117. hard_assert (item && item->type == CONFIG_ITEM_BOOLEAN);
  2118. return item->value.boolean;
  2119. }
  2120. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2121. static struct str_map *
  2122. get_servers_config (struct app_context *ctx)
  2123. {
  2124. return &config_item_get (ctx->config.root, "servers", NULL)->value.object;
  2125. }
  2126. static struct str_map *
  2127. get_aliases_config (struct app_context *ctx)
  2128. {
  2129. return &config_item_get (ctx->config.root, "aliases", NULL)->value.object;
  2130. }
  2131. static struct str_map *
  2132. get_plugins_config (struct app_context *ctx)
  2133. {
  2134. return &config_item_get (ctx->config.root, "plugins", NULL)->value.object;
  2135. }
  2136. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2137. static void
  2138. serialize_configuration (struct config_item *root, struct str *output)
  2139. {
  2140. str_append (output,
  2141. "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
  2142. "#\n"
  2143. "# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}\n"
  2144. "# /" PROGRAM_NAME " as well as in $XDG_CONFIG_DIRS/" PROGRAM_NAME "\n"
  2145. "#\n"
  2146. "# Everything is in UTF-8. Any custom comments will be overwritten.\n"
  2147. "\n");
  2148. config_item_write (root, true, output);
  2149. }
  2150. // --- Terminal output ---------------------------------------------------------
  2151. /// Default color pair
  2152. #define COLOR_DEFAULT -1
  2153. /// Bright versions of the basic color set
  2154. #define COLOR_BRIGHT(x) (COLOR_ ## x + 8)
  2155. /// Builds a color pair for 256-color terminals with a 16-color backup value
  2156. #define COLOR_256(name, c256) \
  2157. (((COLOR_ ## name) & 0xFFFF) | (((c256) & 0xFFFF) << 16))
  2158. typedef int (*terminal_printer_fn) (int);
  2159. static int
  2160. putchar_stderr (int c)
  2161. {
  2162. return fputc (c, stderr);
  2163. }
  2164. static terminal_printer_fn
  2165. get_attribute_printer (FILE *stream)
  2166. {
  2167. if (stream == stdout && g_terminal.stdout_is_tty)
  2168. return putchar;
  2169. if (stream == stderr && g_terminal.stderr_is_tty)
  2170. return putchar_stderr;
  2171. return NULL;
  2172. }
  2173. static void
  2174. vprint_attributed (struct app_context *ctx,
  2175. FILE *stream, intptr_t attribute, const char *fmt, va_list ap)
  2176. {
  2177. terminal_printer_fn printer = get_attribute_printer (stream);
  2178. if (!attribute)
  2179. printer = NULL;
  2180. if (printer)
  2181. tputs (ctx->attrs[attribute], 1, printer);
  2182. vfprintf (stream, fmt, ap);
  2183. if (printer)
  2184. tputs (ctx->attrs[ATTR_RESET], 1, printer);
  2185. }
  2186. static void
  2187. print_attributed (struct app_context *ctx,
  2188. FILE *stream, intptr_t attribute, const char *fmt, ...)
  2189. {
  2190. va_list ap;
  2191. va_start (ap, fmt);
  2192. vprint_attributed (ctx, stream, attribute, fmt, ap);
  2193. va_end (ap);
  2194. }
  2195. static void
  2196. log_message_attributed (void *user_data, const char *quote, const char *fmt,
  2197. va_list ap)
  2198. {
  2199. FILE *stream = stderr;
  2200. struct app_context *ctx = g_ctx;
  2201. CALL (ctx->input, hide);
  2202. print_attributed (ctx, stream, (intptr_t) user_data, "%s", quote);
  2203. vprint_attributed (ctx, stream, (intptr_t) user_data, fmt, ap);
  2204. fputs ("\n", stream);
  2205. CALL (ctx->input, show);
  2206. }
  2207. static ssize_t
  2208. attr_by_name (const char *name)
  2209. {
  2210. static const char *table[ATTR_COUNT] =
  2211. {
  2212. #define XX(x, y, z) [ATTR_ ## x] = y,
  2213. ATTR_TABLE (XX)
  2214. #undef XX
  2215. };
  2216. for (size_t i = 0; i < N_ELEMENTS (table); i++)
  2217. if (!strcmp (name, table[i]))
  2218. return i;
  2219. return -1;
  2220. }
  2221. static void
  2222. on_config_attribute_change (struct config_item *item)
  2223. {
  2224. struct app_context *ctx = item->user_data;
  2225. ssize_t id = attr_by_name (item->schema->name);
  2226. if (id != -1)
  2227. {
  2228. cstr_set (&ctx->attrs[id], xstrdup (item->type == CONFIG_ITEM_NULL
  2229. ? ctx->attrs_defaults[id]
  2230. : item->value.string.str));
  2231. }
  2232. }
  2233. static void
  2234. init_colors (struct app_context *ctx)
  2235. {
  2236. bool have_ti = init_terminal ();
  2237. char **defaults = ctx->attrs_defaults;
  2238. #define INIT_ATTR(id, ti) defaults[ATTR_ ## id] = xstrdup (have_ti ? (ti) : "")
  2239. INIT_ATTR (PROMPT, enter_bold_mode);
  2240. INIT_ATTR (RESET, exit_attribute_mode);
  2241. INIT_ATTR (DATE_CHANGE, enter_bold_mode);
  2242. INIT_ATTR (READ_MARKER, g_terminal.color_set_fg[COLOR_MAGENTA]);
  2243. INIT_ATTR (WARNING, g_terminal.color_set_fg[COLOR_YELLOW]);
  2244. INIT_ATTR (ERROR, g_terminal.color_set_fg[COLOR_RED]);
  2245. INIT_ATTR (EXTERNAL, g_terminal.color_set_fg[COLOR_WHITE]);
  2246. INIT_ATTR (TIMESTAMP, g_terminal.color_set_fg[COLOR_WHITE]);
  2247. INIT_ATTR (ACTION, g_terminal.color_set_fg[COLOR_RED]);
  2248. INIT_ATTR (USERHOST, g_terminal.color_set_fg[COLOR_CYAN]);
  2249. INIT_ATTR (JOIN, g_terminal.color_set_fg[COLOR_GREEN]);
  2250. INIT_ATTR (PART, g_terminal.color_set_fg[COLOR_RED]);
  2251. char *highlight = have_ti ? xstrdup_printf ("%s%s%s",
  2252. g_terminal.color_set_fg[COLOR_YELLOW],
  2253. g_terminal.color_set_bg[COLOR_MAGENTA],
  2254. enter_bold_mode) : NULL;
  2255. INIT_ATTR (HIGHLIGHT, highlight);
  2256. free (highlight);
  2257. #undef INIT_ATTR
  2258. // This prevents formatters from obtaining an attribute printer function
  2259. if (!have_ti)
  2260. {
  2261. g_terminal.stdout_is_tty = false;
  2262. g_terminal.stderr_is_tty = false;
  2263. }
  2264. g_log_message_real = log_message_attributed;
  2265. // Apply the default values so that we start with any formatting at all
  2266. config_schema_call_changed
  2267. (config_item_get (ctx->config.root, "attributes", NULL));
  2268. }
  2269. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2270. // A little tool that tries to make the most of the terminal's capabilities
  2271. // to set up text attributes. It mostly targets just terminal emulators as that
  2272. // is what people are using these days. At least no stupid ncurses limits us
  2273. // with color pairs.
  2274. enum
  2275. {
  2276. TEXT_BOLD = 1 << 0,
  2277. TEXT_ITALIC = 1 << 1,
  2278. TEXT_UNDERLINE = 1 << 2,
  2279. TEXT_INVERSE = 1 << 3,
  2280. TEXT_BLINK = 1 << 4
  2281. };
  2282. struct attr_printer
  2283. {
  2284. char **attrs; ///< Named attributes
  2285. FILE *stream; ///< Output stream
  2286. bool dirty; ///< Attributes are set
  2287. };
  2288. #define ATTR_PRINTER_INIT(ctx, stream) { ctx->attrs, stream, true }
  2289. static void
  2290. attr_printer_tputs (struct attr_printer *self, const char *attr)
  2291. {
  2292. terminal_printer_fn printer = get_attribute_printer (self->stream);
  2293. if (printer)
  2294. tputs (attr, 1, printer);
  2295. else
  2296. // We shouldn't really do this but we need it to
  2297. // output formatting to the backlog
  2298. fputs (attr, self->stream);
  2299. }
  2300. static void
  2301. attr_printer_reset (struct attr_printer *self)
  2302. {
  2303. if (self->dirty)
  2304. attr_printer_tputs (self, self->attrs[ATTR_RESET]);
  2305. self->dirty = false;
  2306. }
  2307. static void
  2308. attr_printer_apply_named (struct attr_printer *self, int attribute)
  2309. {
  2310. attr_printer_reset (self);
  2311. if (attribute != ATTR_RESET)
  2312. {
  2313. attr_printer_tputs (self, self->attrs[attribute]);
  2314. self->dirty = true;
  2315. }
  2316. }
  2317. // NOTE: commonly terminals have:
  2318. // 8 colors (worst, bright fg with BOLD, bg sometimes with BLINK)
  2319. // 16 colors (okayish, we have the full basic range guaranteed)
  2320. // 88 colors (the same plus a 4^3 RGB cube and a few shades of gray)
  2321. // 256 colors (best, like above but with a larger cube and more gray)
  2322. /// Interpolate from the 256-color palette to the 88-color one
  2323. static int
  2324. attr_printer_256_to_88 (int color)
  2325. {
  2326. // These colours are the same everywhere
  2327. if (color < 16)
  2328. return color;
  2329. // 24 -> 8 extra shades of gray
  2330. if (color >= 232)
  2331. return 80 + (color - 232) / 3;
  2332. // 6 * 6 * 6 cube -> 4 * 4 * 4 cube
  2333. int x[6] = { 0, 1, 1, 2, 2, 3 };
  2334. int index = color - 16;
  2335. return 16 +
  2336. ( x[ index / 36 ] << 8
  2337. | x[(index / 6) % 6 ] << 4
  2338. | x[(index % 6) ] );
  2339. }
  2340. static int
  2341. attr_printer_decode_color (int color, bool *is_bright)
  2342. {
  2343. int16_t c16 = color; hard_assert (c16 < 16);
  2344. int16_t c256 = color >> 16; hard_assert (c256 < 256);
  2345. *is_bright = false;
  2346. switch (max_colors)
  2347. {
  2348. case 8:
  2349. if (c16 >= 8)
  2350. {
  2351. c16 -= 8;
  2352. *is_bright = true;
  2353. }
  2354. // Fall-through
  2355. case 16:
  2356. return c16;
  2357. case 88:
  2358. return c256 <= 0 ? c16 : attr_printer_256_to_88 (c256);
  2359. case 256:
  2360. return c256 <= 0 ? c16 : c256;
  2361. default:
  2362. // Unsupported palette
  2363. return -1;
  2364. }
  2365. }
  2366. static void
  2367. attr_printer_apply (struct attr_printer *self,
  2368. int text_attrs, int wanted_fg, int wanted_bg)
  2369. {
  2370. bool fg_is_bright;
  2371. int fg = attr_printer_decode_color (wanted_fg, &fg_is_bright);
  2372. bool bg_is_bright;
  2373. int bg = attr_printer_decode_color (wanted_bg, &bg_is_bright);
  2374. bool have_inverse = !!(text_attrs & TEXT_INVERSE);
  2375. if (have_inverse)
  2376. {
  2377. bool tmp = fg_is_bright;
  2378. fg_is_bright = bg_is_bright;
  2379. bg_is_bright = tmp;
  2380. }
  2381. // In 8 colour mode, some terminals don't support bright backgrounds.
  2382. // However, we can make use of the fact that the brightness change caused
  2383. // by the bold attribute is retained when inverting the colours.
  2384. // This has the downside of making the text bold when it's not supposed
  2385. // to be, and we still can't make both colours bright, so it's more of
  2386. // an interesting hack rather than anything else.
  2387. if (!fg_is_bright && bg_is_bright && have_inverse)
  2388. text_attrs |= TEXT_BOLD;
  2389. else if (!fg_is_bright && bg_is_bright
  2390. && !have_inverse && fg >= 0 && bg >= 0)
  2391. {
  2392. // As long as none of the colours is the default, we can swap them
  2393. int tmp = fg; fg = bg; bg = tmp;
  2394. text_attrs |= TEXT_BOLD | TEXT_INVERSE;
  2395. }
  2396. else
  2397. {
  2398. // This is what works on normal, decent terminals
  2399. if (fg_is_bright) text_attrs |= TEXT_BOLD;
  2400. if (bg_is_bright) text_attrs |= TEXT_BLINK;
  2401. }
  2402. attr_printer_reset (self);
  2403. if (text_attrs)
  2404. attr_printer_tputs (self, tparm (set_attributes,
  2405. 0, // standout
  2406. text_attrs & TEXT_UNDERLINE,
  2407. text_attrs & TEXT_INVERSE,
  2408. text_attrs & TEXT_BLINK,
  2409. 0, // dim
  2410. text_attrs & TEXT_BOLD,
  2411. 0, // blank
  2412. 0, // protect
  2413. 0)); // acs
  2414. if (enter_italics_mode && (text_attrs & TEXT_ITALIC))
  2415. attr_printer_tputs (self, enter_italics_mode);
  2416. if (fg >= 0)
  2417. attr_printer_tputs (self, g_terminal.color_set_fg[fg]);
  2418. if (bg >= 0)
  2419. attr_printer_tputs (self, g_terminal.color_set_bg[bg]);
  2420. self->dirty = true;
  2421. }
  2422. // --- Helpers -----------------------------------------------------------------
  2423. static int
  2424. irc_server_strcmp (struct server *s, const char *a, const char *b)
  2425. {
  2426. int x;
  2427. while (*a || *b)
  2428. if ((x = s->irc_tolower (*a++) - s->irc_tolower (*b++)))
  2429. return x;
  2430. return 0;
  2431. }
  2432. static int
  2433. irc_server_strncmp (struct server *s, const char *a, const char *b, size_t n)
  2434. {
  2435. int x;
  2436. while (n-- && (*a || *b))
  2437. if ((x = s->irc_tolower (*a++) - s->irc_tolower (*b++)))
  2438. return x;
  2439. return 0;
  2440. }
  2441. static char *
  2442. irc_cut_nickname (const char *prefix)
  2443. {
  2444. return cstr_cut_until (prefix, "!@");
  2445. }
  2446. static const char *
  2447. irc_find_userhost (const char *prefix)
  2448. {
  2449. const char *p = strchr (prefix, '!');
  2450. return p ? p + 1 : NULL;
  2451. }
  2452. static bool
  2453. irc_is_this_us (struct server *s, const char *prefix)
  2454. {
  2455. // This shouldn't be called before successfully registering.
  2456. // Better safe than sorry, though.
  2457. if (!s->irc_user)
  2458. return false;
  2459. char *nick = irc_cut_nickname (prefix);
  2460. bool result = !irc_server_strcmp (s, nick, s->irc_user->nickname);
  2461. free (nick);
  2462. return result;
  2463. }
  2464. static bool
  2465. irc_is_channel (struct server *s, const char *ident)
  2466. {
  2467. return *ident
  2468. && (!!strchr (s->irc_chantypes, *ident) ||
  2469. !!strchr (s->irc_idchan_prefixes, *ident));
  2470. }
  2471. // Message targets can be prefixed by a character filtering their targets
  2472. static const char *
  2473. irc_skip_statusmsg (struct server *s, const char *target)
  2474. {
  2475. return target + (*target && strchr (s->irc_statusmsg, *target));
  2476. }
  2477. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2478. // As of 2015, everything should be in UTF-8. And if it's not, we'll decode it
  2479. // as ISO Latin 1. This function should not be called on the whole message.
  2480. static char *
  2481. irc_to_utf8 (const char *text)
  2482. {
  2483. if (!text)
  2484. return NULL;
  2485. size_t len = strlen (text) + 1;
  2486. if (utf8_validate (text, len))
  2487. return xstrdup (text);
  2488. // Windows 1252 redefines several silly C1 control characters as glyphs
  2489. static const char c1[32][4] =
  2490. {
  2491. "\xe2\x82\xac", "\xc2\x81", "\xe2\x80\x9a", "\xc6\x92",
  2492. "\xe2\x80\x9e", "\xe2\x80\xa6", "\xe2\x80\xa0", "\xe2\x80\xa1",
  2493. "\xcb\x86", "\xe2\x80\xb0", "\xc5\xa0", "\xe2\x80\xb9",
  2494. "\xc5\x92", "\xc2\x8d", "\xc5\xbd", "\xc2\x8f",
  2495. "\xc2\x90", "\xe2\x80\x98", "\xe2\x80\x99", "\xe2\x80\x9c",
  2496. "\xe2\x80\x9d", "\xe2\x80\xa2", "\xe2\x80\x93", "\xe2\x80\x94",
  2497. "\xcb\x9c", "\xe2\x84\xa2", "\xc5\xa1", "\xe2\x80\xba",
  2498. "\xc5\x93", "\xc2\x9d", "\xc5\xbe", "\xc5\xb8",
  2499. };
  2500. struct str s = str_make ();
  2501. for (const char *p = text; *p; p++)
  2502. {
  2503. int c = *(unsigned char *) p;
  2504. if (c < 0x80)
  2505. str_append_c (&s, c);
  2506. else if (c < 0xA0)
  2507. str_append (&s, c1[c & 0x1f]);
  2508. else
  2509. str_append_data (&s,
  2510. (char[]) {0xc0 | (c >> 6), 0x80 | (c & 0x3f)}, 2);
  2511. }
  2512. return str_steal (&s);
  2513. }
  2514. // This function is used to output debugging IRC traffic to the terminal.
  2515. // It's far from ideal, as any non-UTF-8 text degrades the entire line to
  2516. // ISO Latin 1. But it should work good enough most of the time.
  2517. static char *
  2518. irc_to_term (struct app_context *ctx, const char *text)
  2519. {
  2520. char *utf8 = irc_to_utf8 (text);
  2521. char *term = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL);
  2522. free (utf8);
  2523. return term;
  2524. }
  2525. // --- Output formatter --------------------------------------------------------
  2526. // This complicated piece of code makes attributed text formatting simple.
  2527. // We use a printf-inspired syntax to push attributes and text to the object,
  2528. // then flush it either to a terminal, or a log file with formatting stripped.
  2529. //
  2530. // Format strings use a #-quoted notation, to differentiate from printf:
  2531. // #s inserts a string (expected to be in UTF-8)
  2532. // #d inserts a signed integer
  2533. // #l inserts a locale-encoded string
  2534. //
  2535. // #S inserts a string from the server with unknown encoding
  2536. // #m inserts a mIRC-formatted string (auto-resets at boundaries)
  2537. // #n cuts the nickname from a string and automatically colours it
  2538. // #N is like #n but also appends userhost, if present
  2539. //
  2540. // #a inserts named attributes (auto-resets)
  2541. // #r resets terminal attributes
  2542. // #c sets foreground color
  2543. // #C sets background color
  2544. //
  2545. // Modifiers:
  2546. // & free() the string argument after using it
  2547. static void
  2548. formatter_add_item (struct formatter *self, struct formatter_item template_)
  2549. {
  2550. if (template_.text)
  2551. template_.text = xstrdup (template_.text);
  2552. if (self->items_len == self->items_alloc)
  2553. self->items = xreallocarray
  2554. (self->items, sizeof *self->items, (self->items_alloc <<= 1));
  2555. self->items[self->items_len++] = template_;
  2556. }
  2557. #define FORMATTER_ADD_ITEM(self, type_, ...) formatter_add_item ((self), \
  2558. (struct formatter_item) { .type = FORMATTER_ITEM_ ## type_, __VA_ARGS__ })
  2559. #define FORMATTER_ADD_RESET(self) \
  2560. FORMATTER_ADD_ITEM ((self), ATTR, .attribute = ATTR_RESET)
  2561. #define FORMATTER_ADD_TEXT(self, text_) \
  2562. FORMATTER_ADD_ITEM ((self), TEXT, .text = (text_))
  2563. #define FORMATTER_ADD_SIMPLE(self, attribute_) \
  2564. FORMATTER_ADD_ITEM ((self), SIMPLE, .attribute = TEXT_ ## attribute_)
  2565. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2566. enum
  2567. {
  2568. MIRC_WHITE, MIRC_BLACK, MIRC_BLUE, MIRC_GREEN,
  2569. MIRC_L_RED, MIRC_RED, MIRC_PURPLE, MIRC_ORANGE,
  2570. MIRC_YELLOW, MIRC_L_GREEN, MIRC_CYAN, MIRC_L_CYAN,
  2571. MIRC_L_BLUE, MIRC_L_PURPLE, MIRC_GRAY, MIRC_L_GRAY,
  2572. };
  2573. // We use estimates from the 16 color terminal palette, or the 256 color cube,
  2574. // which is not always available. The mIRC orange colour is only in the cube.
  2575. static const int g_mirc_to_terminal[] =
  2576. {
  2577. [MIRC_WHITE] = COLOR_256 (BRIGHT (WHITE), 231),
  2578. [MIRC_BLACK] = COLOR_256 (BLACK, 16),
  2579. [MIRC_BLUE] = COLOR_256 (BLUE, 19),
  2580. [MIRC_GREEN] = COLOR_256 (GREEN, 34),
  2581. [MIRC_L_RED] = COLOR_256 (BRIGHT (RED), 196),
  2582. [MIRC_RED] = COLOR_256 (RED, 124),
  2583. [MIRC_PURPLE] = COLOR_256 (MAGENTA, 127),
  2584. [MIRC_ORANGE] = COLOR_256 (BRIGHT (YELLOW), 214),
  2585. [MIRC_YELLOW] = COLOR_256 (BRIGHT (YELLOW), 226),
  2586. [MIRC_L_GREEN] = COLOR_256 (BRIGHT (GREEN), 46),
  2587. [MIRC_CYAN] = COLOR_256 (CYAN, 37),
  2588. [MIRC_L_CYAN] = COLOR_256 (BRIGHT (CYAN), 51),
  2589. [MIRC_L_BLUE] = COLOR_256 (BRIGHT (BLUE), 21),
  2590. [MIRC_L_PURPLE] = COLOR_256 (BRIGHT (MAGENTA),201),
  2591. [MIRC_GRAY] = COLOR_256 (BRIGHT (BLACK), 244),
  2592. [MIRC_L_GRAY] = COLOR_256 (WHITE, 252),
  2593. };
  2594. // TODO: support more colors, see https://modern.ircdocs.horse/formatting.html
  2595. // + http://anti.teamidiot.de/static/nei/*/extended_mirc_color_proposal.html
  2596. static const char *
  2597. formatter_parse_mirc_color (struct formatter *self, const char *s)
  2598. {
  2599. if (!isdigit_ascii (*s))
  2600. {
  2601. FORMATTER_ADD_ITEM (self, FG_COLOR, .color = -1);
  2602. FORMATTER_ADD_ITEM (self, BG_COLOR, .color = -1);
  2603. return s;
  2604. }
  2605. int fg = *s++ - '0';
  2606. if (isdigit_ascii (*s))
  2607. fg = fg * 10 + (*s++ - '0');
  2608. if (fg >= 0 && fg < 16)
  2609. FORMATTER_ADD_ITEM (self, FG_COLOR, .color = g_mirc_to_terminal[fg]);
  2610. if (*s != ',' || !isdigit_ascii (s[1]))
  2611. return s;
  2612. s++;
  2613. int bg = *s++ - '0';
  2614. if (isdigit_ascii (*s))
  2615. bg = bg * 10 + (*s++ - '0');
  2616. if (bg >= 0 && bg < 16)
  2617. FORMATTER_ADD_ITEM (self, BG_COLOR, .color = g_mirc_to_terminal[bg]);
  2618. return s;
  2619. }
  2620. static void
  2621. formatter_parse_mirc (struct formatter *self, const char *s)
  2622. {
  2623. FORMATTER_ADD_RESET (self);
  2624. struct str buf = str_make ();
  2625. unsigned char c;
  2626. while ((c = *s++))
  2627. {
  2628. if (buf.len && c < 0x20)
  2629. {
  2630. FORMATTER_ADD_TEXT (self, buf.str);
  2631. str_reset (&buf);
  2632. }
  2633. switch (c)
  2634. {
  2635. case '\x02': FORMATTER_ADD_SIMPLE (self, BOLD); break;
  2636. case '\x1d': FORMATTER_ADD_SIMPLE (self, ITALIC); break;
  2637. case '\x1f': FORMATTER_ADD_SIMPLE (self, UNDERLINE); break;
  2638. case '\x16': FORMATTER_ADD_SIMPLE (self, INVERSE); break;
  2639. case '\x03':
  2640. s = formatter_parse_mirc_color (self, s);
  2641. break;
  2642. case '\x0f':
  2643. FORMATTER_ADD_RESET (self);
  2644. break;
  2645. default:
  2646. str_append_c (&buf, c);
  2647. }
  2648. }
  2649. if (buf.len)
  2650. FORMATTER_ADD_TEXT (self, buf.str);
  2651. str_free (&buf);
  2652. FORMATTER_ADD_RESET (self);
  2653. }
  2654. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2655. static void
  2656. formatter_parse_nick (struct formatter *self, const char *s)
  2657. {
  2658. // For outgoing messages; maybe we should add a special #t for them
  2659. // which would also make us not cut off the userhost part, ever
  2660. if (irc_is_channel (self->s, irc_skip_statusmsg (self->s, s)))
  2661. {
  2662. char *tmp = irc_to_utf8 (s);
  2663. FORMATTER_ADD_TEXT (self, tmp);
  2664. free (tmp);
  2665. return;
  2666. }
  2667. char *nick = irc_cut_nickname (s);
  2668. int color = siphash_wrapper (nick, strlen (nick)) % 7;
  2669. // Never use the black colour, could become transparent on black terminals;
  2670. // white is similarly excluded from the range
  2671. if (color == COLOR_BLACK)
  2672. color = (uint16_t) -1;
  2673. // Use a color from the 256-color cube if available
  2674. color |= self->ctx->nick_palette[siphash_wrapper (nick,
  2675. strlen (nick)) % self->ctx->nick_palette_len] << 16;
  2676. // We always use the default color for ourselves
  2677. if (self->s && irc_is_this_us (self->s, nick))
  2678. color = -1;
  2679. FORMATTER_ADD_ITEM (self, FG_COLOR, .color = color);
  2680. char *x = irc_to_utf8 (nick);
  2681. free (nick);
  2682. FORMATTER_ADD_TEXT (self, x);
  2683. free (x);
  2684. // Need to reset the color afterwards
  2685. FORMATTER_ADD_ITEM (self, FG_COLOR, .color = -1);
  2686. }
  2687. static void
  2688. formatter_parse_nick_full (struct formatter *self, const char *s)
  2689. {
  2690. formatter_parse_nick (self, s);
  2691. const char *userhost;
  2692. if (!(userhost = irc_find_userhost (s)))
  2693. return;
  2694. FORMATTER_ADD_TEXT (self, " (");
  2695. FORMATTER_ADD_ITEM (self, ATTR, .attribute = ATTR_USERHOST);
  2696. char *x = irc_to_utf8 (userhost);
  2697. FORMATTER_ADD_TEXT (self, x);
  2698. free (x);
  2699. FORMATTER_ADD_RESET (self);
  2700. FORMATTER_ADD_TEXT (self, ")");
  2701. }
  2702. static const char *
  2703. formatter_parse_field (struct formatter *self,
  2704. const char *field, struct str *buf, va_list *ap)
  2705. {
  2706. bool free_string = false;
  2707. char *s = NULL;
  2708. char *tmp = NULL;
  2709. int c;
  2710. restart:
  2711. switch ((c = *field++))
  2712. {
  2713. // We can push boring text content to the caller's buffer
  2714. // and let it flush the buffer only when it's actually needed
  2715. case 'd':
  2716. tmp = xstrdup_printf ("%d", va_arg (*ap, int));
  2717. str_append (buf, tmp);
  2718. free (tmp);
  2719. break;
  2720. case 's':
  2721. str_append (buf, (s = va_arg (*ap, char *)));
  2722. break;
  2723. case 'l':
  2724. if (!(tmp = iconv_xstrdup (self->ctx->term_to_utf8,
  2725. (s = va_arg (*ap, char *)), -1, NULL)))
  2726. print_error ("character conversion failed for: %s", "output");
  2727. else
  2728. str_append (buf, tmp);
  2729. free (tmp);
  2730. break;
  2731. case 'S':
  2732. tmp = irc_to_utf8 ((s = va_arg (*ap, char *)));
  2733. str_append (buf, tmp);
  2734. free (tmp);
  2735. break;
  2736. case 'm':
  2737. tmp = irc_to_utf8 ((s = va_arg (*ap, char *)));
  2738. formatter_parse_mirc (self, tmp);
  2739. free (tmp);
  2740. break;
  2741. case 'n':
  2742. formatter_parse_nick (self, (s = va_arg (*ap, char *)));
  2743. break;
  2744. case 'N':
  2745. formatter_parse_nick_full (self, (s = va_arg (*ap, char *)));
  2746. break;
  2747. case 'a':
  2748. FORMATTER_ADD_ITEM (self, ATTR, .attribute = va_arg (*ap, int));
  2749. break;
  2750. case 'c':
  2751. FORMATTER_ADD_ITEM (self, FG_COLOR, .color = va_arg (*ap, int));
  2752. break;
  2753. case 'C':
  2754. FORMATTER_ADD_ITEM (self, BG_COLOR, .color = va_arg (*ap, int));
  2755. break;
  2756. case 'r':
  2757. FORMATTER_ADD_RESET (self);
  2758. break;
  2759. default:
  2760. if (c == '&' && !free_string)
  2761. free_string = true;
  2762. else if (c)
  2763. hard_assert (!"unexpected format specifier");
  2764. else
  2765. hard_assert (!"unexpected end of format string");
  2766. goto restart;
  2767. }
  2768. if (free_string)
  2769. free (s);
  2770. return field;
  2771. }
  2772. // I was unable to take a pointer of a bare "va_list" when it was passed in
  2773. // as a function argument, so it has to be a pointer from the beginning
  2774. static void
  2775. formatter_addv (struct formatter *self, const char *format, va_list *ap)
  2776. {
  2777. struct str buf = str_make ();
  2778. while (*format)
  2779. {
  2780. if (*format != '#' || *++format == '#')
  2781. {
  2782. str_append_c (&buf, *format++);
  2783. continue;
  2784. }
  2785. if (buf.len)
  2786. {
  2787. FORMATTER_ADD_TEXT (self, buf.str);
  2788. str_reset (&buf);
  2789. }
  2790. format = formatter_parse_field (self, format, &buf, ap);
  2791. }
  2792. if (buf.len)
  2793. FORMATTER_ADD_TEXT (self, buf.str);
  2794. str_free (&buf);
  2795. }
  2796. static void
  2797. formatter_add (struct formatter *self, const char *format, ...)
  2798. {
  2799. va_list ap;
  2800. va_start (ap, format);
  2801. formatter_addv (self, format, &ap);
  2802. va_end (ap);
  2803. }
  2804. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2805. struct line_char_attrs
  2806. {
  2807. int named; ///< Named attribute or -1
  2808. int text; ///< Text attributes
  2809. int fg; ///< Foreground color (-1 for default)
  2810. int bg; ///< Background color (-1 for default)
  2811. };
  2812. struct line_char
  2813. {
  2814. LIST_HEADER (struct line_char)
  2815. char bytes[MB_LEN_MAX]; ///< The character
  2816. size_t len; ///< Length of the character in bytes
  2817. wchar_t wide; ///< The character as a wchar_t
  2818. int width; ///< Width of the character in cells
  2819. struct line_char_attrs attrs; ///< Attributes
  2820. };
  2821. static struct line_char *
  2822. line_char_new (const char *mb, size_t mb_len, wchar_t wc)
  2823. {
  2824. struct line_char *self = xcalloc (1, sizeof *self);
  2825. memcpy (self->bytes, mb, (self->len = MIN (mb_len, sizeof self->bytes)));
  2826. self->width = wcwidth ((self->wide = wc));
  2827. // Typically various control characters
  2828. if (self->width < 0)
  2829. self->width = 0;
  2830. self->attrs.bg = self->attrs.fg = -1;
  2831. self->attrs.named = ATTR_RESET;
  2832. return self;
  2833. }
  2834. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2835. struct line_wrap_mark
  2836. {
  2837. struct line_char *start; ///< First character
  2838. int used; ///< Display cells used
  2839. };
  2840. static void
  2841. line_wrap_mark_push (struct line_wrap_mark *mark, struct line_char *c)
  2842. {
  2843. if (!mark->start)
  2844. mark->start = c;
  2845. mark->used += c->width;
  2846. }
  2847. struct line_wrap_state
  2848. {
  2849. struct line_char *result; ///< Head of result
  2850. struct line_char *result_tail; ///< Tail of result
  2851. int line_used; ///< Line length before marks
  2852. int line_max; ///< Maximum line length
  2853. struct line_wrap_mark chunk; ///< All buffered text
  2854. struct line_wrap_mark overflow; ///< Overflowing text
  2855. };
  2856. static void
  2857. line_wrap_flush_split (struct line_wrap_state *s, struct line_wrap_mark *before)
  2858. {
  2859. struct line_char *nl = line_char_new ("\n", 1, L'\n');
  2860. LIST_INSERT_WITH_TAIL (s->result, s->result_tail, nl, before->start);
  2861. s->line_used = before->used;
  2862. }
  2863. static void
  2864. line_wrap_flush (struct line_wrap_state *s, bool force_split)
  2865. {
  2866. if (!s->overflow.start)
  2867. s->line_used += s->chunk.used;
  2868. else if (force_split || s->chunk.used > s->line_max)
  2869. {
  2870. #ifdef WRAP_UNNECESSARILY
  2871. // When the line wraps at the end of the screen and a background colour
  2872. // is set, the terminal paints the entire new line with that colour.
  2873. // Explicitly inserting a newline with the default attributes fixes it.
  2874. line_wrap_flush_split (s, &s->overflow);
  2875. #else
  2876. // Splitting here breaks link searching mechanisms in some terminals,
  2877. // though, so we make a trade-off and let the chunk wrap naturally.
  2878. // Fuck terminals, really.
  2879. s->line_used = s->overflow.used;
  2880. #endif
  2881. }
  2882. else
  2883. // Print the chunk in its entirety on a new line
  2884. line_wrap_flush_split (s, &s->chunk);
  2885. memset (&s->chunk, 0, sizeof s->chunk);
  2886. memset (&s->overflow, 0, sizeof s->overflow);
  2887. }
  2888. static void
  2889. line_wrap_nl (struct line_wrap_state *s)
  2890. {
  2891. line_wrap_flush (s, true);
  2892. struct line_char *nl = line_char_new ("\n", 1, L'\n');
  2893. LIST_APPEND_WITH_TAIL (s->result, s->result_tail, nl);
  2894. s->line_used = 0;
  2895. }
  2896. static void
  2897. line_wrap_tab (struct line_wrap_state *s, struct line_char *c)
  2898. {
  2899. line_wrap_flush (s, true);
  2900. if (s->line_used >= s->line_max)
  2901. line_wrap_nl (s);
  2902. // Compute the number of characters needed to get to the next tab stop
  2903. int tab_width = ((s->line_used + 8) & ~7) - s->line_used;
  2904. // On overflow just fill the rest of the line with spaces
  2905. if (s->line_used + tab_width > s->line_max)
  2906. tab_width = s->line_max - s->line_used;
  2907. s->line_used += tab_width;
  2908. while (tab_width--)
  2909. {
  2910. struct line_char *space = line_char_new (" ", 1, L' ');
  2911. space->attrs = c->attrs;
  2912. LIST_APPEND_WITH_TAIL (s->result, s->result_tail, space);
  2913. }
  2914. }
  2915. static void
  2916. line_wrap_push_char (struct line_wrap_state *s, struct line_char *c)
  2917. {
  2918. // Note that when processing whitespace here, any non-WS chunk has already
  2919. // been flushed, and thus it matters little if we flush with force split
  2920. if (wcschr (L"\r\f\v", c->wide))
  2921. /* Skip problematic characters */;
  2922. else if (c->wide == L'\n')
  2923. line_wrap_nl (s);
  2924. else if (c->wide == L'\t')
  2925. line_wrap_tab (s, c);
  2926. else
  2927. goto use_as_is;
  2928. free (c);
  2929. return;
  2930. use_as_is:
  2931. if (s->overflow.start
  2932. || s->line_used + s->chunk.used + c->width > s->line_max)
  2933. {
  2934. if (s->overflow.used + c->width > s->line_max)
  2935. {
  2936. #ifdef WRAP_UNNECESSARILY
  2937. // If the overflow overflows, restart on a new line
  2938. line_wrap_nl (s);
  2939. #else
  2940. // See line_wrap_flush(), we would end up on a new line anyway
  2941. line_wrap_flush (s, true);
  2942. s->line_used = 0;
  2943. #endif
  2944. }
  2945. else
  2946. line_wrap_mark_push (&s->overflow, c);
  2947. }
  2948. line_wrap_mark_push (&s->chunk, c);
  2949. LIST_APPEND_WITH_TAIL (s->result, s->result_tail, c);
  2950. }
  2951. /// Basic word wrapping that respects wcwidth(3) and expands tabs.
  2952. /// Besides making text easier to read, it also fixes the problem with
  2953. /// formatting spilling over the entire new line on line wrap.
  2954. static struct line_char *
  2955. line_wrap (struct line_char *line, int max_width)
  2956. {
  2957. struct line_wrap_state s = { .line_max = max_width };
  2958. bool last_was_word_char = false;
  2959. LIST_FOR_EACH (struct line_char, c, line)
  2960. {
  2961. // Act on the right boundary of (\s*\S+) chunks
  2962. bool this_is_word_char = !wcschr (L" \t\r\n\f\v", c->wide);
  2963. if (last_was_word_char && !this_is_word_char)
  2964. line_wrap_flush (&s, false);
  2965. last_was_word_char = this_is_word_char;
  2966. LIST_UNLINK (line, c);
  2967. line_wrap_push_char (&s, c);
  2968. }
  2969. // Make sure to process the last word and return the modified list
  2970. line_wrap_flush (&s, false);
  2971. return s.result;
  2972. }
  2973. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  2974. struct exploder
  2975. {
  2976. struct app_context *ctx; ///< Application context
  2977. struct line_char *result; ///< Result
  2978. struct line_char *result_tail; ///< Tail of result
  2979. struct line_char_attrs attrs; ///< Current attributes
  2980. };
  2981. static bool
  2982. explode_formatter_attr (struct exploder *self, struct formatter_item *item)
  2983. {
  2984. switch (item->type)
  2985. {
  2986. case FORMATTER_ITEM_ATTR:
  2987. self->attrs.named = item->attribute;
  2988. self->attrs.text = 0;
  2989. self->attrs.fg = -1;
  2990. self->attrs.bg = -1;
  2991. return true;
  2992. case FORMATTER_ITEM_SIMPLE:
  2993. self->attrs.named = -1;
  2994. self->attrs.text ^= item->attribute;
  2995. return true;
  2996. case FORMATTER_ITEM_FG_COLOR:
  2997. self->attrs.named = -1;
  2998. self->attrs.fg = item->color;
  2999. return true;
  3000. case FORMATTER_ITEM_BG_COLOR:
  3001. self->attrs.named = -1;
  3002. self->attrs.bg = item->color;
  3003. return true;
  3004. default:
  3005. return false;
  3006. }
  3007. }
  3008. static void
  3009. explode_text (struct exploder *self, const char *text)
  3010. {
  3011. // Throw away any potentially harmful control characters first
  3012. struct str filtered = str_make ();
  3013. for (const char *p = text; *p; p++)
  3014. if (!strchr ("\a\b\x1b", *p))
  3015. str_append_c (&filtered, *p);
  3016. size_t term_len = 0;
  3017. char *term = iconv_xstrdup (self->ctx->term_from_utf8,
  3018. filtered.str, filtered.len + 1, &term_len);
  3019. str_free (&filtered);
  3020. mbstate_t ps;
  3021. memset (&ps, 0, sizeof ps);
  3022. wchar_t wch;
  3023. size_t len, processed = 0;
  3024. while ((len = mbrtowc (&wch, term + processed, term_len - processed, &ps)))
  3025. {
  3026. hard_assert (len != (size_t) -2 && len != (size_t) -1);
  3027. processed += len;
  3028. struct line_char *c = line_char_new (term + processed - len, len, wch);
  3029. c->attrs = self->attrs;
  3030. LIST_APPEND_WITH_TAIL (self->result, self->result_tail, c);
  3031. }
  3032. free (term);
  3033. }
  3034. static struct line_char *
  3035. formatter_to_chars (struct formatter *formatter)
  3036. {
  3037. struct exploder self = { .ctx = formatter->ctx };
  3038. self.attrs.fg = self.attrs.bg = self.attrs.named = -1;
  3039. int attribute_ignore = 0;
  3040. for (size_t i = 0; i < formatter->items_len; i++)
  3041. {
  3042. struct formatter_item *iter = &formatter->items[i];
  3043. if (iter->type == FORMATTER_ITEM_TEXT)
  3044. explode_text (&self, iter->text);
  3045. else if (iter->type == FORMATTER_ITEM_IGNORE_ATTR)
  3046. attribute_ignore += iter->attribute;
  3047. else if (attribute_ignore <= 0
  3048. && !explode_formatter_attr (&self, iter))
  3049. hard_assert (!"unhandled formatter item type");
  3050. }
  3051. return self.result;
  3052. }
  3053. enum
  3054. {
  3055. FLUSH_OPT_RAW = (1 << 0), ///< Print raw attributes
  3056. FLUSH_OPT_NOWRAP = (1 << 1) ///< Do not wrap
  3057. };
  3058. static void
  3059. formatter_flush (struct formatter *self, FILE *stream, int flush_opts)
  3060. {
  3061. struct line_char *line = formatter_to_chars (self);
  3062. bool is_tty = !!get_attribute_printer (stream);
  3063. if (!is_tty && !(flush_opts & FLUSH_OPT_RAW))
  3064. {
  3065. LIST_FOR_EACH (struct line_char, c, line)
  3066. {
  3067. fwrite (c->bytes, c->len, 1, stream);
  3068. free (c);
  3069. }
  3070. return;
  3071. }
  3072. if (self->ctx->word_wrapping && !(flush_opts & FLUSH_OPT_NOWRAP))
  3073. line = line_wrap (line, g_terminal.columns);
  3074. struct attr_printer state = ATTR_PRINTER_INIT (self->ctx, stream);
  3075. struct line_char_attrs attrs = {}; // Won't compare equal to anything
  3076. LIST_FOR_EACH (struct line_char, c, line)
  3077. {
  3078. if (attrs.fg != c->attrs.fg
  3079. || attrs.bg != c->attrs.bg
  3080. || attrs.named != c->attrs.named
  3081. || attrs.text != c->attrs.text)
  3082. {
  3083. attrs = c->attrs;
  3084. if (attrs.named != -1)
  3085. attr_printer_apply_named (&state, attrs.named);
  3086. else
  3087. attr_printer_apply (&state, attrs.text, attrs.fg, attrs.bg);
  3088. }
  3089. fwrite (c->bytes, c->len, 1, stream);
  3090. free (c);
  3091. }
  3092. attr_printer_reset (&state);
  3093. }
  3094. // --- Buffers -----------------------------------------------------------------
  3095. static void
  3096. buffer_pop_excess_lines (struct app_context *ctx, struct buffer *self)
  3097. {
  3098. int to_delete = (int) self->lines_count - (int) ctx->backlog_limit;
  3099. while (to_delete-- > 0 && self->lines)
  3100. {
  3101. struct buffer_line *excess = self->lines;
  3102. LIST_UNLINK_WITH_TAIL (self->lines, self->lines_tail, excess);
  3103. buffer_line_destroy (excess);
  3104. self->lines_count--;
  3105. }
  3106. }
  3107. static void
  3108. on_config_backlog_limit_change (struct config_item *item)
  3109. {
  3110. struct app_context *ctx = item->user_data;
  3111. ctx->backlog_limit = MIN (item->value.integer, INT_MAX);
  3112. LIST_FOR_EACH (struct buffer, iter, ctx->buffers)
  3113. buffer_pop_excess_lines (ctx, iter);
  3114. }
  3115. static void
  3116. buffer_update_time (struct app_context *ctx, time_t now, FILE *stream,
  3117. int flush_opts)
  3118. {
  3119. struct tm last, current;
  3120. if (!localtime_r (&ctx->last_displayed_msg_time, &last)
  3121. || !localtime_r (&now, &current))
  3122. {
  3123. // Strange but nonfatal
  3124. print_error ("%s: %s", "localtime_r", strerror (errno));
  3125. return;
  3126. }
  3127. ctx->last_displayed_msg_time = now;
  3128. if (last.tm_year == current.tm_year
  3129. && last.tm_mon == current.tm_mon
  3130. && last.tm_mday == current.tm_mday)
  3131. return;
  3132. char buf[64] = "";
  3133. const char *format =
  3134. get_config_string (ctx->config.root, "behaviour.date_change_line");
  3135. if (!strftime (buf, sizeof buf, format, &current))
  3136. {
  3137. print_error ("%s: %s", "strftime", strerror (errno));
  3138. return;
  3139. }
  3140. struct formatter f = formatter_make (ctx, NULL);
  3141. formatter_add (&f, "#a#s\n", ATTR_DATE_CHANGE, buf);
  3142. formatter_flush (&f, stream, flush_opts);
  3143. // Flush the trailing formatting reset item
  3144. fflush (stream);
  3145. formatter_free (&f);
  3146. }
  3147. static void
  3148. buffer_line_flush (struct buffer_line *line, struct formatter *f, FILE *output,
  3149. int flush_opts)
  3150. {
  3151. int flags = line->flags;
  3152. if (flags & BUFFER_LINE_INDENT) formatter_add (f, " ");
  3153. if (flags & BUFFER_LINE_STATUS) formatter_add (f, " - ");
  3154. if (flags & BUFFER_LINE_ERROR) formatter_add (f, "#a=!=#r ", ATTR_ERROR);
  3155. for (struct formatter_item *iter = line->items; iter->type; iter++)
  3156. formatter_add_item (f, *iter);
  3157. formatter_add (f, "\n");
  3158. formatter_flush (f, output, flush_opts);
  3159. formatter_free (f);
  3160. }
  3161. static void
  3162. buffer_line_write_time (struct formatter *f, struct buffer_line *line,
  3163. FILE *stream, int flush_opts)
  3164. {
  3165. // Normal timestamps don't include the date, make sure the user won't be
  3166. // confused as to when an event has happened
  3167. buffer_update_time (f->ctx, line->when, stream, flush_opts);
  3168. struct tm current;
  3169. char buf[9];
  3170. if (!localtime_r (&line->when, &current))
  3171. print_error ("%s: %s", "localtime_r", strerror (errno));
  3172. else if (!strftime (buf, sizeof buf, "%T", &current))
  3173. print_error ("%s: %s", "strftime", "buffer too small");
  3174. else
  3175. formatter_add (f, "#a#s#r ", ATTR_TIMESTAMP, buf);
  3176. }
  3177. #define buffer_line_will_show_up(buffer, line) \
  3178. (!(buffer)->hide_unimportant || !((line)->flags & BUFFER_LINE_UNIMPORTANT))
  3179. static void
  3180. buffer_line_display (struct app_context *ctx,
  3181. struct buffer *buffer, struct buffer_line *line, bool is_external)
  3182. {
  3183. if (!buffer_line_will_show_up (buffer, line))
  3184. return;
  3185. CALL (ctx->input, hide);
  3186. struct formatter f = formatter_make (ctx, NULL);
  3187. buffer_line_write_time (&f, line, stdout, 0);
  3188. // Ignore all formatting for messages coming from other buffers, that is
  3189. // either from the global or server buffer. Instead print them in grey.
  3190. if (is_external)
  3191. {
  3192. formatter_add (&f, "#a", ATTR_EXTERNAL);
  3193. FORMATTER_ADD_ITEM (&f, IGNORE_ATTR, .attribute = 1);
  3194. }
  3195. buffer_line_flush (line, &f, stdout, 0);
  3196. // Flush the trailing formatting reset item
  3197. fflush (stdout);
  3198. CALL (ctx->input, show);
  3199. }
  3200. static void
  3201. buffer_line_write_to_backlog (struct app_context *ctx,
  3202. struct buffer_line *line, FILE *log_file, int flush_opts)
  3203. {
  3204. struct formatter f = formatter_make (ctx, NULL);
  3205. buffer_line_write_time (&f, line, log_file, flush_opts);
  3206. buffer_line_flush (line, &f, log_file, flush_opts);
  3207. }
  3208. static void
  3209. buffer_line_write_to_log (struct app_context *ctx,
  3210. struct buffer_line *line, FILE *log_file)
  3211. {
  3212. if (line->flags & BUFFER_LINE_SKIP_FILE)
  3213. return;
  3214. struct formatter f = formatter_make (ctx, NULL);
  3215. struct tm current;
  3216. char buf[20];
  3217. if (!gmtime_r (&line->when, &current))
  3218. print_error ("%s: %s", "gmtime_r", strerror (errno));
  3219. else if (!strftime (buf, sizeof buf, "%F %T", &current))
  3220. print_error ("%s: %s", "strftime", "buffer too small");
  3221. else
  3222. formatter_add (&f, "#s ", buf);
  3223. // The target is not a terminal, thus it won't wrap in spite of the 0
  3224. buffer_line_flush (line, &f, log_file, 0);
  3225. }
  3226. static void
  3227. log_formatter (struct app_context *ctx,
  3228. struct buffer *buffer, int flags, struct formatter *f)
  3229. {
  3230. if (!buffer)
  3231. buffer = ctx->global_buffer;
  3232. struct buffer_line *line = buffer_line_new (f);
  3233. line->flags = flags;
  3234. // TODO: allow providing custom time (IRCv3.2 server-time)
  3235. line->when = time (NULL);
  3236. buffer_pop_excess_lines (ctx, buffer);
  3237. LIST_APPEND_WITH_TAIL (buffer->lines, buffer->lines_tail, line);
  3238. buffer->lines_count++;
  3239. if (buffer->log_file)
  3240. buffer_line_write_to_log (ctx, line, buffer->log_file);
  3241. bool unseen_pm = buffer->type == BUFFER_PM
  3242. && buffer != ctx->current_buffer
  3243. && !(flags & BUFFER_LINE_UNIMPORTANT);
  3244. bool important = (flags & BUFFER_LINE_HIGHLIGHT) || unseen_pm;
  3245. if (ctx->beep_on_highlight && important)
  3246. // XXX: this may disturb any other foreground process
  3247. CALL (ctx->input, ding);
  3248. bool can_leak = false;
  3249. if ((buffer == ctx->global_buffer)
  3250. || (ctx->current_buffer->type == BUFFER_GLOBAL
  3251. && buffer->type == BUFFER_SERVER)
  3252. || (ctx->current_buffer->type != BUFFER_GLOBAL
  3253. && buffer == ctx->current_buffer->server->buffer))
  3254. can_leak = true;
  3255. bool displayed = true;
  3256. if (ctx->terminal_suspended > 0)
  3257. // Another process is using the terminal
  3258. displayed = false;
  3259. else if (buffer == ctx->current_buffer)
  3260. buffer_line_display (ctx, buffer, line, false);
  3261. else if (!ctx->isolate_buffers && can_leak)
  3262. buffer_line_display (ctx, buffer, line, true);
  3263. else
  3264. displayed = false;
  3265. // Advance the unread marker in active buffers but don't create a new one
  3266. if (!displayed
  3267. || (buffer == ctx->current_buffer && buffer->new_messages_count))
  3268. {
  3269. buffer->new_messages_count++;
  3270. if (flags & BUFFER_LINE_UNIMPORTANT)
  3271. buffer->new_unimportant_count++;
  3272. buffer->highlighted |= important;
  3273. }
  3274. if (!displayed)
  3275. refresh_prompt (ctx);
  3276. }
  3277. static void
  3278. log_full (struct app_context *ctx, struct server *s, struct buffer *buffer,
  3279. int flags, const char *format, ...)
  3280. {
  3281. va_list ap;
  3282. va_start (ap, format);
  3283. struct formatter f = formatter_make (ctx, s);
  3284. formatter_addv (&f, format, &ap);
  3285. log_formatter (ctx, buffer, flags, &f);
  3286. va_end (ap);
  3287. }
  3288. #define log_global(ctx, flags, ...) \
  3289. log_full ((ctx), NULL, (ctx)->global_buffer, flags, __VA_ARGS__)
  3290. #define log_server(s, buffer, flags, ...) \
  3291. log_full ((s)->ctx, s, (buffer), flags, __VA_ARGS__)
  3292. #define log_global_status(ctx, ...) \
  3293. log_global ((ctx), BUFFER_LINE_STATUS, __VA_ARGS__)
  3294. #define log_global_error(ctx, ...) \
  3295. log_global ((ctx), BUFFER_LINE_ERROR, __VA_ARGS__)
  3296. #define log_global_indent(ctx, ...) \
  3297. log_global ((ctx), BUFFER_LINE_INDENT, __VA_ARGS__)
  3298. #define log_server_status(s, buffer, ...) \
  3299. log_server ((s), (buffer), BUFFER_LINE_STATUS, __VA_ARGS__)
  3300. #define log_server_error(s, buffer, ...) \
  3301. log_server ((s), (buffer), BUFFER_LINE_ERROR, __VA_ARGS__)
  3302. #define log_global_debug(ctx, ...) \
  3303. BLOCK_START \
  3304. if (g_debug_mode) \
  3305. log_global ((ctx), 0, "(*) " __VA_ARGS__); \
  3306. BLOCK_END
  3307. #define log_server_debug(s, ...) \
  3308. BLOCK_START \
  3309. if (g_debug_mode) \
  3310. log_server ((s), (s)->buffer, 0, "(*) " __VA_ARGS__); \
  3311. BLOCK_END
  3312. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3313. // Lines that are used in more than one place
  3314. #define log_nick_self(s, buffer, new_) \
  3315. log_server ((s), (buffer), BUFFER_LINE_STATUS | BUFFER_LINE_UNIMPORTANT, \
  3316. "You are now known as #n", (new_))
  3317. #define log_nick(s, buffer, old, new_) \
  3318. log_server ((s), (buffer), BUFFER_LINE_STATUS | BUFFER_LINE_UNIMPORTANT, \
  3319. "#n is now known as #n", (old), (new_))
  3320. #define log_outcoming_notice(s, buffer, who, text) \
  3321. log_server_status ((s), (buffer), "#s(#n): #m", "Notice", (who), (text))
  3322. #define log_outcoming_privmsg(s, buffer, prefixes, who, text) \
  3323. log_server ((s), (buffer), 0, "<#s#n> #m", (prefixes), (who), (text))
  3324. #define log_outcoming_action(s, buffer, who, text) \
  3325. log_server ((s), (buffer), 0, " #a*#r #n #m", ATTR_ACTION, (who), (text))
  3326. #define log_outcoming_orphan_notice(s, target, text) \
  3327. log_server_status ((s), (s)->buffer, "Notice -> #n: #m", (target), (text))
  3328. #define log_outcoming_orphan_privmsg(s, target, text) \
  3329. log_server_status ((s), (s)->buffer, "MSG(#n): #m", (target), (text))
  3330. #define log_ctcp_query(s, target, tag) \
  3331. log_server_status ((s), (s)->buffer, "CTCP query to #S: #S", target, tag)
  3332. #define log_ctcp_reply(s, target, reply /* freed! */) \
  3333. log_server_status ((s), (s)->buffer, "CTCP reply to #S: #&S", target, reply)
  3334. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3335. static void
  3336. make_log_filename (const char *filename, struct str *output)
  3337. {
  3338. for (const char *p = filename; *p; p++)
  3339. // XXX: anything more to replace?
  3340. if (strchr ("/\\ ", *p))
  3341. str_append_c (output, '_');
  3342. else
  3343. str_append_c (output, tolower_ascii (*p));
  3344. }
  3345. static char *
  3346. buffer_get_log_path (struct buffer *buffer)
  3347. {
  3348. struct str path = str_make ();
  3349. get_xdg_home_dir (&path, "XDG_DATA_HOME", ".local/share");
  3350. str_append_printf (&path, "/%s/%s", PROGRAM_NAME, "logs");
  3351. (void) mkdir_with_parents (path.str, NULL);
  3352. str_append_c (&path, '/');
  3353. make_log_filename (buffer->name, &path);
  3354. str_append (&path, ".log");
  3355. return str_steal (&path);
  3356. }
  3357. static void
  3358. buffer_open_log_file (struct app_context *ctx, struct buffer *buffer)
  3359. {
  3360. if (!ctx->logging || buffer->log_file)
  3361. return;
  3362. // TODO: should we try to reopen files wrt. case mapping?
  3363. char *path = buffer_get_log_path (buffer);
  3364. if (!(buffer->log_file = fopen (path, "ab")))
  3365. log_global_error (ctx, "Couldn't open log file `#s': #l",
  3366. path, strerror (errno));
  3367. else
  3368. set_cloexec (fileno (buffer->log_file));
  3369. free (path);
  3370. }
  3371. static void
  3372. buffer_close_log_file (struct buffer *buffer)
  3373. {
  3374. if (buffer->log_file)
  3375. (void) fclose (buffer->log_file);
  3376. buffer->log_file = NULL;
  3377. }
  3378. static void
  3379. on_config_logging_change (struct config_item *item)
  3380. {
  3381. struct app_context *ctx = item->user_data;
  3382. ctx->logging = item->value.boolean;
  3383. for (struct buffer *buffer = ctx->buffers; buffer; buffer = buffer->next)
  3384. if (ctx->logging)
  3385. buffer_open_log_file (ctx, buffer);
  3386. else
  3387. buffer_close_log_file (buffer);
  3388. }
  3389. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3390. static struct buffer *
  3391. buffer_by_name (struct app_context *ctx, const char *name)
  3392. {
  3393. return str_map_find (&ctx->buffers_by_name, name);
  3394. }
  3395. static void
  3396. buffer_add (struct app_context *ctx, struct buffer *buffer)
  3397. {
  3398. hard_assert (!buffer_by_name (ctx, buffer->name));
  3399. str_map_set (&ctx->buffers_by_name, buffer->name, buffer);
  3400. LIST_APPEND_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
  3401. buffer_open_log_file (ctx, buffer);
  3402. // Normally this doesn't cause changes in the prompt but a prompt hook
  3403. // could decide to show some information for all buffers nonetheless
  3404. refresh_prompt (ctx);
  3405. }
  3406. static void
  3407. buffer_remove (struct app_context *ctx, struct buffer *buffer)
  3408. {
  3409. hard_assert (buffer != ctx->current_buffer);
  3410. hard_assert (buffer != ctx->global_buffer);
  3411. CALL_ (ctx->input, buffer_destroy, buffer->input_data);
  3412. buffer->input_data = NULL;
  3413. // And make sure to unlink the buffer from "irc_buffer_map"
  3414. struct server *s = buffer->server;
  3415. if (buffer->channel)
  3416. str_map_set (&s->irc_buffer_map, buffer->channel->name, NULL);
  3417. if (buffer->user)
  3418. str_map_set (&s->irc_buffer_map, buffer->user->nickname, NULL);
  3419. if (buffer == ctx->last_buffer)
  3420. ctx->last_buffer = NULL;
  3421. if (buffer->type == BUFFER_SERVER)
  3422. buffer->server->buffer = NULL;
  3423. str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
  3424. LIST_UNLINK_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
  3425. buffer_unref (buffer);
  3426. refresh_prompt (ctx);
  3427. }
  3428. static void
  3429. buffer_print_read_marker (struct app_context *ctx, FILE *stream, int flush_opts)
  3430. {
  3431. struct formatter f = formatter_make (ctx, NULL);
  3432. formatter_add (&f, "#a-- -- -- ---\n", ATTR_READ_MARKER);
  3433. formatter_flush (&f, stream, flush_opts);
  3434. // Flush the trailing formatting reset item
  3435. fflush (stream);
  3436. formatter_free (&f);
  3437. }
  3438. static void
  3439. buffer_print_backlog (struct app_context *ctx, struct buffer *buffer)
  3440. {
  3441. // The prompt can take considerable time to redraw
  3442. CALL (ctx->input, hide);
  3443. // Simulate curses-like fullscreen buffers if the terminal allows it
  3444. if (g_terminal.initialized && clear_screen)
  3445. {
  3446. terminal_printer_fn printer = get_attribute_printer (stdout);
  3447. tputs (clear_screen, 1, printer);
  3448. if (cursor_to_ll)
  3449. tputs (cursor_to_ll, 1, printer);
  3450. else if (row_address)
  3451. tputs (tparm (row_address, g_terminal.lines - 1,
  3452. 0, 0, 0, 0, 0, 0, 0, 0), 1, printer);
  3453. else if (cursor_address)
  3454. tputs (tparm (cursor_address, g_terminal.lines - 1,
  3455. 0, 0, 0, 0, 0, 0, 0, 0), 1, printer);
  3456. fflush (stdout);
  3457. // We should update "last_displayed_msg_time" here just to be sure
  3458. // that the first date marker, if necessary, is shown, but in practice
  3459. // the value should always be from today when this function is called
  3460. }
  3461. else
  3462. {
  3463. char *buffer_name_localized =
  3464. iconv_xstrdup (ctx->term_from_utf8, buffer->name, -1, NULL);
  3465. print_status ("%s", buffer_name_localized);
  3466. free (buffer_name_localized);
  3467. }
  3468. // That is, minus the readline prompt (taking at least one line)
  3469. int display_limit = MAX (10, g_terminal.lines - 1);
  3470. int to_display = 0;
  3471. struct buffer_line *line;
  3472. for (line = buffer->lines_tail; line; line = line->prev)
  3473. {
  3474. to_display++;
  3475. if (buffer_line_will_show_up (buffer, line))
  3476. display_limit--;
  3477. if (!line->prev || display_limit <= 0)
  3478. break;
  3479. }
  3480. // Once we've found where we want to start with the backlog, print it
  3481. int until_marker = to_display - (int) buffer->new_messages_count;
  3482. for (; line; line = line->next)
  3483. {
  3484. if (until_marker-- == 0
  3485. && buffer->new_messages_count != buffer->lines_count)
  3486. buffer_print_read_marker (ctx, stdout, 0);
  3487. buffer_line_display (ctx, buffer, line, 0);
  3488. }
  3489. // So that it is obvious if the last line in the buffer is not from today
  3490. buffer_update_time (ctx, time (NULL), stdout, 0);
  3491. refresh_prompt (ctx);
  3492. CALL (ctx->input, show);
  3493. }
  3494. static void
  3495. buffer_activate (struct app_context *ctx, struct buffer *buffer)
  3496. {
  3497. if (ctx->current_buffer == buffer)
  3498. return;
  3499. // This is the only place where the unread messages marker
  3500. // and highlight indicator are reset
  3501. if (ctx->current_buffer)
  3502. {
  3503. ctx->current_buffer->new_messages_count = 0;
  3504. ctx->current_buffer->new_unimportant_count = 0;
  3505. ctx->current_buffer->highlighted = false;
  3506. }
  3507. buffer_print_backlog (ctx, buffer);
  3508. CALL_ (ctx->input, buffer_switch, buffer->input_data);
  3509. // Now at last we can switch the pointers
  3510. ctx->last_buffer = ctx->current_buffer;
  3511. ctx->current_buffer = buffer;
  3512. refresh_prompt (ctx);
  3513. }
  3514. static void
  3515. buffer_merge (struct app_context *ctx,
  3516. struct buffer *buffer, struct buffer *merged)
  3517. {
  3518. // XXX: anything better to do? This situation is arguably rare and I'm
  3519. // not entirely sure what action to take.
  3520. log_full (ctx, NULL, buffer, BUFFER_LINE_STATUS,
  3521. "Buffer #s was merged into this buffer", merged->name);
  3522. // Find all lines from "merged" newer than the newest line in "buffer"
  3523. struct buffer_line *start = merged->lines;
  3524. if (buffer->lines_tail)
  3525. while (start && start->when < buffer->lines_tail->when)
  3526. start = start->next;
  3527. if (!start)
  3528. return;
  3529. // Count how many of them we have
  3530. size_t n = 0;
  3531. for (struct buffer_line *iter = start; iter; iter = iter->next)
  3532. n++;
  3533. struct buffer_line *tail = merged->lines_tail;
  3534. // Cut them from the original buffer
  3535. if (start == merged->lines)
  3536. merged->lines = NULL;
  3537. else if (start->prev)
  3538. start->prev->next = NULL;
  3539. merged->lines_tail = start->prev;
  3540. merged->lines_count -= n;
  3541. // And append them to current lines in the buffer
  3542. buffer->lines_tail->next = start;
  3543. start->prev = buffer->lines_tail;
  3544. buffer->lines_tail = tail;
  3545. buffer->lines_count += n;
  3546. log_full (ctx, NULL, buffer, BUFFER_LINE_STATUS | BUFFER_LINE_SKIP_FILE,
  3547. "End of merged content");
  3548. }
  3549. static void
  3550. buffer_rename (struct app_context *ctx,
  3551. struct buffer *buffer, const char *new_name)
  3552. {
  3553. struct buffer *collision = str_map_find (&ctx->buffers_by_name, new_name);
  3554. if (collision == buffer)
  3555. return;
  3556. hard_assert (!collision);
  3557. str_map_set (&ctx->buffers_by_name, buffer->name, NULL);
  3558. str_map_set (&ctx->buffers_by_name, new_name, buffer);
  3559. buffer_close_log_file (buffer);
  3560. buffer_open_log_file (ctx, buffer);
  3561. cstr_set (&buffer->name, xstrdup (new_name));
  3562. // We might have renamed the current buffer
  3563. refresh_prompt (ctx);
  3564. }
  3565. static void
  3566. buffer_clear (struct buffer *buffer)
  3567. {
  3568. LIST_FOR_EACH (struct buffer_line, iter, buffer->lines)
  3569. buffer_line_destroy (iter);
  3570. buffer->lines = buffer->lines_tail = NULL;
  3571. buffer->lines_count = 0;
  3572. }
  3573. static struct buffer *
  3574. buffer_at_index (struct app_context *ctx, int n)
  3575. {
  3576. int i = 0;
  3577. LIST_FOR_EACH (struct buffer, iter, ctx->buffers)
  3578. if (++i == n)
  3579. return iter;
  3580. return NULL;
  3581. }
  3582. static struct buffer *
  3583. buffer_next (struct app_context *ctx, int count)
  3584. {
  3585. struct buffer *new_buffer = ctx->current_buffer;
  3586. while (count-- > 0)
  3587. if (!(new_buffer = new_buffer->next))
  3588. new_buffer = ctx->buffers;
  3589. return new_buffer;
  3590. }
  3591. static struct buffer *
  3592. buffer_previous (struct app_context *ctx, int count)
  3593. {
  3594. struct buffer *new_buffer = ctx->current_buffer;
  3595. while (count-- > 0)
  3596. if (!(new_buffer = new_buffer->prev))
  3597. new_buffer = ctx->buffers_tail;
  3598. return new_buffer;
  3599. }
  3600. static bool
  3601. buffer_goto (struct app_context *ctx, int n)
  3602. {
  3603. struct buffer *buffer = buffer_at_index (ctx, n);
  3604. if (!buffer)
  3605. return false;
  3606. buffer_activate (ctx, buffer);
  3607. return true;
  3608. }
  3609. static int
  3610. buffer_count (struct app_context *ctx)
  3611. {
  3612. int total = 0;
  3613. LIST_FOR_EACH (struct buffer, iter, ctx->buffers)
  3614. total++;
  3615. return total;
  3616. }
  3617. static void
  3618. buffer_move (struct app_context *ctx, struct buffer *buffer, int n)
  3619. {
  3620. hard_assert (n >= 1 && n <= buffer_count (ctx));
  3621. LIST_UNLINK_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer);
  3622. struct buffer *following = ctx->buffers;
  3623. while (--n && following)
  3624. following = following->next;
  3625. LIST_INSERT_WITH_TAIL (ctx->buffers, ctx->buffers_tail, buffer, following);
  3626. refresh_prompt (ctx);
  3627. }
  3628. static int
  3629. buffer_get_index (struct app_context *ctx, struct buffer *buffer)
  3630. {
  3631. int index = 1;
  3632. LIST_FOR_EACH (struct buffer, iter, ctx->buffers)
  3633. {
  3634. if (iter == buffer)
  3635. return index;
  3636. index++;
  3637. }
  3638. return -1;
  3639. }
  3640. static void
  3641. buffer_remove_safe (struct app_context *ctx, struct buffer *buffer)
  3642. {
  3643. if (buffer == ctx->current_buffer)
  3644. buffer_activate (ctx, ctx->last_buffer
  3645. ? ctx->last_buffer
  3646. : buffer_next (ctx, 1));
  3647. buffer_remove (ctx, buffer);
  3648. }
  3649. static void
  3650. init_global_buffer (struct app_context *ctx)
  3651. {
  3652. struct buffer *global = ctx->global_buffer = buffer_new (ctx->input);
  3653. global->type = BUFFER_GLOBAL;
  3654. global->name = xstrdup (PROGRAM_NAME);
  3655. buffer_add (ctx, global);
  3656. buffer_activate (ctx, global);
  3657. }
  3658. // --- Users, channels ---------------------------------------------------------
  3659. static void
  3660. irc_user_on_destroy (void *object, void *user_data)
  3661. {
  3662. struct user *user = object;
  3663. struct server *s = user_data;
  3664. if (!s->rehashing)
  3665. str_map_set (&s->irc_users, user->nickname, NULL);
  3666. }
  3667. static struct user *
  3668. irc_make_user (struct server *s, char *nickname)
  3669. {
  3670. hard_assert (!str_map_find (&s->irc_users, nickname));
  3671. struct user *user = user_new ();
  3672. (void) user_weak_ref (user, irc_user_on_destroy, s);
  3673. user->nickname = nickname;
  3674. str_map_set (&s->irc_users, user->nickname, user);
  3675. return user;
  3676. }
  3677. struct user *
  3678. irc_get_or_make_user (struct server *s, const char *nickname)
  3679. {
  3680. struct user *user = str_map_find (&s->irc_users, nickname);
  3681. if (user)
  3682. return user_ref (user);
  3683. return irc_make_user (s, xstrdup (nickname));
  3684. }
  3685. static struct buffer *
  3686. irc_get_or_make_user_buffer (struct server *s, const char *nickname)
  3687. {
  3688. struct buffer *buffer = str_map_find (&s->irc_buffer_map, nickname);
  3689. if (buffer)
  3690. return buffer;
  3691. struct user *user = irc_get_or_make_user (s, nickname);
  3692. // Open a new buffer for the user
  3693. buffer = buffer_new (s->ctx->input);
  3694. buffer->type = BUFFER_PM;
  3695. buffer->name = xstrdup_printf ("%s.%s", s->name, nickname);
  3696. buffer->server = s;
  3697. buffer->user = user;
  3698. str_map_set (&s->irc_buffer_map, user->nickname, buffer);
  3699. buffer_add (s->ctx, buffer);
  3700. return buffer;
  3701. }
  3702. static void
  3703. irc_get_channel_user_prefix (struct server *s,
  3704. struct channel_user *channel_user, struct str *output)
  3705. {
  3706. if (s->ctx->show_all_prefixes)
  3707. str_append (output, channel_user->prefixes.str);
  3708. else if (channel_user->prefixes.len)
  3709. str_append_c (output, channel_user->prefixes.str[0]);
  3710. }
  3711. static bool
  3712. irc_channel_is_joined (struct channel *channel)
  3713. {
  3714. // TODO: find a better way of checking if we're on a channel
  3715. return !!channel->users_len;
  3716. }
  3717. // Note that this eats the user reference
  3718. static void
  3719. irc_channel_link_user (struct channel *channel, struct user *user,
  3720. const char *prefixes)
  3721. {
  3722. struct user_channel *user_channel = user_channel_new ();
  3723. user_channel->channel = channel;
  3724. LIST_PREPEND (user->channels, user_channel);
  3725. struct channel_user *channel_user = channel_user_new ();
  3726. channel_user->user = user;
  3727. str_append (&channel_user->prefixes, prefixes);
  3728. LIST_PREPEND (channel->users, channel_user);
  3729. channel->users_len++;
  3730. }
  3731. static void
  3732. irc_channel_unlink_user
  3733. (struct channel *channel, struct channel_user *channel_user)
  3734. {
  3735. // First destroy the user's weak references to the channel
  3736. struct user *user = channel_user->user;
  3737. LIST_FOR_EACH (struct user_channel, iter, user->channels)
  3738. if (iter->channel == channel)
  3739. {
  3740. LIST_UNLINK (user->channels, iter);
  3741. user_channel_destroy (iter);
  3742. }
  3743. // Then just unlink the user from the channel
  3744. LIST_UNLINK (channel->users, channel_user);
  3745. channel_user_destroy (channel_user);
  3746. channel->users_len--;
  3747. }
  3748. static void
  3749. irc_channel_on_destroy (void *object, void *user_data)
  3750. {
  3751. struct channel *channel = object;
  3752. struct server *s = user_data;
  3753. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  3754. irc_channel_unlink_user (channel, iter);
  3755. if (!s->rehashing)
  3756. str_map_set (&s->irc_channels, channel->name, NULL);
  3757. }
  3758. static struct channel *
  3759. irc_make_channel (struct server *s, char *name)
  3760. {
  3761. hard_assert (!str_map_find (&s->irc_channels, name));
  3762. struct channel *channel = channel_new ();
  3763. (void) channel_weak_ref (channel, irc_channel_on_destroy, s);
  3764. channel->name = name;
  3765. channel->topic = NULL;
  3766. str_map_set (&s->irc_channels, channel->name, channel);
  3767. return channel;
  3768. }
  3769. static struct channel_user *
  3770. irc_channel_get_user (struct channel *channel, struct user *user)
  3771. {
  3772. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  3773. if (iter->user == user)
  3774. return iter;
  3775. return NULL;
  3776. }
  3777. static void
  3778. irc_remove_user_from_channel (struct user *user, struct channel *channel)
  3779. {
  3780. struct channel_user *channel_user = irc_channel_get_user (channel, user);
  3781. if (channel_user)
  3782. irc_channel_unlink_user (channel, channel_user);
  3783. }
  3784. static void
  3785. irc_left_channel (struct channel *channel)
  3786. {
  3787. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  3788. irc_channel_unlink_user (channel, iter);
  3789. }
  3790. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3791. static void
  3792. remove_conflicting_buffer (struct server *s, struct buffer *buffer)
  3793. {
  3794. log_server_status (s, s->buffer,
  3795. "Removed buffer #s because of casemapping conflict", buffer->name);
  3796. if (s->ctx->current_buffer == buffer)
  3797. buffer_activate (s->ctx, s->buffer);
  3798. buffer_remove (s->ctx, buffer);
  3799. }
  3800. static void
  3801. irc_try_readd_user (struct server *s,
  3802. struct user *user, struct buffer *buffer)
  3803. {
  3804. if (str_map_find (&s->irc_users, user->nickname))
  3805. {
  3806. // Remove user from all channels and destroy any PM buffer
  3807. user_ref (user);
  3808. LIST_FOR_EACH (struct user_channel, iter, user->channels)
  3809. irc_remove_user_from_channel (user, iter->channel);
  3810. if (buffer)
  3811. remove_conflicting_buffer (s, buffer);
  3812. user_unref (user);
  3813. }
  3814. else
  3815. {
  3816. str_map_set (&s->irc_users, user->nickname, user);
  3817. str_map_set (&s->irc_buffer_map, user->nickname, buffer);
  3818. }
  3819. }
  3820. static void
  3821. irc_try_readd_channel (struct server *s,
  3822. struct channel *channel, struct buffer *buffer)
  3823. {
  3824. if (str_map_find (&s->irc_channels, channel->name))
  3825. {
  3826. // Remove all users from channel and destroy any channel buffer
  3827. channel_ref (channel);
  3828. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  3829. irc_channel_unlink_user (channel, iter);
  3830. if (buffer)
  3831. remove_conflicting_buffer (s, buffer);
  3832. channel_unref (channel);
  3833. }
  3834. else
  3835. {
  3836. str_map_set (&s->irc_channels, channel->name, channel);
  3837. str_map_set (&s->irc_buffer_map, channel->name, buffer);
  3838. }
  3839. }
  3840. static void
  3841. irc_rehash_and_fix_conflicts (struct server *s)
  3842. {
  3843. // Save the old maps and initialize new ones
  3844. struct str_map old_users = s->irc_users;
  3845. struct str_map old_channels = s->irc_channels;
  3846. struct str_map old_buffer_map = s->irc_buffer_map;
  3847. s->irc_users = str_map_make (NULL);
  3848. s->irc_channels = str_map_make (NULL);
  3849. s->irc_buffer_map = str_map_make (NULL);
  3850. s->irc_users .key_xfrm = s->irc_strxfrm;
  3851. s->irc_channels .key_xfrm = s->irc_strxfrm;
  3852. s->irc_buffer_map.key_xfrm = s->irc_strxfrm;
  3853. // Prevent channels and users from unsetting themselves
  3854. // from server maps upon removing the last reference to them
  3855. s->rehashing = true;
  3856. // XXX: to be perfectly sure, we should also check
  3857. // whether any users collide with channels and vice versa
  3858. // Our own user always takes priority, add him first
  3859. if (s->irc_user)
  3860. irc_try_readd_user (s, s->irc_user,
  3861. str_map_find (&old_buffer_map, s->irc_user->nickname));
  3862. struct str_map_iter iter;
  3863. struct user *user;
  3864. struct channel *channel;
  3865. iter = str_map_iter_make (&old_users);
  3866. while ((user = str_map_iter_next (&iter)))
  3867. irc_try_readd_user (s, user,
  3868. str_map_find (&old_buffer_map, user->nickname));
  3869. iter = str_map_iter_make (&old_channels);
  3870. while ((channel = str_map_iter_next (&iter)))
  3871. irc_try_readd_channel (s, channel,
  3872. str_map_find (&old_buffer_map, channel->name));
  3873. // Hopefully we've either moved or destroyed all the old content
  3874. s->rehashing = false;
  3875. str_map_free (&old_users);
  3876. str_map_free (&old_channels);
  3877. str_map_free (&old_buffer_map);
  3878. }
  3879. static void
  3880. irc_set_casemapping (struct server *s,
  3881. irc_tolower_fn tolower, irc_strxfrm_fn strxfrm)
  3882. {
  3883. if (tolower == s->irc_tolower
  3884. && strxfrm == s->irc_strxfrm)
  3885. return;
  3886. s->irc_tolower = tolower;
  3887. s->irc_strxfrm = strxfrm;
  3888. // Ideally we would never have to do this but I can't think of a workaround
  3889. irc_rehash_and_fix_conflicts (s);
  3890. }
  3891. // --- Core functionality ------------------------------------------------------
  3892. static bool
  3893. irc_is_connected (struct server *s)
  3894. {
  3895. return s->state != IRC_DISCONNECTED && s->state != IRC_CONNECTING;
  3896. }
  3897. static void
  3898. irc_update_poller (struct server *s, const struct pollfd *pfd)
  3899. {
  3900. int new_events = s->transport->get_poll_events (s);
  3901. hard_assert (new_events != 0);
  3902. if (!pfd || pfd->events != new_events)
  3903. poller_fd_set (&s->socket_event, new_events);
  3904. }
  3905. static void
  3906. irc_cancel_timers (struct server *s)
  3907. {
  3908. poller_timer_reset (&s->timeout_tmr);
  3909. poller_timer_reset (&s->ping_tmr);
  3910. poller_timer_reset (&s->reconnect_tmr);
  3911. poller_timer_reset (&s->autojoin_tmr);
  3912. }
  3913. static void
  3914. irc_reset_connection_timeouts (struct server *s)
  3915. {
  3916. poller_timer_set (&s->timeout_tmr, 3 * 60 * 1000);
  3917. poller_timer_set (&s->ping_tmr, (3 * 60 + 30) * 1000);
  3918. poller_timer_reset (&s->reconnect_tmr);
  3919. }
  3920. static int64_t
  3921. irc_get_reconnect_delay (struct server *s)
  3922. {
  3923. int64_t delay = get_config_integer (s->config, "reconnect_delay");
  3924. int64_t delay_factor = get_config_integer (s->ctx->config.root,
  3925. "behaviour.reconnect_delay_growing");
  3926. for (unsigned i = 0; i < s->reconnect_attempt; i++)
  3927. {
  3928. if (delay_factor && delay > INT64_MAX / delay_factor)
  3929. break;
  3930. delay *= delay_factor;
  3931. }
  3932. int64_t delay_max = get_config_integer (s->ctx->config.root,
  3933. "behaviour.reconnect_delay_max");
  3934. return MIN (delay, delay_max);
  3935. }
  3936. static void
  3937. irc_queue_reconnect (struct server *s)
  3938. {
  3939. // As long as the user wants us to, that is
  3940. if (!get_config_boolean (s->config, "reconnect"))
  3941. return;
  3942. // XXX: maybe add a state for when a connect is queued?
  3943. hard_assert (s->state == IRC_DISCONNECTED);
  3944. int64_t delay = irc_get_reconnect_delay (s);
  3945. s->reconnect_attempt++;
  3946. log_server_status (s, s->buffer,
  3947. "Trying to reconnect in #&s seconds...",
  3948. xstrdup_printf ("%" PRId64, delay));
  3949. poller_timer_set (&s->reconnect_tmr, delay * 1000);
  3950. }
  3951. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3952. static void irc_process_sent_message
  3953. (const struct irc_message *msg, struct server *s);
  3954. static void irc_send (struct server *s,
  3955. const char *format, ...) ATTRIBUTE_PRINTF (2, 3);
  3956. static void
  3957. irc_send (struct server *s, const char *format, ...)
  3958. {
  3959. if (!soft_assert (irc_is_connected (s)))
  3960. {
  3961. log_server_debug (s, "sending a message to a dead server connection");
  3962. return;
  3963. }
  3964. if (s->state == IRC_CLOSING
  3965. || s->state == IRC_HALF_CLOSED)
  3966. return;
  3967. va_list ap;
  3968. va_start (ap, format);
  3969. struct str str = str_make ();
  3970. str_append_vprintf (&str, format, ap);
  3971. va_end (ap);
  3972. log_server_debug (s, "#a<< \"#S\"#r", ATTR_PART, str.str);
  3973. struct irc_message msg;
  3974. irc_parse_message (&msg, str.str);
  3975. irc_process_sent_message (&msg, s);
  3976. irc_free_message (&msg);
  3977. str_append_str (&s->write_buffer, &str);
  3978. str_free (&str);
  3979. str_append (&s->write_buffer, "\r\n");
  3980. irc_update_poller (s, NULL);
  3981. }
  3982. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3983. static void
  3984. irc_real_shutdown (struct server *s)
  3985. {
  3986. hard_assert (irc_is_connected (s) && s->state != IRC_HALF_CLOSED);
  3987. if (s->transport
  3988. && s->transport->in_before_shutdown)
  3989. s->transport->in_before_shutdown (s);
  3990. while (shutdown (s->socket, SHUT_WR) == -1)
  3991. // XXX: we get ENOTCONN with OpenSSL (not plain) when a localhost
  3992. // server is aborted, why? strace says read 0, write 31, shutdown -1.
  3993. if (!soft_assert (errno == EINTR))
  3994. break;
  3995. s->state = IRC_HALF_CLOSED;
  3996. }
  3997. static void
  3998. irc_shutdown (struct server *s)
  3999. {
  4000. if (s->state == IRC_CLOSING
  4001. || s->state == IRC_HALF_CLOSED)
  4002. return;
  4003. // TODO: set a timer to cut the connection if we don't receive an EOF
  4004. s->state = IRC_CLOSING;
  4005. // Either there's still some data in the write buffer and we wait
  4006. // until they're sent, or we send an EOF to the server right away
  4007. if (!s->write_buffer.len)
  4008. irc_real_shutdown (s);
  4009. }
  4010. static void
  4011. irc_destroy_connector (struct server *s)
  4012. {
  4013. if (s->connector)
  4014. connector_free (s->connector);
  4015. free (s->connector);
  4016. s->connector = NULL;
  4017. if (s->socks_conn)
  4018. socks_connector_free (s->socks_conn);
  4019. free (s->socks_conn);
  4020. s->socks_conn = NULL;
  4021. // Not connecting anymore
  4022. s->state = IRC_DISCONNECTED;
  4023. }
  4024. static void
  4025. try_finish_quit (struct app_context *ctx)
  4026. {
  4027. if (!ctx->quitting)
  4028. return;
  4029. bool disconnected_all = true;
  4030. struct str_map_iter iter = str_map_iter_make (&ctx->servers);
  4031. struct server *s;
  4032. while ((s = str_map_iter_next (&iter)))
  4033. if (irc_is_connected (s))
  4034. disconnected_all = false;
  4035. if (disconnected_all)
  4036. ctx->polling = false;
  4037. }
  4038. static void
  4039. irc_destroy_transport (struct server *s)
  4040. {
  4041. if (s->transport
  4042. && s->transport->cleanup)
  4043. s->transport->cleanup (s);
  4044. s->transport = NULL;
  4045. poller_fd_reset (&s->socket_event);
  4046. xclose (s->socket);
  4047. s->socket = -1;
  4048. s->state = IRC_DISCONNECTED;
  4049. str_reset (&s->read_buffer);
  4050. str_reset (&s->write_buffer);
  4051. }
  4052. static void
  4053. irc_destroy_state (struct server *s)
  4054. {
  4055. struct str_map_iter iter = str_map_iter_make (&s->irc_channels);
  4056. struct channel *channel;
  4057. while ((channel = str_map_iter_next (&iter)))
  4058. irc_left_channel (channel);
  4059. if (s->irc_user)
  4060. {
  4061. user_unref (s->irc_user);
  4062. s->irc_user = NULL;
  4063. }
  4064. str_reset (&s->irc_user_mode);
  4065. cstr_set (&s->irc_user_host, NULL);
  4066. s->cap_echo_message = false;
  4067. // Need to call this before server_init_specifics()
  4068. irc_set_casemapping (s, irc_tolower, irc_strxfrm);
  4069. server_free_specifics (s);
  4070. server_init_specifics (s);
  4071. }
  4072. static void
  4073. irc_disconnect (struct server *s)
  4074. {
  4075. hard_assert (irc_is_connected (s));
  4076. struct str_map_iter iter = str_map_iter_make (&s->irc_buffer_map);
  4077. struct buffer *buffer;
  4078. while ((buffer = str_map_iter_next (&iter)))
  4079. log_server (s, buffer, BUFFER_LINE_STATUS | BUFFER_LINE_UNIMPORTANT,
  4080. "Disconnected from server");
  4081. irc_cancel_timers (s);
  4082. irc_destroy_transport (s);
  4083. irc_destroy_state (s);
  4084. // Take any relevant actions
  4085. if (s->ctx->quitting)
  4086. try_finish_quit (s->ctx);
  4087. else if (s->manual_disconnect)
  4088. s->manual_disconnect = false;
  4089. else
  4090. {
  4091. s->reconnect_attempt = 0;
  4092. irc_queue_reconnect (s);
  4093. }
  4094. refresh_prompt (s->ctx);
  4095. }
  4096. static void
  4097. irc_initiate_disconnect (struct server *s, const char *reason)
  4098. {
  4099. hard_assert (irc_is_connected (s));
  4100. // It can take a very long time for sending QUIT to take effect
  4101. if (s->manual_disconnect)
  4102. {
  4103. log_server_error (s, s->buffer, "#s: #s", "Disconnected from server",
  4104. "connection torn down early per user request");
  4105. irc_disconnect (s);
  4106. return;
  4107. }
  4108. if (reason)
  4109. irc_send (s, "QUIT :%s", reason);
  4110. else
  4111. // TODO: make the default QUIT message customizable
  4112. // -> global/per server/both?
  4113. // -> implement IRC output hooks for plugins?
  4114. irc_send (s, "QUIT :%s", PROGRAM_NAME " " PROGRAM_VERSION);
  4115. s->manual_disconnect = true;
  4116. irc_shutdown (s);
  4117. }
  4118. static void
  4119. initiate_quit (struct app_context *ctx, const char *message)
  4120. {
  4121. log_global_status (ctx, "Shutting down");
  4122. // Hide the user interface
  4123. CALL (ctx->input, hide);
  4124. // Initiate a connection close
  4125. struct str_map_iter iter = str_map_iter_make (&ctx->servers);
  4126. struct server *s;
  4127. while ((s = str_map_iter_next (&iter)))
  4128. {
  4129. // There may be a timer set to reconnect to the server
  4130. poller_timer_reset (&s->reconnect_tmr);
  4131. if (irc_is_connected (s))
  4132. irc_initiate_disconnect (s, message);
  4133. else if (s->state == IRC_CONNECTING)
  4134. irc_destroy_connector (s);
  4135. }
  4136. ctx->quitting = true;
  4137. try_finish_quit (ctx);
  4138. }
  4139. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4140. static void
  4141. on_irc_ping_timeout (void *user_data)
  4142. {
  4143. struct server *s = user_data;
  4144. log_server_error (s, s->buffer,
  4145. "#s: #s", "Disconnected from server", "timeout");
  4146. irc_disconnect (s);
  4147. }
  4148. static void
  4149. on_irc_timeout (void *user_data)
  4150. {
  4151. // Provoke a response from the server
  4152. struct server *s = user_data;
  4153. irc_send (s, "PING :%" PRIi64, (int64_t) time (NULL));
  4154. }
  4155. static void
  4156. on_irc_autojoin_timeout (void *user_data)
  4157. {
  4158. struct server *s = user_data;
  4159. // Since we may not have information from RPL_ISUPPORT yet,
  4160. // it's our safest bet to send the channels one at a time
  4161. struct str_map joins_sent = str_map_make (NULL);
  4162. // We don't know the casemapping yet either, however ASCII should do
  4163. joins_sent.key_xfrm = tolower_ascii_strxfrm;
  4164. // First join autojoin channels in their given order
  4165. const char *autojoin = get_config_string (s->config, "autojoin");
  4166. if (autojoin)
  4167. {
  4168. struct strv v = strv_make ();
  4169. cstr_split (autojoin, ",", true, &v);
  4170. for (size_t i = 0; i < v.len; i++)
  4171. {
  4172. irc_send (s, "JOIN %s", v.vector[i]);
  4173. str_map_set (&joins_sent, v.vector[i], (void *) 1);
  4174. }
  4175. strv_free (&v);
  4176. }
  4177. // Then also rejoin any channels from the last disconnect
  4178. struct str_map_iter iter = str_map_iter_make (&s->irc_channels);
  4179. struct channel *channel;
  4180. while ((channel = str_map_iter_next (&iter)))
  4181. {
  4182. struct str target = str_make ();
  4183. str_append (&target, channel->name);
  4184. const char *key;
  4185. if ((key = str_map_find (&channel->param_modes, "k")))
  4186. str_append_printf (&target, " %s", key);
  4187. // When a channel is both autojoined and rejoined, both keys are tried
  4188. if (!channel->left_manually
  4189. && !str_map_find (&joins_sent, target.str))
  4190. irc_send (s, "JOIN %s", target.str);
  4191. str_free (&target);
  4192. }
  4193. str_map_free (&joins_sent);
  4194. }
  4195. // --- Server I/O --------------------------------------------------------------
  4196. static char *
  4197. irc_process_hooks (struct server *s, char *input)
  4198. {
  4199. log_server_debug (s, "#a>> \"#S\"#r", ATTR_JOIN, input);
  4200. uint64_t hash = siphash_wrapper (input, strlen (input));
  4201. LIST_FOR_EACH (struct hook, iter, s->ctx->irc_hooks)
  4202. {
  4203. struct irc_hook *hook = (struct irc_hook *) iter;
  4204. if (!(input = hook->filter (hook, s, input)))
  4205. {
  4206. log_server_debug (s, "#a>= #s#r", ATTR_JOIN, "thrown away by hook");
  4207. return NULL;
  4208. }
  4209. // The old input may get freed, so we compare against a hash of it
  4210. uint64_t new_hash = siphash_wrapper (input, strlen (input));
  4211. if (new_hash != hash)
  4212. log_server_debug (s, "#a>= \"#S\"#r", ATTR_JOIN, input);
  4213. hash = new_hash;
  4214. }
  4215. return input;
  4216. }
  4217. static void irc_process_message
  4218. (const struct irc_message *msg, struct server *s);
  4219. static void
  4220. irc_process_buffer_custom (struct server *s, struct str *buf)
  4221. {
  4222. const char *start = buf->str, *end = start + buf->len;
  4223. for (const char *p = start; p + 1 < end; p++)
  4224. {
  4225. // Split the input on newlines
  4226. if (p[0] != '\r' || p[1] != '\n')
  4227. continue;
  4228. char *processed = irc_process_hooks (s, xstrndup (start, p - start));
  4229. start = p + 2;
  4230. if (!processed)
  4231. continue;
  4232. struct irc_message msg;
  4233. irc_parse_message (&msg, processed);
  4234. irc_process_message (&msg, s);
  4235. irc_free_message (&msg);
  4236. free (processed);
  4237. }
  4238. str_remove_slice (buf, 0, start - buf->str);
  4239. }
  4240. static enum socket_io_result
  4241. irc_try_read (struct server *s)
  4242. {
  4243. enum socket_io_result result = s->transport->try_read (s);
  4244. if (s->read_buffer.len >= (1 << 20))
  4245. {
  4246. // XXX: this is stupid; if anything, count it in dependence of time;
  4247. // we could make transport_tls_try_read() limit the immediate amount
  4248. // of data read like socket_io_try_read() does and remove this check
  4249. log_server_error (s, s->buffer,
  4250. "The IRC server seems to spew out data frantically");
  4251. return SOCKET_IO_ERROR;
  4252. }
  4253. if (s->read_buffer.len)
  4254. irc_process_buffer_custom (s, &s->read_buffer);
  4255. return result;
  4256. }
  4257. static enum socket_io_result
  4258. irc_try_write (struct server *s)
  4259. {
  4260. enum socket_io_result result = s->transport->try_write (s);
  4261. if (result == SOCKET_IO_OK)
  4262. {
  4263. // If we're flushing the write buffer and our job is complete, we send
  4264. // an EOF to the server, changing the state to IRC_HALF_CLOSED
  4265. if (s->state == IRC_CLOSING && !s->write_buffer.len)
  4266. irc_real_shutdown (s);
  4267. }
  4268. return result;
  4269. }
  4270. static bool
  4271. irc_try_read_write (struct server *s)
  4272. {
  4273. enum socket_io_result read_result;
  4274. enum socket_io_result write_result;
  4275. if ((read_result = irc_try_read (s)) == SOCKET_IO_ERROR
  4276. || (write_result = irc_try_write (s)) == SOCKET_IO_ERROR)
  4277. {
  4278. log_server_error (s, s->buffer, "Server connection failed");
  4279. return false;
  4280. }
  4281. // FIXME: this may probably fire multiple times when we're flushing,
  4282. // we should probably store a flag next to the state
  4283. if (read_result == SOCKET_IO_EOF
  4284. || write_result == SOCKET_IO_EOF)
  4285. log_server_error (s, s->buffer, "Server closed the connection");
  4286. // If the write needs to read and we receive an EOF, we can't flush
  4287. if (write_result == SOCKET_IO_EOF)
  4288. return false;
  4289. if (read_result == SOCKET_IO_EOF)
  4290. {
  4291. // Eventually initiate shutdown to flush the write buffer
  4292. irc_shutdown (s);
  4293. // If there's nothing to write, we can disconnect now
  4294. if (s->state == IRC_HALF_CLOSED)
  4295. return false;
  4296. }
  4297. return true;
  4298. }
  4299. static void
  4300. on_irc_ready (const struct pollfd *pfd, struct server *s)
  4301. {
  4302. if (irc_try_read_write (s))
  4303. {
  4304. // XXX: shouldn't we rather wait for PONG messages?
  4305. irc_reset_connection_timeouts (s);
  4306. irc_update_poller (s, pfd);
  4307. }
  4308. else
  4309. // We don't want to keep the socket anymore
  4310. irc_disconnect (s);
  4311. }
  4312. // --- Plain transport ---------------------------------------------------------
  4313. static enum socket_io_result
  4314. transport_plain_try_read (struct server *s)
  4315. {
  4316. enum socket_io_result result =
  4317. socket_io_try_read (s->socket, &s->read_buffer);
  4318. if (result == SOCKET_IO_ERROR)
  4319. print_debug ("%s: %s", __func__, strerror (errno));
  4320. return result;
  4321. }
  4322. static enum socket_io_result
  4323. transport_plain_try_write (struct server *s)
  4324. {
  4325. enum socket_io_result result =
  4326. socket_io_try_write (s->socket, &s->write_buffer);
  4327. if (result == SOCKET_IO_ERROR)
  4328. print_debug ("%s: %s", __func__, strerror (errno));
  4329. return result;
  4330. }
  4331. static int
  4332. transport_plain_get_poll_events (struct server *s)
  4333. {
  4334. int events = POLLIN;
  4335. if (s->write_buffer.len)
  4336. events |= POLLOUT;
  4337. return events;
  4338. }
  4339. static struct transport g_transport_plain =
  4340. {
  4341. .try_read = transport_plain_try_read,
  4342. .try_write = transport_plain_try_write,
  4343. .get_poll_events = transport_plain_get_poll_events,
  4344. };
  4345. // --- TLS transport -----------------------------------------------------------
  4346. struct transport_tls_data
  4347. {
  4348. SSL_CTX *ssl_ctx; ///< SSL context
  4349. SSL *ssl; ///< SSL connection
  4350. bool ssl_rx_want_tx; ///< SSL_read() wants to write
  4351. bool ssl_tx_want_rx; ///< SSL_write() wants to read
  4352. };
  4353. /// The index in SSL_CTX user data for a reference to the server
  4354. static int g_transport_tls_data_index = -1;
  4355. static int
  4356. transport_tls_verify_callback (int preverify_ok, X509_STORE_CTX *ctx)
  4357. {
  4358. SSL *ssl = X509_STORE_CTX_get_ex_data
  4359. (ctx, SSL_get_ex_data_X509_STORE_CTX_idx ());
  4360. struct server *s = SSL_CTX_get_ex_data
  4361. (SSL_get_SSL_CTX (ssl), g_transport_tls_data_index);
  4362. X509 *cert = X509_STORE_CTX_get_current_cert (ctx);
  4363. char *subject = X509_NAME_oneline (X509_get_subject_name (cert), NULL, 0);
  4364. char *issuer = X509_NAME_oneline (X509_get_issuer_name (cert), NULL, 0);
  4365. log_server_status (s, s->buffer, "Certificate subject: #s", subject);
  4366. log_server_status (s, s->buffer, "Certificate issuer: #s", issuer);
  4367. if (!preverify_ok)
  4368. {
  4369. log_server_error (s, s->buffer,
  4370. "Certificate verification failed: #s",
  4371. X509_verify_cert_error_string (X509_STORE_CTX_get_error (ctx)));
  4372. }
  4373. free (subject);
  4374. free (issuer);
  4375. return preverify_ok;
  4376. }
  4377. static bool
  4378. transport_tls_init_ca_set (SSL_CTX *ssl_ctx, const char *file, const char *path,
  4379. struct error **e)
  4380. {
  4381. ERR_clear_error ();
  4382. if (file || path)
  4383. {
  4384. if (SSL_CTX_load_verify_locations (ssl_ctx, file, path))
  4385. return true;
  4386. return error_set (e, "%s: %s",
  4387. "Failed to set locations for the CA certificate bundle",
  4388. ERR_reason_error_string (ERR_get_error ()));
  4389. }
  4390. if (!SSL_CTX_set_default_verify_paths (ssl_ctx))
  4391. return error_set (e, "%s: %s",
  4392. "Couldn't load the default CA certificate bundle",
  4393. ERR_reason_error_string (ERR_get_error ()));
  4394. return true;
  4395. }
  4396. static bool
  4397. transport_tls_init_ca (struct server *s, SSL_CTX *ssl_ctx, struct error **e)
  4398. {
  4399. const char *ca_file = get_config_string (s->config, "tls_ca_file");
  4400. const char *ca_path = get_config_string (s->config, "tls_ca_path");
  4401. char *full_ca_file = ca_file
  4402. ? resolve_filename (ca_file, resolve_relative_config_filename) : NULL;
  4403. char *full_ca_path = ca_path
  4404. ? resolve_filename (ca_path, resolve_relative_config_filename) : NULL;
  4405. bool ok = false;
  4406. if (ca_file && !full_ca_file)
  4407. error_set (e, "Couldn't find the CA bundle file");
  4408. else if (ca_path && !full_ca_path)
  4409. error_set (e, "Couldn't find the CA bundle path");
  4410. else
  4411. ok = transport_tls_init_ca_set (ssl_ctx, full_ca_file, full_ca_path, e);
  4412. free (full_ca_file);
  4413. free (full_ca_path);
  4414. return ok;
  4415. }
  4416. static bool
  4417. transport_tls_init_ctx (struct server *s, SSL_CTX *ssl_ctx, struct error **e)
  4418. {
  4419. bool verify = get_config_boolean (s->config, "tls_verify");
  4420. SSL_CTX_set_verify (ssl_ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
  4421. transport_tls_verify_callback);
  4422. if (g_transport_tls_data_index == -1)
  4423. g_transport_tls_data_index =
  4424. SSL_CTX_get_ex_new_index (0, "server", NULL, NULL, NULL);
  4425. SSL_CTX_set_ex_data (ssl_ctx, g_transport_tls_data_index, s);
  4426. const char *ciphers = get_config_string (s->config, "tls_ciphers");
  4427. if (ciphers && !SSL_CTX_set_cipher_list (ssl_ctx, ciphers))
  4428. log_server_error (s, s->buffer,
  4429. "Failed to select any cipher from the cipher list");
  4430. SSL_CTX_set_mode (ssl_ctx,
  4431. SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
  4432. // Disable deprecated protocols (see RFC 7568)
  4433. SSL_CTX_set_options (ssl_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
  4434. // This seems to consume considerable amounts of memory while not giving
  4435. // that much in return; in addition to that, I'm not sure about security
  4436. // (see RFC 7525, section 3.3)
  4437. #ifdef SSL_OP_NO_COMPRESSION
  4438. SSL_CTX_set_options (ssl_ctx, SSL_OP_NO_COMPRESSION);
  4439. #endif // SSL_OP_NO_COMPRESSION
  4440. struct error *error = NULL;
  4441. if (!transport_tls_init_ca (s, ssl_ctx, &error))
  4442. {
  4443. if (verify)
  4444. {
  4445. error_propagate (e, error);
  4446. return false;
  4447. }
  4448. // Just inform the user if we're not actually verifying
  4449. log_server_error (s, s->buffer, "#s", error->message);
  4450. error_free (error);
  4451. }
  4452. return true;
  4453. }
  4454. static bool
  4455. transport_tls_init_cert (struct server *s, SSL *ssl, struct error **e)
  4456. {
  4457. const char *tls_cert = get_config_string (s->config, "tls_cert");
  4458. if (!tls_cert)
  4459. return true;
  4460. ERR_clear_error ();
  4461. bool result = false;
  4462. char *path = resolve_filename (tls_cert, resolve_relative_config_filename);
  4463. if (!path)
  4464. error_set (e, "%s: %s", "Cannot open file", tls_cert);
  4465. // XXX: perhaps we should read the file ourselves for better messages
  4466. else if (!SSL_use_certificate_file (ssl, path, SSL_FILETYPE_PEM)
  4467. || !SSL_use_PrivateKey_file (ssl, path, SSL_FILETYPE_PEM))
  4468. error_set (e, "%s: %s", "Setting the TLS client certificate failed",
  4469. ERR_reason_error_string (ERR_get_error ()));
  4470. else
  4471. result = true;
  4472. free (path);
  4473. return result;
  4474. }
  4475. static bool
  4476. transport_tls_init (struct server *s, const char *hostname, struct error **e)
  4477. {
  4478. ERR_clear_error ();
  4479. struct error *error = NULL;
  4480. SSL_CTX *ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
  4481. if (!ssl_ctx)
  4482. goto error_ssl_1;
  4483. if (!transport_tls_init_ctx (s, ssl_ctx, &error))
  4484. goto error_ssl_2;
  4485. SSL *ssl = SSL_new (ssl_ctx);
  4486. if (!ssl)
  4487. goto error_ssl_2;
  4488. if (!transport_tls_init_cert (s, ssl, &error))
  4489. {
  4490. // XXX: is this a reason to abort the connection?
  4491. log_server_error (s, s->buffer, "#s", error->message);
  4492. error_free (error);
  4493. error = NULL;
  4494. }
  4495. SSL_set_connect_state (ssl);
  4496. if (!SSL_set_fd (ssl, s->socket))
  4497. goto error_ssl_3;
  4498. // Enable SNI, FWIW; literal IP addresses aren't allowed
  4499. struct in6_addr dummy;
  4500. if (!inet_pton (AF_INET, hostname, &dummy)
  4501. && !inet_pton (AF_INET6, hostname, &dummy))
  4502. SSL_set_tlsext_host_name (ssl, hostname);
  4503. struct transport_tls_data *data = xcalloc (1, sizeof *data);
  4504. data->ssl_ctx = ssl_ctx;
  4505. data->ssl = ssl;
  4506. // Forces a handshake even if neither side wants to transmit data
  4507. data->ssl_rx_want_tx = true;
  4508. s->transport_data = data;
  4509. return true;
  4510. error_ssl_3:
  4511. SSL_free (ssl);
  4512. error_ssl_2:
  4513. SSL_CTX_free (ssl_ctx);
  4514. error_ssl_1:
  4515. if (!error)
  4516. error_set (&error, "%s: %s", "Could not initialize TLS",
  4517. ERR_reason_error_string (ERR_get_error ()));
  4518. error_propagate (e, error);
  4519. return false;
  4520. }
  4521. static void
  4522. transport_tls_cleanup (struct server *s)
  4523. {
  4524. struct transport_tls_data *data = s->transport_data;
  4525. if (data->ssl)
  4526. SSL_free (data->ssl);
  4527. if (data->ssl_ctx)
  4528. SSL_CTX_free (data->ssl_ctx);
  4529. free (data);
  4530. }
  4531. static enum socket_io_result
  4532. transport_tls_try_read (struct server *s)
  4533. {
  4534. struct transport_tls_data *data = s->transport_data;
  4535. if (data->ssl_tx_want_rx)
  4536. return SOCKET_IO_OK;
  4537. struct str *buf = &s->read_buffer;
  4538. data->ssl_rx_want_tx = false;
  4539. while (true)
  4540. {
  4541. ERR_clear_error ();
  4542. str_reserve (buf, 512);
  4543. int n_read = SSL_read (data->ssl, buf->str + buf->len,
  4544. buf->alloc - buf->len - 1 /* null byte */);
  4545. const char *error_info = NULL;
  4546. switch (xssl_get_error (data->ssl, n_read, &error_info))
  4547. {
  4548. case SSL_ERROR_NONE:
  4549. buf->str[buf->len += n_read] = '\0';
  4550. continue;
  4551. case SSL_ERROR_ZERO_RETURN:
  4552. return SOCKET_IO_EOF;
  4553. case SSL_ERROR_WANT_READ:
  4554. return SOCKET_IO_OK;
  4555. case SSL_ERROR_WANT_WRITE:
  4556. data->ssl_rx_want_tx = true;
  4557. return SOCKET_IO_OK;
  4558. case XSSL_ERROR_TRY_AGAIN:
  4559. continue;
  4560. default:
  4561. LOG_FUNC_FAILURE ("SSL_read", error_info);
  4562. return SOCKET_IO_ERROR;
  4563. }
  4564. }
  4565. }
  4566. static enum socket_io_result
  4567. transport_tls_try_write (struct server *s)
  4568. {
  4569. struct transport_tls_data *data = s->transport_data;
  4570. if (data->ssl_rx_want_tx)
  4571. return SOCKET_IO_OK;
  4572. struct str *buf = &s->write_buffer;
  4573. data->ssl_tx_want_rx = false;
  4574. while (buf->len)
  4575. {
  4576. ERR_clear_error ();
  4577. int n_written = SSL_write (data->ssl, buf->str, buf->len);
  4578. const char *error_info = NULL;
  4579. switch (xssl_get_error (data->ssl, n_written, &error_info))
  4580. {
  4581. case SSL_ERROR_NONE:
  4582. str_remove_slice (buf, 0, n_written);
  4583. continue;
  4584. case SSL_ERROR_ZERO_RETURN:
  4585. return SOCKET_IO_EOF;
  4586. case SSL_ERROR_WANT_WRITE:
  4587. return SOCKET_IO_OK;
  4588. case SSL_ERROR_WANT_READ:
  4589. data->ssl_tx_want_rx = true;
  4590. return SOCKET_IO_OK;
  4591. case XSSL_ERROR_TRY_AGAIN:
  4592. continue;
  4593. default:
  4594. LOG_FUNC_FAILURE ("SSL_write", error_info);
  4595. return SOCKET_IO_ERROR;
  4596. }
  4597. }
  4598. return SOCKET_IO_OK;
  4599. }
  4600. static int
  4601. transport_tls_get_poll_events (struct server *s)
  4602. {
  4603. struct transport_tls_data *data = s->transport_data;
  4604. int events = POLLIN;
  4605. if (s->write_buffer.len || data->ssl_rx_want_tx)
  4606. events |= POLLOUT;
  4607. // While we're waiting for an opposite event, we ignore the original
  4608. if (data->ssl_rx_want_tx) events &= ~POLLIN;
  4609. if (data->ssl_tx_want_rx) events &= ~POLLOUT;
  4610. return events;
  4611. }
  4612. static void
  4613. transport_tls_in_before_shutdown (struct server *s)
  4614. {
  4615. struct transport_tls_data *data = s->transport_data;
  4616. (void) SSL_shutdown (data->ssl);
  4617. }
  4618. static struct transport g_transport_tls =
  4619. {
  4620. .init = transport_tls_init,
  4621. .cleanup = transport_tls_cleanup,
  4622. .try_read = transport_tls_try_read,
  4623. .try_write = transport_tls_try_write,
  4624. .get_poll_events = transport_tls_get_poll_events,
  4625. .in_before_shutdown = transport_tls_in_before_shutdown,
  4626. };
  4627. // --- Connection establishment ------------------------------------------------
  4628. static bool
  4629. irc_autofill_user_info (struct server *s, struct error **e)
  4630. {
  4631. const char *nicks = get_config_string (s->config, "nicks");
  4632. const char *username = get_config_string (s->config, "username");
  4633. const char *realname = get_config_string (s->config, "realname");
  4634. if (nicks && *nicks && username && *username && realname)
  4635. return true;
  4636. // Read POSIX user info and fill the configuration if needed
  4637. struct passwd *pwd = getpwuid (geteuid ());
  4638. if (!pwd)
  4639. {
  4640. return error_set (e,
  4641. "cannot retrieve user information: %s", strerror (errno));
  4642. }
  4643. // FIXME: set_config_strings() writes errors on its own
  4644. if (!nicks || !*nicks)
  4645. set_config_string (s->config, "nicks", pwd->pw_name);
  4646. if (!username || !*username)
  4647. set_config_string (s->config, "username", pwd->pw_name);
  4648. // Not all systems have the GECOS field but the vast majority does
  4649. if (!realname)
  4650. {
  4651. char *gecos = pwd->pw_gecos;
  4652. // The first comma, if any, ends the user's real name
  4653. char *comma = strchr (gecos, ',');
  4654. if (comma)
  4655. *comma = '\0';
  4656. set_config_string (s->config, "realname", gecos);
  4657. }
  4658. return true;
  4659. }
  4660. static char *
  4661. irc_fetch_next_nickname (struct server *s)
  4662. {
  4663. struct strv v = strv_make ();
  4664. cstr_split (get_config_string (s->config, "nicks"), ",", true, &v);
  4665. char *result = NULL;
  4666. if (s->nick_counter >= 0 && (size_t) s->nick_counter < v.len)
  4667. result = xstrdup (v.vector[s->nick_counter++]);
  4668. if ((size_t) s->nick_counter >= v.len)
  4669. // Exhausted all nicknames
  4670. s->nick_counter = -1;
  4671. strv_free (&v);
  4672. return result;
  4673. }
  4674. static void
  4675. irc_register (struct server *s)
  4676. {
  4677. // Fill in user information automatically if needed
  4678. irc_autofill_user_info (s, NULL);
  4679. const char *username = get_config_string (s->config, "username");
  4680. const char *realname = get_config_string (s->config, "realname");
  4681. hard_assert (username && realname);
  4682. // Start IRCv3.1 capability negotiation;
  4683. // at worst the server will ignore this or send a harmless error message
  4684. irc_send (s, "CAP LS");
  4685. const char *password = get_config_string (s->config, "password");
  4686. if (password)
  4687. irc_send (s, "PASS :%s", password);
  4688. s->nick_counter = 0;
  4689. char *nickname = irc_fetch_next_nickname (s);
  4690. if (nickname)
  4691. irc_send (s, "NICK :%s", nickname);
  4692. else
  4693. log_server_error (s, s->buffer, "No nicks present in configuration");
  4694. free (nickname);
  4695. // IRC servers may ignore the last argument if it's empty
  4696. irc_send (s, "USER %s 8 * :%s", username, *realname ? realname : " ");
  4697. }
  4698. static void
  4699. irc_finish_connection (struct server *s, int socket, const char *hostname)
  4700. {
  4701. struct app_context *ctx = s->ctx;
  4702. // Most of our output comes from the user one full command at a time and we
  4703. // use output buffering, so it makes a lot of sense to avoid these delays
  4704. int yes = 1;
  4705. soft_assert (setsockopt (socket, IPPROTO_TCP, TCP_NODELAY,
  4706. &yes, sizeof yes) != -1);
  4707. set_blocking (socket, false);
  4708. s->socket = socket;
  4709. s->transport = get_config_boolean (s->config, "tls")
  4710. ? &g_transport_tls
  4711. : &g_transport_plain;
  4712. struct error *e = NULL;
  4713. if (s->transport->init && !s->transport->init (s, hostname, &e))
  4714. {
  4715. log_server_error (s, s->buffer, "Connection failed: #s", e->message);
  4716. error_free (e);
  4717. xclose (s->socket);
  4718. s->socket = -1;
  4719. s->transport = NULL;
  4720. return;
  4721. }
  4722. log_server_status (s, s->buffer, "Connection established");
  4723. s->state = IRC_CONNECTED;
  4724. s->socket_event = poller_fd_make (&ctx->poller, s->socket);
  4725. s->socket_event.dispatcher = (poller_fd_fn) on_irc_ready;
  4726. s->socket_event.user_data = s;
  4727. irc_update_poller (s, NULL);
  4728. irc_reset_connection_timeouts (s);
  4729. irc_register (s);
  4730. refresh_prompt (s->ctx);
  4731. }
  4732. /// Unwrap IPv6 addresses in format_host_port_pair() format
  4733. static void
  4734. irc_split_host_port (char *s, char **host, char **port)
  4735. {
  4736. *host = s;
  4737. *port = "6667";
  4738. char *right_bracket = strchr (s, ']');
  4739. if (s[0] == '[' && right_bracket)
  4740. {
  4741. *right_bracket = '\0';
  4742. *host = s + 1;
  4743. s = right_bracket + 1;
  4744. }
  4745. char *colon = strchr (s, ':');
  4746. if (colon)
  4747. {
  4748. *colon = '\0';
  4749. *port = colon + 1;
  4750. }
  4751. }
  4752. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4753. static void
  4754. irc_on_connector_connecting (void *user_data, const char *address)
  4755. {
  4756. struct server *s = user_data;
  4757. log_server_status (s, s->buffer, "Connecting to #s...", address);
  4758. }
  4759. static void
  4760. irc_on_connector_error (void *user_data, const char *error)
  4761. {
  4762. struct server *s = user_data;
  4763. log_server_error (s, s->buffer, "Connection failed: #s", error);
  4764. }
  4765. static void
  4766. irc_on_connector_failure (void *user_data)
  4767. {
  4768. struct server *s = user_data;
  4769. irc_destroy_connector (s);
  4770. irc_queue_reconnect (s);
  4771. }
  4772. static void
  4773. irc_on_connector_connected (void *user_data, int socket, const char *hostname)
  4774. {
  4775. struct server *s = user_data;
  4776. char *hostname_copy = xstrdup (hostname);
  4777. irc_destroy_connector (s);
  4778. irc_finish_connection (s, socket, hostname_copy);
  4779. free (hostname_copy);
  4780. }
  4781. static void
  4782. irc_setup_connector (struct server *s, const struct strv *addresses)
  4783. {
  4784. struct connector *connector = xmalloc (sizeof *connector);
  4785. connector_init (connector, &s->ctx->poller);
  4786. s->connector = connector;
  4787. connector->user_data = s;
  4788. connector->on_connecting = irc_on_connector_connecting;
  4789. connector->on_error = irc_on_connector_error;
  4790. connector->on_connected = irc_on_connector_connected;
  4791. connector->on_failure = irc_on_connector_failure;
  4792. for (size_t i = 0; i < addresses->len; i++)
  4793. {
  4794. char *host, *port;
  4795. irc_split_host_port (addresses->vector[i], &host, &port);
  4796. connector_add_target (connector, host, port);
  4797. }
  4798. }
  4799. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4800. // TODO: see if we can further merge code for the two connectors, for example
  4801. // by making SOCKS 4A and 5 mere plugins for the connector, or by using
  4802. // a virtual interface common to them both (seems more likely)
  4803. static void
  4804. irc_on_socks_connecting (void *user_data,
  4805. const char *address, const char *via, const char *version)
  4806. {
  4807. struct server *s = user_data;
  4808. log_server_status (s, s->buffer,
  4809. "Connecting to #s via #s (#s)...", address, via, version);
  4810. }
  4811. static bool
  4812. irc_setup_connector_socks (struct server *s, const struct strv *addresses,
  4813. struct error **e)
  4814. {
  4815. const char *socks_host = get_config_string (s->config, "socks_host");
  4816. int64_t socks_port_int = get_config_integer (s->config, "socks_port");
  4817. if (!socks_host)
  4818. return false;
  4819. struct socks_connector *connector = xmalloc (sizeof *connector);
  4820. socks_connector_init (connector, &s->ctx->poller);
  4821. s->socks_conn = connector;
  4822. connector->user_data = s;
  4823. connector->on_connecting = irc_on_socks_connecting;
  4824. connector->on_error = irc_on_connector_error;
  4825. connector->on_connected = irc_on_connector_connected;
  4826. connector->on_failure = irc_on_connector_failure;
  4827. for (size_t i = 0; i < addresses->len; i++)
  4828. {
  4829. char *host, *port;
  4830. irc_split_host_port (addresses->vector[i], &host, &port);
  4831. if (!socks_connector_add_target (connector, host, port, e))
  4832. return false;
  4833. }
  4834. char *service = xstrdup_printf ("%" PRIi64, socks_port_int);
  4835. socks_connector_run (connector, socks_host, service,
  4836. get_config_string (s->config, "socks_username"),
  4837. get_config_string (s->config, "socks_password"));
  4838. free (service);
  4839. // The SOCKS connector can have already failed; we mustn't return true then
  4840. if (!s->socks_conn)
  4841. return error_set (e, "SOCKS connection failed");
  4842. return true;
  4843. }
  4844. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  4845. static void
  4846. irc_initiate_connect (struct server *s)
  4847. {
  4848. hard_assert (s->state == IRC_DISCONNECTED);
  4849. const char *addresses = get_config_string (s->config, "addresses");
  4850. if (!addresses || !addresses[strspn (addresses, ",")])
  4851. {
  4852. // No sense in trying to reconnect
  4853. log_server_error (s, s->buffer,
  4854. "No addresses specified in configuration");
  4855. return;
  4856. }
  4857. struct strv servers = strv_make ();
  4858. cstr_split (addresses, ",", true, &servers);
  4859. struct error *e = NULL;
  4860. if (!irc_setup_connector_socks (s, &servers, &e) && !e)
  4861. irc_setup_connector (s, &servers);
  4862. strv_free (&servers);
  4863. if (e)
  4864. {
  4865. irc_destroy_connector (s);
  4866. log_server_error (s, s->buffer, "#s", e->message);
  4867. error_free (e);
  4868. irc_queue_reconnect (s);
  4869. }
  4870. else if (s->state != IRC_CONNECTED)
  4871. s->state = IRC_CONNECTING;
  4872. }
  4873. // --- Input prompt ------------------------------------------------------------
  4874. static void
  4875. make_unseen_prefix (struct app_context *ctx, struct str *active_buffers)
  4876. {
  4877. size_t buffer_no = 0;
  4878. LIST_FOR_EACH (struct buffer, iter, ctx->buffers)
  4879. {
  4880. buffer_no++;
  4881. if (!(iter->new_messages_count - iter->new_unimportant_count)
  4882. || iter == ctx->current_buffer)
  4883. continue;
  4884. if (active_buffers->len)
  4885. str_append_c (active_buffers, ',');
  4886. if (iter->highlighted)
  4887. str_append_c (active_buffers, '!');
  4888. str_append_printf (active_buffers, "%zu", buffer_no);
  4889. }
  4890. }
  4891. static void
  4892. make_chanmode_postfix (struct channel *channel, struct str *modes)
  4893. {
  4894. if (channel->no_param_modes.len)
  4895. str_append (modes, channel->no_param_modes.str);
  4896. struct str_map_iter iter = str_map_iter_make (&channel->param_modes);
  4897. char *param;
  4898. while ((param = str_map_iter_next (&iter)))
  4899. str_append_c (modes, iter.link->key[0]);
  4900. }
  4901. static void
  4902. make_server_postfix_registered (struct buffer *buffer, struct str *output)
  4903. {
  4904. struct server *s = buffer->server;
  4905. if (buffer->type == BUFFER_CHANNEL)
  4906. {
  4907. struct channel_user *channel_user =
  4908. irc_channel_get_user (buffer->channel, s->irc_user);
  4909. if (channel_user)
  4910. irc_get_channel_user_prefix (s, channel_user, output);
  4911. }
  4912. str_append (output, s->irc_user->nickname);
  4913. if (s->irc_user_mode.len)
  4914. str_append_printf (output, "(%s)", s->irc_user_mode.str);
  4915. }
  4916. static void
  4917. make_server_postfix (struct buffer *buffer, struct str *output)
  4918. {
  4919. struct server *s = buffer->server;
  4920. str_append_c (output, ' ');
  4921. if (!irc_is_connected (s))
  4922. str_append (output, "(disconnected)");
  4923. else if (s->state != IRC_REGISTERED)
  4924. str_append (output, "(unregistered)");
  4925. else
  4926. make_server_postfix_registered (buffer, output);
  4927. }
  4928. static void
  4929. make_prompt (struct app_context *ctx, struct str *output)
  4930. {
  4931. LIST_FOR_EACH (struct hook, iter, ctx->prompt_hooks)
  4932. {
  4933. struct prompt_hook *hook = (struct prompt_hook *) iter;
  4934. char *made = hook->make (hook);
  4935. if (made)
  4936. {
  4937. str_append (output, made);
  4938. free (made);
  4939. return;
  4940. }
  4941. }
  4942. struct buffer *buffer = ctx->current_buffer;
  4943. if (!buffer)
  4944. return;
  4945. str_append_c (output, '[');
  4946. struct str active_buffers = str_make ();
  4947. make_unseen_prefix (ctx, &active_buffers);
  4948. if (active_buffers.len)
  4949. str_append_printf (output, "(%s) ", active_buffers.str);
  4950. str_free (&active_buffers);
  4951. str_append_printf (output, "%d:%s",
  4952. buffer_get_index (ctx, buffer), buffer->name);
  4953. // We remember old modes, don't show them while we're not on the channel
  4954. if (buffer->type == BUFFER_CHANNEL
  4955. && buffer->channel->users_len)
  4956. {
  4957. struct str modes = str_make ();
  4958. make_chanmode_postfix (buffer->channel, &modes);
  4959. if (modes.len)
  4960. str_append_printf (output, "(+%s)", modes.str);
  4961. str_free (&modes);
  4962. str_append_printf (output, "{%zu}", buffer->channel->users_len);
  4963. }
  4964. if (buffer->hide_unimportant)
  4965. str_append (output, "<H>");
  4966. if (buffer != ctx->global_buffer)
  4967. make_server_postfix (buffer, output);
  4968. str_append_c (output, ']');
  4969. str_append_c (output, ' ');
  4970. }
  4971. static void
  4972. input_maybe_set_prompt (struct input *self, char *new_prompt)
  4973. {
  4974. // Redisplay can be an expensive operation
  4975. const char *prompt = CALL (self, get_prompt);
  4976. if (prompt && !strcmp (new_prompt, prompt))
  4977. free (new_prompt);
  4978. else
  4979. CALL_ (self, set_prompt, new_prompt);
  4980. }
  4981. static void
  4982. on_refresh_prompt (struct app_context *ctx)
  4983. {
  4984. poller_idle_reset (&ctx->prompt_event);
  4985. bool have_attributes = !!get_attribute_printer (stdout);
  4986. struct str prompt = str_make ();
  4987. make_prompt (ctx, &prompt);
  4988. char *localized = iconv_xstrdup (ctx->term_from_utf8, prompt.str, -1, NULL);
  4989. str_free (&prompt);
  4990. if (have_attributes)
  4991. {
  4992. // XXX: to be completely correct, we should use tputs, but we cannot
  4993. input_maybe_set_prompt (ctx->input, xstrdup_printf ("%c%s%c%s%c%s%c",
  4994. INPUT_START_IGNORE, ctx->attrs[ATTR_PROMPT],
  4995. INPUT_END_IGNORE,
  4996. localized,
  4997. INPUT_START_IGNORE, ctx->attrs[ATTR_RESET],
  4998. INPUT_END_IGNORE));
  4999. free (localized);
  5000. }
  5001. else
  5002. input_maybe_set_prompt (ctx->input, localized);
  5003. }
  5004. // --- Helpers -----------------------------------------------------------------
  5005. static struct buffer *
  5006. irc_get_buffer_for_message (struct server *s,
  5007. const struct irc_message *msg, const char *target)
  5008. {
  5009. // TODO: display such messages differently
  5010. target = irc_skip_statusmsg (s, target);
  5011. struct buffer *buffer = str_map_find (&s->irc_buffer_map, target);
  5012. if (irc_is_channel (s, target))
  5013. {
  5014. struct channel *channel = str_map_find (&s->irc_channels, target);
  5015. hard_assert (channel || !buffer);
  5016. // This is weird
  5017. if (!channel)
  5018. return NULL;
  5019. }
  5020. else if (!buffer)
  5021. {
  5022. // Outgoing messages needn't have a prefix, no buffer associated
  5023. if (!msg->prefix)
  5024. return NULL;
  5025. // Don't make user buffers for servers (they can send NOTICEs)
  5026. if (!irc_find_userhost (msg->prefix))
  5027. return s->buffer;
  5028. char *nickname = irc_cut_nickname (msg->prefix);
  5029. if (irc_is_this_us (s, target))
  5030. buffer = irc_get_or_make_user_buffer (s, nickname);
  5031. free (nickname);
  5032. // With the IRCv3.2 echo-message capability, we can receive messages
  5033. // as they are delivered to the target; in that case we return NULL
  5034. // and the caller should check the origin
  5035. }
  5036. return buffer;
  5037. }
  5038. static bool
  5039. irc_is_highlight (struct server *s, const char *message)
  5040. {
  5041. // This may be called by notices before even successfully registering
  5042. if (!s->irc_user)
  5043. return false;
  5044. // Strip formatting from the message so that it doesn't interfere
  5045. // with nickname detection (color sequences in particular)
  5046. struct formatter f = formatter_make (s->ctx, NULL);
  5047. formatter_parse_mirc (&f, message);
  5048. struct str stripped = str_make ();
  5049. for (size_t i = 0; i < f.items_len; i++)
  5050. {
  5051. if (f.items[i].type == FORMATTER_ITEM_TEXT)
  5052. str_append (&stripped, f.items[i].text);
  5053. }
  5054. formatter_free (&f);
  5055. // Well, this is rather crude but it should make most users happy.
  5056. // We could do this in proper Unicode but that's two more conversions per
  5057. // message when both the nickname and the message are likely valid UTF-8.
  5058. char *copy = str_steal (&stripped);
  5059. cstr_transform (copy, s->irc_tolower);
  5060. char *nick = xstrdup (s->irc_user->nickname);
  5061. cstr_transform (nick, s->irc_tolower);
  5062. // Special characters allowed in nicknames by RFC 2812: []\`_^{|} and -
  5063. // Also excluded from the ASCII: common user channel prefixes: +%@&~
  5064. // XXX: why did I exclude those? It won't match when IRC newbies use them.
  5065. const char *delimiters = ",.;:!?()<>/=#$* \t\r\n\v\f\"'";
  5066. bool result = false;
  5067. char *save = NULL;
  5068. for (char *token = strtok_r (copy, delimiters, &save);
  5069. token; token = strtok_r (NULL, delimiters, &save))
  5070. if (!strcmp (token, nick))
  5071. {
  5072. result = true;
  5073. break;
  5074. }
  5075. free (copy);
  5076. free (nick);
  5077. return result;
  5078. }
  5079. static char *
  5080. irc_get_privmsg_prefix (struct server *s, struct user *user, const char *target)
  5081. {
  5082. struct str prefix = str_make ();
  5083. if (user && irc_is_channel (s, (target = irc_skip_statusmsg (s, target))))
  5084. {
  5085. struct channel *channel;
  5086. struct channel_user *channel_user;
  5087. if ((channel = str_map_find (&s->irc_channels, target))
  5088. && (channel_user = irc_channel_get_user (channel, user)))
  5089. irc_get_channel_user_prefix (s, channel_user, &prefix);
  5090. }
  5091. return str_steal (&prefix);
  5092. }
  5093. // --- Mode processor ----------------------------------------------------------
  5094. struct mode_processor
  5095. {
  5096. char **params; ///< Mode string parameters
  5097. bool adding; ///< Currently adding modes
  5098. char mode_char; ///< Currently processed mode char
  5099. // User data:
  5100. struct server *s; ///< Server
  5101. struct channel *channel; ///< The channel being modified
  5102. unsigned changes; ///< Count of all changes
  5103. unsigned usermode_changes; ///< Count of all usermode changes
  5104. };
  5105. /// Process a single mode character
  5106. typedef bool (*mode_processor_apply_fn) (struct mode_processor *);
  5107. static const char *
  5108. mode_processor_next_param (struct mode_processor *self)
  5109. {
  5110. if (!*self->params)
  5111. return NULL;
  5112. return *self->params++;
  5113. }
  5114. static void
  5115. mode_processor_run (struct mode_processor *self,
  5116. char **params, mode_processor_apply_fn apply_cb)
  5117. {
  5118. self->params = params;
  5119. const char *mode_string;
  5120. while ((mode_string = mode_processor_next_param (self)))
  5121. {
  5122. self->adding = true;
  5123. while ((self->mode_char = *mode_string++))
  5124. {
  5125. if (self->mode_char == '+') self->adding = true;
  5126. else if (self->mode_char == '-') self->adding = false;
  5127. else if (!apply_cb (self))
  5128. break;
  5129. }
  5130. }
  5131. }
  5132. static int
  5133. mode_char_cmp (const void *a, const void *b)
  5134. {
  5135. return *(const char *) a - *(const char *) b;
  5136. }
  5137. /// Add/remove the current mode character to/from the given ordered list
  5138. static void
  5139. mode_processor_toggle (struct mode_processor *self, struct str *modes)
  5140. {
  5141. const char *pos = strchr (modes->str, self->mode_char);
  5142. if (self->adding == !!pos)
  5143. return;
  5144. if (self->adding)
  5145. {
  5146. str_append_c (modes, self->mode_char);
  5147. qsort (modes->str, modes->len, 1, mode_char_cmp);
  5148. }
  5149. else
  5150. str_remove_slice (modes, pos - modes->str, 1);
  5151. }
  5152. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5153. static void
  5154. mode_processor_do_user (struct mode_processor *self)
  5155. {
  5156. const char *nickname;
  5157. struct user *user;
  5158. struct channel_user *channel_user;
  5159. if (!(nickname = mode_processor_next_param (self))
  5160. || !(user = str_map_find (&self->s->irc_users, nickname))
  5161. || !(channel_user = irc_channel_get_user (self->channel, user)))
  5162. return;
  5163. // Translate mode character to user prefix character
  5164. const char *all_prefixes = self->s->irc_chanuser_prefixes;
  5165. const char *all_modes = self->s->irc_chanuser_modes;
  5166. const char *mode = strchr (all_modes, self->mode_char);
  5167. hard_assert (mode && (size_t) (mode - all_modes) < strlen (all_prefixes));
  5168. char prefix = all_prefixes[mode - all_modes];
  5169. struct str *prefixes = &channel_user->prefixes;
  5170. const char *pos = strchr (prefixes->str, prefix);
  5171. if (self->adding == !!pos)
  5172. return;
  5173. if (self->adding)
  5174. {
  5175. // Add the new mode prefix while retaining the right order
  5176. char *old_prefixes = str_steal (prefixes);
  5177. *prefixes = str_make ();
  5178. for (const char *p = all_prefixes; *p; p++)
  5179. if (*p == prefix || strchr (old_prefixes, *p))
  5180. str_append_c (prefixes, *p);
  5181. free (old_prefixes);
  5182. }
  5183. else
  5184. str_remove_slice (prefixes, pos - prefixes->str, 1);
  5185. }
  5186. static void
  5187. mode_processor_do_param_always (struct mode_processor *self)
  5188. {
  5189. const char *param = NULL;
  5190. if (!(param = mode_processor_next_param (self)))
  5191. return;
  5192. char key[2] = { self->mode_char, 0 };
  5193. str_map_set (&self->channel->param_modes, key,
  5194. self->adding ? xstrdup (param) : NULL);
  5195. }
  5196. static void
  5197. mode_processor_do_param_when_set (struct mode_processor *self)
  5198. {
  5199. const char *param = NULL;
  5200. if (self->adding && !(param = mode_processor_next_param (self)))
  5201. return;
  5202. char key[2] = { self->mode_char, 0 };
  5203. str_map_set (&self->channel->param_modes, key,
  5204. self->adding ? xstrdup (param) : NULL);
  5205. }
  5206. static bool
  5207. mode_processor_apply_channel (struct mode_processor *self)
  5208. {
  5209. self->changes++;
  5210. if (strchr (self->s->irc_chanuser_modes, self->mode_char))
  5211. {
  5212. self->usermode_changes++;
  5213. mode_processor_do_user (self);
  5214. }
  5215. else if (strchr (self->s->irc_chanmodes_list, self->mode_char))
  5216. // Nothing to do here, just skip the next argument if there's any
  5217. (void) mode_processor_next_param (self);
  5218. else if (strchr (self->s->irc_chanmodes_param_always, self->mode_char))
  5219. mode_processor_do_param_always (self);
  5220. else if (strchr (self->s->irc_chanmodes_param_when_set, self->mode_char))
  5221. mode_processor_do_param_when_set (self);
  5222. else if (strchr (self->s->irc_chanmodes_param_never, self->mode_char))
  5223. mode_processor_toggle (self, &self->channel->no_param_modes);
  5224. else
  5225. // It's not safe to continue, results could be undesired
  5226. return false;
  5227. return true;
  5228. }
  5229. /// Returns whether the change has only affected channel user modes
  5230. static bool
  5231. irc_handle_mode_channel
  5232. (struct server *s, struct channel *channel, char **params)
  5233. {
  5234. struct mode_processor p = { .s = s, .channel = channel };
  5235. mode_processor_run (&p, params, mode_processor_apply_channel);
  5236. return p.changes == p.usermode_changes;
  5237. }
  5238. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5239. static bool
  5240. mode_processor_apply_user (struct mode_processor *self)
  5241. {
  5242. mode_processor_toggle (self, &self->s->irc_user_mode);
  5243. return true;
  5244. }
  5245. static void
  5246. irc_handle_mode_user (struct server *s, char **params)
  5247. {
  5248. struct mode_processor p = { .s = s };
  5249. mode_processor_run (&p, params, mode_processor_apply_user);
  5250. }
  5251. // --- Output processing -------------------------------------------------------
  5252. // Both user and plugins can send whatever the heck they want to,
  5253. // we need to parse it back so that it's evident what's happening
  5254. static void
  5255. irc_handle_sent_cap (struct server *s, const struct irc_message *msg)
  5256. {
  5257. if (msg->params.len < 2)
  5258. return;
  5259. const char *subcommand = msg->params.vector[1];
  5260. const char *args = (msg->params.len > 2) ? msg->params.vector[2] : "";
  5261. if (!strcasecmp_ascii (subcommand, "REQ"))
  5262. log_server_status (s, s->buffer,
  5263. "#s: #S", "Capabilities requested", args);
  5264. }
  5265. static void
  5266. irc_handle_sent_notice_text (struct server *s,
  5267. const struct irc_message *msg, struct str *text)
  5268. {
  5269. const char *target = msg->params.vector[0];
  5270. struct buffer *buffer = irc_get_buffer_for_message (s, msg, target);
  5271. if (buffer && soft_assert (s->irc_user))
  5272. log_outcoming_notice (s, buffer, s->irc_user->nickname, text->str);
  5273. else
  5274. log_outcoming_orphan_notice (s, target, text->str);
  5275. }
  5276. static void
  5277. irc_handle_sent_notice (struct server *s, const struct irc_message *msg)
  5278. {
  5279. if (msg->params.len < 2 || s->cap_echo_message)
  5280. return;
  5281. // This ignores empty messages which we should not normally send
  5282. struct ctcp_chunk *chunks = ctcp_parse (msg->params.vector[1]);
  5283. LIST_FOR_EACH (struct ctcp_chunk, iter, chunks)
  5284. {
  5285. if (iter->is_extended)
  5286. log_ctcp_reply (s, msg->params.vector[0],
  5287. xstrdup_printf ("%s %s", iter->tag.str, iter->text.str));
  5288. else
  5289. irc_handle_sent_notice_text (s, msg, &iter->text);
  5290. }
  5291. ctcp_destroy (chunks);
  5292. }
  5293. static void
  5294. irc_handle_sent_privmsg_text (struct server *s,
  5295. const struct irc_message *msg, struct str *text, bool is_action)
  5296. {
  5297. const char *target = msg->params.vector[0];
  5298. struct buffer *buffer = irc_get_buffer_for_message (s, msg, target);
  5299. if (buffer && soft_assert (s->irc_user))
  5300. {
  5301. char *prefixes = irc_get_privmsg_prefix (s, s->irc_user, target);
  5302. if (is_action)
  5303. log_outcoming_action (s, buffer, s->irc_user->nickname, text->str);
  5304. else
  5305. log_outcoming_privmsg (s, buffer,
  5306. prefixes, s->irc_user->nickname, text->str);
  5307. free (prefixes);
  5308. }
  5309. else
  5310. // TODO: also handle actions here
  5311. log_outcoming_orphan_privmsg (s, target, text->str);
  5312. }
  5313. static void
  5314. irc_handle_sent_privmsg (struct server *s, const struct irc_message *msg)
  5315. {
  5316. if (msg->params.len < 2 || s->cap_echo_message)
  5317. return;
  5318. // This ignores empty messages which we should not normally send
  5319. // and the server is likely going to reject with an error reply anyway
  5320. struct ctcp_chunk *chunks = ctcp_parse (msg->params.vector[1]);
  5321. LIST_FOR_EACH (struct ctcp_chunk, iter, chunks)
  5322. {
  5323. if (!iter->is_extended)
  5324. irc_handle_sent_privmsg_text (s, msg, &iter->text, false);
  5325. else if (!strcmp (iter->tag.str, "ACTION"))
  5326. irc_handle_sent_privmsg_text (s, msg, &iter->text, true);
  5327. else
  5328. log_ctcp_query (s, msg->params.vector[0], iter->tag.str);
  5329. }
  5330. ctcp_destroy (chunks);
  5331. }
  5332. static struct irc_handler
  5333. {
  5334. const char *name;
  5335. void (*handler) (struct server *s, const struct irc_message *msg);
  5336. }
  5337. g_irc_sent_handlers[] =
  5338. {
  5339. // This list needs to stay sorted
  5340. { "CAP", irc_handle_sent_cap },
  5341. { "NOTICE", irc_handle_sent_notice },
  5342. { "PRIVMSG", irc_handle_sent_privmsg },
  5343. };
  5344. static int
  5345. irc_handler_cmp_by_name (const void *a, const void *b)
  5346. {
  5347. const struct irc_handler *first = a;
  5348. const struct irc_handler *second = b;
  5349. return strcasecmp_ascii (first->name, second->name);
  5350. }
  5351. static void
  5352. irc_process_sent_message (const struct irc_message *msg, struct server *s)
  5353. {
  5354. // The server is free to reject even a matching prefix
  5355. // XXX: even though no prefix should normally be present, this is racy
  5356. if (msg->prefix && !irc_is_this_us (s, msg->prefix))
  5357. return;
  5358. struct irc_handler key = { .name = msg->command };
  5359. struct irc_handler *handler = bsearch (&key, g_irc_sent_handlers,
  5360. N_ELEMENTS (g_irc_sent_handlers), sizeof key, irc_handler_cmp_by_name);
  5361. if (handler)
  5362. handler->handler (s, msg);
  5363. }
  5364. // --- Input handling ----------------------------------------------------------
  5365. static void
  5366. irc_handle_cap (struct server *s, const struct irc_message *msg)
  5367. {
  5368. if (msg->params.len < 2)
  5369. return;
  5370. struct strv v = strv_make ();
  5371. const char *args = "";
  5372. if (msg->params.len > 2)
  5373. cstr_split ((args = msg->params.vector[2]), " ", true, &v);
  5374. const char *subcommand = msg->params.vector[1];
  5375. if (!strcasecmp_ascii (subcommand, "ACK"))
  5376. {
  5377. log_server_status (s, s->buffer,
  5378. "#s: #S", "Capabilities acknowledged", args);
  5379. for (size_t i = 0; i < v.len; i++)
  5380. {
  5381. const char *cap = v.vector[i];
  5382. bool active = true;
  5383. if (*cap == '-')
  5384. {
  5385. active = false;
  5386. cap++;
  5387. }
  5388. if (!strcasecmp_ascii (cap, "echo-message"))
  5389. s->cap_echo_message = active;
  5390. }
  5391. irc_send (s, "CAP END");
  5392. }
  5393. else if (!strcasecmp_ascii (subcommand, "NAK"))
  5394. {
  5395. log_server_error (s, s->buffer,
  5396. "#s: #S", "Capabilities not acknowledged", args);
  5397. irc_send (s, "CAP END");
  5398. }
  5399. else if (!strcasecmp_ascii (subcommand, "LS"))
  5400. {
  5401. log_server_status (s, s->buffer,
  5402. "#s: #S", "Capabilities supported", args);
  5403. struct strv chosen = strv_make ();
  5404. struct strv use = strv_make ();
  5405. cstr_split (get_config_string (s->config, "capabilities"),
  5406. ",", true, &use);
  5407. // Filter server capabilities for ones we can make use of
  5408. for (size_t i = 0; i < v.len; i++)
  5409. {
  5410. const char *cap = v.vector[i];
  5411. for (size_t k = 0; k < use.len; k++)
  5412. if (!strcasecmp_ascii (use.vector[k], cap))
  5413. strv_append (&chosen, cap);
  5414. }
  5415. char *chosen_str = strv_join (&chosen, " ");
  5416. strv_free (&chosen);
  5417. strv_free (&use);
  5418. irc_send (s, "CAP REQ :%s", chosen_str);
  5419. free (chosen_str);
  5420. }
  5421. strv_free (&v);
  5422. }
  5423. static void
  5424. irc_handle_error (struct server *s, const struct irc_message *msg)
  5425. {
  5426. if (msg->params.len < 1)
  5427. return;
  5428. log_server_error (s, s->buffer, "#m", msg->params.vector[0]);
  5429. }
  5430. static void
  5431. irc_handle_invite (struct server *s, const struct irc_message *msg)
  5432. {
  5433. if (!msg->prefix || msg->params.len < 2)
  5434. return;
  5435. const char *target = msg->params.vector[0];
  5436. const char *channel_name = msg->params.vector[1];
  5437. struct buffer *buffer;
  5438. if (!(buffer = str_map_find (&s->irc_buffer_map, channel_name)))
  5439. buffer = s->buffer;
  5440. // IRCv3.2 invite-notify extension allows the target to be someone else
  5441. if (irc_is_this_us (s, target))
  5442. log_server_status (s, buffer,
  5443. "#n has invited you to #S", msg->prefix, channel_name);
  5444. else
  5445. log_server_status (s, buffer,
  5446. "#n has invited #n to #S", msg->prefix, target, channel_name);
  5447. }
  5448. static void
  5449. irc_handle_join (struct server *s, const struct irc_message *msg)
  5450. {
  5451. if (!msg->prefix || msg->params.len < 1)
  5452. return;
  5453. const char *channel_name = msg->params.vector[0];
  5454. if (!irc_is_channel (s, channel_name))
  5455. return;
  5456. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  5457. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  5458. hard_assert (channel || !buffer);
  5459. // We've joined a new channel
  5460. if (!channel && irc_is_this_us (s, msg->prefix))
  5461. {
  5462. buffer = buffer_new (s->ctx->input);
  5463. buffer->type = BUFFER_CHANNEL;
  5464. buffer->name = xstrdup_printf ("%s.%s", s->name, channel_name);
  5465. buffer->server = s;
  5466. buffer->channel = channel =
  5467. irc_make_channel (s, xstrdup (channel_name));
  5468. str_map_set (&s->irc_buffer_map, channel->name, buffer);
  5469. buffer_add (s->ctx, buffer);
  5470. buffer_activate (s->ctx, buffer);
  5471. }
  5472. if (irc_is_this_us (s, msg->prefix))
  5473. {
  5474. // Reset the field so that we rejoin the channel after reconnecting
  5475. channel->left_manually = false;
  5476. // Request the channel mode as we don't get it automatically
  5477. str_reset (&channel->no_param_modes);
  5478. str_map_clear (&channel->param_modes);
  5479. irc_send (s, "MODE %s", channel_name);
  5480. }
  5481. // This is weird, ignoring
  5482. if (!channel)
  5483. return;
  5484. // Add the user to the channel
  5485. char *nickname = irc_cut_nickname (msg->prefix);
  5486. irc_channel_link_user (channel, irc_get_or_make_user (s, nickname), "");
  5487. free (nickname);
  5488. // Finally log the message
  5489. if (buffer)
  5490. {
  5491. log_server (s, buffer, BUFFER_LINE_UNIMPORTANT, "#a-->#r #N #a#s#r #S",
  5492. ATTR_JOIN, msg->prefix, ATTR_JOIN, "has joined", channel_name);
  5493. }
  5494. }
  5495. static void
  5496. irc_handle_kick (struct server *s, const struct irc_message *msg)
  5497. {
  5498. if (!msg->prefix || msg->params.len < 2)
  5499. return;
  5500. const char *channel_name = msg->params.vector[0];
  5501. const char *target = msg->params.vector[1];
  5502. if (!irc_is_channel (s, channel_name)
  5503. || irc_is_channel (s, target))
  5504. return;
  5505. const char *message = NULL;
  5506. if (msg->params.len > 2)
  5507. message = msg->params.vector[2];
  5508. struct user *user = str_map_find (&s->irc_users, target);
  5509. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  5510. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  5511. hard_assert (channel || !buffer);
  5512. // It would be weird for this to be false
  5513. if (user && channel)
  5514. {
  5515. if (irc_is_this_us (s, target))
  5516. irc_left_channel (channel);
  5517. else
  5518. irc_remove_user_from_channel (user, channel);
  5519. }
  5520. if (buffer)
  5521. {
  5522. struct formatter f = formatter_make (s->ctx, s);
  5523. formatter_add (&f, "#a<--#r #N #a#s#r #n",
  5524. ATTR_PART, msg->prefix, ATTR_PART, "has kicked", target);
  5525. if (message)
  5526. formatter_add (&f, " (#m)", message);
  5527. log_formatter (s->ctx, buffer, 0, &f);
  5528. }
  5529. }
  5530. static void
  5531. irc_handle_kill (struct server *s, const struct irc_message *msg)
  5532. {
  5533. if (!msg->prefix || msg->params.len < 2)
  5534. return;
  5535. const char *target = msg->params.vector[0];
  5536. const char *comment = msg->params.vector[1];
  5537. if (irc_is_this_us (s, target))
  5538. log_server_status (s, s->buffer,
  5539. "You've been killed by #n (#m)", msg->prefix, comment);
  5540. }
  5541. static void
  5542. irc_handle_mode (struct server *s, const struct irc_message *msg)
  5543. {
  5544. if (!msg->prefix || msg->params.len < 1)
  5545. return;
  5546. const char *context = msg->params.vector[0];
  5547. // Join the modes back to a single string
  5548. struct strv copy = strv_make ();
  5549. strv_append_vector (&copy, msg->params.vector + 1);
  5550. char *modes = strv_join (&copy, " ");
  5551. strv_free (&copy);
  5552. if (irc_is_channel (s, context))
  5553. {
  5554. struct channel *channel = str_map_find (&s->irc_channels, context);
  5555. struct buffer *buffer = str_map_find (&s->irc_buffer_map, context);
  5556. hard_assert (channel || !buffer);
  5557. int flags = 0;
  5558. if (channel
  5559. && irc_handle_mode_channel (s, channel, msg->params.vector + 1))
  5560. // This is 90% automode spam, let's not let it steal attention,
  5561. // maybe this behaviour should be configurable though
  5562. flags = BUFFER_LINE_UNIMPORTANT;
  5563. if (buffer)
  5564. {
  5565. log_server (s, buffer, BUFFER_LINE_STATUS | flags,
  5566. "Mode #S [#S] by #n", context, modes, msg->prefix);
  5567. }
  5568. }
  5569. else if (irc_is_this_us (s, context))
  5570. {
  5571. irc_handle_mode_user (s, msg->params.vector + 1);
  5572. log_server_status (s, s->buffer,
  5573. "User mode [#S] by #n", modes, msg->prefix);
  5574. }
  5575. free (modes);
  5576. }
  5577. static void
  5578. irc_handle_nick (struct server *s, const struct irc_message *msg)
  5579. {
  5580. if (!msg->prefix || msg->params.len < 1)
  5581. return;
  5582. const char *new_nickname = msg->params.vector[0];
  5583. char *nickname = irc_cut_nickname (msg->prefix);
  5584. struct user *user = str_map_find (&s->irc_users, nickname);
  5585. free (nickname);
  5586. if (!user)
  5587. return;
  5588. bool lexicographically_different =
  5589. !!irc_server_strcmp (s, user->nickname, new_nickname);
  5590. // What the fuck, someone renamed themselves to ourselves
  5591. // TODO: probably log a message and force a reconnect
  5592. if (lexicographically_different
  5593. && !irc_server_strcmp (s, new_nickname, s->irc_user->nickname))
  5594. return;
  5595. // Log a message in any PM buffer (we may even have one for ourselves)
  5596. struct buffer *pm_buffer =
  5597. str_map_find (&s->irc_buffer_map, user->nickname);
  5598. if (pm_buffer)
  5599. {
  5600. if (irc_is_this_us (s, msg->prefix))
  5601. log_nick_self (s, pm_buffer, new_nickname);
  5602. else
  5603. log_nick (s, pm_buffer, msg->prefix, new_nickname);
  5604. }
  5605. // The new nickname may collide with a user referenced by a PM buffer,
  5606. // or in case of data inconsistency with the server, channels.
  5607. // In the latter case we need the colliding user to leave all of them.
  5608. struct user *user_collision = NULL;
  5609. if (lexicographically_different
  5610. && (user_collision = str_map_find (&s->irc_users, new_nickname)))
  5611. LIST_FOR_EACH (struct user_channel, iter, user_collision->channels)
  5612. irc_remove_user_from_channel (user_collision, iter->channel);
  5613. struct buffer *buffer_collision = NULL;
  5614. if (lexicographically_different
  5615. && (buffer_collision = str_map_find (&s->irc_buffer_map, new_nickname)))
  5616. {
  5617. hard_assert (buffer_collision->type == BUFFER_PM);
  5618. hard_assert (buffer_collision->user == user_collision);
  5619. user_unref (buffer_collision->user);
  5620. buffer_collision->user = user_ref (user);
  5621. }
  5622. if (pm_buffer && buffer_collision)
  5623. {
  5624. // There's not much else we can do other than somehow try to merge
  5625. // one buffer into the other. In our case, the original buffer wins.
  5626. buffer_merge (s->ctx, buffer_collision, pm_buffer);
  5627. if (s->ctx->current_buffer == pm_buffer)
  5628. buffer_activate (s->ctx, buffer_collision);
  5629. buffer_remove (s->ctx, pm_buffer);
  5630. pm_buffer = buffer_collision;
  5631. }
  5632. // The colliding user should be completely gone by now
  5633. if (lexicographically_different)
  5634. hard_assert (!str_map_find (&s->irc_users, new_nickname));
  5635. // Now we can rename the PM buffer to reflect the new nickname
  5636. if (pm_buffer)
  5637. {
  5638. str_map_set (&s->irc_buffer_map, user->nickname, NULL);
  5639. str_map_set (&s->irc_buffer_map, new_nickname, pm_buffer);
  5640. char *x = xstrdup_printf ("%s.%s", s->name, new_nickname);
  5641. buffer_rename (s->ctx, pm_buffer, x);
  5642. free (x);
  5643. }
  5644. if (irc_is_this_us (s, msg->prefix))
  5645. {
  5646. log_nick_self (s, s->buffer, new_nickname);
  5647. // Log a message in all open buffers on this server
  5648. struct str_map_iter iter = str_map_iter_make (&s->irc_buffer_map);
  5649. struct buffer *buffer;
  5650. while ((buffer = str_map_iter_next (&iter)))
  5651. {
  5652. // We've already done that
  5653. if (buffer != pm_buffer)
  5654. log_nick_self (s, buffer, new_nickname);
  5655. }
  5656. }
  5657. else
  5658. {
  5659. // Log a message in all channels the user is in
  5660. LIST_FOR_EACH (struct user_channel, iter, user->channels)
  5661. {
  5662. struct buffer *buffer =
  5663. str_map_find (&s->irc_buffer_map, iter->channel->name);
  5664. hard_assert (buffer != NULL);
  5665. log_nick (s, buffer, msg->prefix, new_nickname);
  5666. }
  5667. }
  5668. // Finally rename the user as it should be safe now
  5669. str_map_set (&s->irc_users, user->nickname, NULL);
  5670. str_map_set (&s->irc_users, new_nickname, user);
  5671. cstr_set (&user->nickname, xstrdup (new_nickname));
  5672. }
  5673. static void
  5674. irc_handle_ctcp_reply (struct server *s,
  5675. const struct irc_message *msg, struct ctcp_chunk *chunk)
  5676. {
  5677. const char *target = msg->params.vector[0];
  5678. if (irc_is_this_us (s, msg->prefix))
  5679. log_ctcp_reply (s, target,
  5680. xstrdup_printf ("%s %s", chunk->tag.str, chunk->text.str));
  5681. else
  5682. log_server_status (s, s->buffer, "CTCP reply from #n: #S #S",
  5683. msg->prefix, chunk->tag.str, chunk->text.str);
  5684. }
  5685. static void
  5686. irc_handle_notice_text (struct server *s,
  5687. const struct irc_message *msg, struct str *text)
  5688. {
  5689. const char *target = msg->params.vector[0];
  5690. struct buffer *buffer = irc_get_buffer_for_message (s, msg, target);
  5691. if (!buffer)
  5692. {
  5693. if (irc_is_this_us (s, msg->prefix))
  5694. log_outcoming_orphan_notice (s, target, text->str);
  5695. return;
  5696. }
  5697. char *nick = irc_cut_nickname (msg->prefix);
  5698. // IRCv3.2 echo-message could otherwise cause us to highlight ourselves
  5699. if (!irc_is_this_us (s, msg->prefix) && irc_is_highlight (s, text->str))
  5700. log_server (s, buffer, BUFFER_LINE_STATUS | BUFFER_LINE_HIGHLIGHT,
  5701. "#a#s(#S)#r: #m", ATTR_HIGHLIGHT, "Notice", nick, text->str);
  5702. else
  5703. log_outcoming_notice (s, buffer, msg->prefix, text->str);
  5704. free (nick);
  5705. }
  5706. static void
  5707. irc_handle_notice (struct server *s, const struct irc_message *msg)
  5708. {
  5709. if (!msg->prefix || msg->params.len < 2)
  5710. return;
  5711. // This ignores empty messages which we should never receive anyway
  5712. struct ctcp_chunk *chunks = ctcp_parse (msg->params.vector[1]);
  5713. LIST_FOR_EACH (struct ctcp_chunk, iter, chunks)
  5714. if (!iter->is_extended)
  5715. irc_handle_notice_text (s, msg, &iter->text);
  5716. else
  5717. irc_handle_ctcp_reply (s, msg, iter);
  5718. ctcp_destroy (chunks);
  5719. }
  5720. static void
  5721. irc_handle_part (struct server *s, const struct irc_message *msg)
  5722. {
  5723. if (!msg->prefix || msg->params.len < 1)
  5724. return;
  5725. const char *channel_name = msg->params.vector[0];
  5726. if (!irc_is_channel (s, channel_name))
  5727. return;
  5728. const char *message = NULL;
  5729. if (msg->params.len > 1)
  5730. message = msg->params.vector[1];
  5731. char *nickname = irc_cut_nickname (msg->prefix);
  5732. struct user *user = str_map_find (&s->irc_users, nickname);
  5733. free (nickname);
  5734. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  5735. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  5736. hard_assert (channel || !buffer);
  5737. // It would be weird for this to be false
  5738. if (user && channel)
  5739. {
  5740. if (irc_is_this_us (s, msg->prefix))
  5741. irc_left_channel (channel);
  5742. else
  5743. irc_remove_user_from_channel (user, channel);
  5744. }
  5745. if (buffer)
  5746. {
  5747. struct formatter f = formatter_make (s->ctx, s);
  5748. formatter_add (&f, "#a<--#r #N #a#s#r #S",
  5749. ATTR_PART, msg->prefix, ATTR_PART, "has left", channel_name);
  5750. if (message)
  5751. formatter_add (&f, " (#m)", message);
  5752. log_formatter (s->ctx, buffer, BUFFER_LINE_UNIMPORTANT, &f);
  5753. }
  5754. }
  5755. static void
  5756. irc_handle_ping (struct server *s, const struct irc_message *msg)
  5757. {
  5758. if (msg->params.len)
  5759. irc_send (s, "PONG :%s", msg->params.vector[0]);
  5760. else
  5761. irc_send (s, "PONG");
  5762. }
  5763. static char *
  5764. ctime_now (char buf[26])
  5765. {
  5766. struct tm tm_;
  5767. time_t now = time (NULL);
  5768. if (!asctime_r (localtime_r (&now, &tm_), buf))
  5769. return NULL;
  5770. // Annoying thing
  5771. *strchr (buf, '\n') = '\0';
  5772. return buf;
  5773. }
  5774. static void irc_send_ctcp_reply (struct server *s, const char *recipient,
  5775. const char *format, ...) ATTRIBUTE_PRINTF (3, 4);
  5776. static void
  5777. irc_send_ctcp_reply (struct server *s,
  5778. const char *recipient, const char *format, ...)
  5779. {
  5780. struct str m = str_make ();
  5781. va_list ap;
  5782. va_start (ap, format);
  5783. str_append_vprintf (&m, format, ap);
  5784. va_end (ap);
  5785. irc_send (s, "NOTICE %s :\x01%s\x01", recipient, m.str);
  5786. str_free (&m);
  5787. }
  5788. static void
  5789. irc_handle_ctcp_request (struct server *s,
  5790. const struct irc_message *msg, struct ctcp_chunk *chunk)
  5791. {
  5792. const char *target = msg->params.vector[0];
  5793. if (irc_is_this_us (s, msg->prefix))
  5794. {
  5795. if (s->cap_echo_message)
  5796. log_ctcp_query (s, target, chunk->tag.str);
  5797. if (!irc_is_this_us (s, target))
  5798. return;
  5799. }
  5800. struct formatter f = formatter_make (s->ctx, s);
  5801. formatter_add (&f, "CTCP requested by #n", msg->prefix);
  5802. if (irc_is_channel (s, irc_skip_statusmsg (s, target)))
  5803. formatter_add (&f, " (to #S)", target);
  5804. formatter_add (&f, ": #S", chunk->tag.str);
  5805. log_formatter (s->ctx, s->buffer, BUFFER_LINE_STATUS, &f);
  5806. char *nickname = irc_cut_nickname (msg->prefix);
  5807. if (!strcmp (chunk->tag.str, "CLIENTINFO"))
  5808. irc_send_ctcp_reply (s, nickname, "CLIENTINFO %s %s %s %s",
  5809. "PING", "VERSION", "TIME", "CLIENTINFO");
  5810. else if (!strcmp (chunk->tag.str, "PING"))
  5811. irc_send_ctcp_reply (s, nickname, "PING %s", chunk->text.str);
  5812. else if (!strcmp (chunk->tag.str, "VERSION"))
  5813. {
  5814. struct utsname info;
  5815. if (uname (&info))
  5816. LOG_LIBC_FAILURE ("uname");
  5817. else
  5818. irc_send_ctcp_reply (s, nickname, "VERSION %s %s on %s %s",
  5819. PROGRAM_NAME, PROGRAM_VERSION, info.sysname, info.machine);
  5820. }
  5821. else if (!strcmp (chunk->tag.str, "TIME"))
  5822. {
  5823. char buf[26];
  5824. if (!ctime_now (buf))
  5825. LOG_LIBC_FAILURE ("asctime_r");
  5826. else
  5827. irc_send_ctcp_reply (s, nickname, "TIME %s", buf);
  5828. }
  5829. free (nickname);
  5830. }
  5831. static void
  5832. irc_handle_privmsg_text (struct server *s,
  5833. const struct irc_message *msg, struct str *text, bool is_action)
  5834. {
  5835. const char *target = msg->params.vector[0];
  5836. struct buffer *buffer = irc_get_buffer_for_message (s, msg, target);
  5837. if (!buffer)
  5838. {
  5839. if (irc_is_this_us (s, msg->prefix))
  5840. log_outcoming_orphan_privmsg (s, target, text->str);
  5841. return;
  5842. }
  5843. char *nickname = irc_cut_nickname (msg->prefix);
  5844. char *prefixes = irc_get_privmsg_prefix
  5845. (s, str_map_find (&s->irc_users, nickname), target);
  5846. // IRCv3.2 echo-message could otherwise cause us to highlight ourselves
  5847. if (irc_is_this_us (s, msg->prefix) || !irc_is_highlight (s, text->str))
  5848. {
  5849. if (is_action)
  5850. log_outcoming_action (s, buffer, nickname, text->str);
  5851. else
  5852. log_outcoming_privmsg (s, buffer, prefixes, nickname, text->str);
  5853. }
  5854. else if (is_action)
  5855. log_server (s, buffer, BUFFER_LINE_HIGHLIGHT,
  5856. " #a*#r #n #m", ATTR_HIGHLIGHT, msg->prefix, text->str);
  5857. else
  5858. log_server (s, buffer, BUFFER_LINE_HIGHLIGHT,
  5859. "#a<#S#S>#r #m", ATTR_HIGHLIGHT, prefixes, nickname, text->str);
  5860. free (nickname);
  5861. free (prefixes);
  5862. }
  5863. static void
  5864. irc_handle_privmsg (struct server *s, const struct irc_message *msg)
  5865. {
  5866. if (!msg->prefix || msg->params.len < 2)
  5867. return;
  5868. // This ignores empty messages which we should never receive anyway
  5869. struct ctcp_chunk *chunks = ctcp_parse (msg->params.vector[1]);
  5870. LIST_FOR_EACH (struct ctcp_chunk, iter, chunks)
  5871. if (!iter->is_extended)
  5872. irc_handle_privmsg_text (s, msg, &iter->text, false);
  5873. else if (!strcmp (iter->tag.str, "ACTION"))
  5874. irc_handle_privmsg_text (s, msg, &iter->text, true);
  5875. else
  5876. irc_handle_ctcp_request (s, msg, iter);
  5877. ctcp_destroy (chunks);
  5878. }
  5879. static void
  5880. log_quit (struct server *s,
  5881. struct buffer *buffer, const char *prefix, const char *reason)
  5882. {
  5883. struct formatter f = formatter_make (s->ctx, s);
  5884. formatter_add (&f, "#a<--#r #N #a#s#r",
  5885. ATTR_PART, prefix, ATTR_PART, "has quit");
  5886. if (reason)
  5887. formatter_add (&f, " (#m)", reason);
  5888. log_formatter (s->ctx, buffer, BUFFER_LINE_UNIMPORTANT, &f);
  5889. }
  5890. static void
  5891. irc_handle_quit (struct server *s, const struct irc_message *msg)
  5892. {
  5893. if (!msg->prefix)
  5894. return;
  5895. // What the fuck, the server never sends this back
  5896. if (irc_is_this_us (s, msg->prefix))
  5897. return;
  5898. char *nickname = irc_cut_nickname (msg->prefix);
  5899. struct user *user = str_map_find (&s->irc_users, nickname);
  5900. free (nickname);
  5901. if (!user)
  5902. return;
  5903. const char *message = NULL;
  5904. if (msg->params.len > 0)
  5905. message = msg->params.vector[0];
  5906. // Log a message in any PM buffer
  5907. struct buffer *buffer =
  5908. str_map_find (&s->irc_buffer_map, user->nickname);
  5909. if (buffer)
  5910. {
  5911. log_quit (s, buffer, msg->prefix, message);
  5912. // TODO: set some kind of a flag in the buffer and when the user
  5913. // reappears on a channel (JOIN), log a "is back online" message.
  5914. // Also set this flag when we receive a "no such nick" numeric
  5915. // and reset it when we send something to the buffer.
  5916. }
  5917. // Log a message in all channels the user is in
  5918. LIST_FOR_EACH (struct user_channel, iter, user->channels)
  5919. {
  5920. if ((buffer = str_map_find (&s->irc_buffer_map, iter->channel->name)))
  5921. log_quit (s, buffer, msg->prefix, message);
  5922. // This destroys "iter" which doesn't matter to us
  5923. irc_remove_user_from_channel (user, iter->channel);
  5924. }
  5925. }
  5926. static void
  5927. irc_handle_topic (struct server *s, const struct irc_message *msg)
  5928. {
  5929. if (!msg->prefix || msg->params.len < 2)
  5930. return;
  5931. const char *channel_name = msg->params.vector[0];
  5932. const char *topic = msg->params.vector[1];
  5933. if (!irc_is_channel (s, channel_name))
  5934. return;
  5935. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  5936. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  5937. hard_assert (channel || !buffer);
  5938. // It would be is weird for this to be false
  5939. if (channel)
  5940. cstr_set (&channel->topic, xstrdup (topic));
  5941. if (buffer)
  5942. {
  5943. log_server (s, buffer, BUFFER_LINE_STATUS, "#n #s \"#m\"",
  5944. msg->prefix, "has changed the topic to", topic);
  5945. }
  5946. }
  5947. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5948. static struct irc_handler g_irc_handlers[] =
  5949. {
  5950. // This list needs to stay sorted
  5951. { "CAP", irc_handle_cap },
  5952. { "ERROR", irc_handle_error },
  5953. { "INVITE", irc_handle_invite },
  5954. { "JOIN", irc_handle_join },
  5955. { "KICK", irc_handle_kick },
  5956. { "KILL", irc_handle_kill },
  5957. { "MODE", irc_handle_mode },
  5958. { "NICK", irc_handle_nick },
  5959. { "NOTICE", irc_handle_notice },
  5960. { "PART", irc_handle_part },
  5961. { "PING", irc_handle_ping },
  5962. { "PRIVMSG", irc_handle_privmsg },
  5963. { "QUIT", irc_handle_quit },
  5964. { "TOPIC", irc_handle_topic },
  5965. };
  5966. static bool
  5967. irc_try_parse_word_for_userhost (struct server *s, const char *word)
  5968. {
  5969. regex_t re;
  5970. int err = regcomp (&re, "^[^!@]+!([^!@]+@[^!@]+)$", REG_EXTENDED);
  5971. if (!soft_assert (!err))
  5972. return false;
  5973. regmatch_t matches[2];
  5974. bool result = false;
  5975. if (!regexec (&re, word, 2, matches, 0))
  5976. {
  5977. cstr_set (&s->irc_user_host, xstrndup (word + matches[1].rm_so,
  5978. matches[1].rm_eo - matches[1].rm_so));
  5979. result = true;
  5980. }
  5981. regfree (&re);
  5982. return result;
  5983. }
  5984. static void
  5985. irc_try_parse_welcome_for_userhost (struct server *s, const char *m)
  5986. {
  5987. struct strv v = strv_make ();
  5988. cstr_split (m, " ", true, &v);
  5989. for (size_t i = 0; i < v.len; i++)
  5990. if (irc_try_parse_word_for_userhost (s, v.vector[i]))
  5991. break;
  5992. strv_free (&v);
  5993. }
  5994. static bool process_input_utf8
  5995. (struct app_context *, struct buffer *, const char *, int);
  5996. static void on_autoaway_timer (struct app_context *ctx);
  5997. static void
  5998. irc_on_registered (struct server *s, const char *nickname)
  5999. {
  6000. s->irc_user = irc_get_or_make_user (s, nickname);
  6001. str_reset (&s->irc_user_mode);
  6002. cstr_set (&s->irc_user_host, NULL);
  6003. s->state = IRC_REGISTERED;
  6004. refresh_prompt (s->ctx);
  6005. // XXX: we can also use WHOIS if it's not supported (optional by RFC 2812)
  6006. // TODO: maybe rather always use RPL_ISUPPORT NICKLEN & USERLEN & HOSTLEN
  6007. // since we don't seem to follow any subsequent changes in userhost;
  6008. // unrealircd sends RPL_HOSTHIDDEN (396), which has an optional user part,
  6009. // and there is also CAP CHGHOST which /may/ send it to ourselves
  6010. irc_send (s, "USERHOST %s", s->irc_user->nickname);
  6011. // A little hack that reinstates auto-away status when we get disconnected
  6012. if (s->autoaway_active)
  6013. on_autoaway_timer (s->ctx);
  6014. const char *command = get_config_string (s->config, "command");
  6015. if (command)
  6016. {
  6017. log_server_debug (s, "Executing \"#s\"", command);
  6018. process_input_utf8 (s->ctx, s->buffer, command, 0);
  6019. }
  6020. int64_t command_delay = get_config_integer (s->config, "command_delay");
  6021. log_server_debug (s, "Autojoining channels in #&s seconds...",
  6022. xstrdup_printf ("%" PRId64, command_delay));
  6023. poller_timer_set (&s->autojoin_tmr, command_delay * 1000);
  6024. }
  6025. static void
  6026. irc_handle_rpl_userhost (struct server *s, const struct irc_message *msg)
  6027. {
  6028. if (msg->params.len < 2)
  6029. return;
  6030. const char *response = msg->params.vector[1];
  6031. struct strv v = strv_make ();
  6032. cstr_split (response, " ", true, &v);
  6033. for (size_t i = 0; i < v.len; i++)
  6034. {
  6035. char *nick = v.vector[i];
  6036. char *equals = strchr (nick, '=');
  6037. if (!equals || equals == nick)
  6038. continue;
  6039. // User is an IRC operator
  6040. if (equals[-1] == '*')
  6041. equals[-1] = '\0';
  6042. else
  6043. equals[ 0] = '\0';
  6044. // TODO: make use of this (away status polling?)
  6045. char away_status = equals[1];
  6046. if (!strchr ("+-", away_status))
  6047. continue;
  6048. char *userhost = equals + 2;
  6049. if (irc_is_this_us (s, nick))
  6050. cstr_set (&s->irc_user_host, xstrdup (userhost));
  6051. }
  6052. strv_free (&v);
  6053. }
  6054. static void
  6055. irc_handle_rpl_umodeis (struct server *s, const struct irc_message *msg)
  6056. {
  6057. if (msg->params.len < 2)
  6058. return;
  6059. str_reset (&s->irc_user_mode);
  6060. irc_handle_mode_user (s, msg->params.vector + 1);
  6061. // XXX: do we want to log a message?
  6062. }
  6063. static void
  6064. irc_handle_rpl_namreply (struct server *s, const struct irc_message *msg)
  6065. {
  6066. if (msg->params.len < 4)
  6067. return;
  6068. const char *channel_name = msg->params.vector[2];
  6069. const char *nicks = msg->params.vector[3];
  6070. // Just push the nicknames to a string vector to process later
  6071. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  6072. if (channel)
  6073. cstr_split (nicks, " ", true, &channel->names_buf);
  6074. }
  6075. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6076. struct channel_user_sort_entry
  6077. {
  6078. struct server *s; ///< Server (because of the qsort API)
  6079. struct channel_user *channel_user; ///< Channel user
  6080. };
  6081. static int
  6082. channel_user_sort_entry_cmp (const void *entry_a, const void *entry_b)
  6083. {
  6084. const struct channel_user_sort_entry *a = entry_a;
  6085. const struct channel_user_sort_entry *b = entry_b;
  6086. struct server *s = a->s;
  6087. // First order by the most significant channel user prefix
  6088. const char *prio_a = strchr (s->irc_chanuser_prefixes,
  6089. *a->channel_user->prefixes.str);
  6090. const char *prio_b = strchr (s->irc_chanuser_prefixes,
  6091. *b->channel_user->prefixes.str);
  6092. // Put unrecognized prefixes at the end of the list
  6093. if (prio_a || prio_b)
  6094. {
  6095. if (!prio_a) return 1;
  6096. if (!prio_b) return -1;
  6097. if (prio_a != prio_b)
  6098. return prio_a - prio_b;
  6099. }
  6100. return irc_server_strcmp (s,
  6101. a->channel_user->user->nickname,
  6102. b->channel_user->user->nickname);
  6103. }
  6104. static char *
  6105. make_channel_users_list (struct server *s, struct channel *channel)
  6106. {
  6107. size_t n_users = 0;
  6108. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  6109. n_users++;
  6110. struct channel_user_sort_entry entries[n_users];
  6111. size_t i = 0;
  6112. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  6113. {
  6114. entries[i].s = s;
  6115. entries[i].channel_user = iter;
  6116. i++;
  6117. }
  6118. qsort (entries, n_users, sizeof *entries, channel_user_sort_entry_cmp);
  6119. struct str list = str_make ();
  6120. for (i = 0; i < n_users; i++)
  6121. {
  6122. irc_get_channel_user_prefix (s, entries[i].channel_user, &list);
  6123. str_append (&list, entries[i].channel_user->user->nickname);
  6124. str_append_c (&list, ' ');
  6125. }
  6126. if (list.len)
  6127. list.str[--list.len] = '\0';
  6128. return str_steal (&list);
  6129. }
  6130. static void
  6131. irc_sync_channel_user (struct server *s, struct channel *channel,
  6132. const char *nickname, const char *prefixes)
  6133. {
  6134. struct user *user = irc_get_or_make_user (s, nickname);
  6135. struct channel_user *channel_user =
  6136. irc_channel_get_user (channel, user);
  6137. if (!channel_user)
  6138. {
  6139. irc_channel_link_user (channel, user, prefixes);
  6140. return;
  6141. }
  6142. user_unref (user);
  6143. // If our idea of the user's modes disagrees with what the server's
  6144. // sent us (the most powerful modes differ), use the latter one
  6145. if (channel_user->prefixes.str[0] != prefixes[0])
  6146. {
  6147. str_reset (&channel_user->prefixes);
  6148. str_append (&channel_user->prefixes, prefixes);
  6149. }
  6150. }
  6151. static void
  6152. irc_process_names (struct server *s, struct channel *channel)
  6153. {
  6154. struct str_map present = str_map_make (NULL);
  6155. present.key_xfrm = s->irc_strxfrm;
  6156. struct strv *updates = &channel->names_buf;
  6157. for (size_t i = 0; i < updates->len; i++)
  6158. {
  6159. const char *item = updates->vector[i];
  6160. size_t n_prefixes = strspn (item, s->irc_chanuser_prefixes);
  6161. const char *nickname = item + n_prefixes;
  6162. // Store the nickname in a hashset
  6163. str_map_set (&present, nickname, (void *) 1);
  6164. char *prefixes = xstrndup (item, n_prefixes);
  6165. irc_sync_channel_user (s, channel, nickname, prefixes);
  6166. free (prefixes);
  6167. }
  6168. // Get rid of channel users missing from "updates"
  6169. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  6170. if (!str_map_find (&present, iter->user->nickname))
  6171. irc_channel_unlink_user (channel, iter);
  6172. str_map_free (&present);
  6173. strv_reset (&channel->names_buf);
  6174. char *all_users = make_channel_users_list (s, channel);
  6175. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel->name);
  6176. if (buffer)
  6177. {
  6178. log_server_status (s, buffer, "Users on #S: #S",
  6179. channel->name, all_users);
  6180. }
  6181. free (all_users);
  6182. }
  6183. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6184. static void
  6185. irc_handle_rpl_endofnames (struct server *s, const struct irc_message *msg)
  6186. {
  6187. if (msg->params.len < 2)
  6188. return;
  6189. const char *channel_name = msg->params.vector[1];
  6190. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  6191. if (!strcmp (channel_name, "*"))
  6192. {
  6193. struct str_map_iter iter = str_map_iter_make (&s->irc_channels);
  6194. struct channel *channel;
  6195. while ((channel = str_map_iter_next (&iter)))
  6196. irc_process_names (s, channel);
  6197. }
  6198. else if (channel)
  6199. irc_process_names (s, channel);
  6200. }
  6201. static void
  6202. irc_handle_rpl_topic (struct server *s, const struct irc_message *msg)
  6203. {
  6204. if (msg->params.len < 3)
  6205. return;
  6206. const char *channel_name = msg->params.vector[1];
  6207. const char *topic = msg->params.vector[2];
  6208. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  6209. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  6210. hard_assert (channel || !buffer);
  6211. if (channel)
  6212. cstr_set (&channel->topic, xstrdup (topic));
  6213. if (buffer)
  6214. log_server_status (s, buffer, "The topic is: #m", topic);
  6215. }
  6216. static void
  6217. irc_handle_rpl_channelmodeis (struct server *s, const struct irc_message *msg)
  6218. {
  6219. if (msg->params.len < 2)
  6220. return;
  6221. const char *channel_name = msg->params.vector[1];
  6222. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  6223. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  6224. hard_assert (channel || !buffer);
  6225. if (channel)
  6226. {
  6227. str_reset (&channel->no_param_modes);
  6228. str_map_clear (&channel->param_modes);
  6229. irc_handle_mode_channel (s, channel, msg->params.vector + 1);
  6230. }
  6231. // XXX: do we want to log a message?
  6232. }
  6233. static char *
  6234. make_time_string (time_t time)
  6235. {
  6236. char buf[32];
  6237. struct tm tm;
  6238. strftime (buf, sizeof buf, "%a %b %d %Y %T", localtime_r (&time, &tm));
  6239. return xstrdup (buf);
  6240. }
  6241. static void
  6242. irc_handle_rpl_creationtime (struct server *s, const struct irc_message *msg)
  6243. {
  6244. if (msg->params.len < 3)
  6245. return;
  6246. const char *channel_name = msg->params.vector[1];
  6247. const char *creation_time = msg->params.vector[2];
  6248. unsigned long created;
  6249. if (!xstrtoul (&created, creation_time, 10))
  6250. return;
  6251. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  6252. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  6253. hard_assert (channel || !buffer);
  6254. if (buffer)
  6255. {
  6256. log_server_status (s, buffer, "Channel created on #&s",
  6257. make_time_string (created));
  6258. }
  6259. }
  6260. static void
  6261. irc_handle_rpl_topicwhotime (struct server *s, const struct irc_message *msg)
  6262. {
  6263. if (msg->params.len < 4)
  6264. return;
  6265. const char *channel_name = msg->params.vector[1];
  6266. const char *who = msg->params.vector[2];
  6267. const char *change_time = msg->params.vector[3];
  6268. unsigned long changed;
  6269. if (!xstrtoul (&changed, change_time, 10))
  6270. return;
  6271. struct channel *channel = str_map_find (&s->irc_channels, channel_name);
  6272. struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel_name);
  6273. hard_assert (channel || !buffer);
  6274. if (buffer)
  6275. {
  6276. log_server_status (s, buffer, "Topic set by #N on #&s",
  6277. who, make_time_string (changed));
  6278. }
  6279. }
  6280. static void
  6281. irc_handle_rpl_inviting (struct server *s, const struct irc_message *msg)
  6282. {
  6283. if (msg->params.len < 3)
  6284. return;
  6285. const char *nickname = msg->params.vector[1];
  6286. const char *channel_name = msg->params.vector[2];
  6287. struct buffer *buffer;
  6288. if (!(buffer = str_map_find (&s->irc_buffer_map, channel_name)))
  6289. buffer = s->buffer;
  6290. log_server_status (s, buffer,
  6291. "You have invited #n to #S", nickname, channel_name);
  6292. }
  6293. static void
  6294. irc_handle_err_nicknameinuse (struct server *s, const struct irc_message *msg)
  6295. {
  6296. if (msg->params.len < 2)
  6297. return;
  6298. log_server_error (s, s->buffer,
  6299. "Nickname is already in use: #S", msg->params.vector[1]);
  6300. // Only do this while we haven't successfully registered yet
  6301. if (s->state != IRC_CONNECTED)
  6302. return;
  6303. char *nickname = irc_fetch_next_nickname (s);
  6304. if (nickname)
  6305. {
  6306. log_server_status (s, s->buffer, "Retrying with #s...", nickname);
  6307. irc_send (s, "NICK :%s", nickname);
  6308. free (nickname);
  6309. }
  6310. }
  6311. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6312. static void
  6313. irc_handle_isupport_prefix (struct server *s, char *value)
  6314. {
  6315. char *modes = value;
  6316. char *prefixes = strchr (value, ')');
  6317. size_t n_prefixes = prefixes - modes;
  6318. if (*modes++ != '(' || !prefixes++ || strlen (value) != 2 * n_prefixes--)
  6319. return;
  6320. cstr_set (&s->irc_chanuser_modes, xstrndup (modes, n_prefixes));
  6321. cstr_set (&s->irc_chanuser_prefixes, xstrndup (prefixes, n_prefixes));
  6322. }
  6323. static void
  6324. irc_handle_isupport_casemapping (struct server *s, char *value)
  6325. {
  6326. if (!strcmp (value, "ascii"))
  6327. irc_set_casemapping (s, tolower_ascii, tolower_ascii_strxfrm);
  6328. else if (!strcmp (value, "rfc1459"))
  6329. irc_set_casemapping (s, irc_tolower, irc_strxfrm);
  6330. else if (!strcmp (value, "rfc1459-strict"))
  6331. irc_set_casemapping (s, irc_tolower_strict, irc_strxfrm_strict);
  6332. }
  6333. static void
  6334. irc_handle_isupport_chantypes (struct server *s, char *value)
  6335. {
  6336. cstr_set (&s->irc_chantypes, xstrdup (value));
  6337. }
  6338. static void
  6339. irc_handle_isupport_idchan (struct server *s, char *value)
  6340. {
  6341. struct str prefixes = str_make ();
  6342. struct strv v = strv_make ();
  6343. cstr_split (value, ",", true, &v);
  6344. for (size_t i = 0; i < v.len; i++)
  6345. {
  6346. // Not using or validating the numeric part
  6347. const char *pair = v.vector[i];
  6348. const char *colon = strchr (pair, ':');
  6349. if (colon)
  6350. str_append_data (&prefixes, pair, colon - pair);
  6351. }
  6352. strv_free (&v);
  6353. cstr_set (&s->irc_idchan_prefixes, str_steal (&prefixes));
  6354. }
  6355. static void
  6356. irc_handle_isupport_statusmsg (struct server *s, char *value)
  6357. {
  6358. cstr_set (&s->irc_statusmsg, xstrdup (value));
  6359. }
  6360. static void
  6361. irc_handle_isupport_chanmodes (struct server *s, char *value)
  6362. {
  6363. struct strv v = strv_make ();
  6364. cstr_split (value, ",", true, &v);
  6365. if (v.len >= 4)
  6366. {
  6367. cstr_set (&s->irc_chanmodes_list, xstrdup (v.vector[0]));
  6368. cstr_set (&s->irc_chanmodes_param_always, xstrdup (v.vector[1]));
  6369. cstr_set (&s->irc_chanmodes_param_when_set, xstrdup (v.vector[2]));
  6370. cstr_set (&s->irc_chanmodes_param_never, xstrdup (v.vector[3]));
  6371. }
  6372. strv_free (&v);
  6373. }
  6374. static void
  6375. irc_handle_isupport_modes (struct server *s, char *value)
  6376. {
  6377. unsigned long modes;
  6378. if (!*value)
  6379. s->irc_max_modes = UINT_MAX;
  6380. else if (xstrtoul (&modes, value, 10) && modes && modes <= UINT_MAX)
  6381. s->irc_max_modes = modes;
  6382. }
  6383. static void
  6384. unescape_isupport_value (const char *value, struct str *output)
  6385. {
  6386. const char *alphabet = "0123456789abcdef", *a, *b;
  6387. for (const char *p = value; *p; p++)
  6388. {
  6389. if (p[0] == '\\'
  6390. && p[1] == 'x'
  6391. && p[2] && (a = strchr (alphabet, tolower_ascii (p[2])))
  6392. && p[3] && (b = strchr (alphabet, tolower_ascii (p[3]))))
  6393. {
  6394. str_append_c (output, (a - alphabet) << 4 | (b - alphabet));
  6395. p += 3;
  6396. }
  6397. else
  6398. str_append_c (output, *p);
  6399. }
  6400. }
  6401. static void
  6402. dispatch_isupport (struct server *s, const char *name, char *value)
  6403. {
  6404. #define MATCH(from, to) if (!strcmp (name, (from))) { (to) (s, value); return; }
  6405. // TODO: also make use of TARGMAX to split client commands as necessary
  6406. MATCH ("PREFIX", irc_handle_isupport_prefix);
  6407. MATCH ("CASEMAPPING", irc_handle_isupport_casemapping);
  6408. MATCH ("CHANTYPES", irc_handle_isupport_chantypes);
  6409. MATCH ("IDCHAN", irc_handle_isupport_idchan);
  6410. MATCH ("STATUSMSG", irc_handle_isupport_statusmsg);
  6411. MATCH ("CHANMODES", irc_handle_isupport_chanmodes);
  6412. MATCH ("MODES", irc_handle_isupport_modes);
  6413. #undef MATCH
  6414. }
  6415. static void
  6416. irc_handle_rpl_isupport (struct server *s, const struct irc_message *msg)
  6417. {
  6418. if (msg->params.len < 2)
  6419. return;
  6420. for (size_t i = 1; i < msg->params.len - 1; i++)
  6421. {
  6422. // TODO: if the parameter starts with "-", it resets to default
  6423. char *param = msg->params.vector[i];
  6424. char *value = param + strcspn (param, "=");
  6425. if (*value) *value++ = '\0';
  6426. struct str value_unescaped = str_make ();
  6427. unescape_isupport_value (value, &value_unescaped);
  6428. dispatch_isupport (s, param, value_unescaped.str);
  6429. str_free (&value_unescaped);
  6430. }
  6431. }
  6432. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6433. static void
  6434. irc_process_numeric (struct server *s,
  6435. const struct irc_message *msg, unsigned long numeric)
  6436. {
  6437. // Numerics typically have human-readable information
  6438. // Get rid of the first parameter, if there's any at all,
  6439. // as it contains our nickname and is of no practical use to the user
  6440. struct strv copy = strv_make ();
  6441. strv_append_vector (&copy, msg->params.vector + !!msg->params.len);
  6442. struct buffer *buffer = s->buffer;
  6443. int flags = BUFFER_LINE_STATUS;
  6444. switch (numeric)
  6445. {
  6446. case IRC_RPL_WELCOME:
  6447. irc_on_registered (s, msg->params.vector[0]);
  6448. // We still issue a USERHOST anyway as this is in general unreliable
  6449. if (msg->params.len == 2)
  6450. irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]);
  6451. break;
  6452. case IRC_RPL_ISUPPORT:
  6453. irc_handle_rpl_isupport (s, msg); break;
  6454. case IRC_RPL_USERHOST:
  6455. irc_handle_rpl_userhost (s, msg); break;
  6456. case IRC_RPL_UMODEIS:
  6457. irc_handle_rpl_umodeis (s, msg); buffer = NULL; break;
  6458. case IRC_RPL_NAMREPLY:
  6459. irc_handle_rpl_namreply (s, msg); buffer = NULL; break;
  6460. case IRC_RPL_ENDOFNAMES:
  6461. irc_handle_rpl_endofnames (s, msg); buffer = NULL; break;
  6462. case IRC_RPL_TOPIC:
  6463. irc_handle_rpl_topic (s, msg); buffer = NULL; break;
  6464. case IRC_RPL_CHANNELMODEIS:
  6465. irc_handle_rpl_channelmodeis (s, msg); buffer = NULL; break;
  6466. case IRC_RPL_CREATIONTIME:
  6467. irc_handle_rpl_creationtime (s, msg); buffer = NULL; break;
  6468. case IRC_RPL_TOPICWHOTIME:
  6469. irc_handle_rpl_topicwhotime (s, msg); buffer = NULL; break;
  6470. case IRC_RPL_INVITING:
  6471. irc_handle_rpl_inviting (s, msg); buffer = NULL; break;
  6472. case IRC_ERR_NICKNAMEINUSE:
  6473. irc_handle_err_nicknameinuse (s, msg); buffer = NULL; break;
  6474. // Auto-away spams server buffers with activity
  6475. case IRC_RPL_NOWAWAY:
  6476. flags |= BUFFER_LINE_UNIMPORTANT;
  6477. if (s->irc_user) s->irc_user->away = true;
  6478. break;
  6479. case IRC_RPL_UNAWAY:
  6480. flags |= BUFFER_LINE_UNIMPORTANT;
  6481. if (s->irc_user) s->irc_user->away = false;
  6482. break;
  6483. case IRC_RPL_LIST:
  6484. case IRC_RPL_WHOREPLY:
  6485. case IRC_RPL_ENDOFWHO:
  6486. case IRC_ERR_UNKNOWNCOMMAND:
  6487. case IRC_ERR_NEEDMOREPARAMS:
  6488. // Just preventing these commands from getting printed in a more
  6489. // specific buffer as that would be unwanted
  6490. break;
  6491. default:
  6492. // If the second parameter is something we have a buffer for
  6493. // (a channel, a PM buffer), log it in that buffer. This is very basic.
  6494. // TODO: whitelist/blacklist a lot more replies in here.
  6495. // TODO: we should either strip the first parameter from the resulting
  6496. // buffer line, or at least put it in brackets
  6497. if (msg->params.len > 1)
  6498. {
  6499. struct buffer *x;
  6500. if ((x = str_map_find (&s->irc_buffer_map, msg->params.vector[1])))
  6501. buffer = x;
  6502. }
  6503. }
  6504. if (buffer)
  6505. {
  6506. // Join the parameter vector back and send it to the server buffer
  6507. log_server (s, buffer, flags, "#&m", strv_join (&copy, " "));
  6508. }
  6509. strv_free (&copy);
  6510. }
  6511. static void
  6512. irc_process_message (const struct irc_message *msg, struct server *s)
  6513. {
  6514. // TODO: make use of IRCv3.2 server-time (with fallback to unixtime_msec())
  6515. // -> change all calls to log_{server,nick,outcoming,ctcp}*() to take
  6516. // an extra argument specifying time
  6517. struct irc_handler key = { .name = msg->command };
  6518. struct irc_handler *handler = bsearch (&key, g_irc_handlers,
  6519. N_ELEMENTS (g_irc_handlers), sizeof key, irc_handler_cmp_by_name);
  6520. if (handler)
  6521. handler->handler (s, msg);
  6522. unsigned long numeric;
  6523. if (xstrtoul (&numeric, msg->command, 10))
  6524. irc_process_numeric (s, msg, numeric);
  6525. // Better always make sure everything is in sync rather than care about
  6526. // each case explicitly whether anything might have changed
  6527. refresh_prompt (s->ctx);
  6528. }
  6529. // --- Message autosplitting magic ---------------------------------------------
  6530. // This is the most basic acceptable algorithm; something like ICU with proper
  6531. // locale specification would be needed to make it work better.
  6532. static size_t
  6533. wrap_text_for_single_line (const char *text, size_t text_len,
  6534. size_t line_len, struct str *output)
  6535. {
  6536. size_t eaten = 0;
  6537. // First try going word by word
  6538. const char *word_start;
  6539. const char *word_end = text + strcspn (text, " ");
  6540. size_t word_len = word_end - text;
  6541. while (line_len && word_len <= line_len)
  6542. {
  6543. if (word_len)
  6544. {
  6545. str_append_data (output, text, word_len);
  6546. text += word_len;
  6547. eaten += word_len;
  6548. line_len -= word_len;
  6549. }
  6550. // Find the next word's end
  6551. word_start = text + strspn (text, " ");
  6552. word_end = word_start + strcspn (word_start, " ");
  6553. word_len = word_end - text;
  6554. }
  6555. if (eaten)
  6556. // Discard whitespace between words if split
  6557. return eaten + (word_start - text);
  6558. // And if that doesn't help, cut the longest valid block of characters
  6559. for (const char *p = text; (size_t) (p - text) <= line_len; )
  6560. {
  6561. eaten = p - text;
  6562. hard_assert ((p = utf8_next (p, text_len - eaten, NULL)));
  6563. }
  6564. str_append_data (output, text, eaten);
  6565. return eaten;
  6566. }
  6567. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6568. static bool
  6569. wrap_message (const char *message,
  6570. int line_max, struct strv *output, struct error **e)
  6571. {
  6572. if (line_max <= 0)
  6573. goto error;
  6574. int message_left = strlen (message);
  6575. while (message_left > line_max)
  6576. {
  6577. struct str m = str_make ();
  6578. size_t eaten = wrap_text_for_single_line
  6579. (message, message_left, line_max, &m);
  6580. if (!eaten)
  6581. {
  6582. str_free (&m);
  6583. goto error;
  6584. }
  6585. strv_append_owned (output, str_steal (&m));
  6586. message += eaten;
  6587. message_left -= eaten;
  6588. }
  6589. if (message_left)
  6590. strv_append (output, message);
  6591. return true;
  6592. error:
  6593. // Well, that's just weird
  6594. error_set (e,
  6595. "Message splitting was unsuccessful as there was "
  6596. "too little room for UTF-8 characters");
  6597. return false;
  6598. }
  6599. /// Automatically splits messages that arrive at other clients with our prefix
  6600. /// so that they don't arrive cut off by the server
  6601. static bool
  6602. irc_autosplit_message (struct server *s, const char *message,
  6603. int fixed_part, struct strv *output, struct error **e)
  6604. {
  6605. // :<nick>!<user>@<host> <fixed-part><message>
  6606. int space_in_one_message = 0;
  6607. if (s->irc_user && s->irc_user_host)
  6608. space_in_one_message = 510
  6609. - 1 - (int) strlen (s->irc_user->nickname)
  6610. - 1 - (int) strlen (s->irc_user_host)
  6611. - 1 - fixed_part;
  6612. // However we don't always have the full info for message splitting
  6613. if (!space_in_one_message)
  6614. strv_append (output, message);
  6615. else if (!wrap_message (message, space_in_one_message, output, e))
  6616. return false;
  6617. return true;
  6618. }
  6619. static void
  6620. send_autosplit_message (struct server *s,
  6621. const char *command, const char *target, const char *message,
  6622. const char *prefix, const char *suffix)
  6623. {
  6624. struct buffer *buffer = str_map_find (&s->irc_buffer_map, target);
  6625. int fixed_part = strlen (command) + 1 + strlen (target) + 1 + 1
  6626. + strlen (prefix) + strlen (suffix);
  6627. // We might also want to preserve attributes across splits but
  6628. // that would make this code a lot more complicated
  6629. struct strv lines = strv_make ();
  6630. struct error *e = NULL;
  6631. if (!irc_autosplit_message (s, message, fixed_part, &lines, &e))
  6632. {
  6633. log_server_error (s, buffer ? buffer : s->buffer, "#s", e->message);
  6634. error_free (e);
  6635. }
  6636. else
  6637. {
  6638. for (size_t i = 0; i < lines.len; i++)
  6639. irc_send (s, "%s %s :%s%s%s", command, target,
  6640. prefix, lines.vector[i], suffix);
  6641. }
  6642. strv_free (&lines);
  6643. }
  6644. #define SEND_AUTOSPLIT_ACTION(s, target, message) \
  6645. send_autosplit_message ((s), "PRIVMSG", (target), (message), \
  6646. "\x01" "ACTION ", "\x01")
  6647. #define SEND_AUTOSPLIT_PRIVMSG(s, target, message) \
  6648. send_autosplit_message ((s), "PRIVMSG", (target), (message), "", "")
  6649. #define SEND_AUTOSPLIT_NOTICE(s, target, message) \
  6650. send_autosplit_message ((s), "NOTICE", (target), (message), "", "")
  6651. // --- Configuration dumper ----------------------------------------------------
  6652. struct config_dump_data
  6653. {
  6654. struct strv path; ///< Levels
  6655. struct strv *output; ///< Where to place new entries
  6656. };
  6657. static void config_dump_item
  6658. (struct config_item *item, struct config_dump_data *data);
  6659. static void
  6660. config_dump_children
  6661. (struct config_item *object, struct config_dump_data *data)
  6662. {
  6663. hard_assert (object->type == CONFIG_ITEM_OBJECT);
  6664. struct str_map_iter iter = str_map_iter_make (&object->value.object);
  6665. struct config_item *child;
  6666. while ((child = str_map_iter_next (&iter)))
  6667. {
  6668. strv_append_owned (&data->path, iter.link->key);
  6669. config_dump_item (child, data);
  6670. strv_steal (&data->path, data->path.len - 1);
  6671. }
  6672. }
  6673. static void
  6674. config_dump_item (struct config_item *item, struct config_dump_data *data)
  6675. {
  6676. // Empty objects will show as such
  6677. if (item->type == CONFIG_ITEM_OBJECT
  6678. && item->value.object.len)
  6679. {
  6680. config_dump_children (item, data);
  6681. return;
  6682. }
  6683. // Currently there's no reason for us to dump unknown items
  6684. struct config_schema *schema = item->schema;
  6685. if (!schema)
  6686. return;
  6687. struct str line = str_make ();
  6688. if (data->path.len)
  6689. str_append (&line, data->path.vector[0]);
  6690. for (size_t i = 1; i < data->path.len; i++)
  6691. str_append_printf (&line, ".%s", data->path.vector[i]);
  6692. struct str value = str_make ();
  6693. config_item_write (item, false, &value);
  6694. // Don't bother writing out null values everywhere
  6695. bool has_default = schema && schema->default_;
  6696. if (item->type != CONFIG_ITEM_NULL || has_default)
  6697. {
  6698. str_append (&line, " = ");
  6699. str_append_str (&line, &value);
  6700. }
  6701. if (!schema)
  6702. str_append (&line, " (unrecognized)");
  6703. else if (has_default && strcmp (schema->default_, value.str))
  6704. str_append_printf (&line, " (default: %s)", schema->default_);
  6705. else if (!has_default && item->type != CONFIG_ITEM_NULL)
  6706. str_append_printf (&line, " (default: %s)", "null");
  6707. str_free (&value);
  6708. strv_append_owned (data->output, str_steal (&line));
  6709. }
  6710. static void
  6711. config_dump (struct config_item *root, struct strv *output)
  6712. {
  6713. struct config_dump_data data;
  6714. data.path = strv_make ();
  6715. data.output = output;
  6716. config_dump_item (root, &data);
  6717. hard_assert (!data.path.len);
  6718. strv_free (&data.path);
  6719. }
  6720. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6721. static int
  6722. strv_sort_cb (const void *a, const void *b)
  6723. {
  6724. return strcmp (*(const char **) a, *(const char **) b);
  6725. }
  6726. static void
  6727. strv_sort (struct strv *self)
  6728. {
  6729. qsort (self->vector, self->len, sizeof *self->vector, strv_sort_cb);
  6730. }
  6731. static void
  6732. dump_matching_options
  6733. (struct config_item *root, const char *mask, struct strv *output)
  6734. {
  6735. config_dump (root, output);
  6736. strv_sort (output);
  6737. // Filter out results by wildcard matching
  6738. for (size_t i = 0; i < output->len; i++)
  6739. {
  6740. // Yeah, I know
  6741. char *key = cstr_cut_until (output->vector[i], " ");
  6742. if (fnmatch (mask, key, 0))
  6743. strv_remove (output, i--);
  6744. free (key);
  6745. }
  6746. }
  6747. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6748. static void
  6749. save_configuration (struct app_context *ctx)
  6750. {
  6751. struct str data = str_make ();
  6752. serialize_configuration (ctx->config.root, &data);
  6753. struct error *e = NULL;
  6754. char *filename = write_configuration_file (NULL, &data, &e);
  6755. str_free (&data);
  6756. if (!filename)
  6757. {
  6758. log_global_error (ctx,
  6759. "#s: #s", "Saving configuration failed", e->message);
  6760. error_free (e);
  6761. }
  6762. else
  6763. log_global_status (ctx, "Configuration written to `#s'", filename);
  6764. free (filename);
  6765. }
  6766. // --- Server management -------------------------------------------------------
  6767. static bool
  6768. validate_server_name (const char *name)
  6769. {
  6770. for (const unsigned char *p = (const unsigned char *) name; *p; p++)
  6771. if (*p < 32 || *p == '.')
  6772. return false;
  6773. return true;
  6774. }
  6775. static const char *
  6776. check_server_name_for_addition (struct app_context *ctx, const char *name)
  6777. {
  6778. if (!strcasecmp_ascii (name, ctx->global_buffer->name))
  6779. return "name collides with the global buffer";
  6780. if (str_map_find (&ctx->servers, name))
  6781. return "server already exists";
  6782. if (!validate_server_name (name))
  6783. return "invalid server name";
  6784. return NULL;
  6785. }
  6786. static struct server *
  6787. server_add (struct app_context *ctx,
  6788. const char *name, struct config_item *subtree)
  6789. {
  6790. hard_assert (!str_map_find (&ctx->servers, name));
  6791. struct server *s = server_new (&ctx->poller);
  6792. s->ctx = ctx;
  6793. s->name = xstrdup (name);
  6794. str_map_set (&ctx->servers, s->name, s);
  6795. s->config = subtree;
  6796. // Add a buffer and activate it
  6797. struct buffer *buffer = s->buffer = buffer_new (ctx->input);
  6798. buffer->type = BUFFER_SERVER;
  6799. buffer->name = xstrdup (s->name);
  6800. buffer->server = s;
  6801. buffer_add (ctx, buffer);
  6802. buffer_activate (ctx, buffer);
  6803. config_schema_apply_to_object (g_config_server, subtree, s);
  6804. config_schema_call_changed (subtree);
  6805. if (get_config_boolean (s->config, "autoconnect"))
  6806. // Connect to the server ASAP
  6807. poller_timer_set (&s->reconnect_tmr, 0);
  6808. return s;
  6809. }
  6810. static void
  6811. server_add_new (struct app_context *ctx, const char *name)
  6812. {
  6813. // Note that there may already be something in the configuration under
  6814. // that key that we've ignored earlier, and there may also be
  6815. // a case-insensitive conflict. Those things may only happen as a result
  6816. // of manual edits to the configuration, though, and they're not really
  6817. // going to break anything. They only cause surprises when loading.
  6818. struct str_map *servers = get_servers_config (ctx);
  6819. struct config_item *subtree = config_item_object ();
  6820. str_map_set (servers, name, subtree);
  6821. struct server *s = server_add (ctx, name, subtree);
  6822. struct error *e = NULL;
  6823. if (!irc_autofill_user_info (s, &e))
  6824. {
  6825. log_server_error (s, s->buffer,
  6826. "#s: #s", "Failed to fill in user details", e->message);
  6827. error_free (e);
  6828. }
  6829. }
  6830. static void
  6831. server_remove (struct app_context *ctx, struct server *s)
  6832. {
  6833. hard_assert (!irc_is_connected (s));
  6834. if (s->buffer)
  6835. buffer_remove_safe (ctx, s->buffer);
  6836. struct str_map_unset_iter iter =
  6837. str_map_unset_iter_make (&s->irc_buffer_map);
  6838. struct buffer *buffer;
  6839. while ((buffer = str_map_unset_iter_next (&iter)))
  6840. buffer_remove_safe (ctx, buffer);
  6841. str_map_unset_iter_free (&iter);
  6842. hard_assert (!s->buffer);
  6843. hard_assert (!s->irc_buffer_map.len);
  6844. hard_assert (!s->irc_channels.len);
  6845. soft_assert (!s->irc_users.len);
  6846. str_map_set (get_servers_config (ctx), s->name, NULL);
  6847. s->config = NULL;
  6848. // This actually destroys the server as it's owned by the map
  6849. str_map_set (&ctx->servers, s->name, NULL);
  6850. }
  6851. static void
  6852. server_rename (struct app_context *ctx, struct server *s, const char *new_name)
  6853. {
  6854. str_map_set (&ctx->servers, new_name,
  6855. str_map_steal (&ctx->servers, s->name));
  6856. struct str_map *servers = get_servers_config (ctx);
  6857. str_map_set (servers, new_name, str_map_steal (servers, s->name));
  6858. cstr_set (&s->name, xstrdup (new_name));
  6859. buffer_rename (ctx, s->buffer, new_name);
  6860. struct str_map_iter iter = str_map_iter_make (&s->irc_buffer_map);
  6861. struct buffer *buffer;
  6862. while ((buffer = str_map_iter_next (&iter)))
  6863. {
  6864. // TODO: creation of buffer names should be centralized -> replace
  6865. // calls to buffer_rename() and manual setting of buffer names
  6866. // with something like buffer_autorename() -- just mind the mess
  6867. // in irc_handle_nick(), which can hopefully be simplified
  6868. char *x = NULL;
  6869. switch (buffer->type)
  6870. {
  6871. case BUFFER_PM:
  6872. x = xstrdup_printf ("%s.%s", s->name, buffer->user->nickname);
  6873. break;
  6874. case BUFFER_CHANNEL:
  6875. x = xstrdup_printf ("%s.%s", s->name, buffer->channel->name);
  6876. break;
  6877. default:
  6878. hard_assert (!"unexpected type of server-related buffer");
  6879. }
  6880. buffer_rename (ctx, buffer, x);
  6881. free (x);
  6882. }
  6883. }
  6884. // --- Plugins -----------------------------------------------------------------
  6885. /// Returns the basename of the plugin's name without any extensions,
  6886. /// or NULL if the name isn't suitable (starts with a dot)
  6887. static char *
  6888. plugin_config_name (struct plugin *self)
  6889. {
  6890. const char *begin = self->name;
  6891. for (const char *p = begin; *p; )
  6892. if (*p++ == '/')
  6893. begin = p;
  6894. size_t len = strcspn (begin, ".");
  6895. if (!len)
  6896. return NULL;
  6897. // XXX: we might also allow arbitrary strings as object keys (except dots)
  6898. char *copy = xstrndup (begin, len);
  6899. for (char *p = copy; *p; p++)
  6900. if (!config_tokenizer_is_word_char (*p))
  6901. *p = '_';
  6902. return copy;
  6903. }
  6904. // --- Lua ---------------------------------------------------------------------
  6905. // Each plugin has its own Lua state object, so that a/ they don't disturb each
  6906. // other and b/ unloading a plugin releases all resources.
  6907. //
  6908. // References to internal objects (buffers, servers) are all weak.
  6909. #ifdef HAVE_LUA
  6910. struct lua_plugin
  6911. {
  6912. struct plugin super; ///< The structure we're deriving
  6913. struct app_context *ctx; ///< Application context
  6914. lua_State *L; ///< Lua state for the main thread
  6915. struct lua_schema_item *schemas; ///< Registered schema items
  6916. };
  6917. static void
  6918. lua_plugin_free (struct plugin *self_)
  6919. {
  6920. struct lua_plugin *self = (struct lua_plugin *) self_;
  6921. lua_close (self->L);
  6922. }
  6923. struct plugin_vtable lua_plugin_vtable =
  6924. {
  6925. .free = lua_plugin_free,
  6926. };
  6927. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6928. // The registry can be used as a cache for weakly referenced objects
  6929. static bool
  6930. lua_cache_get (lua_State *L, void *object)
  6931. {
  6932. lua_rawgetp (L, LUA_REGISTRYINDEX, object);
  6933. if (lua_isnil (L, -1))
  6934. {
  6935. lua_pop (L, 1);
  6936. return false;
  6937. }
  6938. return true;
  6939. }
  6940. static void
  6941. lua_cache_store (lua_State *L, void *object, int index)
  6942. {
  6943. lua_pushvalue (L, index);
  6944. lua_rawsetp (L, LUA_REGISTRYINDEX, object);
  6945. }
  6946. static void
  6947. lua_cache_invalidate (lua_State *L, void *object)
  6948. {
  6949. lua_pushnil (L);
  6950. lua_rawsetp (L, LUA_REGISTRYINDEX, object);
  6951. }
  6952. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6953. /// Append a traceback to all errors so that we can later extract it
  6954. static int
  6955. lua_plugin_error_handler (lua_State *L)
  6956. {
  6957. luaL_traceback (L, L, luaL_checkstring (L, 1), 1);
  6958. return 1;
  6959. }
  6960. static bool
  6961. lua_plugin_process_error (struct lua_plugin *self, const char *message,
  6962. struct error **e)
  6963. {
  6964. struct strv v = strv_make ();
  6965. cstr_split (message, "\n", true, &v);
  6966. if (v.len < 2)
  6967. error_set (e, "%s", message);
  6968. else
  6969. {
  6970. error_set (e, "%s", v.vector[0]);
  6971. log_global_debug (self->ctx, "Lua: plugin \"#s\": #s",
  6972. self->super.name, v.vector[1]);
  6973. for (size_t i = 2; i < v.len; i++)
  6974. log_global_debug (self->ctx, " #s", v.vector[i]);
  6975. }
  6976. strv_free (&v);
  6977. return false;
  6978. }
  6979. /// Call a Lua function and process errors using our special error handler
  6980. static bool
  6981. lua_plugin_call (struct lua_plugin *self,
  6982. int n_params, int n_results, struct error **e)
  6983. {
  6984. // XXX: this may eventually be called from a thread, then this is wrong
  6985. lua_State *L = self->L;
  6986. // We need to pop the error handler at the end
  6987. lua_pushcfunction (L, lua_plugin_error_handler);
  6988. int error_handler_idx = -n_params - 2;
  6989. lua_insert (L, error_handler_idx);
  6990. if (!lua_pcall (L, n_params, n_results, error_handler_idx))
  6991. {
  6992. lua_remove (L, -n_results - 1);
  6993. return true;
  6994. }
  6995. (void) lua_plugin_process_error (self, lua_tostring (L, -1), e);
  6996. lua_pop (L, 2);
  6997. return false;
  6998. }
  6999. /// Convenience function; replaces the "original" string or produces an error
  7000. static bool
  7001. lua_plugin_handle_string_filter_result (struct lua_plugin *self,
  7002. char **original, bool utf8, struct error **e)
  7003. {
  7004. lua_State *L = self->L;
  7005. if (lua_isnil (L, -1))
  7006. {
  7007. cstr_set (original, NULL);
  7008. return true;
  7009. }
  7010. if (!lua_isstring (L, -1))
  7011. return error_set (e, "must return either a string or nil");
  7012. size_t len;
  7013. const char *processed = lua_tolstring (L, -1, &len);
  7014. if (utf8 && !utf8_validate (processed, len))
  7015. return error_set (e, "must return valid UTF-8");
  7016. // Only replace the string if it's different
  7017. if (strcmp (processed, *original))
  7018. cstr_set (original, xstrdup (processed));
  7019. return true;
  7020. }
  7021. static const char *
  7022. lua_plugin_check_utf8 (lua_State *L, int arg)
  7023. {
  7024. size_t len;
  7025. const char *s = luaL_checklstring (L, arg, &len);
  7026. luaL_argcheck (L, utf8_validate (s, len), arg, "must be valid UTF-8");
  7027. return s;
  7028. }
  7029. static void
  7030. lua_plugin_log_error
  7031. (struct lua_plugin *self, const char *where, struct error *error)
  7032. {
  7033. log_global_error (self->ctx, "Lua: plugin \"#s\": #s: #s",
  7034. self->super.name, where, error->message);
  7035. error_free (error);
  7036. }
  7037. /// Pop "n" values from the stack into a table, using their indexes as keys
  7038. static void
  7039. lua_plugin_pack (lua_State *L, int n)
  7040. {
  7041. lua_createtable (L, n, 0);
  7042. lua_insert (L, -n - 1);
  7043. for (int i = n; i; i--)
  7044. lua_rawseti (L, -i - 1, i);
  7045. }
  7046. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7047. static void
  7048. lua_plugin_kv (lua_State *L, const char *key, const char *value)
  7049. {
  7050. lua_pushstring (L, value);
  7051. lua_setfield (L, -2, key);
  7052. }
  7053. static void
  7054. lua_plugin_push_message (lua_State *L, const struct irc_message *msg)
  7055. {
  7056. lua_createtable (L, 0, 4);
  7057. lua_createtable (L, msg->tags.len, 0);
  7058. struct str_map_iter iter = str_map_iter_make (&msg->tags);
  7059. const char *value;
  7060. while ((value = str_map_iter_next (&iter)))
  7061. lua_plugin_kv (L, iter.link->key, value);
  7062. lua_setfield (L, -2, "tags");
  7063. // TODO: parse the prefix further?
  7064. if (msg->prefix) lua_plugin_kv (L, "prefix", msg->prefix);
  7065. if (msg->command) lua_plugin_kv (L, "command", msg->command);
  7066. lua_createtable (L, msg->params.len, 0);
  7067. for (size_t i = 0; i < msg->params.len; i++)
  7068. {
  7069. lua_pushstring (L, msg->params.vector[i]);
  7070. lua_rawseti (L, -2, i + 1);
  7071. }
  7072. lua_setfield (L, -2, "params");
  7073. }
  7074. static int
  7075. lua_plugin_parse (lua_State *L)
  7076. {
  7077. struct irc_message msg;
  7078. irc_parse_message (&msg, luaL_checkstring (L, 1));
  7079. lua_plugin_push_message (L, &msg);
  7080. irc_free_message (&msg);
  7081. return 1;
  7082. }
  7083. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7084. // Lua code can use weakly referenced wrappers for internal objects.
  7085. typedef struct weak_ref_link *
  7086. (*lua_weak_ref_fn) (void *object, destroy_cb_fn cb, void *user_data);
  7087. typedef void (*lua_weak_unref_fn) (void *object, struct weak_ref_link **link);
  7088. struct lua_weak_info
  7089. {
  7090. const char *name; ///< Metatable name
  7091. struct ispect_field *ispect; ///< Introspection data
  7092. lua_weak_ref_fn ref; ///< Weak link invalidator
  7093. lua_weak_unref_fn unref; ///< Weak link generator
  7094. };
  7095. struct lua_weak
  7096. {
  7097. struct lua_plugin *plugin; ///< The plugin we belong to
  7098. struct lua_weak_info *info; ///< Introspection data
  7099. void *object; ///< The object
  7100. struct weak_ref_link *weak_ref; ///< A weak reference link
  7101. };
  7102. static void
  7103. lua_weak_invalidate (void *object, void *user_data)
  7104. {
  7105. struct lua_weak *wrapper = user_data;
  7106. wrapper->object = NULL;
  7107. wrapper->weak_ref = NULL;
  7108. // This can in theory call the GC, order isn't arbitrary here
  7109. lua_cache_invalidate (wrapper->plugin->L, object);
  7110. }
  7111. static void
  7112. lua_weak_push (lua_State *L, struct lua_plugin *plugin, void *object,
  7113. struct lua_weak_info *info)
  7114. {
  7115. if (!object)
  7116. {
  7117. lua_pushnil (L);
  7118. return;
  7119. }
  7120. if (lua_cache_get (L, object))
  7121. return;
  7122. struct lua_weak *wrapper = lua_newuserdata (L, sizeof *wrapper);
  7123. luaL_setmetatable (L, info->name);
  7124. wrapper->plugin = plugin;
  7125. wrapper->info = info;
  7126. wrapper->object = object;
  7127. wrapper->weak_ref = NULL;
  7128. if (info->ref)
  7129. wrapper->weak_ref = info->ref (object, lua_weak_invalidate, wrapper);
  7130. lua_cache_store (L, object, -1);
  7131. }
  7132. static int
  7133. lua_weak_gc (lua_State *L, const struct lua_weak_info *info)
  7134. {
  7135. struct lua_weak *wrapper = luaL_checkudata (L, 1, info->name);
  7136. if (wrapper->object)
  7137. {
  7138. lua_cache_invalidate (L, wrapper->object);
  7139. if (info->unref)
  7140. info->unref (wrapper->object, &wrapper->weak_ref);
  7141. wrapper->object = NULL;
  7142. }
  7143. return 0;
  7144. }
  7145. static struct lua_weak *
  7146. lua_weak_deref (lua_State *L, const struct lua_weak_info *info)
  7147. {
  7148. struct lua_weak *weak = luaL_checkudata (L, 1, info->name);
  7149. luaL_argcheck (L, weak->object, 1, "dead reference used");
  7150. return weak;
  7151. }
  7152. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7153. #define LUA_WEAK_DECLARE(id, metatable_id) \
  7154. static struct lua_weak_info lua_ ## id ## _info = \
  7155. { \
  7156. .name = metatable_id, \
  7157. .ispect = g_ ## id ## _ispect, \
  7158. .ref = (lua_weak_ref_fn) id ## _weak_ref, \
  7159. .unref = (lua_weak_unref_fn) id ## _weak_unref, \
  7160. };
  7161. #define XLUA_USER_METATABLE "user" ///< Identifier for Lua metatable
  7162. #define XLUA_CHANNEL_METATABLE "channel" ///< Identifier for Lua metatable
  7163. #define XLUA_BUFFER_METATABLE "buffer" ///< Identifier for Lua metatable
  7164. #define XLUA_SERVER_METATABLE "server" ///< Identifier for Lua metatable
  7165. LUA_WEAK_DECLARE (user, XLUA_USER_METATABLE)
  7166. LUA_WEAK_DECLARE (channel, XLUA_CHANNEL_METATABLE)
  7167. LUA_WEAK_DECLARE (buffer, XLUA_BUFFER_METATABLE)
  7168. LUA_WEAK_DECLARE (server, XLUA_SERVER_METATABLE)
  7169. // The global context is kind of fake and doesn't have any ref-counting,
  7170. // however it's still very much an object
  7171. static struct lua_weak_info lua_ctx_info =
  7172. {
  7173. .name = PROGRAM_NAME,
  7174. .ispect = g_ctx_ispect,
  7175. };
  7176. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7177. static int
  7178. lua_user_gc (lua_State *L)
  7179. {
  7180. return lua_weak_gc (L, &lua_user_info);
  7181. }
  7182. static int
  7183. lua_user_get_channels (lua_State *L)
  7184. {
  7185. struct lua_weak *wrapper = lua_weak_deref (L, &lua_user_info);
  7186. struct user *user = wrapper->object;
  7187. int i = 1;
  7188. lua_newtable (L);
  7189. LIST_FOR_EACH (struct user_channel, iter, user->channels)
  7190. {
  7191. lua_weak_push (L, wrapper->plugin, iter->channel, &lua_channel_info);
  7192. lua_rawseti (L, -2, i++);
  7193. }
  7194. return 1;
  7195. }
  7196. static luaL_Reg lua_user_table[] =
  7197. {
  7198. { "__gc", lua_user_gc },
  7199. { "get_channels", lua_user_get_channels },
  7200. { NULL, NULL }
  7201. };
  7202. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7203. static int
  7204. lua_channel_gc (lua_State *L)
  7205. {
  7206. return lua_weak_gc (L, &lua_channel_info);
  7207. }
  7208. static int
  7209. lua_channel_get_users (lua_State *L)
  7210. {
  7211. struct lua_weak *wrapper = lua_weak_deref (L, &lua_channel_info);
  7212. struct channel *channel = wrapper->object;
  7213. int i = 1;
  7214. lua_newtable (L);
  7215. LIST_FOR_EACH (struct channel_user, iter, channel->users)
  7216. {
  7217. lua_createtable (L, 0, 2);
  7218. lua_weak_push (L, wrapper->plugin, iter->user, &lua_user_info);
  7219. lua_setfield (L, -2, "user");
  7220. lua_plugin_kv (L, "prefixes", iter->prefixes.str);
  7221. lua_rawseti (L, -2, i++);
  7222. }
  7223. return 1;
  7224. }
  7225. static luaL_Reg lua_channel_table[] =
  7226. {
  7227. { "__gc", lua_channel_gc },
  7228. { "get_users", lua_channel_get_users },
  7229. { NULL, NULL }
  7230. };
  7231. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7232. static int
  7233. lua_buffer_gc (lua_State *L)
  7234. {
  7235. return lua_weak_gc (L, &lua_buffer_info);
  7236. }
  7237. static int
  7238. lua_buffer_log (lua_State *L)
  7239. {
  7240. struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
  7241. struct buffer *buffer = wrapper->object;
  7242. const char *message = lua_plugin_check_utf8 (L, 2);
  7243. log_full (wrapper->plugin->ctx, buffer->server, buffer,
  7244. BUFFER_LINE_STATUS, "#s", message);
  7245. return 0;
  7246. }
  7247. static int
  7248. lua_buffer_execute (lua_State *L)
  7249. {
  7250. struct lua_weak *wrapper = lua_weak_deref (L, &lua_buffer_info);
  7251. struct buffer *buffer = wrapper->object;
  7252. const char *line = lua_plugin_check_utf8 (L, 2);
  7253. process_input_utf8 (wrapper->plugin->ctx, buffer, line, 0);
  7254. return 0;
  7255. }
  7256. static luaL_Reg lua_buffer_table[] =
  7257. {
  7258. { "__gc", lua_buffer_gc },
  7259. { "log", lua_buffer_log },
  7260. { "execute", lua_buffer_execute },
  7261. { NULL, NULL }
  7262. };
  7263. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7264. static int
  7265. lua_server_gc (lua_State *L)
  7266. {
  7267. return lua_weak_gc (L, &lua_server_info);
  7268. }
  7269. static int
  7270. lua_server_get_state (lua_State *L)
  7271. {
  7272. struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
  7273. struct server *server = wrapper->object;
  7274. switch (server->state)
  7275. {
  7276. case IRC_DISCONNECTED: lua_pushstring (L, "disconnected"); break;
  7277. case IRC_CONNECTING: lua_pushstring (L, "connecting"); break;
  7278. case IRC_CONNECTED: lua_pushstring (L, "connected"); break;
  7279. case IRC_REGISTERED: lua_pushstring (L, "registered"); break;
  7280. case IRC_CLOSING: lua_pushstring (L, "closing"); break;
  7281. case IRC_HALF_CLOSED: lua_pushstring (L, "half_closed"); break;
  7282. }
  7283. return 1;
  7284. }
  7285. static int
  7286. lua_server_send (lua_State *L)
  7287. {
  7288. struct lua_weak *wrapper = lua_weak_deref (L, &lua_server_info);
  7289. struct server *server = wrapper->object;
  7290. irc_send (server, "%s", luaL_checkstring (L, 2));
  7291. return 0;
  7292. }
  7293. static luaL_Reg lua_server_table[] =
  7294. {
  7295. { "__gc", lua_server_gc },
  7296. { "get_state", lua_server_get_state },
  7297. { "send", lua_server_send },
  7298. { NULL, NULL }
  7299. };
  7300. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7301. #define XLUA_HOOK_METATABLE "hook" ///< Identifier for the Lua metatable
  7302. enum lua_hook_type
  7303. {
  7304. XLUA_HOOK_DEFUNCT, ///< No longer functional
  7305. XLUA_HOOK_INPUT, ///< Input hook
  7306. XLUA_HOOK_IRC, ///< IRC hook
  7307. XLUA_HOOK_PROMPT, ///< Prompt hook
  7308. XLUA_HOOK_COMPLETION, ///< Autocomplete
  7309. };
  7310. struct lua_hook
  7311. {
  7312. struct lua_plugin *plugin; ///< The plugin we belong to
  7313. enum lua_hook_type type; ///< Type of the hook
  7314. int ref_callback; ///< Reference to the callback
  7315. union
  7316. {
  7317. struct hook hook; ///< Hook base structure
  7318. struct input_hook input_hook; ///< Input hook
  7319. struct irc_hook irc_hook; ///< IRC hook
  7320. struct prompt_hook prompt_hook; ///< IRC hook
  7321. struct completion_hook c_hook; ///< Autocomplete hook
  7322. }
  7323. data; ///< Hook data
  7324. };
  7325. static int
  7326. lua_hook_unhook (lua_State *L)
  7327. {
  7328. struct lua_hook *hook = luaL_checkudata (L, 1, XLUA_HOOK_METATABLE);
  7329. switch (hook->type)
  7330. {
  7331. case XLUA_HOOK_INPUT:
  7332. LIST_UNLINK (hook->plugin->ctx->input_hooks, &hook->data.hook);
  7333. break;
  7334. case XLUA_HOOK_IRC:
  7335. LIST_UNLINK (hook->plugin->ctx->irc_hooks, &hook->data.hook);
  7336. break;
  7337. case XLUA_HOOK_PROMPT:
  7338. LIST_UNLINK (hook->plugin->ctx->prompt_hooks, &hook->data.hook);
  7339. refresh_prompt (hook->plugin->ctx);
  7340. break;
  7341. case XLUA_HOOK_COMPLETION:
  7342. LIST_UNLINK (hook->plugin->ctx->completion_hooks, &hook->data.hook);
  7343. break;
  7344. default:
  7345. hard_assert (!"invalid hook type");
  7346. case XLUA_HOOK_DEFUNCT:
  7347. break;
  7348. }
  7349. luaL_unref (L, LUA_REGISTRYINDEX, hook->ref_callback);
  7350. hook->ref_callback = LUA_REFNIL;
  7351. // The hook no longer has to stay alive
  7352. hook->type = XLUA_HOOK_DEFUNCT;
  7353. lua_cache_invalidate (L, hook);
  7354. return 0;
  7355. }
  7356. // The hook dies either when the plugin requests it or at plugin unload
  7357. static luaL_Reg lua_hook_table[] =
  7358. {
  7359. { "unhook", lua_hook_unhook },
  7360. { "__gc", lua_hook_unhook },
  7361. { NULL, NULL }
  7362. };
  7363. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7364. static char *
  7365. lua_input_hook_filter (struct input_hook *self, struct buffer *buffer,
  7366. char *input)
  7367. {
  7368. struct lua_hook *hook =
  7369. CONTAINER_OF (self, struct lua_hook, data.input_hook);
  7370. struct lua_plugin *plugin = hook->plugin;
  7371. lua_State *L = plugin->L;
  7372. lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
  7373. lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
  7374. lua_weak_push (L, plugin, buffer, &lua_buffer_info); // 2: buffer
  7375. lua_pushstring (L, input); // 3: input
  7376. struct error *e = NULL;
  7377. if (lua_plugin_call (plugin, 3, 1, &e))
  7378. {
  7379. lua_plugin_handle_string_filter_result (plugin, &input, true, &e);
  7380. lua_pop (L, 1);
  7381. }
  7382. if (e)
  7383. lua_plugin_log_error (plugin, "input hook", e);
  7384. return input;
  7385. }
  7386. static char *
  7387. lua_irc_hook_filter (struct irc_hook *self, struct server *s, char *message)
  7388. {
  7389. struct lua_hook *hook =
  7390. CONTAINER_OF (self, struct lua_hook, data.irc_hook);
  7391. struct lua_plugin *plugin = hook->plugin;
  7392. lua_State *L = plugin->L;
  7393. lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
  7394. lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
  7395. lua_weak_push (L, plugin, s, &lua_server_info); // 2: server
  7396. lua_pushstring (L, message); // 3: message
  7397. struct error *e = NULL;
  7398. if (lua_plugin_call (plugin, 3, 1, &e))
  7399. {
  7400. lua_plugin_handle_string_filter_result (plugin, &message, false, &e);
  7401. lua_pop (L, 1);
  7402. }
  7403. if (e)
  7404. lua_plugin_log_error (plugin, "IRC hook", e);
  7405. return message;
  7406. }
  7407. static char *
  7408. lua_prompt_hook_make (struct prompt_hook *self)
  7409. {
  7410. struct lua_hook *hook =
  7411. CONTAINER_OF (self, struct lua_hook, data.prompt_hook);
  7412. struct lua_plugin *plugin = hook->plugin;
  7413. lua_State *L = plugin->L;
  7414. lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
  7415. lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
  7416. struct error *e = NULL;
  7417. char *prompt = xstrdup ("");
  7418. if (lua_plugin_call (plugin, 1, 1, &e))
  7419. {
  7420. lua_plugin_handle_string_filter_result (plugin, &prompt, true, &e);
  7421. lua_pop (L, 1);
  7422. }
  7423. if (e)
  7424. lua_plugin_log_error (plugin, "prompt hook", e);
  7425. return prompt;
  7426. }
  7427. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7428. static void
  7429. lua_plugin_push_completion (lua_State *L, struct completion *data)
  7430. {
  7431. lua_createtable (L, 0, 3);
  7432. lua_pushstring (L, data->line);
  7433. lua_setfield (L, -2, "line");
  7434. lua_createtable (L, data->words_len, 0);
  7435. for (size_t i = 0; i < data->words_len; i++)
  7436. {
  7437. lua_pushlstring (L, data->line + data->words[i].start,
  7438. data->words[i].end - data->words[i].start);
  7439. lua_rawseti (L, -2, i + 1);
  7440. }
  7441. lua_setfield (L, -2, "words");
  7442. lua_pushinteger (L, data->location);
  7443. lua_setfield (L, -2, "location");
  7444. }
  7445. static bool
  7446. lua_completion_hook_process_value (lua_State *L, struct strv *output,
  7447. struct error **e)
  7448. {
  7449. if (lua_type (L, -1) != LUA_TSTRING)
  7450. {
  7451. return error_set (e,
  7452. "%s: %s", "invalid type", lua_typename (L, lua_type (L, -1)));
  7453. }
  7454. size_t len;
  7455. const char *value = lua_tolstring (L, -1, &len);
  7456. if (!utf8_validate (value, len))
  7457. return error_set (e, "must be valid UTF-8");
  7458. strv_append (output, value);
  7459. return true;
  7460. }
  7461. static bool
  7462. lua_completion_hook_process (lua_State *L, struct strv *output,
  7463. struct error **e)
  7464. {
  7465. if (lua_isnil (L, -1))
  7466. return true;
  7467. if (!lua_istable (L, -1))
  7468. return error_set (e, "must return either a table or nil");
  7469. bool success = true;
  7470. for (lua_Integer i = 1; success && lua_rawgeti (L, -1, i); i++)
  7471. if ((success = lua_completion_hook_process_value (L, output, e)))
  7472. lua_pop (L, 1);
  7473. lua_pop (L, 1);
  7474. return success;
  7475. }
  7476. static void
  7477. lua_completion_hook_complete (struct completion_hook *self,
  7478. struct completion *data, const char *word, struct strv *output)
  7479. {
  7480. struct lua_hook *hook =
  7481. CONTAINER_OF (self, struct lua_hook, data.c_hook);
  7482. struct lua_plugin *plugin = hook->plugin;
  7483. lua_State *L = plugin->L;
  7484. lua_rawgeti (L, LUA_REGISTRYINDEX, hook->ref_callback);
  7485. lua_rawgetp (L, LUA_REGISTRYINDEX, hook); // 1: hook
  7486. lua_plugin_push_completion (L, data); // 2: data
  7487. lua_weak_push (L, plugin, plugin->ctx->current_buffer, &lua_buffer_info);
  7488. lua_setfield (L, -2, "buffer");
  7489. lua_pushstring (L, word); // 3: word
  7490. struct error *e = NULL;
  7491. if (lua_plugin_call (plugin, 3, 1, &e))
  7492. {
  7493. lua_completion_hook_process (L, output, &e);
  7494. lua_pop (L, 1);
  7495. }
  7496. if (e)
  7497. lua_plugin_log_error (plugin, "autocomplete hook", e);
  7498. }
  7499. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7500. static struct lua_hook *
  7501. lua_plugin_push_hook (lua_State *L, struct lua_plugin *plugin,
  7502. int callback_index, enum lua_hook_type type, int priority)
  7503. {
  7504. luaL_checktype (L, callback_index, LUA_TFUNCTION);
  7505. struct lua_hook *hook = lua_newuserdata (L, sizeof *hook);
  7506. luaL_setmetatable (L, XLUA_HOOK_METATABLE);
  7507. memset (hook, 0, sizeof *hook);
  7508. hook->data.hook.priority = priority;
  7509. hook->type = type;
  7510. hook->plugin = plugin;
  7511. lua_pushvalue (L, callback_index);
  7512. hook->ref_callback = luaL_ref (L, LUA_REGISTRYINDEX);
  7513. // Make sure the hook doesn't get garbage collected and return it
  7514. lua_cache_store (L, hook, -1);
  7515. return hook;
  7516. }
  7517. static int
  7518. lua_plugin_hook_input (lua_State *L)
  7519. {
  7520. struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
  7521. struct lua_hook *hook = lua_plugin_push_hook
  7522. (L, plugin, 1, XLUA_HOOK_INPUT, luaL_optinteger (L, 2, 0));
  7523. hook->data.input_hook.filter = lua_input_hook_filter;
  7524. plugin->ctx->input_hooks =
  7525. hook_insert (plugin->ctx->input_hooks, &hook->data.hook);
  7526. return 1;
  7527. }
  7528. static int
  7529. lua_plugin_hook_irc (lua_State *L)
  7530. {
  7531. struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
  7532. struct lua_hook *hook = lua_plugin_push_hook
  7533. (L, plugin, 1, XLUA_HOOK_IRC, luaL_optinteger (L, 2, 0));
  7534. hook->data.irc_hook.filter = lua_irc_hook_filter;
  7535. plugin->ctx->irc_hooks =
  7536. hook_insert (plugin->ctx->irc_hooks, &hook->data.hook);
  7537. return 1;
  7538. }
  7539. static int
  7540. lua_plugin_hook_prompt (lua_State *L)
  7541. {
  7542. struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
  7543. struct lua_hook *hook = lua_plugin_push_hook
  7544. (L, plugin, 1, XLUA_HOOK_PROMPT, luaL_optinteger (L, 2, 0));
  7545. hook->data.prompt_hook.make = lua_prompt_hook_make;
  7546. plugin->ctx->prompt_hooks =
  7547. hook_insert (plugin->ctx->prompt_hooks, &hook->data.hook);
  7548. refresh_prompt (plugin->ctx);
  7549. return 1;
  7550. }
  7551. static int
  7552. lua_plugin_hook_completion (lua_State *L)
  7553. {
  7554. struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
  7555. struct lua_hook *hook = lua_plugin_push_hook
  7556. (L, plugin, 1, XLUA_HOOK_COMPLETION, luaL_optinteger (L, 2, 0));
  7557. hook->data.c_hook.complete = lua_completion_hook_complete;
  7558. plugin->ctx->completion_hooks =
  7559. hook_insert (plugin->ctx->completion_hooks, &hook->data.hook);
  7560. return 1;
  7561. }
  7562. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7563. #define XLUA_SCHEMA_METATABLE "schema" ///< Identifier for the Lua metatable
  7564. struct lua_schema_item
  7565. {
  7566. LIST_HEADER (struct lua_schema_item)
  7567. struct lua_plugin *plugin; ///< The plugin we belong to
  7568. struct config_item *item; ///< The item managed by the schema
  7569. struct config_schema schema; ///< Schema itself
  7570. int ref_validate; ///< Reference to "validate" callback
  7571. int ref_on_change; ///< Reference to "on_change" callback
  7572. };
  7573. static void
  7574. lua_schema_item_discard (struct lua_schema_item *self)
  7575. {
  7576. if (self->item)
  7577. {
  7578. self->item->schema = NULL;
  7579. self->item->user_data = NULL;
  7580. self->item = NULL;
  7581. LIST_UNLINK (self->plugin->schemas, self);
  7582. }
  7583. // Now that we've disconnected from the item, allow garbage collection
  7584. lua_cache_invalidate (self->plugin->L, self);
  7585. }
  7586. static int
  7587. lua_schema_item_gc (lua_State *L)
  7588. {
  7589. struct lua_schema_item *self =
  7590. luaL_checkudata (L, 1, XLUA_SCHEMA_METATABLE);
  7591. lua_schema_item_discard (self);
  7592. free ((char *) self->schema.name);
  7593. free ((char *) self->schema.comment);
  7594. free ((char *) self->schema.default_);
  7595. luaL_unref (L, LUA_REGISTRYINDEX, self->ref_validate);
  7596. luaL_unref (L, LUA_REGISTRYINDEX, self->ref_on_change);
  7597. return 0;
  7598. }
  7599. static luaL_Reg lua_schema_table[] =
  7600. {
  7601. { "__gc", lua_schema_item_gc },
  7602. { NULL, NULL }
  7603. };
  7604. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7605. /// Unfortunately this has the same problem as JSON libraries in that Lua
  7606. /// cannot store null values in containers (it has no distinct "undefined" type)
  7607. static void
  7608. lua_plugin_push_config_item (lua_State *L, const struct config_item *item)
  7609. {
  7610. switch (item->type)
  7611. {
  7612. case CONFIG_ITEM_NULL:
  7613. lua_pushnil (L);
  7614. break;
  7615. case CONFIG_ITEM_OBJECT:
  7616. {
  7617. lua_createtable (L, 0, item->value.object.len);
  7618. struct str_map_iter iter = str_map_iter_make (&item->value.object);
  7619. struct config_item *child;
  7620. while ((child = str_map_iter_next (&iter)))
  7621. {
  7622. lua_plugin_push_config_item (L, child);
  7623. lua_setfield (L, -2, iter.link->key);
  7624. }
  7625. break;
  7626. }
  7627. case CONFIG_ITEM_BOOLEAN:
  7628. lua_pushboolean (L, item->value.boolean);
  7629. break;
  7630. case CONFIG_ITEM_INTEGER:
  7631. lua_pushinteger (L, item->value.integer);
  7632. break;
  7633. case CONFIG_ITEM_STRING:
  7634. case CONFIG_ITEM_STRING_ARRAY:
  7635. lua_pushlstring (L, item->value.string.str, item->value.string.len);
  7636. break;
  7637. }
  7638. }
  7639. static bool
  7640. lua_schema_item_validate (const struct config_item *item, struct error **e)
  7641. {
  7642. struct lua_schema_item *self = item->user_data;
  7643. if (self->ref_validate == LUA_REFNIL)
  7644. return true;
  7645. lua_State *L = self->plugin->L;
  7646. lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_validate);
  7647. lua_plugin_push_config_item (L, item);
  7648. // The callback can make use of error("...", 0) to produce nice messages
  7649. return lua_plugin_call (self->plugin, 1, 0, e);
  7650. }
  7651. static void
  7652. lua_schema_item_on_change (struct config_item *item)
  7653. {
  7654. struct lua_schema_item *self = item->user_data;
  7655. if (self->ref_on_change == LUA_REFNIL)
  7656. return;
  7657. lua_State *L = self->plugin->L;
  7658. lua_rawgeti (L, LUA_REGISTRYINDEX, self->ref_on_change);
  7659. lua_plugin_push_config_item (L, item);
  7660. struct error *e = NULL;
  7661. if (!lua_plugin_call (self->plugin, 1, 0, &e))
  7662. lua_plugin_log_error (self->plugin, "schema on_change", e);
  7663. }
  7664. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7665. static int
  7666. lua_plugin_decode_config_item_type (const char *type)
  7667. {
  7668. if (!strcmp (type, "null")) return CONFIG_ITEM_NULL;
  7669. if (!strcmp (type, "object")) return CONFIG_ITEM_OBJECT;
  7670. if (!strcmp (type, "boolean")) return CONFIG_ITEM_BOOLEAN;
  7671. if (!strcmp (type, "integer")) return CONFIG_ITEM_INTEGER;
  7672. if (!strcmp (type, "string")) return CONFIG_ITEM_STRING;
  7673. if (!strcmp (type, "string_array")) return CONFIG_ITEM_STRING_ARRAY;
  7674. return -1;
  7675. }
  7676. static bool
  7677. lua_plugin_check_field (lua_State *L, int idx, const char *name,
  7678. int expected, bool optional)
  7679. {
  7680. int found = lua_getfield (L, idx, name);
  7681. if (found == expected)
  7682. return true;
  7683. if (optional && found == LUA_TNIL)
  7684. return false;
  7685. const char *message = optional
  7686. ? "invalid field \"%s\" (found: %s, expected: %s or nil)"
  7687. : "invalid or missing field \"%s\" (found: %s, expected: %s)";
  7688. return luaL_error (L, message, name,
  7689. lua_typename (L, found), lua_typename (L, expected));
  7690. }
  7691. static int
  7692. lua_plugin_add_config_schema (lua_State *L, struct lua_plugin *plugin,
  7693. struct config_item *subtree, const char *name)
  7694. {
  7695. struct config_item *item = str_map_find (&subtree->value.object, name);
  7696. // This should only ever happen because of a conflict with another plugin;
  7697. // this is the price we pay for simplicity
  7698. if (item && item->schema)
  7699. {
  7700. struct lua_schema_item *owner = item->user_data;
  7701. return luaL_error (L, "conflicting schema item: %s (owned by: %s)",
  7702. name, owner->plugin->super.name);
  7703. }
  7704. // Create and initialize a full userdata wrapper for the schema item
  7705. struct lua_schema_item *self = lua_newuserdata (L, sizeof *self);
  7706. luaL_setmetatable (L, XLUA_SCHEMA_METATABLE);
  7707. memset (self, 0, sizeof *self);
  7708. self->plugin = plugin;
  7709. self->ref_on_change = LUA_REFNIL;
  7710. self->ref_validate = LUA_REFNIL;
  7711. struct config_schema *schema = &self->schema;
  7712. schema->name = xstrdup (name);
  7713. schema->comment = NULL;
  7714. schema->default_ = NULL;
  7715. schema->type = CONFIG_ITEM_NULL;
  7716. schema->on_change = lua_schema_item_on_change;
  7717. schema->validate = lua_schema_item_validate;
  7718. // Try to update the defaults with values provided by the plugin
  7719. int values = lua_absindex (L, -2);
  7720. (void) lua_plugin_check_field (L, values, "type", LUA_TSTRING, false);
  7721. int item_type = schema->type =
  7722. lua_plugin_decode_config_item_type (lua_tostring (L, -1));
  7723. if (item_type == -1)
  7724. return luaL_error (L, "invalid type of schema item");
  7725. if (lua_plugin_check_field (L, values, "comment", LUA_TSTRING, true))
  7726. schema->comment = xstrdup (lua_tostring (L, -1));
  7727. if (lua_plugin_check_field (L, values, "default", LUA_TSTRING, true))
  7728. schema->default_ = xstrdup (lua_tostring (L, -1));
  7729. lua_pop (L, 3);
  7730. (void) lua_plugin_check_field (L, values, "on_change", LUA_TFUNCTION, true);
  7731. self->ref_on_change = luaL_ref (L, LUA_REGISTRYINDEX);
  7732. (void) lua_plugin_check_field (L, values, "validate", LUA_TFUNCTION, true);
  7733. self->ref_validate = luaL_ref (L, LUA_REGISTRYINDEX);
  7734. // Try to install the created schema item into our configuration
  7735. struct error *warning = NULL, *e = NULL;
  7736. item = config_schema_initialize_item
  7737. (&self->schema, subtree, self, &warning, &e);
  7738. if (warning)
  7739. {
  7740. log_global_error (plugin->ctx, "Lua: plugin \"#s\": #s",
  7741. plugin->super.name, warning->message);
  7742. error_free (warning);
  7743. }
  7744. if (e)
  7745. {
  7746. const char *error = lua_pushstring (L, e->message);
  7747. error_free (e);
  7748. return luaL_error (L, "%s", error);
  7749. }
  7750. self->item = item;
  7751. LIST_PREPEND (plugin->schemas, self);
  7752. // On the stack there should be the schema table and the resulting object;
  7753. // we need to make sure Lua doesn't GC the second and get rid of them both
  7754. lua_cache_store (L, self, -1);
  7755. lua_pop (L, 2);
  7756. return 0;
  7757. }
  7758. static int
  7759. lua_plugin_setup_config (lua_State *L)
  7760. {
  7761. struct lua_plugin *plugin = lua_touserdata (L, lua_upvalueindex (1));
  7762. luaL_checktype (L, 1, LUA_TTABLE);
  7763. struct app_context *ctx = plugin->ctx;
  7764. char *config_name = plugin_config_name (&plugin->super);
  7765. if (!config_name)
  7766. return luaL_error (L, "unsuitable plugin name");
  7767. struct str_map *plugins = get_plugins_config (ctx);
  7768. struct config_item *subtree = str_map_find (plugins, config_name);
  7769. if (!subtree || subtree->type != CONFIG_ITEM_OBJECT)
  7770. str_map_set (plugins, config_name, (subtree = config_item_object ()));
  7771. free (config_name);
  7772. LIST_FOR_EACH (struct lua_schema_item, iter, plugin->schemas)
  7773. lua_schema_item_discard (iter);
  7774. // Load all schema items and apply them to the plugin's subtree
  7775. lua_pushnil (L);
  7776. while (lua_next (L, 1))
  7777. {
  7778. if (lua_type (L, -2) != LUA_TSTRING
  7779. || lua_type (L, -1) != LUA_TTABLE)
  7780. return luaL_error (L, "%s: %s -> %s", "invalid types",
  7781. lua_typename (L, lua_type (L, -2)),
  7782. lua_typename (L, lua_type (L, -1)));
  7783. lua_plugin_add_config_schema (L, plugin, subtree, lua_tostring (L, -2));
  7784. }
  7785. // Let the plugin read out configuration via on_change callbacks
  7786. config_schema_call_changed (subtree);
  7787. return 0;
  7788. }
  7789. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7790. /// Identifier for the Lua metatable
  7791. #define XLUA_CONNECTION_METATABLE "connection"
  7792. struct lua_connection
  7793. {
  7794. struct lua_plugin *plugin; ///< The plugin we belong to
  7795. struct poller_fd socket_event; ///< Socket is ready
  7796. int socket_fd; ///< Underlying connected socket
  7797. bool got_eof; ///< Half-closed by remote host
  7798. bool closing; ///< We're closing the connection
  7799. struct str read_buffer; ///< Read buffer
  7800. struct str write_buffer; ///< Write buffer
  7801. };
  7802. static void
  7803. lua_connection_update_poller (struct lua_connection *self)
  7804. {
  7805. poller_fd_set (&self->socket_event,
  7806. self->write_buffer.len ? (POLLIN | POLLOUT) : POLLIN);
  7807. }
  7808. static int
  7809. lua_connection_send (lua_State *L)
  7810. {
  7811. struct lua_connection *self =
  7812. luaL_checkudata (L, 1, XLUA_CONNECTION_METATABLE);
  7813. if (self->socket_fd == -1)
  7814. return luaL_error (L, "connection has been closed");
  7815. size_t len;
  7816. const char *s = luaL_checklstring (L, 2, &len);
  7817. str_append_data (&self->write_buffer, s, len);
  7818. lua_connection_update_poller (self);
  7819. return 0;
  7820. }
  7821. static void
  7822. lua_connection_discard (struct lua_connection *self)
  7823. {
  7824. if (self->socket_fd != -1)
  7825. {
  7826. poller_fd_reset (&self->socket_event);
  7827. xclose (self->socket_fd);
  7828. self->socket_fd = -1;
  7829. str_free (&self->read_buffer);
  7830. str_free (&self->write_buffer);
  7831. }
  7832. // Connection is dead, we don't need to hold onto any resources anymore
  7833. lua_cache_invalidate (self->plugin->L, self);
  7834. }
  7835. static int
  7836. lua_connection_close (lua_State *L)
  7837. {
  7838. struct lua_connection *self =
  7839. luaL_checkudata (L, 1, XLUA_CONNECTION_METATABLE);
  7840. if (self->socket_fd != -1)
  7841. {
  7842. self->closing = true;
  7843. // NOTE: this seems to do nothing on Linux
  7844. (void) shutdown (self->socket_fd, SHUT_RD);
  7845. // Right now we want to wait until all data is flushed to the socket
  7846. // and can't call close() here immediately -- a rewrite to use async
  7847. // would enable the user to await on either :send() or :flush();
  7848. // a successful send() doesn't necessarily mean anything though
  7849. if (!self->write_buffer.len)
  7850. lua_connection_discard (self);
  7851. }
  7852. return 0;
  7853. }
  7854. static int
  7855. lua_connection_gc (lua_State *L)
  7856. {
  7857. lua_connection_discard (luaL_checkudata (L, 1, XLUA_CONNECTION_METATABLE));
  7858. return 0;
  7859. }
  7860. static luaL_Reg lua_connection_table[] =
  7861. {
  7862. { "send", lua_connection_send },
  7863. { "close", lua_connection_close },
  7864. { "__gc", lua_connection_gc },
  7865. { NULL, NULL }
  7866. };
  7867. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  7868. static int
  7869. lua_connection_check_fn (lua_State *L)
  7870. {
  7871. lua_plugin_check_field (L, 1, luaL_checkstring (L, 2), LUA_TFUNCTION, true);
  7872. return 1;
  7873. }
  7874. // We need to run it in a protected environment because of lua_getfield()
  7875. static bool
  7876. lua_connection_cb_lookup (struct lua_connection *self, const char *name,
  7877. struct error **e)
  7878. {
  7879. lua_State *L = self->plugin->L;
  7880. lua_pushcfunction (L, lua_connection_check_fn);
  7881. hard_assert (lua_cache_get (L, self));
  7882. lua_pushstring (L, name);
  7883. return lua_plugin_call (self->plugin, 2, 1, e);
  7884. }
  7885. // Ideally lua_connection_cb_lookup() would return a ternary value
  7886. static bool
  7887. lua_connection_eat_nil (struct lua_connection *self)
  7888. {
  7889. if (lua_toboolean (self->plugin->L, -1))
  7890. return false;
  7891. lua_pop (self->plugin->L, 1);
  7892. return true;
  7893. }
  7894. static bool
  7895. lua_connection_invoke_on_data (struct lua_connection *self, struct error **e)
  7896. {
  7897. if (!lua_connection_cb_lookup (self, "on_data", e))
  7898. return false;
  7899. if (lua_connection_eat_nil (self))
  7900. return true;
  7901. lua_pushlstring (self->plugin->L,
  7902. self->read_buffer.str, self->read_buffer.len);
  7903. return lua_plugin_call (self->plugin, 1, 0, e);
  7904. }
  7905. static bool
  7906. lua_connection_invoke_on_eof (struct lua_connection *self, struct error **e)
  7907. {
  7908. if (!lua_connection_cb_lookup (self, "on_eof", e))
  7909. return false;
  7910. if (lua_connection_eat_nil (self))
  7911. return true;
  7912. return lua_plugin_call (self->plugin, 0, 0, e);
  7913. }
  7914. static bool
  7915. lua_connection_invoke_on_error (struct lua_connection *self,
  7916. const char *error, struct error **e)
  7917. {
  7918. // XXX: not sure if ignoring errors after :close() is always desired;
  7919. // code might want to make sure that data are transferred successfully
  7920. if (!self->closing
  7921. && lua_connection_cb_lookup (self, "on_error", e)
  7922. && !lua_connection_eat_nil (self))
  7923. {
  7924. lua_pushstring (self->plugin->L, error);
  7925. lua_plugin_call (self->plugin, 1, 0, e);
  7926. }
  7927. return false;
  7928. }
  7929. static bool
  7930. lua_connection_try_read (struct lua_connection *self, struct error **e)
  7931. {
  7932. // Avoid the read call when it's obviously not going to return any data
  7933. // and would only cause unwanted invocation of callbacks
  7934. if (self->closing || self->got_eof)
  7935. return true;
  7936. enum socket_io_result read_result =
  7937. socket_io_try_read (self->socket_fd, &self->read_buffer);
  7938. const char *error = strerror (errno);
  7939. // Dispatch any data that we got before an EOF or any error
  7940. if (self->read_buffer.len)
  7941. {
  7942. if (!lua_connection_invoke_on_data (self, e))
  7943. return false;
  7944. str_reset (&self->read_buffer);
  7945. }
  7946. if (read_result == SOCKET_IO_EOF)
  7947. {
  7948. if (!lua_connection_invoke_on_eof (self, e))
  7949. return false;
  7950. self->got_eof = true;
  7951. }
  7952. if (read_result == SOCKET_IO_ERROR)
  7953. return lua_connection_invoke_on_error (self, error, e);
  7954. return true;
  7955. }
  7956. static bool
  7957. lua_connection_try_write (struct lua_connection *self, struct error **e)
  7958. {
  7959. enum socket_io_result write_result =
  7960. socket_io_try_write (self->socket_fd, &self->write_buffer);
  7961. const char *error = strerror (errno);
  7962. if (write_result == SOCKET_IO_ERROR)
  7963. return lua_connection_invoke_on_error (self, error, e);
  7964. return !self->closing || self->write_buffer.len;
  7965. }
  7966. static void
  7967. lua_connection_on_ready (const struct pollfd *pfd, struct lua_connection *self)
  7968. {
  7969. (void) pfd;
  7970. // Hold a reference so that it doesn't get collected on close()
  7971. hard_assert (lua_cache_get (self->plugin->L, self));
  7972. struct error *e = NULL;
  7973. bool keep = lua_connection_try_read (self, &e)
  7974. && lua_connection_try_write (self, &e);
  7975. if (e)
  7976. lua_plugin_log_error (self->plugin, "network I/O", e);
  7977. if (keep)
  7978. lua_connection_update_poller (self);
  7979. else
  7980. lua_connection_discard (self);
  7981. lua_pop (self->plugin->L, 1);
  7982. }
  7983. static struct lua_connection *
  7984. lua_plugin_push_connection (struct lua_plugin *plugin, int socket_fd)
  7985. {
  7986. lua_State *L = plugin->L;
  7987. struct lua_connection *self = lua_newuserdata (L, sizeof *self);
  7988. luaL_setmetatable (L, XLUA_CONNECTION_METATABLE);
  7989. memset (self, 0, sizeof *self);
  7990. self->plugin = plugin;
  7991. set_blocking (socket_fd, false);
  7992. self->socket_event = poller_fd_make
  7993. (&plugin->ctx->poller, (self->socket_fd = socket_fd));
  7994. self->socket_event.dispatcher = (poller_fd_fn) lua_connection_on_ready;
  7995. self->socket_event.user_data = self;
  7996. poller_fd_set (&self->socket_event, POLLIN);
  7997. self->read_buffer = str_make ();
  7998. self->write_buffer = str_make ();
  7999. // Make sure the connection doesn't get garbage collected and return it
  8000. lua_cache_store (L, self, -1);
  8001. return self;
  8002. }
  8003. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  8004. // The script can create as many wait channels as wanted. They only actually
  8005. // do anything once they get yielded to the main lua_resume() call.
  8006. /// Identifier for the Lua metatable
  8007. #define XLUA_WCHANNEL_METATABLE "wchannel"
  8008. struct lua_wait_channel
  8009. {
  8010. LIST_HEADER (struct lua_wait_channel)
  8011. struct lua_task *task; ///< The task we're active in
  8012. /// Check if the event is ready and eventually push values to the thread;
  8013. /// the channel then may release any resources
  8014. bool (*check) (struct lua_wait_channel *self);
  8015. /// Release all resources held by the subclass
  8016. void (*cleanup) (struct lua_wait_channel *self);
  8017. };
  8018. static int
  8019. lua_wchannel_gc (lua_State *L)
  8020. {
  8021. struct lua_wait_channel *self =
  8022. luaL_checkudata (L, 1, XLUA_WCHANNEL_METATABLE);
  8023. if (self->cleanup)
  8024. self->cleanup (self);
  8025. return 0;
  8026. }
  8027. static luaL_Reg lua_wchannel_table[] =
  8028. {
  8029. { "__gc", lua_wchannel_gc },
  8030. { NULL, NULL }
  8031. };
  8032. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  8033. // A task encapsulates a thread so that wait channels yielded from its main
  8034. // function get waited upon by the event loop
  8035. #define XLUA_TASK_METATABLE "task" ///< Identifier for the Lua metatable
  8036. struct lua_task
  8037. {
  8038. LIST_HEADER (struct lua_task)
  8039. struct lua_plugin *plugin; ///< The plugin we belong to
  8040. lua_State *thread; ///< Lua thread
  8041. struct lua_wait_channel *active; ///< Channels we're waiting on
  8042. struct poller_idle idle; ///< Idle job
  8043. };
  8044. static void
  8045. lua_task_unregister_channels (struct lua_task *self)
  8046. {
  8047. LIST_FOR_EACH (struct lua_wait_channel, iter, self->active)
  8048. {
  8049. iter->task = NULL;
  8050. LIST_UNLINK (self->active, iter);
  8051. lua_cache_invalidate (self->plugin->L, iter);
  8052. }
  8053. }
  8054. static void
  8055. lua_task_cancel_internal (struct lua_task *self)
  8056. {
  8057. if (self->thread)
  8058. {
  8059. lua_cache_invalidate (self->plugin->L, self->thread);
  8060. self->thread = NULL;
  8061. }
  8062. lua_task_unregister_channels (self);
  8063. poller_idle_reset (&self->idle);
  8064. // The task no longer has to stay alive
  8065. lua_cache_invalidate (self->plugin->L, self);
  8066. }
  8067. static int
  8068. lua_task_cancel (lua_State *L)
  8069. {
  8070. struct lua_task *self = luaL_checkudata (L, 1, XLUA_TASK_METATABLE);
  8071. // We could also yield and make lua_task_resume() check "self->thread",
  8072. // however the main issue here is that the script should just return
  8073. luaL_argcheck (L, L != self->thread, 1,
  8074. "cannot cancel task from within itself");
  8075. lua_task_cancel_internal (self);
  8076. return 0;
  8077. }
  8078. #define lua_task_wakeup(self) poller_idle_set (&(self)->idle)
  8079. static bool
  8080. lua_task_schedule (struct lua_task *self, int n, struct error **e)
  8081. {
  8082. lua_State *L = self->thread;
  8083. for (int i = -1; -i <= n; i--)
  8084. {
  8085. struct lua_wait_channel *channel =
  8086. luaL_testudata (L, i, XLUA_WCHANNEL_METATABLE);
  8087. if (!channel)
  8088. return error_set (e, "bad argument #%d to yield: %s", -i + n + 1,
  8089. "tasks can only yield wait channels");
  8090. if (channel->task)
  8091. return error_set (e, "bad argument #%d to yield: %s", -i + n + 1,
  8092. "wait channels can only be active in one task at most");
  8093. }
  8094. for (int i = -1; -i <= n; i--)
  8095. {
  8096. // Quietly ignore duplicate channels
  8097. struct lua_wait_channel *channel = lua_touserdata (L, i);
  8098. if (channel->task)
  8099. continue;
  8100. // By going in reverse the list ends up in the right order
  8101. channel->task = self;
  8102. LIST_PREPEND (self->active, channel);
  8103. lua_cache_store (self->plugin->L, channel, i);
  8104. }
  8105. lua_pop (L, n);
  8106. // There doesn't have to be a single channel
  8107. // We can also be waiting on a channel that is already ready
  8108. lua_task_wakeup (self);
  8109. return true;
  8110. }
  8111. static void
  8112. lua_task_resume (struct lua_task *self, int index)
  8113. {
  8114. lua_State *L = self->thread;
  8115. bool waiting_on_multiple = self->active && self->active->next;
  8116. // Since we've ended the wait, we don't need to hold on to them anymore
  8117. lua_task_unregister_channels (self);
  8118. // On the first run we also have the main function on the stack,
  8119. // before any initial arguments
  8120. int n = lua_gettop (L) - (lua_status (L) == LUA_OK);
  8121. // Pack the values in a table and prepend the index of the channel, so that
  8122. // the caller doesn't need to care about the number of return values
  8123. if (waiting_on_multiple)
  8124. {
  8125. lua_plugin_pack (L, n);
  8126. lua_pushinteger (L, index);
  8127. lua_insert (L, -2);
  8128. n = 2;
  8129. }
  8130. int res = lua_resume (L, NULL, n);
  8131. struct error *error = NULL;
  8132. if (res == LUA_YIELD)
  8133. {
  8134. // AFAIK we don't get any good error context information from here
  8135. if (lua_task_schedule (self, lua_gettop (L), &error))
  8136. return;
  8137. }
  8138. // For simplicity ignore any results from successful returns
  8139. else if (res != LUA_OK)
  8140. {
  8141. luaL_traceback (L, L, lua_tostring (L, -1), 0 /* or 1? */);
  8142. lua_plugin_process_error (self->plugin, lua_tostring (L, -1), &error);
  8143. lua_pop (L, 2);
  8144. }
  8145. if (error)
  8146. lua_plugin_log_error (self->plugin, "task", error);
  8147. lua_task_cancel_internal (self);
  8148. }
  8149. static void
  8150. lua_task_check (struct lua_task *self)
  8151. {
  8152. poller_idle_reset (&self->idle);
  8153. lua_Integer i = 0;
  8154. LIST_FOR_EACH (struct lua_wait_channel, iter, self->active)
  8155. {
  8156. i++;
  8157. if (iter->check (iter))
  8158. {
  8159. lua_task_resume (self, i);
  8160. return;
  8161. }
  8162. }
  8163. if (!self->active)
  8164. lua_task_resume (self, i);
  8165. }
  8166. // The task dies either when it finishes, it is cancelled, or at plugin unload
  8167. static luaL_Reg lua_task_table[] =
  8168. {
  8169. { "cancel", lua_task_cancel },
  8170. { "__gc", lua_task_cancel },
  8171. { NULL, NULL }
  8172. };
  8173. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  8174. struct lua_wait_timer
  8175. {
  8176. struct lua_wait_channel super; ///< The structure we're deriving
  8177. struct poller_timer timer; ///< Timer event
  8178. bool expired; ///< Whether the timer has expired
  8179. };
  8180. static bool
  8181. lua_wait_timer_check (struct lua_wait_channel *wchannel)
  8182. {
  8183. struct lua_wait_timer *self =
  8184. CONTAINER_OF (wchannel, struct lua_wait_timer, super);
  8185. return self->super.task && self->expired;
  8186. }
  8187. static void
  8188. lua_wait_timer_cleanup (struct lua_wait_channel *wchannel)
  8189. {
  8190. struct lua_wait_timer *self =
  8191. CONTAINER_OF (wchannel, struct lua_wait_timer, super);
  8192. poller_timer_reset (&self->timer);
  8193. }
  8194. static void
  8195. lua_wait_timer_dispatch (struct lua_wait_timer *self)
  8196. {
  8197. self->expired = true;
  8198. if (self->super.task)
  8199. lua_task_wakeup (self->super.task);
  8200. }
  8201. static int
  8202. lua_plugin_push_wait_timer (struct lua_plugin *plugin, lua_State *L,
  8203. lua_Integer timeout)
  8204. {
  8205. struct lua_wait_timer *self = lua_newuserdata (L, sizeof *self);
  8206. luaL_setmetatable (L, XLUA_WCHANNEL_METATABLE);
  8207. memset (self, 0, sizeof *self);
  8208. self->super.check = lua_wait_timer_check;
  8209. self->super.cleanup = lua_wait_timer_cleanup;
  8210. self->timer = poller_timer_make (&plugin->ctx->poller);
  8211. self->timer.dispatcher = (poller_timer_fn) lua_wait_timer_dispatch;
  8212. self->timer.user_data = self;
  8213. if (timeout)
  8214. poller_timer_set (&self->timer, timeout);
  8215. else
  8216. self->expired = true;
  8217. return 1;
  8218. }
  8219. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  8220. struct lua_wait_dial
  8221. {
  8222. struct lua_wait_channel super; ///< The structure we're deriving
  8223. struct lua_plugin *plugin; ///< The plugin we belong to
  8224. struct connector connector; ///< Connector object
  8225. bool active; ///< Whether the connector is alive
  8226. struct lua_connection *connection; ///< Established connection
  8227. char *hostname; ///< Target hostname
  8228. char *last_error; ///< Connecting error, if any
  8229. };
  8230. static bool
  8231. lua_wait_dial_check (struct lua_wait_channel *wchannel)
  8232. {
  8233. struct lua_wait_dial *self =
  8234. CONTAINER_OF (wchannel, struct lua_wait_dial, super);
  8235. lua_State *L = self->super.task->thread;
  8236. if (self->connection)
  8237. {
  8238. // FIXME: this way the connection may leak -- we pass the value to the
  8239. // task manager on the stack and forget about it but still leave the
  8240. // connection in the cache. That is because right now, when Lua code
  8241. // sets up callbacks in the connection object and returns, it might
  8242. // get otherwise GC'd since nothing else keeps referencing it.
  8243. // By rewriting lua_connection using async, tasks and wait channels
  8244. // would hold a reference, allowing us to remove it from the cache.
  8245. lua_cache_get (L, self->connection);
  8246. lua_pushstring (L, self->hostname);
  8247. self->connection = NULL;
  8248. }
  8249. else if (self->last_error)
  8250. {
  8251. lua_pushnil (L);
  8252. lua_pushnil (L);
  8253. lua_pushstring (L, self->last_error);
  8254. }
  8255. else
  8256. return false; <