pval.c 167 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2006, Digium, Inc.
  5. *
  6. * Steve Murphy <murf@parsetree.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions, version 2.
  21. *
  22. */
  23. /*** MODULEINFO
  24. <support_level>extended</support_level>
  25. ***/
  26. #include "asterisk.h"
  27. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  28. #include <sys/types.h>
  29. #include <stdlib.h>
  30. #include <unistd.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <errno.h>
  35. #include <regex.h>
  36. #include <sys/stat.h>
  37. #include "asterisk/pbx.h"
  38. #include "asterisk/config.h"
  39. #include "asterisk/module.h"
  40. #include "asterisk/logger.h"
  41. #include "asterisk/cli.h"
  42. #include "asterisk/app.h"
  43. #include "asterisk/channel.h"
  44. #include "asterisk/callerid.h"
  45. #include "asterisk/pval.h"
  46. #include "asterisk/ael_structs.h"
  47. #ifdef AAL_ARGCHECK
  48. #include "asterisk/argdesc.h"
  49. #endif
  50. #include "asterisk/utils.h"
  51. extern struct ast_flags ast_compat;
  52. extern int localized_pbx_load_module(void);
  53. static char expr_output[2096];
  54. #define AST_PBX_MAX_STACK 128
  55. #define BUF_SIZE 2000
  56. /* these functions are in ../ast_expr2.fl */
  57. static int errs, warns;
  58. static int notes;
  59. #ifdef STANDALONE
  60. static int extensions_dot_conf_loaded = 0;
  61. #endif
  62. static char *registrar = "pbx_ael";
  63. static pval *current_db;
  64. static pval *current_context;
  65. static pval *current_extension;
  66. static const char *match_context;
  67. static const char *match_exten;
  68. static const char *match_label;
  69. static int in_abstract_context;
  70. static int count_labels; /* true, put matcher in label counting mode */
  71. static int label_count; /* labels are only meant to be counted in a context or exten */
  72. static int return_on_context_match;
  73. static pval *last_matched_label;
  74. struct pval *match_pval(pval *item);
  75. static void check_timerange(pval *p);
  76. static void check_dow(pval *DOW);
  77. static void check_day(pval *DAY);
  78. static void check_month(pval *MON);
  79. static void check_expr2_input(pval *expr, char *str);
  80. static int extension_matches(pval *here, const char *exten, const char *pattern);
  81. static void check_goto(pval *item);
  82. static void find_pval_goto_item(pval *item, int lev);
  83. static void find_pval_gotos(pval *item, int lev);
  84. static int check_break(pval *item);
  85. static int check_continue(pval *item);
  86. static void check_label(pval *item);
  87. static void check_macro_returns(pval *macro);
  88. static struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont);
  89. static struct pval *find_first_label_in_current_context(char *label, pval *curr_cont);
  90. static void print_pval_list(FILE *fin, pval *item, int depth);
  91. static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext);
  92. static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label);
  93. static pval *get_goto_target(pval *item);
  94. static int label_inside_case(pval *label);
  95. static void attach_exten(struct ael_extension **list, struct ael_extension *newmem);
  96. static void fix_gotos_in_extensions(struct ael_extension *exten);
  97. static pval *get_extension_or_contxt(pval *p);
  98. static pval *get_contxt(pval *p);
  99. static void remove_spaces_before_equals(char *str);
  100. /* PRETTY PRINTER FOR AEL: ============================================================================= */
  101. static void print_pval(FILE *fin, pval *item, int depth)
  102. {
  103. int i;
  104. pval *lp;
  105. for (i=0; i<depth; i++) {
  106. fprintf(fin, "\t"); /* depth == indentation */
  107. }
  108. switch ( item->type ) {
  109. case PV_WORD:
  110. fprintf(fin,"%s;\n", item->u1.str); /* usually, words are encapsulated in something else */
  111. break;
  112. case PV_MACRO:
  113. fprintf(fin,"macro %s(", item->u1.str);
  114. for (lp=item->u2.arglist; lp; lp=lp->next) {
  115. if (lp != item->u2.arglist )
  116. fprintf(fin,", ");
  117. fprintf(fin,"%s", lp->u1.str);
  118. }
  119. fprintf(fin,") {\n");
  120. print_pval_list(fin,item->u3.macro_statements,depth+1);
  121. for (i=0; i<depth; i++) {
  122. fprintf(fin,"\t"); /* depth == indentation */
  123. }
  124. fprintf(fin,"};\n\n");
  125. break;
  126. case PV_CONTEXT:
  127. if ( item->u3.abstract )
  128. fprintf(fin,"abstract context %s {\n", item->u1.str);
  129. else
  130. fprintf(fin,"context %s {\n", item->u1.str);
  131. print_pval_list(fin,item->u2.statements,depth+1);
  132. for (i=0; i<depth; i++) {
  133. fprintf(fin,"\t"); /* depth == indentation */
  134. }
  135. fprintf(fin,"};\n\n");
  136. break;
  137. case PV_MACRO_CALL:
  138. fprintf(fin,"&%s(", item->u1.str);
  139. for (lp=item->u2.arglist; lp; lp=lp->next) {
  140. if ( lp != item->u2.arglist )
  141. fprintf(fin,", ");
  142. fprintf(fin,"%s", lp->u1.str);
  143. }
  144. fprintf(fin,");\n");
  145. break;
  146. case PV_APPLICATION_CALL:
  147. fprintf(fin,"%s(", item->u1.str);
  148. for (lp=item->u2.arglist; lp; lp=lp->next) {
  149. if ( lp != item->u2.arglist )
  150. fprintf(fin,",");
  151. fprintf(fin,"%s", lp->u1.str);
  152. }
  153. fprintf(fin,");\n");
  154. break;
  155. case PV_CASE:
  156. fprintf(fin,"case %s:\n", item->u1.str);
  157. print_pval_list(fin,item->u2.statements, depth+1);
  158. break;
  159. case PV_PATTERN:
  160. fprintf(fin,"pattern %s:\n", item->u1.str);
  161. print_pval_list(fin,item->u2.statements, depth+1);
  162. break;
  163. case PV_DEFAULT:
  164. fprintf(fin,"default:\n");
  165. print_pval_list(fin,item->u2.statements, depth+1);
  166. break;
  167. case PV_CATCH:
  168. fprintf(fin,"catch %s {\n", item->u1.str);
  169. print_pval_list(fin,item->u2.statements, depth+1);
  170. for (i=0; i<depth; i++) {
  171. fprintf(fin,"\t"); /* depth == indentation */
  172. }
  173. fprintf(fin,"};\n");
  174. break;
  175. case PV_SWITCHES:
  176. fprintf(fin,"switches {\n");
  177. print_pval_list(fin,item->u1.list,depth+1);
  178. for (i=0; i<depth; i++) {
  179. fprintf(fin,"\t"); /* depth == indentation */
  180. }
  181. fprintf(fin,"};\n");
  182. break;
  183. case PV_ESWITCHES:
  184. fprintf(fin,"eswitches {\n");
  185. print_pval_list(fin,item->u1.list,depth+1);
  186. for (i=0; i<depth; i++) {
  187. fprintf(fin,"\t"); /* depth == indentation */
  188. }
  189. fprintf(fin,"};\n");
  190. break;
  191. case PV_INCLUDES:
  192. fprintf(fin,"includes {\n");
  193. for (lp=item->u1.list; lp; lp=lp->next) {
  194. for (i=0; i<depth+1; i++) {
  195. fprintf(fin,"\t"); /* depth == indentation */
  196. }
  197. fprintf(fin,"%s", lp->u1.str); /* usually, words are encapsulated in something else */
  198. if (lp->u2.arglist)
  199. fprintf(fin,"|%s|%s|%s|%s",
  200. lp->u2.arglist->u1.str,
  201. lp->u2.arglist->next->u1.str,
  202. lp->u2.arglist->next->next->u1.str,
  203. lp->u2.arglist->next->next->next->u1.str
  204. );
  205. fprintf(fin,";\n"); /* usually, words are encapsulated in something else */
  206. }
  207. for (i=0; i<depth; i++) {
  208. fprintf(fin,"\t"); /* depth == indentation */
  209. }
  210. fprintf(fin,"};\n");
  211. break;
  212. case PV_STATEMENTBLOCK:
  213. fprintf(fin,"{\n");
  214. print_pval_list(fin,item->u1.list, depth+1);
  215. for (i=0; i<depth; i++) {
  216. fprintf(fin,"\t"); /* depth == indentation */
  217. }
  218. fprintf(fin,"}\n");
  219. break;
  220. case PV_VARDEC:
  221. fprintf(fin,"%s=%s;\n", item->u1.str, item->u2.val);
  222. break;
  223. case PV_LOCALVARDEC:
  224. fprintf(fin,"local %s=%s;\n", item->u1.str, item->u2.val);
  225. break;
  226. case PV_GOTO:
  227. fprintf(fin,"goto %s", item->u1.list->u1.str);
  228. if ( item->u1.list->next )
  229. fprintf(fin,",%s", item->u1.list->next->u1.str);
  230. if ( item->u1.list->next && item->u1.list->next->next )
  231. fprintf(fin,",%s", item->u1.list->next->next->u1.str);
  232. fprintf(fin,"\n");
  233. break;
  234. case PV_LABEL:
  235. fprintf(fin,"%s:\n", item->u1.str);
  236. break;
  237. case PV_FOR:
  238. fprintf(fin,"for (%s; %s; %s)\n", item->u1.for_init, item->u2.for_test, item->u3.for_inc);
  239. print_pval_list(fin,item->u4.for_statements,depth+1);
  240. break;
  241. case PV_WHILE:
  242. fprintf(fin,"while (%s)\n", item->u1.str);
  243. print_pval_list(fin,item->u2.statements,depth+1);
  244. break;
  245. case PV_BREAK:
  246. fprintf(fin,"break;\n");
  247. break;
  248. case PV_RETURN:
  249. fprintf(fin,"return;\n");
  250. break;
  251. case PV_CONTINUE:
  252. fprintf(fin,"continue;\n");
  253. break;
  254. case PV_RANDOM:
  255. case PV_IFTIME:
  256. case PV_IF:
  257. if ( item->type == PV_IFTIME ) {
  258. fprintf(fin,"ifTime ( %s|%s|%s|%s )\n",
  259. item->u1.list->u1.str,
  260. item->u1.list->next->u1.str,
  261. item->u1.list->next->next->u1.str,
  262. item->u1.list->next->next->next->u1.str
  263. );
  264. } else if ( item->type == PV_RANDOM ) {
  265. fprintf(fin,"random ( %s )\n", item->u1.str );
  266. } else
  267. fprintf(fin,"if ( %s )\n", item->u1.str);
  268. if ( item->u2.statements && item->u2.statements->next ) {
  269. for (i=0; i<depth; i++) {
  270. fprintf(fin,"\t"); /* depth == indentation */
  271. }
  272. fprintf(fin,"{\n");
  273. print_pval_list(fin,item->u2.statements,depth+1);
  274. for (i=0; i<depth; i++) {
  275. fprintf(fin,"\t"); /* depth == indentation */
  276. }
  277. if ( item->u3.else_statements )
  278. fprintf(fin,"}\n");
  279. else
  280. fprintf(fin,"};\n");
  281. } else if (item->u2.statements ) {
  282. print_pval_list(fin,item->u2.statements,depth+1);
  283. } else {
  284. if (item->u3.else_statements )
  285. fprintf(fin, " {} ");
  286. else
  287. fprintf(fin, " {}; ");
  288. }
  289. if ( item->u3.else_statements ) {
  290. for (i=0; i<depth; i++) {
  291. fprintf(fin,"\t"); /* depth == indentation */
  292. }
  293. fprintf(fin,"else\n");
  294. print_pval_list(fin,item->u3.else_statements, depth);
  295. }
  296. break;
  297. case PV_SWITCH:
  298. fprintf(fin,"switch( %s ) {\n", item->u1.str);
  299. print_pval_list(fin,item->u2.statements,depth+1);
  300. for (i=0; i<depth; i++) {
  301. fprintf(fin,"\t"); /* depth == indentation */
  302. }
  303. fprintf(fin,"}\n");
  304. break;
  305. case PV_EXTENSION:
  306. if ( item->u4.regexten )
  307. fprintf(fin, "regexten ");
  308. if ( item->u3.hints )
  309. fprintf(fin,"hints(%s) ", item->u3.hints);
  310. fprintf(fin,"%s => ", item->u1.str);
  311. print_pval_list(fin,item->u2.statements,depth+1);
  312. fprintf(fin,"\n");
  313. break;
  314. case PV_IGNOREPAT:
  315. fprintf(fin,"ignorepat => %s;\n", item->u1.str);
  316. break;
  317. case PV_GLOBALS:
  318. fprintf(fin,"globals {\n");
  319. print_pval_list(fin,item->u1.statements,depth+1);
  320. for (i=0; i<depth; i++) {
  321. fprintf(fin,"\t"); /* depth == indentation */
  322. }
  323. fprintf(fin,"}\n");
  324. break;
  325. }
  326. }
  327. static void print_pval_list(FILE *fin, pval *item, int depth)
  328. {
  329. pval *i;
  330. for (i=item; i; i=i->next) {
  331. print_pval(fin, i, depth);
  332. }
  333. }
  334. void ael2_print(char *fname, pval *tree)
  335. {
  336. FILE *fin = fopen(fname,"w");
  337. if ( !fin ) {
  338. ast_log(LOG_ERROR, "Couldn't open %s for writing.\n", fname);
  339. return;
  340. }
  341. print_pval_list(fin, tree, 0);
  342. fclose(fin);
  343. }
  344. /* EMPTY TEMPLATE FUNCS FOR AEL TRAVERSAL: ============================================================================= */
  345. void traverse_pval_template(pval *item, int depth);
  346. void traverse_pval_item_template(pval *item, int depth);
  347. void traverse_pval_item_template(pval *item, int depth)/* depth comes in handy for a pretty print (indentation),
  348. but you may not need it */
  349. {
  350. pval *lp;
  351. switch ( item->type ) {
  352. case PV_WORD:
  353. /* fields: item->u1.str == string associated with this (word). */
  354. break;
  355. case PV_MACRO:
  356. /* fields: item->u1.str == name of macro
  357. item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
  358. item->u2.arglist->u1.str == argument
  359. item->u2.arglist->next == next arg
  360. item->u3.macro_statements == pval list of statements in macro body.
  361. */
  362. for (lp=item->u2.arglist; lp; lp=lp->next) {
  363. }
  364. traverse_pval_item_template(item->u3.macro_statements,depth+1);
  365. break;
  366. case PV_CONTEXT:
  367. /* fields: item->u1.str == name of context
  368. item->u2.statements == pval list of statements in context body
  369. item->u3.abstract == int 1 if an abstract keyword were present
  370. */
  371. traverse_pval_item_template(item->u2.statements,depth+1);
  372. break;
  373. case PV_MACRO_CALL:
  374. /* fields: item->u1.str == name of macro to call
  375. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  376. item->u2.arglist->u1.str == argument
  377. item->u2.arglist->next == next arg
  378. */
  379. for (lp=item->u2.arglist; lp; lp=lp->next) {
  380. }
  381. break;
  382. case PV_APPLICATION_CALL:
  383. /* fields: item->u1.str == name of application to call
  384. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  385. item->u2.arglist->u1.str == argument
  386. item->u2.arglist->next == next arg
  387. */
  388. for (lp=item->u2.arglist; lp; lp=lp->next) {
  389. }
  390. break;
  391. case PV_CASE:
  392. /* fields: item->u1.str == value of case
  393. item->u2.statements == pval list of statements under the case
  394. */
  395. traverse_pval_item_template(item->u2.statements,depth+1);
  396. break;
  397. case PV_PATTERN:
  398. /* fields: item->u1.str == value of case
  399. item->u2.statements == pval list of statements under the case
  400. */
  401. traverse_pval_item_template(item->u2.statements,depth+1);
  402. break;
  403. case PV_DEFAULT:
  404. /* fields:
  405. item->u2.statements == pval list of statements under the case
  406. */
  407. traverse_pval_item_template(item->u2.statements,depth+1);
  408. break;
  409. case PV_CATCH:
  410. /* fields: item->u1.str == name of extension to catch
  411. item->u2.statements == pval list of statements in context body
  412. */
  413. traverse_pval_item_template(item->u2.statements,depth+1);
  414. break;
  415. case PV_SWITCHES:
  416. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  417. */
  418. traverse_pval_item_template(item->u1.list,depth+1);
  419. break;
  420. case PV_ESWITCHES:
  421. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  422. */
  423. traverse_pval_item_template(item->u1.list,depth+1);
  424. break;
  425. case PV_INCLUDES:
  426. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  427. item->u2.arglist == pval list of 4 PV_WORD elements for time values
  428. */
  429. traverse_pval_item_template(item->u1.list,depth+1);
  430. traverse_pval_item_template(item->u2.arglist,depth+1);
  431. break;
  432. case PV_STATEMENTBLOCK:
  433. /* fields: item->u1.list == pval list of statements in block, one per entry in the list
  434. */
  435. traverse_pval_item_template(item->u1.list,depth+1);
  436. break;
  437. case PV_LOCALVARDEC:
  438. case PV_VARDEC:
  439. /* fields: item->u1.str == variable name
  440. item->u2.val == variable value to assign
  441. */
  442. break;
  443. case PV_GOTO:
  444. /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
  445. item->u1.list->u1.str == where the data on a PV_WORD will always be.
  446. */
  447. if ( item->u1.list->next )
  448. ;
  449. if ( item->u1.list->next && item->u1.list->next->next )
  450. ;
  451. break;
  452. case PV_LABEL:
  453. /* fields: item->u1.str == label name
  454. */
  455. break;
  456. case PV_FOR:
  457. /* fields: item->u1.for_init == a string containing the initalizer
  458. item->u2.for_test == a string containing the loop test
  459. item->u3.for_inc == a string containing the loop increment
  460. item->u4.for_statements == a pval list of statements in the for ()
  461. */
  462. traverse_pval_item_template(item->u4.for_statements,depth+1);
  463. break;
  464. case PV_WHILE:
  465. /* fields: item->u1.str == the while conditional, as supplied by user
  466. item->u2.statements == a pval list of statements in the while ()
  467. */
  468. traverse_pval_item_template(item->u2.statements,depth+1);
  469. break;
  470. case PV_BREAK:
  471. /* fields: none
  472. */
  473. break;
  474. case PV_RETURN:
  475. /* fields: none
  476. */
  477. break;
  478. case PV_CONTINUE:
  479. /* fields: none
  480. */
  481. break;
  482. case PV_IFTIME:
  483. /* fields: item->u1.list == there are 4 linked PV_WORDs here.
  484. item->u2.statements == a pval list of statements in the if ()
  485. item->u3.else_statements == a pval list of statements in the else
  486. (could be zero)
  487. */
  488. traverse_pval_item_template(item->u2.statements,depth+1);
  489. if ( item->u3.else_statements ) {
  490. traverse_pval_item_template(item->u3.else_statements,depth+1);
  491. }
  492. break;
  493. case PV_RANDOM:
  494. /* fields: item->u1.str == the random number expression, as supplied by user
  495. item->u2.statements == a pval list of statements in the if ()
  496. item->u3.else_statements == a pval list of statements in the else
  497. (could be zero)
  498. */
  499. traverse_pval_item_template(item->u2.statements,depth+1);
  500. if ( item->u3.else_statements ) {
  501. traverse_pval_item_template(item->u3.else_statements,depth+1);
  502. }
  503. break;
  504. case PV_IF:
  505. /* fields: item->u1.str == the if conditional, as supplied by user
  506. item->u2.statements == a pval list of statements in the if ()
  507. item->u3.else_statements == a pval list of statements in the else
  508. (could be zero)
  509. */
  510. traverse_pval_item_template(item->u2.statements,depth+1);
  511. if ( item->u3.else_statements ) {
  512. traverse_pval_item_template(item->u3.else_statements,depth+1);
  513. }
  514. break;
  515. case PV_SWITCH:
  516. /* fields: item->u1.str == the switch expression
  517. item->u2.statements == a pval list of statements in the switch,
  518. (will be case statements, most likely!)
  519. */
  520. traverse_pval_item_template(item->u2.statements,depth+1);
  521. break;
  522. case PV_EXTENSION:
  523. /* fields: item->u1.str == the extension name, label, whatever it's called
  524. item->u2.statements == a pval list of statements in the extension
  525. item->u3.hints == a char * hint argument
  526. item->u4.regexten == an int boolean. non-zero says that regexten was specified
  527. */
  528. traverse_pval_item_template(item->u2.statements,depth+1);
  529. break;
  530. case PV_IGNOREPAT:
  531. /* fields: item->u1.str == the ignorepat data
  532. */
  533. break;
  534. case PV_GLOBALS:
  535. /* fields: item->u1.statements == pval list of statements, usually vardecs
  536. */
  537. traverse_pval_item_template(item->u1.statements,depth+1);
  538. break;
  539. }
  540. }
  541. void traverse_pval_template(pval *item, int depth) /* depth comes in handy for a pretty print (indentation),
  542. but you may not need it */
  543. {
  544. pval *i;
  545. for (i=item; i; i=i->next) {
  546. traverse_pval_item_template(i, depth);
  547. }
  548. }
  549. /* SEMANTIC CHECKING FOR AEL: ============================================================================= */
  550. /* (not all that is syntactically legal is good! */
  551. static void check_macro_returns(pval *macro)
  552. {
  553. pval *i;
  554. if (!macro->u3.macro_statements)
  555. {
  556. pval *z = calloc(1, sizeof(struct pval));
  557. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s is empty! I will insert a return.\n",
  558. macro->filename, macro->startline, macro->endline, macro->u1.str);
  559. z->type = PV_RETURN;
  560. z->startline = macro->startline;
  561. z->endline = macro->endline;
  562. z->startcol = macro->startcol;
  563. z->endcol = macro->endcol;
  564. z->filename = strdup(macro->filename);
  565. macro->u3.macro_statements = z;
  566. return;
  567. }
  568. for (i=macro->u3.macro_statements; i; i=i->next) {
  569. /* if the last statement in the list is not return, then insert a return there */
  570. if (i->next == NULL) {
  571. if (i->type != PV_RETURN) {
  572. pval *z = calloc(1, sizeof(struct pval));
  573. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The macro %s does not end with a return; I will insert one.\n",
  574. macro->filename, macro->startline, macro->endline, macro->u1.str);
  575. z->type = PV_RETURN;
  576. z->startline = macro->startline;
  577. z->endline = macro->endline;
  578. z->startcol = macro->startcol;
  579. z->endcol = macro->endcol;
  580. z->filename = strdup(macro->filename);
  581. i->next = z;
  582. return;
  583. }
  584. }
  585. }
  586. return;
  587. }
  588. static int extension_matches(pval *here, const char *exten, const char *pattern)
  589. {
  590. int err1;
  591. regex_t preg;
  592. /* simple case, they match exactly, the pattern and exten name */
  593. if (strcmp(pattern,exten) == 0)
  594. return 1;
  595. if (pattern[0] == '_') {
  596. char reg1[2000];
  597. const char *p;
  598. char *r = reg1;
  599. if ( strlen(pattern)*5 >= 2000 ) /* safety valve */ {
  600. ast_log(LOG_ERROR,"Error: The pattern %s is way too big. Pattern matching cancelled.\n",
  601. pattern);
  602. return 0;
  603. }
  604. /* form a regular expression from the pattern, and then match it against exten */
  605. *r++ = '^'; /* what if the extension is a pattern ?? */
  606. *r++ = '_'; /* what if the extension is a pattern ?? */
  607. *r++ = '?';
  608. for (p=pattern+1; *p; p++) {
  609. switch ( *p ) {
  610. case 'X':
  611. *r++ = '[';
  612. *r++ = '0';
  613. *r++ = '-';
  614. *r++ = '9';
  615. *r++ = 'X';
  616. *r++ = ']';
  617. break;
  618. case 'Z':
  619. *r++ = '[';
  620. *r++ = '1';
  621. *r++ = '-';
  622. *r++ = '9';
  623. *r++ = 'Z';
  624. *r++ = ']';
  625. break;
  626. case 'N':
  627. *r++ = '[';
  628. *r++ = '2';
  629. *r++ = '-';
  630. *r++ = '9';
  631. *r++ = 'N';
  632. *r++ = ']';
  633. break;
  634. case '[':
  635. while ( *p && *p != ']' ) {
  636. *r++ = *p++;
  637. }
  638. *r++ = ']';
  639. if ( *p != ']') {
  640. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The extension pattern '%s' is missing a closing bracket \n",
  641. here->filename, here->startline, here->endline, pattern);
  642. }
  643. break;
  644. case '.':
  645. case '!':
  646. *r++ = '.';
  647. *r++ = '*';
  648. break;
  649. case '*':
  650. *r++ = '\\';
  651. *r++ = '*';
  652. break;
  653. default:
  654. *r++ = *p;
  655. break;
  656. }
  657. }
  658. *r++ = '$'; /* what if the extension is a pattern ?? */
  659. *r++ = *p++; /* put in the closing null */
  660. err1 = regcomp(&preg, reg1, REG_NOSUB|REG_EXTENDED);
  661. if ( err1 ) {
  662. char errmess[500];
  663. regerror(err1,&preg,errmess,sizeof(errmess));
  664. regfree(&preg);
  665. ast_log(LOG_WARNING, "Regcomp of %s failed, error code %d\n",
  666. reg1, err1);
  667. return 0;
  668. }
  669. err1 = regexec(&preg, exten, 0, 0, 0);
  670. regfree(&preg);
  671. if ( err1 ) {
  672. /* ast_log(LOG_NOTICE,"*****************************[%d]Extension %s did not match %s(%s)\n",
  673. err1,exten, pattern, reg1); */
  674. return 0; /* no match */
  675. } else {
  676. /* ast_log(LOG_NOTICE,"*****************************Extension %s matched %s\n",
  677. exten, pattern); */
  678. return 1;
  679. }
  680. } else {
  681. if ( strcmp(exten,pattern) == 0 ) {
  682. return 1;
  683. } else
  684. return 0;
  685. }
  686. }
  687. static void check_expr2_input(pval *expr, char *str)
  688. {
  689. int spaces = strspn(str,"\t \n");
  690. if ( !strncmp(str+spaces,"$[",2) ) {
  691. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The expression '%s' is redundantly wrapped in '$[ ]'. \n",
  692. expr->filename, expr->startline, expr->endline, str);
  693. warns++;
  694. }
  695. }
  696. static void check_includes(pval *includes)
  697. {
  698. struct pval *p4;
  699. for (p4=includes->u1.list; p4; p4=p4->next) {
  700. /* for each context pointed to, find it, then find a context/label that matches the
  701. target here! */
  702. char *incl_context = p4->u1.str;
  703. /* find a matching context name */
  704. struct pval *that_other_context = find_context(incl_context);
  705. if (!that_other_context && strcmp(incl_context, "parkedcalls") != 0) {
  706. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The included context '%s' cannot be found.\n\
  707. (You may ignore this warning if '%s' exists in extensions.conf, or is created by another module. I cannot check for those.)\n",
  708. includes->filename, includes->startline, includes->endline, incl_context, incl_context);
  709. warns++;
  710. }
  711. }
  712. }
  713. static void check_timerange(pval *p)
  714. {
  715. char *times;
  716. char *e;
  717. int s1, s2;
  718. int e1, e2;
  719. times = ast_strdupa(p->u1.str);
  720. /* Star is all times */
  721. if (ast_strlen_zero(times) || !strcmp(times, "*")) {
  722. return;
  723. }
  724. /* Otherwise expect a range */
  725. e = strchr(times, '-');
  726. if (!e) {
  727. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) requires a '-' surrounded by two 24-hour times of day!\n",
  728. p->filename, p->startline, p->endline, times);
  729. warns++;
  730. return;
  731. }
  732. *e = '\0';
  733. e++;
  734. while (*e && !isdigit(*e))
  735. e++;
  736. if (!*e) {
  737. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The time range format (%s) is missing the end time!\n",
  738. p->filename, p->startline, p->endline, p->u1.str);
  739. warns++;
  740. }
  741. if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
  742. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) isn't quite right!\n",
  743. p->filename, p->startline, p->endline, times);
  744. warns++;
  745. }
  746. if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
  747. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) isn't quite right!\n",
  748. p->filename, p->startline, p->endline, times);
  749. warns++;
  750. }
  751. s1 = s1 * 30 + s2/2;
  752. if ((s1 < 0) || (s1 >= 24*30)) {
  753. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start time (%s) is out of range!\n",
  754. p->filename, p->startline, p->endline, times);
  755. warns++;
  756. }
  757. e1 = e1 * 30 + e2/2;
  758. if ((e1 < 0) || (e1 >= 24*30)) {
  759. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end time (%s) is out of range!\n",
  760. p->filename, p->startline, p->endline, e);
  761. warns++;
  762. }
  763. return;
  764. }
  765. static char *days[] =
  766. {
  767. "sun",
  768. "mon",
  769. "tue",
  770. "wed",
  771. "thu",
  772. "fri",
  773. "sat",
  774. };
  775. /*! \brief get_dow: Get day of week */
  776. static void check_dow(pval *DOW)
  777. {
  778. char *dow;
  779. char *c;
  780. /* The following line is coincidence, really! */
  781. int s, e;
  782. dow = ast_strdupa(DOW->u1.str);
  783. /* Check for all days */
  784. if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
  785. return;
  786. /* Get start and ending days */
  787. c = strchr(dow, '-');
  788. if (c) {
  789. *c = '\0';
  790. c++;
  791. } else
  792. c = NULL;
  793. /* Find the start */
  794. s = 0;
  795. while ((s < 7) && strcasecmp(dow, days[s])) s++;
  796. if (s >= 7) {
  797. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
  798. DOW->filename, DOW->startline, DOW->endline, dow);
  799. warns++;
  800. }
  801. if (c) {
  802. e = 0;
  803. while ((e < 7) && strcasecmp(c, days[e])) e++;
  804. if (e >= 7) {
  805. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day (%s) must be one of 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', or 'sat'!\n",
  806. DOW->filename, DOW->startline, DOW->endline, c);
  807. warns++;
  808. }
  809. } else
  810. e = s;
  811. }
  812. static void check_day(pval *DAY)
  813. {
  814. char *day;
  815. char *c;
  816. /* The following line is coincidence, really! */
  817. int s, e;
  818. day = ast_strdupa(DAY->u1.str);
  819. /* Check for all days */
  820. if (ast_strlen_zero(day) || !strcmp(day, "*")) {
  821. return;
  822. }
  823. /* Get start and ending days */
  824. c = strchr(day, '-');
  825. if (c) {
  826. *c = '\0';
  827. c++;
  828. }
  829. /* Find the start */
  830. if (sscanf(day, "%2d", &s) != 1) {
  831. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number!\n",
  832. DAY->filename, DAY->startline, DAY->endline, day);
  833. warns++;
  834. }
  835. else if ((s < 1) || (s > 31)) {
  836. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start day of month (%s) must be a number in the range [1-31]!\n",
  837. DAY->filename, DAY->startline, DAY->endline, day);
  838. warns++;
  839. }
  840. s--;
  841. if (c) {
  842. if (sscanf(c, "%2d", &e) != 1) {
  843. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number!\n",
  844. DAY->filename, DAY->startline, DAY->endline, c);
  845. warns++;
  846. }
  847. else if ((e < 1) || (e > 31)) {
  848. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end day of month (%s) must be a number in the range [1-31]!\n",
  849. DAY->filename, DAY->startline, DAY->endline, day);
  850. warns++;
  851. }
  852. e--;
  853. } else
  854. e = s;
  855. }
  856. static char *months[] =
  857. {
  858. "jan",
  859. "feb",
  860. "mar",
  861. "apr",
  862. "may",
  863. "jun",
  864. "jul",
  865. "aug",
  866. "sep",
  867. "oct",
  868. "nov",
  869. "dec",
  870. };
  871. static void check_month(pval *MON)
  872. {
  873. char *mon;
  874. char *c;
  875. /* The following line is coincidence, really! */
  876. int s, e;
  877. mon = ast_strdupa(MON->u1.str);
  878. /* Check for all days */
  879. if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
  880. return ;
  881. /* Get start and ending days */
  882. c = strchr(mon, '-');
  883. if (c) {
  884. *c = '\0';
  885. c++;
  886. }
  887. /* Find the start */
  888. s = 0;
  889. while ((s < 12) && strcasecmp(mon, months[s])) s++;
  890. if (s >= 12) {
  891. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The start month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
  892. MON->filename, MON->startline, MON->endline, mon);
  893. warns++;
  894. }
  895. if (c) {
  896. e = 0;
  897. while ((e < 12) && strcasecmp(mon, months[e])) e++;
  898. if (e >= 12) {
  899. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The end month (%s) must be a one of: 'jan', 'feb', ..., 'dec'!\n",
  900. MON->filename, MON->startline, MON->endline, c);
  901. warns++;
  902. }
  903. } else
  904. e = s;
  905. }
  906. static int check_break(pval *item)
  907. {
  908. pval *p = item;
  909. while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
  910. /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
  911. no sense */
  912. if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN
  913. || p->type == PV_WHILE || p->type == PV_FOR ) {
  914. return 1;
  915. }
  916. p = p->dad;
  917. }
  918. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'break' not in switch, for, or while statement!\n",
  919. item->filename, item->startline, item->endline);
  920. errs++;
  921. return 0;
  922. }
  923. static int check_continue(pval *item)
  924. {
  925. pval *p = item;
  926. while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
  927. /* a break is allowed in WHILE, FOR, CASE, DEFAULT, PATTERN; otherwise, it don't make
  928. no sense */
  929. if( p->type == PV_WHILE || p->type == PV_FOR ) {
  930. return 1;
  931. }
  932. p = p->dad;
  933. }
  934. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: 'continue' not in 'for' or 'while' statement!\n",
  935. item->filename, item->startline, item->endline);
  936. errs++;
  937. return 0;
  938. }
  939. static struct pval *in_macro(pval *item)
  940. {
  941. struct pval *curr;
  942. curr = item;
  943. while( curr ) {
  944. if( curr->type == PV_MACRO ) {
  945. return curr;
  946. }
  947. curr = curr->dad;
  948. }
  949. return 0;
  950. }
  951. static struct pval *in_context(pval *item)
  952. {
  953. struct pval *curr;
  954. curr = item;
  955. while( curr ) {
  956. if( curr->type == PV_MACRO || curr->type == PV_CONTEXT ) {
  957. return curr;
  958. }
  959. curr = curr->dad;
  960. }
  961. return 0;
  962. }
  963. /* general purpose goto finder */
  964. static void check_label(pval *item)
  965. {
  966. struct pval *curr;
  967. struct pval *x;
  968. int alright = 0;
  969. /* A label outside an extension just plain does not make sense! */
  970. curr = item;
  971. while( curr ) {
  972. if( curr->type == PV_MACRO || curr->type == PV_EXTENSION ) {
  973. alright = 1;
  974. break;
  975. }
  976. curr = curr->dad;
  977. }
  978. if( !alright )
  979. {
  980. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Label %s is not within an extension or macro!\n",
  981. item->filename, item->startline, item->endline, item->u1.str);
  982. errs++;
  983. }
  984. /* basically, ensure that a label is not repeated in a context. Period.
  985. The method: well, for each label, find the first label in the context
  986. with the same name. If it's not the current label, then throw an error. */
  987. /* printf("==== check_label: ====\n"); */
  988. if( !current_extension )
  989. curr = current_context;
  990. else
  991. curr = current_extension;
  992. x = find_first_label_in_current_context((char *)item->u1.str, curr);
  993. /* printf("Hey, check_label found with item = %x, and x is %x, and currcont is %x, label name is %s\n", item,x, current_context, (char *)item->u1.str); */
  994. if( x && x != item )
  995. {
  996. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: Duplicate label %s! Previously defined at file %s, line %d.\n",
  997. item->filename, item->startline, item->endline, item->u1.str, x->filename, x->startline);
  998. errs++;
  999. }
  1000. /* printf("<<<<< check_label: ====\n"); */
  1001. }
  1002. static pval *get_goto_target(pval *item)
  1003. {
  1004. /* just one item-- the label should be in the current extension */
  1005. pval *curr_ext = get_extension_or_contxt(item); /* containing exten, or macro */
  1006. pval *curr_cont;
  1007. if (!item->u1.list) {
  1008. return NULL;
  1009. }
  1010. if (!item->u1.list->next && !strstr((item->u1.list)->u1.str,"${")) {
  1011. struct pval *x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), curr_ext);
  1012. return x;
  1013. }
  1014. curr_cont = get_contxt(item);
  1015. /* TWO items */
  1016. if (item->u1.list->next && !item->u1.list->next->next) {
  1017. if (!strstr((item->u1.list)->u1.str,"${")
  1018. && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
  1019. struct pval *x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, curr_cont);
  1020. return x;
  1021. }
  1022. }
  1023. /* All 3 items! */
  1024. if (item->u1.list->next && item->u1.list->next->next) {
  1025. /* all three */
  1026. pval *first = item->u1.list;
  1027. pval *second = item->u1.list->next;
  1028. pval *third = item->u1.list->next->next;
  1029. if (!strstr((item->u1.list)->u1.str,"${")
  1030. && !strstr(item->u1.list->next->u1.str,"${")
  1031. && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
  1032. struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
  1033. if (!x) {
  1034. struct pval *p3;
  1035. struct pval *that_context = find_context(item->u1.list->u1.str);
  1036. /* the target of the goto could be in an included context!! Fancy that!! */
  1037. /* look for includes in the current context */
  1038. if (that_context) {
  1039. for (p3=that_context->u2.statements; p3; p3=p3->next) {
  1040. if (p3->type == PV_INCLUDES) {
  1041. struct pval *p4;
  1042. for (p4=p3->u1.list; p4; p4=p4->next) {
  1043. /* for each context pointed to, find it, then find a context/label that matches the
  1044. target here! */
  1045. char *incl_context = p4->u1.str;
  1046. /* find a matching context name */
  1047. struct pval *that_other_context = find_context(incl_context);
  1048. if (that_other_context) {
  1049. struct pval *x3;
  1050. x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
  1051. if (x3) {
  1052. return x3;
  1053. }
  1054. }
  1055. }
  1056. }
  1057. }
  1058. }
  1059. }
  1060. return x;
  1061. }
  1062. }
  1063. return NULL;
  1064. }
  1065. static void check_goto(pval *item)
  1066. {
  1067. if (!item->u1.list) {
  1068. return;
  1069. }
  1070. /* check for the target of the goto-- does it exist? */
  1071. if ( !(item->u1.list)->next && !(item->u1.list)->u1.str ) {
  1072. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: empty label reference found!\n",
  1073. item->filename, item->startline, item->endline);
  1074. errs++;
  1075. }
  1076. /* just one item-- the label should be in the current extension */
  1077. if (!item->u1.list->next && !strstr(item->u1.list->u1.str,"${")) {
  1078. struct pval *z = get_extension_or_contxt(item);
  1079. struct pval *x = 0;
  1080. if (z)
  1081. x = find_label_in_current_extension((char*)((item->u1.list)->u1.str), z); /* if in macro, use current context instead */
  1082. /* printf("Called find_label_in_current_extension with arg %s; current_extension is %x: %d\n",
  1083. (char*)((item->u1.list)->u1.str), current_extension?current_extension:current_context, current_extension?current_extension->type:current_context->type); */
  1084. if (!x) {
  1085. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s exists in the current extension!\n",
  1086. item->filename, item->startline, item->endline, item->u1.list->u1.str);
  1087. errs++;
  1088. }
  1089. else
  1090. return;
  1091. }
  1092. /* TWO items */
  1093. if (item->u1.list->next && !item->u1.list->next->next) {
  1094. /* two items */
  1095. /* printf("Calling find_label_in_current_context with args %s, %s\n",
  1096. (char*)((item->u1.list)->u1.str), (char *)item->u1.list->next->u1.str); */
  1097. if (!strstr((item->u1.list)->u1.str,"${")
  1098. && !strstr(item->u1.list->next->u1.str,"${") ) /* Don't try to match variables */ {
  1099. struct pval *z = get_contxt(item);
  1100. struct pval *x = 0;
  1101. if (z)
  1102. x = find_label_in_current_context((char *)item->u1.list->u1.str, (char *)item->u1.list->next->u1.str, z);
  1103. if (!x) {
  1104. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label '%s,%s' exists in the current context, or any of its inclusions!\n",
  1105. item->filename, item->startline, item->endline, item->u1.list->u1.str, item->u1.list->next->u1.str );
  1106. errs++;
  1107. }
  1108. else
  1109. return;
  1110. }
  1111. }
  1112. /* All 3 items! */
  1113. if (item->u1.list->next && item->u1.list->next->next) {
  1114. /* all three */
  1115. pval *first = item->u1.list;
  1116. pval *second = item->u1.list->next;
  1117. pval *third = item->u1.list->next->next;
  1118. /* printf("Calling find_label_in_current_db with args %s, %s, %s\n",
  1119. (char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str); */
  1120. if (!strstr((item->u1.list)->u1.str,"${")
  1121. && !strstr(item->u1.list->next->u1.str,"${")
  1122. && !strstr(item->u1.list->next->next->u1.str,"${")) /* Don't try to match variables */ {
  1123. struct pval *x = find_label_in_current_db((char*)first->u1.str, (char*)second->u1.str, (char*)third->u1.str);
  1124. if (!x) {
  1125. struct pval *p3;
  1126. struct pval *found = 0;
  1127. struct pval *that_context = find_context(item->u1.list->u1.str);
  1128. /* the target of the goto could be in an included context!! Fancy that!! */
  1129. /* look for includes in the current context */
  1130. if (that_context) {
  1131. for (p3=that_context->u2.statements; p3; p3=p3->next) {
  1132. if (p3->type == PV_INCLUDES) {
  1133. struct pval *p4;
  1134. for (p4=p3->u1.list; p4; p4=p4->next) {
  1135. /* for each context pointed to, find it, then find a context/label that matches the
  1136. target here! */
  1137. char *incl_context = p4->u1.str;
  1138. /* find a matching context name */
  1139. struct pval *that_other_context = find_context(incl_context);
  1140. if (that_other_context) {
  1141. struct pval *x3;
  1142. x3 = find_label_in_current_context((char *)item->u1.list->next->u1.str, (char *)item->u1.list->next->next->u1.str, that_other_context);
  1143. if (x3) {
  1144. found = x3;
  1145. break;
  1146. }
  1147. }
  1148. }
  1149. }
  1150. }
  1151. if (!found) {
  1152. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: goto: no label %s|%s exists in the context %s or its inclusions!\n",
  1153. item->filename, item->startline, item->endline, item->u1.list->next->u1.str, item->u1.list->next->next->u1.str, item->u1.list->u1.str );
  1154. errs++;
  1155. } else {
  1156. struct pval *mac = in_macro(item); /* is this goto inside a macro? */
  1157. if( mac ) { /* yes! */
  1158. struct pval *targ = in_context(found);
  1159. if( mac != targ )
  1160. {
  1161. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
  1162. item->filename, item->startline, item->endline);
  1163. warns++;
  1164. }
  1165. }
  1166. }
  1167. } else {
  1168. /* here is where code would go to check for target existence in extensions.conf files */
  1169. #ifdef STANDALONE
  1170. struct pbx_find_info pfiq = {.stacklen = 0 };
  1171. extern int localized_pbx_load_module(void);
  1172. /* if this is a standalone, we will need to make sure the
  1173. localized load of extensions.conf is done */
  1174. if (!extensions_dot_conf_loaded) {
  1175. localized_pbx_load_module();
  1176. extensions_dot_conf_loaded++;
  1177. }
  1178. pbx_find_extension(NULL, NULL, &pfiq, first->u1.str, second->u1.str, atoi(third->u1.str),
  1179. atoi(third->u1.str) ? NULL : third->u1.str, NULL,
  1180. atoi(third->u1.str) ? E_MATCH : E_FINDLABEL);
  1181. if (pfiq.status != STATUS_SUCCESS) {
  1182. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s, not even in extensions.conf!\n",
  1183. item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
  1184. warns++;
  1185. }
  1186. #else
  1187. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: goto: Couldn't find goto target %s|%s|%s in the AEL code!\n",
  1188. item->filename, item->startline, item->endline, first->u1.str, second->u1.str, third->u1.str);
  1189. warns++;
  1190. #endif
  1191. }
  1192. } else {
  1193. struct pval *mac = in_macro(item); /* is this goto inside a macro? */
  1194. if( mac ) { /* yes! */
  1195. struct pval *targ = in_context(x);
  1196. if( mac != targ )
  1197. {
  1198. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: It's bad form to have a goto in a macro to a target outside the macro!\n",
  1199. item->filename, item->startline, item->endline);
  1200. warns++;
  1201. }
  1202. }
  1203. }
  1204. }
  1205. }
  1206. }
  1207. static void find_pval_goto_item(pval *item, int lev)
  1208. {
  1209. struct pval *p4;
  1210. if (lev>100) {
  1211. ast_log(LOG_ERROR,"find_pval_goto in infinite loop! item_type: %d\n\n", item->type);
  1212. return;
  1213. }
  1214. switch ( item->type ) {
  1215. case PV_MACRO:
  1216. /* fields: item->u1.str == name of macro
  1217. item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
  1218. item->u2.arglist->u1.str == argument
  1219. item->u2.arglist->next == next arg
  1220. item->u3.macro_statements == pval list of statements in macro body.
  1221. */
  1222. /* printf("Descending into macro %s at line %d\n", item->u1.str, item->startline); */
  1223. find_pval_gotos(item->u3.macro_statements,lev+1); /* if we're just searching for a context, don't bother descending into them */
  1224. break;
  1225. case PV_CONTEXT:
  1226. /* fields: item->u1.str == name of context
  1227. item->u2.statements == pval list of statements in context body
  1228. item->u3.abstract == int 1 if an abstract keyword were present
  1229. */
  1230. break;
  1231. case PV_CASE:
  1232. /* fields: item->u1.str == value of case
  1233. item->u2.statements == pval list of statements under the case
  1234. */
  1235. /* printf("Descending into Case of %s\n", item->u1.str); */
  1236. find_pval_gotos(item->u2.statements,lev+1);
  1237. break;
  1238. case PV_PATTERN:
  1239. /* fields: item->u1.str == value of case
  1240. item->u2.statements == pval list of statements under the case
  1241. */
  1242. /* printf("Descending into Pattern of %s\n", item->u1.str); */
  1243. find_pval_gotos(item->u2.statements,lev+1);
  1244. break;
  1245. case PV_DEFAULT:
  1246. /* fields:
  1247. item->u2.statements == pval list of statements under the case
  1248. */
  1249. /* printf("Descending into default\n"); */
  1250. find_pval_gotos(item->u2.statements,lev+1);
  1251. break;
  1252. case PV_CATCH:
  1253. /* fields: item->u1.str == name of extension to catch
  1254. item->u2.statements == pval list of statements in context body
  1255. */
  1256. /* printf("Descending into catch of %s\n", item->u1.str); */
  1257. find_pval_gotos(item->u2.statements,lev+1);
  1258. break;
  1259. case PV_STATEMENTBLOCK:
  1260. /* fields: item->u1.list == pval list of statements in block, one per entry in the list
  1261. */
  1262. /* printf("Descending into statement block\n"); */
  1263. find_pval_gotos(item->u1.list,lev+1);
  1264. break;
  1265. case PV_GOTO:
  1266. /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
  1267. item->u1.list->u1.str == where the data on a PV_WORD will always be.
  1268. */
  1269. check_goto(item); /* THE WHOLE FUNCTION OF THIS ENTIRE ROUTINE!!!! */
  1270. break;
  1271. case PV_INCLUDES:
  1272. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  1273. */
  1274. for (p4=item->u1.list; p4; p4=p4->next) {
  1275. /* for each context pointed to, find it, then find a context/label that matches the
  1276. target here! */
  1277. char *incl_context = p4->u1.str;
  1278. /* find a matching context name */
  1279. struct pval *that_context = find_context(incl_context);
  1280. if (that_context && that_context->u2.statements) {
  1281. /* printf("Descending into include of '%s' at line %d; that_context=%s, that_context type=%d\n", incl_context, item->startline, that_context->u1.str, that_context->type); */
  1282. find_pval_gotos(that_context->u2.statements,lev+1); /* keep working up the includes */
  1283. }
  1284. }
  1285. break;
  1286. case PV_FOR:
  1287. /* fields: item->u1.for_init == a string containing the initalizer
  1288. item->u2.for_test == a string containing the loop test
  1289. item->u3.for_inc == a string containing the loop increment
  1290. item->u4.for_statements == a pval list of statements in the for ()
  1291. */
  1292. /* printf("Descending into for at line %d\n", item->startline); */
  1293. find_pval_gotos(item->u4.for_statements,lev+1);
  1294. break;
  1295. case PV_WHILE:
  1296. /* fields: item->u1.str == the while conditional, as supplied by user
  1297. item->u2.statements == a pval list of statements in the while ()
  1298. */
  1299. /* printf("Descending into while at line %d\n", item->startline); */
  1300. find_pval_gotos(item->u2.statements,lev+1);
  1301. break;
  1302. case PV_RANDOM:
  1303. /* fields: item->u1.str == the random number expression, as supplied by user
  1304. item->u2.statements == a pval list of statements in the if ()
  1305. item->u3.else_statements == a pval list of statements in the else
  1306. (could be zero)
  1307. fall thru to PV_IF */
  1308. case PV_IFTIME:
  1309. /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list
  1310. item->u2.statements == a pval list of statements in the if ()
  1311. item->u3.else_statements == a pval list of statements in the else
  1312. (could be zero)
  1313. fall thru to PV_IF*/
  1314. case PV_IF:
  1315. /* fields: item->u1.str == the if conditional, as supplied by user
  1316. item->u2.statements == a pval list of statements in the if ()
  1317. item->u3.else_statements == a pval list of statements in the else
  1318. (could be zero)
  1319. */
  1320. /* printf("Descending into random/iftime/if at line %d\n", item->startline); */
  1321. find_pval_gotos(item->u2.statements,lev+1);
  1322. if (item->u3.else_statements) {
  1323. /* printf("Descending into random/iftime/if's ELSE at line %d\n", item->startline); */
  1324. find_pval_gotos(item->u3.else_statements,lev+1);
  1325. }
  1326. break;
  1327. case PV_SWITCH:
  1328. /* fields: item->u1.str == the switch expression
  1329. item->u2.statements == a pval list of statements in the switch,
  1330. (will be case statements, most likely!)
  1331. */
  1332. /* printf("Descending into switch at line %d\n", item->startline); */
  1333. find_pval_gotos(item->u3.else_statements,lev+1);
  1334. break;
  1335. case PV_EXTENSION:
  1336. /* fields: item->u1.str == the extension name, label, whatever it's called
  1337. item->u2.statements == a pval list of statements in the extension
  1338. item->u3.hints == a char * hint argument
  1339. item->u4.regexten == an int boolean. non-zero says that regexten was specified
  1340. */
  1341. /* printf("Descending into extension %s at line %d\n", item->u1.str, item->startline); */
  1342. find_pval_gotos(item->u2.statements,lev+1);
  1343. break;
  1344. default:
  1345. break;
  1346. }
  1347. }
  1348. static void find_pval_gotos(pval *item,int lev)
  1349. {
  1350. pval *i;
  1351. for (i=item; i; i=i->next) {
  1352. /* printf("About to call pval_goto_item, itemcount=%d, itemtype=%d\n", item_count, i->type); */
  1353. find_pval_goto_item(i, lev);
  1354. }
  1355. }
  1356. /* general purpose label finder */
  1357. static struct pval *match_pval_item(pval *item)
  1358. {
  1359. pval *x;
  1360. switch ( item->type ) {
  1361. case PV_MACRO:
  1362. /* fields: item->u1.str == name of macro
  1363. item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
  1364. item->u2.arglist->u1.str == argument
  1365. item->u2.arglist->next == next arg
  1366. item->u3.macro_statements == pval list of statements in macro body.
  1367. */
  1368. /* printf(" matching in MACRO %s, match_context=%s; retoncontmtch=%d; \n", item->u1.str, match_context, return_on_context_match); */
  1369. if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
  1370. /* printf("MACRO: match context is: %s\n", match_context); */
  1371. if (return_on_context_match && !strcmp(item->u1.str, match_context)) /* if we're just searching for a context, don't bother descending into them */ {
  1372. /* printf("Returning on matching macro %s\n", match_context); */
  1373. return item;
  1374. }
  1375. if (!return_on_context_match) {
  1376. /* printf("Descending into matching macro %s/%s\n", match_context, item->u1.str); */
  1377. if ((x=match_pval(item->u3.macro_statements))) {
  1378. /* printf("Responded with pval match %x\n", x); */
  1379. return x;
  1380. }
  1381. }
  1382. } else {
  1383. /* printf("Skipping context/macro %s\n", item->u1.str); */
  1384. }
  1385. break;
  1386. case PV_CONTEXT:
  1387. /* fields: item->u1.str == name of context
  1388. item->u2.statements == pval list of statements in context body
  1389. item->u3.abstract == int 1 if an abstract keyword were present
  1390. */
  1391. /* printf(" matching in CONTEXT\n"); */
  1392. if (!strcmp(match_context,"*") || !strcmp(item->u1.str, match_context)) {
  1393. if (return_on_context_match && !strcmp(item->u1.str, match_context)) {
  1394. /* printf("Returning on matching context %s\n", match_context); */
  1395. /* printf("non-CONTEXT: Responded with pval match %x\n", x); */
  1396. return item;
  1397. }
  1398. if (!return_on_context_match ) {
  1399. /* printf("Descending into matching context %s\n", match_context); */
  1400. if ((x=match_pval(item->u2.statements))) /* if we're just searching for a context, don't bother descending into them */ {
  1401. /* printf("CONTEXT: Responded with pval match %x\n", x); */
  1402. return x;
  1403. }
  1404. }
  1405. } else {
  1406. /* printf("Skipping context/macro %s\n", item->u1.str); */
  1407. }
  1408. break;
  1409. case PV_CASE:
  1410. /* fields: item->u1.str == value of case
  1411. item->u2.statements == pval list of statements under the case
  1412. */
  1413. /* printf(" matching in CASE\n"); */
  1414. if ((x=match_pval(item->u2.statements))) {
  1415. /* printf("CASE: Responded with pval match %x\n", x); */
  1416. return x;
  1417. }
  1418. break;
  1419. case PV_PATTERN:
  1420. /* fields: item->u1.str == value of case
  1421. item->u2.statements == pval list of statements under the case
  1422. */
  1423. /* printf(" matching in PATTERN\n"); */
  1424. if ((x=match_pval(item->u2.statements))) {
  1425. /* printf("PATTERN: Responded with pval match %x\n", x); */
  1426. return x;
  1427. }
  1428. break;
  1429. case PV_DEFAULT:
  1430. /* fields:
  1431. item->u2.statements == pval list of statements under the case
  1432. */
  1433. /* printf(" matching in DEFAULT\n"); */
  1434. if ((x=match_pval(item->u2.statements))) {
  1435. /* printf("DEFAULT: Responded with pval match %x\n", x); */
  1436. return x;
  1437. }
  1438. break;
  1439. case PV_CATCH:
  1440. /* fields: item->u1.str == name of extension to catch
  1441. item->u2.statements == pval list of statements in context body
  1442. */
  1443. /* printf(" matching in CATCH\n"); */
  1444. if ((x=match_pval(item->u2.statements))) {
  1445. /* printf("CATCH: Responded with pval match %x\n", x); */
  1446. return x;
  1447. }
  1448. break;
  1449. case PV_STATEMENTBLOCK:
  1450. /* fields: item->u1.list == pval list of statements in block, one per entry in the list
  1451. */
  1452. /* printf(" matching in STATEMENTBLOCK\n"); */
  1453. if ((x=match_pval(item->u1.list))) {
  1454. /* printf("STATEMENTBLOCK: Responded with pval match %x\n", x); */
  1455. return x;
  1456. }
  1457. break;
  1458. case PV_LABEL:
  1459. /* fields: item->u1.str == label name
  1460. */
  1461. /* printf("PV_LABEL %s (cont=%s, exten=%s\n",
  1462. item->u1.str, current_context->u1.str, (current_extension?current_extension->u1.str:"<macro>"));*/
  1463. if (count_labels) {
  1464. if (!strcmp(match_label, item->u1.str)) {
  1465. label_count++;
  1466. last_matched_label = item;
  1467. }
  1468. } else {
  1469. if (!strcmp(match_label, item->u1.str)) {
  1470. /* printf("LABEL: Responded with pval match %x\n", x); */
  1471. return item;
  1472. }
  1473. }
  1474. break;
  1475. case PV_FOR:
  1476. /* fields: item->u1.for_init == a string containing the initalizer
  1477. item->u2.for_test == a string containing the loop test
  1478. item->u3.for_inc == a string containing the loop increment
  1479. item->u4.for_statements == a pval list of statements in the for ()
  1480. */
  1481. /* printf(" matching in FOR\n"); */
  1482. if ((x=match_pval(item->u4.for_statements))) {
  1483. /* printf("FOR: Responded with pval match %x\n", x);*/
  1484. return x;
  1485. }
  1486. break;
  1487. case PV_WHILE:
  1488. /* fields: item->u1.str == the while conditional, as supplied by user
  1489. item->u2.statements == a pval list of statements in the while ()
  1490. */
  1491. /* printf(" matching in WHILE\n"); */
  1492. if ((x=match_pval(item->u2.statements))) {
  1493. /* printf("WHILE: Responded with pval match %x\n", x); */
  1494. return x;
  1495. }
  1496. break;
  1497. case PV_RANDOM:
  1498. /* fields: item->u1.str == the random number expression, as supplied by user
  1499. item->u2.statements == a pval list of statements in the if ()
  1500. item->u3.else_statements == a pval list of statements in the else
  1501. (could be zero)
  1502. fall thru to PV_IF */
  1503. case PV_IFTIME:
  1504. /* fields: item->u1.list == the time values, 4 of them, as PV_WORD structs in a list
  1505. item->u2.statements == a pval list of statements in the if ()
  1506. item->u3.else_statements == a pval list of statements in the else
  1507. (could be zero)
  1508. fall thru to PV_IF*/
  1509. case PV_IF:
  1510. /* fields: item->u1.str == the if conditional, as supplied by user
  1511. item->u2.statements == a pval list of statements in the if ()
  1512. item->u3.else_statements == a pval list of statements in the else
  1513. (could be zero)
  1514. */
  1515. /* printf(" matching in IF/IFTIME/RANDOM\n"); */
  1516. if ((x=match_pval(item->u2.statements))) {
  1517. return x;
  1518. }
  1519. if (item->u3.else_statements) {
  1520. if ((x=match_pval(item->u3.else_statements))) {
  1521. /* printf("IF/IFTIME/RANDOM: Responded with pval match %x\n", x); */
  1522. return x;
  1523. }
  1524. }
  1525. break;
  1526. case PV_SWITCH:
  1527. /* fields: item->u1.str == the switch expression
  1528. item->u2.statements == a pval list of statements in the switch,
  1529. (will be case statements, most likely!)
  1530. */
  1531. /* printf(" matching in SWITCH\n"); */
  1532. if ((x=match_pval(item->u2.statements))) {
  1533. /* printf("SWITCH: Responded with pval match %x\n", x); */
  1534. return x;
  1535. }
  1536. break;
  1537. case PV_EXTENSION:
  1538. /* fields: item->u1.str == the extension name, label, whatever it's called
  1539. item->u2.statements == a pval list of statements in the extension
  1540. item->u3.hints == a char * hint argument
  1541. item->u4.regexten == an int boolean. non-zero says that regexten was specified
  1542. */
  1543. /* printf(" matching in EXTENSION\n"); */
  1544. if (!strcmp(match_exten,"*") || extension_matches(item, match_exten, item->u1.str) ) {
  1545. /* printf("Descending into matching exten %s => %s\n", match_exten, item->u1.str); */
  1546. if (strcmp(match_label,"1") == 0) {
  1547. if (item->u2.statements) {
  1548. struct pval *p5 = item->u2.statements;
  1549. while (p5 && p5->type == PV_LABEL) /* find the first non-label statement in this context. If it exists, there's a "1" */
  1550. p5 = p5->next;
  1551. if (p5)
  1552. return p5;
  1553. else
  1554. return 0;
  1555. }
  1556. else
  1557. return 0;
  1558. }
  1559. if ((x=match_pval(item->u2.statements))) {
  1560. /* printf("EXTENSION: Responded with pval match %x\n", x); */
  1561. return x;
  1562. }
  1563. } else {
  1564. /* printf("Skipping exten %s\n", item->u1.str); */
  1565. }
  1566. break;
  1567. default:
  1568. /* printf(" matching in default = %d\n", item->type); */
  1569. break;
  1570. }
  1571. return 0;
  1572. }
  1573. struct pval *match_pval(pval *item)
  1574. {
  1575. pval *i;
  1576. for (i=item; i; i=i->next) {
  1577. pval *x;
  1578. /* printf(" -- match pval: item %d\n", i->type); */
  1579. if ((x = match_pval_item(i))) {
  1580. /* printf("match_pval: returning x=%x\n", (int)x); */
  1581. return x; /* cut the search short */
  1582. }
  1583. }
  1584. return 0;
  1585. }
  1586. #if 0
  1587. int count_labels_in_current_context(char *label)
  1588. {
  1589. label_count = 0;
  1590. count_labels = 1;
  1591. return_on_context_match = 0;
  1592. match_pval(current_context->u2.statements);
  1593. return label_count;
  1594. }
  1595. #endif
  1596. struct pval *find_first_label_in_current_context(char *label, pval *curr_cont)
  1597. {
  1598. /* printf(" --- Got args %s, %s\n", exten, label); */
  1599. struct pval *ret;
  1600. struct pval *p3;
  1601. count_labels = 0;
  1602. return_on_context_match = 0;
  1603. match_context = "*";
  1604. match_exten = "*";
  1605. match_label = label;
  1606. ret = match_pval(curr_cont);
  1607. if (ret)
  1608. return ret;
  1609. /* the target of the goto could be in an included context!! Fancy that!! */
  1610. /* look for includes in the current context */
  1611. for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
  1612. if (p3->type == PV_INCLUDES) {
  1613. struct pval *p4;
  1614. for (p4=p3->u1.list; p4; p4=p4->next) {
  1615. /* for each context pointed to, find it, then find a context/label that matches the
  1616. target here! */
  1617. char *incl_context = p4->u1.str;
  1618. /* find a matching context name */
  1619. struct pval *that_context = find_context(incl_context);
  1620. if (that_context) {
  1621. struct pval *x3;
  1622. x3 = find_first_label_in_current_context(label, that_context);
  1623. if (x3) {
  1624. return x3;
  1625. }
  1626. }
  1627. }
  1628. }
  1629. }
  1630. return 0;
  1631. }
  1632. struct pval *find_label_in_current_context(char *exten, char *label, pval *curr_cont)
  1633. {
  1634. /* printf(" --- Got args %s, %s\n", exten, label); */
  1635. struct pval *ret;
  1636. struct pval *p3;
  1637. count_labels = 0;
  1638. return_on_context_match = 0;
  1639. match_context = "*";
  1640. match_exten = exten;
  1641. match_label = label;
  1642. ret = match_pval(curr_cont->u2.statements);
  1643. if (ret)
  1644. return ret;
  1645. /* the target of the goto could be in an included context!! Fancy that!! */
  1646. /* look for includes in the current context */
  1647. for (p3=curr_cont->u2.statements; p3; p3=p3->next) {
  1648. if (p3->type == PV_INCLUDES) {
  1649. struct pval *p4;
  1650. for (p4=p3->u1.list; p4; p4=p4->next) {
  1651. /* for each context pointed to, find it, then find a context/label that matches the
  1652. target here! */
  1653. char *incl_context = p4->u1.str;
  1654. /* find a matching context name */
  1655. struct pval *that_context = find_context(incl_context);
  1656. if (that_context) {
  1657. struct pval *x3;
  1658. x3 = find_label_in_current_context(exten, label, that_context);
  1659. if (x3) {
  1660. return x3;
  1661. }
  1662. }
  1663. }
  1664. }
  1665. }
  1666. return 0;
  1667. }
  1668. static struct pval *find_label_in_current_extension(const char *label, pval *curr_ext)
  1669. {
  1670. /* printf(" --- Got args %s\n", label); */
  1671. count_labels = 0;
  1672. return_on_context_match = 0;
  1673. match_context = "*";
  1674. match_exten = "*";
  1675. match_label = label;
  1676. return match_pval(curr_ext);
  1677. }
  1678. static struct pval *find_label_in_current_db(const char *context, const char *exten, const char *label)
  1679. {
  1680. /* printf(" --- Got args %s, %s, %s\n", context, exten, label); */
  1681. count_labels = 0;
  1682. return_on_context_match = 0;
  1683. match_context = context;
  1684. match_exten = exten;
  1685. match_label = label;
  1686. return match_pval(current_db);
  1687. }
  1688. struct pval *find_macro(char *name)
  1689. {
  1690. return_on_context_match = 1;
  1691. count_labels = 0;
  1692. match_context = name;
  1693. match_exten = "*"; /* don't really need to set these, shouldn't be reached */
  1694. match_label = "*";
  1695. return match_pval(current_db);
  1696. }
  1697. struct pval *find_context(char *name)
  1698. {
  1699. return_on_context_match = 1;
  1700. count_labels = 0;
  1701. match_context = name;
  1702. match_exten = "*"; /* don't really need to set these, shouldn't be reached */
  1703. match_label = "*";
  1704. return match_pval(current_db);
  1705. }
  1706. int is_float(char *arg )
  1707. {
  1708. char *s;
  1709. for (s=arg; *s; s++) {
  1710. if (*s != '.' && (*s < '0' || *s > '9'))
  1711. return 0;
  1712. }
  1713. return 1;
  1714. }
  1715. int is_int(char *arg )
  1716. {
  1717. char *s;
  1718. for (s=arg; *s; s++) {
  1719. if (*s < '0' || *s > '9')
  1720. return 0;
  1721. }
  1722. return 1;
  1723. }
  1724. int is_empty(char *arg)
  1725. {
  1726. if (!arg)
  1727. return 1;
  1728. if (*arg == 0)
  1729. return 1;
  1730. while (*arg) {
  1731. if (*arg != ' ' && *arg != '\t')
  1732. return 0;
  1733. arg++;
  1734. }
  1735. return 1;
  1736. }
  1737. #ifdef AAL_ARGCHECK
  1738. int option_matches_j( struct argdesc *should, pval *is, struct argapp *app)
  1739. {
  1740. struct argchoice *ac;
  1741. char *opcop,*q,*p;
  1742. switch (should->dtype) {
  1743. case ARGD_OPTIONSET:
  1744. if ( strstr(is->u1.str,"${") )
  1745. return 0; /* no checking anything if there's a var reference in there! */
  1746. opcop = ast_strdupa(is->u1.str);
  1747. for (q=opcop;*q;q++) { /* erase the innards of X(innard) type arguments, so we don't get confused later */
  1748. if ( *q == '(' ) {
  1749. p = q+1;
  1750. while (*p && *p != ')' )
  1751. *p++ = '+';
  1752. q = p+1;
  1753. }
  1754. }
  1755. for (ac=app->opts; ac; ac=ac->next) {
  1756. if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */
  1757. return 0;
  1758. }
  1759. for (ac=app->opts; ac; ac=ac->next) {
  1760. if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
  1761. char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */
  1762. if (p && *p == 'j') {
  1763. ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The j option in the %s application call is not appropriate for AEL!\n",
  1764. is->filename, is->startline, is->endline, app->name);
  1765. errs++;
  1766. }
  1767. if (p) {
  1768. *p = '+';
  1769. if (ac->name[1] == '(') {
  1770. if (*(p+1) != '(') {
  1771. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call should have an (argument), but doesn't!\n",
  1772. is->filename, is->startline, is->endline, ac->name[0], app->name);
  1773. warns++;
  1774. }
  1775. }
  1776. }
  1777. }
  1778. }
  1779. for (q=opcop; *q; q++) {
  1780. if ( *q != '+' && *q != '(' && *q != ')') {
  1781. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: The %c option in the %s application call is not available as an option!\n",
  1782. is->filename, is->startline, is->endline, *q, app->name);
  1783. warns++;
  1784. }
  1785. }
  1786. return 1;
  1787. break;
  1788. default:
  1789. return 0;
  1790. }
  1791. }
  1792. int option_matches( struct argdesc *should, pval *is, struct argapp *app)
  1793. {
  1794. struct argchoice *ac;
  1795. char *opcop;
  1796. switch (should->dtype) {
  1797. case ARGD_STRING:
  1798. if (is_empty(is->u1.str) && should->type == ARGD_REQUIRED)
  1799. return 0;
  1800. if (is->u1.str && strlen(is->u1.str) > 0) /* most will match */
  1801. return 1;
  1802. break;
  1803. case ARGD_INT:
  1804. if (is_int(is->u1.str))
  1805. return 1;
  1806. else
  1807. return 0;
  1808. break;
  1809. case ARGD_FLOAT:
  1810. if (is_float(is->u1.str))
  1811. return 1;
  1812. else
  1813. return 0;
  1814. break;
  1815. case ARGD_ENUM:
  1816. if( !is->u1.str || strlen(is->u1.str) == 0 )
  1817. return 1; /* a null arg in the call will match an enum, I guess! */
  1818. for (ac=should->choices; ac; ac=ac->next) {
  1819. if (strcmp(ac->name,is->u1.str) == 0)
  1820. return 1;
  1821. }
  1822. return 0;
  1823. break;
  1824. case ARGD_OPTIONSET:
  1825. opcop = ast_strdupa(is->u1.str);
  1826. for (ac=app->opts; ac; ac=ac->next) {
  1827. if (strlen(ac->name)>1 && strchr(ac->name,'(') == 0 && strcmp(ac->name,is->u1.str) == 0) /* multichar option, no parens, and a match? */
  1828. return 1;
  1829. }
  1830. for (ac=app->opts; ac; ac=ac->next) {
  1831. if (strlen(ac->name)==1 || strchr(ac->name,'(')) {
  1832. char *p = strchr(opcop,ac->name[0]); /* wipe out all matched options in the user-supplied string */
  1833. if (p) {
  1834. *p = '+';
  1835. if (ac->name[1] == '(') {
  1836. if (*(p+1) == '(') {
  1837. char *q = p+1;
  1838. while (*q && *q != ')') {
  1839. *q++ = '+';
  1840. }
  1841. *q = '+';
  1842. }
  1843. }
  1844. }
  1845. }
  1846. }
  1847. return 1;
  1848. break;
  1849. case ARGD_VARARG:
  1850. return 1; /* matches anything */
  1851. break;
  1852. }
  1853. return 1; /* unless some for-sure match or non-match returns, then it must be close enough ... */
  1854. }
  1855. #endif
  1856. int check_app_args(pval* appcall, pval *arglist, struct argapp *app)
  1857. {
  1858. #ifdef AAL_ARGCHECK
  1859. struct argdesc *ad = app->args;
  1860. pval *pa;
  1861. int z;
  1862. for (pa = arglist; pa; pa=pa->next) {
  1863. if (!ad) {
  1864. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Extra argument %s not in application call to %s !\n",
  1865. arglist->filename, arglist->startline, arglist->endline, pa->u1.str, app->name);
  1866. warns++;
  1867. return 1;
  1868. } else {
  1869. /* find the first entry in the ad list that will match */
  1870. do {
  1871. if ( ad->dtype == ARGD_VARARG ) /* once we hit the VARARG, all bets are off. Discontinue the comparisons */
  1872. break;
  1873. z= option_matches( ad, pa, app);
  1874. if (!z) {
  1875. if ( !arglist )
  1876. arglist=appcall;
  1877. if (ad->type == ARGD_REQUIRED) {
  1878. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
  1879. arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
  1880. warns++;
  1881. return 1;
  1882. }
  1883. } else if (z && ad->dtype == ARGD_OPTIONSET) {
  1884. option_matches_j( ad, pa, app);
  1885. }
  1886. ad = ad->next;
  1887. } while (ad && !z);
  1888. }
  1889. }
  1890. /* any app nodes left, that are not optional? */
  1891. for ( ; ad; ad=ad->next) {
  1892. if (ad->type == ARGD_REQUIRED && ad->dtype != ARGD_VARARG) {
  1893. if ( !arglist )
  1894. arglist=appcall;
  1895. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: Required argument %s not in application call to %s !\n",
  1896. arglist->filename, arglist->startline, arglist->endline, ad->dtype==ARGD_OPTIONSET?"options":ad->name, app->name);
  1897. warns++;
  1898. return 1;
  1899. }
  1900. }
  1901. return 0;
  1902. #else
  1903. return 0;
  1904. #endif
  1905. }
  1906. void check_switch_expr(pval *item, struct argapp *apps)
  1907. {
  1908. #ifdef AAL_ARGCHECK
  1909. /* get and clean the variable name */
  1910. char *buff1, *p;
  1911. struct argapp *a,*a2;
  1912. struct appsetvar *v,*v2;
  1913. struct argchoice *c;
  1914. pval *t;
  1915. p = item->u1.str;
  1916. while (p && *p && (*p == ' ' || *p == '\t' || *p == '$' || *p == '{' ) )
  1917. p++;
  1918. buff1 = ast_strdupa(p);
  1919. while (strlen(buff1) > 0 && ( buff1[strlen(buff1)-1] == '}' || buff1[strlen(buff1)-1] == ' ' || buff1[strlen(buff1)-1] == '\t'))
  1920. buff1[strlen(buff1)-1] = 0;
  1921. /* buff1 now contains the variable name */
  1922. v = 0;
  1923. for (a=apps; a; a=a->next) {
  1924. for (v=a->setvars;v;v=v->next) {
  1925. if (strcmp(v->name,buff1) == 0) {
  1926. break;
  1927. }
  1928. }
  1929. if ( v )
  1930. break;
  1931. }
  1932. if (v && v->vals) {
  1933. /* we have a match, to a variable that has a set of determined values */
  1934. int def= 0;
  1935. int pat = 0;
  1936. int f1 = 0;
  1937. /* first of all, does this switch have a default case ? */
  1938. for (t=item->u2.statements; t; t=t->next) {
  1939. if (t->type == PV_DEFAULT) {
  1940. def =1;
  1941. break;
  1942. }
  1943. if (t->type == PV_PATTERN) {
  1944. pat++;
  1945. }
  1946. }
  1947. if (def || pat) /* nothing to check. All cases accounted for! */
  1948. return;
  1949. for (c=v->vals; c; c=c->next) {
  1950. f1 = 0;
  1951. for (t=item->u2.statements; t; t=t->next) {
  1952. if (t->type == PV_CASE || t->type == PV_PATTERN) {
  1953. if (!strcmp(t->u1.str,c->name)) {
  1954. f1 = 1;
  1955. break;
  1956. }
  1957. }
  1958. }
  1959. if (!f1) {
  1960. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: switch with expression(%s) does not handle the case of %s !\n",
  1961. item->filename, item->startline, item->endline, item->u1.str, c->name);
  1962. warns++;
  1963. }
  1964. }
  1965. /* next, is there an app call in the current exten, that would set this var? */
  1966. f1 = 0;
  1967. t = current_extension->u2.statements;
  1968. if ( t && t->type == PV_STATEMENTBLOCK )
  1969. t = t->u1.statements;
  1970. for (; t && t != item; t=t->next) {
  1971. if (t->type == PV_APPLICATION_CALL) {
  1972. /* find the application that matches the u1.str */
  1973. for (a2=apps; a2; a2=a2->next) {
  1974. if (strcasecmp(a2->name, t->u1.str)==0) {
  1975. for (v2=a2->setvars; v2; v2=v2->next) {
  1976. if (strcmp(v2->name, buff1) == 0) {
  1977. /* found an app that sets the var */
  1978. f1 = 1;
  1979. break;
  1980. }
  1981. }
  1982. }
  1983. if (f1)
  1984. break;
  1985. }
  1986. }
  1987. if (f1)
  1988. break;
  1989. }
  1990. /* see if it sets the var */
  1991. if (!f1) {
  1992. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find an application call in this extension that sets the expression (%s) value!\n",
  1993. item->filename, item->startline, item->endline, item->u1.str);
  1994. warns++;
  1995. }
  1996. }
  1997. #else
  1998. pval *t,*tl=0,*p2;
  1999. int def= 0;
  2000. /* first of all, does this switch have a default case ? */
  2001. for (t=item->u2.statements; t; t=t->next) {
  2002. if (t->type == PV_DEFAULT) {
  2003. def =1;
  2004. break;
  2005. }
  2006. tl = t;
  2007. }
  2008. if (def) /* nothing to check. All cases accounted for! */
  2009. return;
  2010. /* if no default, warn and insert a default case at the end */
  2011. p2 = tl->next = calloc(1, sizeof(struct pval));
  2012. p2->type = PV_DEFAULT;
  2013. p2->startline = tl->startline;
  2014. p2->endline = tl->endline;
  2015. p2->startcol = tl->startcol;
  2016. p2->endcol = tl->endcol;
  2017. p2->filename = strdup(tl->filename);
  2018. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: A default case was automatically added to the switch.\n",
  2019. p2->filename, p2->startline, p2->endline);
  2020. warns++;
  2021. #endif
  2022. }
  2023. static void check_context_names(void)
  2024. {
  2025. pval *i,*j;
  2026. for (i=current_db; i; i=i->next) {
  2027. if (i->type == PV_CONTEXT || i->type == PV_MACRO) {
  2028. for (j=i->next; j; j=j->next) {
  2029. if ( j->type == PV_CONTEXT || j->type == PV_MACRO ) {
  2030. if ( !strcmp(i->u1.str, j->u1.str) && !(i->u3.abstract&2) && !(j->u3.abstract&2) )
  2031. {
  2032. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: The context name (%s) is also declared in file %s, line %d-%d! (and neither is marked 'extend')\n",
  2033. i->filename, i->startline, i->endline, i->u1.str, j->filename, j->startline, j->endline);
  2034. warns++;
  2035. }
  2036. }
  2037. }
  2038. }
  2039. }
  2040. }
  2041. static void check_abstract_reference(pval *abstract_context)
  2042. {
  2043. pval *i,*j;
  2044. /* find some context includes that reference this context */
  2045. /* otherwise, print out a warning */
  2046. for (i=current_db; i; i=i->next) {
  2047. if (i->type == PV_CONTEXT) {
  2048. for (j=i->u2. statements; j; j=j->next) {
  2049. if ( j->type == PV_INCLUDES ) {
  2050. struct pval *p4;
  2051. for (p4=j->u1.list; p4; p4=p4->next) {
  2052. /* for each context pointed to, find it, then find a context/label that matches the
  2053. target here! */
  2054. if ( !strcmp(p4->u1.str, abstract_context->u1.str) )
  2055. return; /* found a match! */
  2056. }
  2057. }
  2058. }
  2059. }
  2060. }
  2061. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: Couldn't find a reference to this abstract context (%s) in any other context!\n",
  2062. abstract_context->filename, abstract_context->startline, abstract_context->endline, abstract_context->u1.str);
  2063. warns++;
  2064. }
  2065. void check_pval_item(pval *item, struct argapp *apps, int in_globals)
  2066. {
  2067. pval *lp;
  2068. #ifdef AAL_ARGCHECK
  2069. struct argapp *app, *found;
  2070. #endif
  2071. struct pval *macro_def;
  2072. struct pval *app_def;
  2073. char errmsg[4096];
  2074. char *strp;
  2075. switch (item->type) {
  2076. case PV_WORD:
  2077. /* fields: item->u1.str == string associated with this (word).
  2078. item->u2.arglist == pval list of 4 PV_WORD elements for time values (only in PV_INCLUDES) */
  2079. break;
  2080. case PV_MACRO:
  2081. /* fields: item->u1.str == name of macro
  2082. item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
  2083. item->u2.arglist->u1.str == argument
  2084. item->u2.arglist->next == next arg
  2085. item->u3.macro_statements == pval list of statements in macro body.
  2086. */
  2087. in_abstract_context = 0;
  2088. current_context = item;
  2089. current_extension = 0;
  2090. check_macro_returns(item);
  2091. for (lp=item->u2.arglist; lp; lp=lp->next) {
  2092. }
  2093. check_pval(item->u3.macro_statements, apps,in_globals);
  2094. break;
  2095. case PV_CONTEXT:
  2096. /* fields: item->u1.str == name of context
  2097. item->u2.statements == pval list of statements in context body
  2098. item->u3.abstract == int 1 if an abstract keyword were present
  2099. */
  2100. current_context = item;
  2101. current_extension = 0;
  2102. if ( item->u3.abstract ) {
  2103. in_abstract_context = 1;
  2104. check_abstract_reference(item);
  2105. } else
  2106. in_abstract_context = 0;
  2107. check_pval(item->u2.statements, apps,in_globals);
  2108. break;
  2109. case PV_MACRO_CALL:
  2110. /* fields: item->u1.str == name of macro to call
  2111. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  2112. item->u2.arglist->u1.str == argument
  2113. item->u2.arglist->next == next arg
  2114. */
  2115. #ifdef STANDALONE
  2116. /* if this is a standalone, we will need to make sure the
  2117. localized load of extensions.conf is done */
  2118. if (!extensions_dot_conf_loaded) {
  2119. localized_pbx_load_module();
  2120. extensions_dot_conf_loaded++;
  2121. }
  2122. #endif
  2123. macro_def = find_macro(item->u1.str);
  2124. if (!macro_def) {
  2125. #ifdef STANDALONE
  2126. struct pbx_find_info pfiq = {.stacklen = 0 };
  2127. struct pbx_find_info pfiq2 = {.stacklen = 0 };
  2128. /* look for the macro in the extensions.conf world */
  2129. pbx_find_extension(NULL, NULL, &pfiq, item->u1.str, "s", 1, NULL, NULL, E_MATCH);
  2130. if (pfiq.status != STATUS_SUCCESS) {
  2131. char namebuf2[256];
  2132. snprintf(namebuf2, 256, "macro-%s", item->u1.str);
  2133. /* look for the macro in the extensions.conf world */
  2134. pbx_find_extension(NULL, NULL, &pfiq2, namebuf2, "s", 1, NULL, NULL, E_MATCH);
  2135. if (pfiq2.status == STATUS_SUCCESS) {
  2136. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (macro-%s was found in the extensions.conf stuff, but we are using gosubs!)\n",
  2137. item->filename, item->startline, item->endline, item->u1.str, item->u1.str);
  2138. warns++;
  2139. } else {
  2140. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to non-existent %s! (Not even in the extensions.conf stuff!)\n",
  2141. item->filename, item->startline, item->endline, item->u1.str);
  2142. warns++;
  2143. }
  2144. }
  2145. #else
  2146. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s cannot be found in the AEL code!\n",
  2147. item->filename, item->startline, item->endline, item->u1.str);
  2148. warns++;
  2149. #endif
  2150. #ifdef THIS_IS_1DOT4
  2151. char namebuf2[256];
  2152. snprintf(namebuf2, 256, "macro-%s", item->u1.str);
  2153. /* look for the macro in the extensions.conf world */
  2154. pbx_find_extension(NULL, NULL, &pfiq, namebuf2, "s", 1, NULL, NULL, E_MATCH);
  2155. if (pfiq.status != STATUS_SUCCESS) {
  2156. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: macro call to %s was not found in the AEL, nor the extensions.conf !\n",
  2157. item->filename, item->startline, item->endline, item->u1.str);
  2158. warns++;
  2159. }
  2160. #endif
  2161. } else if (macro_def->type != PV_MACRO) {
  2162. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: macro call to %s references a context, not a macro!\n",
  2163. item->filename, item->startline, item->endline, item->u1.str);
  2164. errs++;
  2165. } else {
  2166. /* macro_def is a MACRO, so do the args match in number? */
  2167. int hereargs = 0;
  2168. int thereargs = 0;
  2169. for (lp=item->u2.arglist; lp; lp=lp->next) {
  2170. hereargs++;
  2171. }
  2172. for (lp=macro_def->u2.arglist; lp; lp=lp->next) {
  2173. thereargs++;
  2174. }
  2175. if (hereargs != thereargs ) {
  2176. ast_log(LOG_ERROR, "Error: file %s, line %d-%d: The macro call to %s has %d arguments, but the macro definition has %d arguments\n",
  2177. item->filename, item->startline, item->endline, item->u1.str, hereargs, thereargs);
  2178. errs++;
  2179. }
  2180. }
  2181. break;
  2182. case PV_APPLICATION_CALL:
  2183. /* fields: item->u1.str == name of application to call
  2184. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  2185. item->u2.arglist->u1.str == argument
  2186. item->u2.arglist->next == next arg
  2187. */
  2188. /* Need to check to see if the application is available! */
  2189. app_def = find_context(item->u1.str);
  2190. if (app_def && app_def->type == PV_MACRO) {
  2191. ast_log(LOG_ERROR,"Error: file %s, line %d-%d: application call to %s references an existing macro, but had no & preceding it!\n",
  2192. item->filename, item->startline, item->endline, item->u1.str);
  2193. errs++;
  2194. }
  2195. if (strcasecmp(item->u1.str,"GotoIf") == 0
  2196. || strcasecmp(item->u1.str,"GotoIfTime") == 0
  2197. || strcasecmp(item->u1.str,"while") == 0
  2198. || strcasecmp(item->u1.str,"endwhile") == 0
  2199. || strcasecmp(item->u1.str,"random") == 0
  2200. || strcasecmp(item->u1.str,"gosub") == 0
  2201. || strcasecmp(item->u1.str,"gosubif") == 0
  2202. || strcasecmp(item->u1.str,"continuewhile") == 0
  2203. || strcasecmp(item->u1.str,"endwhile") == 0
  2204. || strcasecmp(item->u1.str,"execif") == 0
  2205. || strcasecmp(item->u1.str,"execiftime") == 0
  2206. || strcasecmp(item->u1.str,"exitwhile") == 0
  2207. || strcasecmp(item->u1.str,"goto") == 0
  2208. || strcasecmp(item->u1.str,"macro") == 0
  2209. || strcasecmp(item->u1.str,"macroexclusive") == 0
  2210. || strcasecmp(item->u1.str,"macroif") == 0
  2211. || strcasecmp(item->u1.str,"stackpop") == 0
  2212. || strcasecmp(item->u1.str,"execIf") == 0 ) {
  2213. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s affects flow of control, and needs to be re-written using AEL if, while, goto, etc. keywords instead!\n",
  2214. item->filename, item->startline, item->endline, item->u1.str);
  2215. warns++;
  2216. }
  2217. if (strcasecmp(item->u1.str,"macroexit") == 0) {
  2218. ast_log(LOG_WARNING, "Warning: file %s, line %d-%d: I am converting the MacroExit call here to a return statement.\n",
  2219. item->filename, item->startline, item->endline);
  2220. item->type = PV_RETURN;
  2221. free(item->u1.str);
  2222. item->u1.str = 0;
  2223. }
  2224. #ifdef AAL_ARGCHECK
  2225. found = 0;
  2226. for (app=apps; app; app=app->next) {
  2227. if (strcasecmp(app->name, item->u1.str) == 0) {
  2228. found =app;
  2229. break;
  2230. }
  2231. }
  2232. if (!found) {
  2233. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: application call to %s not listed in applist database!\n",
  2234. item->filename, item->startline, item->endline, item->u1.str);
  2235. warns++;
  2236. } else
  2237. check_app_args(item, item->u2.arglist, app);
  2238. #endif
  2239. break;
  2240. case PV_CASE:
  2241. /* fields: item->u1.str == value of case
  2242. item->u2.statements == pval list of statements under the case
  2243. */
  2244. /* Make sure sequence of statements under case is terminated with goto, return, or break */
  2245. /* find the last statement */
  2246. check_pval(item->u2.statements, apps,in_globals);
  2247. break;
  2248. case PV_PATTERN:
  2249. /* fields: item->u1.str == value of case
  2250. item->u2.statements == pval list of statements under the case
  2251. */
  2252. /* Make sure sequence of statements under case is terminated with goto, return, or break */
  2253. /* find the last statement */
  2254. check_pval(item->u2.statements, apps,in_globals);
  2255. break;
  2256. case PV_DEFAULT:
  2257. /* fields:
  2258. item->u2.statements == pval list of statements under the case
  2259. */
  2260. check_pval(item->u2.statements, apps,in_globals);
  2261. break;
  2262. case PV_CATCH:
  2263. /* fields: item->u1.str == name of extension to catch
  2264. item->u2.statements == pval list of statements in context body
  2265. */
  2266. check_pval(item->u2.statements, apps,in_globals);
  2267. break;
  2268. case PV_SWITCHES:
  2269. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  2270. */
  2271. check_pval(item->u1.list, apps,in_globals);
  2272. break;
  2273. case PV_ESWITCHES:
  2274. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  2275. */
  2276. check_pval(item->u1.list, apps,in_globals);
  2277. break;
  2278. case PV_INCLUDES:
  2279. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  2280. */
  2281. check_pval(item->u1.list, apps,in_globals);
  2282. check_includes(item);
  2283. for (lp=item->u1.list; lp; lp=lp->next){
  2284. char *incl_context = lp->u1.str;
  2285. struct pval *that_context = find_context(incl_context);
  2286. if ( lp->u2.arglist ) {
  2287. check_timerange(lp->u2.arglist);
  2288. check_dow(lp->u2.arglist->next);
  2289. check_day(lp->u2.arglist->next->next);
  2290. check_month(lp->u2.arglist->next->next->next);
  2291. }
  2292. if (that_context) {
  2293. find_pval_gotos(that_context->u2.statements,0);
  2294. }
  2295. }
  2296. break;
  2297. case PV_STATEMENTBLOCK:
  2298. /* fields: item->u1.list == pval list of statements in block, one per entry in the list
  2299. */
  2300. check_pval(item->u1.list, apps,in_globals);
  2301. break;
  2302. case PV_VARDEC:
  2303. /* fields: item->u1.str == variable name
  2304. item->u2.val == variable value to assign
  2305. */
  2306. /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
  2307. if( !in_globals ) { /* don't check stuff inside the globals context; no wrapping in $[ ] there... */
  2308. snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val);
  2309. ast_expr_register_extra_error_info(errmsg);
  2310. ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
  2311. ast_expr_clear_extra_error_info();
  2312. if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
  2313. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
  2314. item->filename, item->startline, item->endline, item->u2.val);
  2315. warns++;
  2316. }
  2317. check_expr2_input(item,item->u2.val);
  2318. }
  2319. break;
  2320. case PV_LOCALVARDEC:
  2321. /* fields: item->u1.str == variable name
  2322. item->u2.val == variable value to assign
  2323. */
  2324. /* the RHS of a vardec is encapsulated in a $[] expr. Is it legal? */
  2325. snprintf(errmsg,sizeof(errmsg), "file %s, line %d, columns %d-%d, variable declaration expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.val);
  2326. ast_expr_register_extra_error_info(errmsg);
  2327. ast_expr(item->u2.val, expr_output, sizeof(expr_output),NULL);
  2328. ast_expr_clear_extra_error_info();
  2329. if ( strpbrk(item->u2.val,"~!-+<>=*/&^") && !strstr(item->u2.val,"${") ) {
  2330. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
  2331. item->filename, item->startline, item->endline, item->u2.val);
  2332. warns++;
  2333. }
  2334. check_expr2_input(item,item->u2.val);
  2335. break;
  2336. case PV_GOTO:
  2337. /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
  2338. item->u1.list->u1.str == where the data on a PV_WORD will always be.
  2339. */
  2340. /* don't check goto's in abstract contexts */
  2341. if ( in_abstract_context )
  2342. break;
  2343. check_goto(item);
  2344. break;
  2345. case PV_LABEL:
  2346. /* fields: item->u1.str == label name
  2347. */
  2348. if ( strspn(item->u1.str, "0123456789") == strlen(item->u1.str) ) {
  2349. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: label '%s' is numeric, this is bad practice!\n",
  2350. item->filename, item->startline, item->endline, item->u1.str);
  2351. warns++;
  2352. }
  2353. check_label(item);
  2354. break;
  2355. case PV_FOR:
  2356. /* fields: item->u1.for_init == a string containing the initalizer
  2357. item->u2.for_test == a string containing the loop test
  2358. item->u3.for_inc == a string containing the loop increment
  2359. item->u4.for_statements == a pval list of statements in the for ()
  2360. */
  2361. snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, for test expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u2.for_test);
  2362. ast_expr_register_extra_error_info(errmsg);
  2363. strp = strchr(item->u1.for_init, '=');
  2364. if (strp) {
  2365. ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
  2366. }
  2367. ast_expr(item->u2.for_test, expr_output, sizeof(expr_output),NULL);
  2368. strp = strchr(item->u3.for_inc, '=');
  2369. if (strp) {
  2370. ast_expr(strp+1, expr_output, sizeof(expr_output),NULL);
  2371. }
  2372. if ( strpbrk(item->u2.for_test,"~!-+<>=*/&^") && !strstr(item->u2.for_test,"${") ) {
  2373. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
  2374. item->filename, item->startline, item->endline, item->u2.for_test);
  2375. warns++;
  2376. }
  2377. if ( strpbrk(item->u3.for_inc,"~!-+<>=*/&^") && !strstr(item->u3.for_inc,"${") ) {
  2378. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
  2379. item->filename, item->startline, item->endline, item->u3.for_inc);
  2380. warns++;
  2381. }
  2382. check_expr2_input(item,item->u2.for_test);
  2383. check_expr2_input(item,item->u3.for_inc);
  2384. ast_expr_clear_extra_error_info();
  2385. check_pval(item->u4.for_statements, apps,in_globals);
  2386. break;
  2387. case PV_WHILE:
  2388. /* fields: item->u1.str == the while conditional, as supplied by user
  2389. item->u2.statements == a pval list of statements in the while ()
  2390. */
  2391. snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, while expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str);
  2392. ast_expr_register_extra_error_info(errmsg);
  2393. ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
  2394. ast_expr_clear_extra_error_info();
  2395. if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
  2396. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression %s has operators, but no variables. Interesting...\n",
  2397. item->filename, item->startline, item->endline, item->u1.str);
  2398. warns++;
  2399. }
  2400. check_expr2_input(item,item->u1.str);
  2401. check_pval(item->u2.statements, apps,in_globals);
  2402. break;
  2403. case PV_BREAK:
  2404. /* fields: none
  2405. */
  2406. check_break(item);
  2407. break;
  2408. case PV_RETURN:
  2409. /* fields: none
  2410. */
  2411. break;
  2412. case PV_CONTINUE:
  2413. /* fields: none
  2414. */
  2415. check_continue(item);
  2416. break;
  2417. case PV_RANDOM:
  2418. /* fields: item->u1.str == the random number expression, as supplied by user
  2419. item->u2.statements == a pval list of statements in the if ()
  2420. item->u3.else_statements == a pval list of statements in the else
  2421. (could be zero)
  2422. */
  2423. snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, random expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str);
  2424. ast_expr_register_extra_error_info(errmsg);
  2425. ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
  2426. ast_expr_clear_extra_error_info();
  2427. if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
  2428. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: random expression '%s' has operators, but no variables. Interesting...\n",
  2429. item->filename, item->startline, item->endline, item->u1.str);
  2430. warns++;
  2431. }
  2432. check_expr2_input(item,item->u1.str);
  2433. check_pval(item->u2.statements, apps,in_globals);
  2434. if (item->u3.else_statements) {
  2435. check_pval(item->u3.else_statements, apps,in_globals);
  2436. }
  2437. break;
  2438. case PV_IFTIME:
  2439. /* fields: item->u1.list == the if time values, 4 of them, each in PV_WORD, linked list
  2440. item->u2.statements == a pval list of statements in the if ()
  2441. item->u3.else_statements == a pval list of statements in the else
  2442. (could be zero)
  2443. */
  2444. if ( item->u2.arglist ) {
  2445. check_timerange(item->u1.list);
  2446. check_dow(item->u1.list->next);
  2447. check_day(item->u1.list->next->next);
  2448. check_month(item->u1.list->next->next->next);
  2449. }
  2450. check_pval(item->u2.statements, apps,in_globals);
  2451. if (item->u3.else_statements) {
  2452. check_pval(item->u3.else_statements, apps,in_globals);
  2453. }
  2454. break;
  2455. case PV_IF:
  2456. /* fields: item->u1.str == the if conditional, as supplied by user
  2457. item->u2.statements == a pval list of statements in the if ()
  2458. item->u3.else_statements == a pval list of statements in the else
  2459. (could be zero)
  2460. */
  2461. snprintf(errmsg,sizeof(errmsg),"file %s, line %d, columns %d-%d, if expr '%s':", item->filename, item->startline, item->startcol, item->endcol, item->u1.str);
  2462. ast_expr_register_extra_error_info(errmsg);
  2463. ast_expr(item->u1.str, expr_output, sizeof(expr_output),NULL);
  2464. ast_expr_clear_extra_error_info();
  2465. if ( strpbrk(item->u1.str,"~!-+<>=*/&^") && !strstr(item->u1.str,"${") ) {
  2466. ast_log(LOG_WARNING,"Warning: file %s, line %d-%d: expression '%s' has operators, but no variables. Interesting...\n",
  2467. item->filename, item->startline, item->endline, item->u1.str);
  2468. warns++;
  2469. }
  2470. check_expr2_input(item,item->u1.str);
  2471. check_pval(item->u2.statements, apps,in_globals);
  2472. if (item->u3.else_statements) {
  2473. check_pval(item->u3.else_statements, apps,in_globals);
  2474. }
  2475. break;
  2476. case PV_SWITCH:
  2477. /* fields: item->u1.str == the switch expression
  2478. item->u2.statements == a pval list of statements in the switch,
  2479. (will be case statements, most likely!)
  2480. */
  2481. /* we can check the switch expression, see if it matches any of the app variables...
  2482. if it does, then, are all the possible cases accounted for? */
  2483. check_switch_expr(item, apps);
  2484. check_pval(item->u2.statements, apps,in_globals);
  2485. break;
  2486. case PV_EXTENSION:
  2487. /* fields: item->u1.str == the extension name, label, whatever it's called
  2488. item->u2.statements == a pval list of statements in the extension
  2489. item->u3.hints == a char * hint argument
  2490. item->u4.regexten == an int boolean. non-zero says that regexten was specified
  2491. */
  2492. current_extension = item ;
  2493. check_pval(item->u2.statements, apps,in_globals);
  2494. break;
  2495. case PV_IGNOREPAT:
  2496. /* fields: item->u1.str == the ignorepat data
  2497. */
  2498. break;
  2499. case PV_GLOBALS:
  2500. /* fields: item->u1.statements == pval list of statements, usually vardecs
  2501. */
  2502. in_abstract_context = 0;
  2503. check_pval(item->u1.statements, apps, 1);
  2504. break;
  2505. default:
  2506. break;
  2507. }
  2508. }
  2509. void check_pval(pval *item, struct argapp *apps, int in_globals)
  2510. {
  2511. pval *i;
  2512. /* checks to do:
  2513. 1. Do goto's point to actual labels?
  2514. 2. Do macro calls reference a macro?
  2515. 3. Does the number of macro args match the definition?
  2516. 4. Is a macro call missing its & at the front?
  2517. 5. Application calls-- we could check syntax for existing applications,
  2518. but I need some some sort of universal description bnf for a general
  2519. sort of method for checking arguments, in number, maybe even type, at least.
  2520. Don't want to hand code checks for hundreds of applications.
  2521. */
  2522. for (i=item; i; i=i->next) {
  2523. check_pval_item(i,apps,in_globals);
  2524. }
  2525. }
  2526. void ael2_semantic_check(pval *item, int *arg_errs, int *arg_warns, int *arg_notes)
  2527. {
  2528. #ifdef AAL_ARGCHECK
  2529. int argapp_errs =0;
  2530. char *rfilename;
  2531. #endif
  2532. struct argapp *apps=0;
  2533. if (!item)
  2534. return; /* don't check an empty tree */
  2535. #ifdef AAL_ARGCHECK
  2536. rfilename = ast_alloca(10 + strlen(ast_config_AST_VAR_DIR));
  2537. sprintf(rfilename, "%s/applist", ast_config_AST_VAR_DIR);
  2538. apps = argdesc_parse(rfilename, &argapp_errs); /* giveth */
  2539. #endif
  2540. current_db = item;
  2541. errs = warns = notes = 0;
  2542. check_context_names();
  2543. check_pval(item, apps, 0);
  2544. #ifdef AAL_ARGCHECK
  2545. argdesc_destroy(apps); /* taketh away */
  2546. #endif
  2547. current_db = 0;
  2548. *arg_errs = errs;
  2549. *arg_warns = warns;
  2550. *arg_notes = notes;
  2551. }
  2552. /* =============================================================================================== */
  2553. /* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */
  2554. /* =============================================================================================== */
  2555. static int control_statement_count = 0;
  2556. struct ael_priority *new_prio(void)
  2557. {
  2558. struct ael_priority *x = (struct ael_priority *)calloc(sizeof(struct ael_priority),1);
  2559. return x;
  2560. }
  2561. struct ael_extension *new_exten(void)
  2562. {
  2563. struct ael_extension *x = (struct ael_extension *)calloc(sizeof(struct ael_extension),1);
  2564. return x;
  2565. }
  2566. void linkprio(struct ael_extension *exten, struct ael_priority *prio, struct ael_extension *mother_exten)
  2567. {
  2568. char *p1, *p2;
  2569. if (!exten->plist) {
  2570. exten->plist = prio;
  2571. exten->plist_last = prio;
  2572. } else {
  2573. exten->plist_last->next = prio;
  2574. exten->plist_last = prio;
  2575. }
  2576. if( !prio->exten )
  2577. prio->exten = exten; /* don't override the switch value */
  2578. /* The following code will cause all priorities within an extension
  2579. to have ${EXTEN} or ${EXTEN: replaced with ~~EXTEN~~, which is
  2580. set just before the first switch in an exten. The switches
  2581. will muck up the original ${EXTEN} value, so we save it away
  2582. and the user accesses this copy instead. */
  2583. if (prio->appargs && ((mother_exten && mother_exten->has_switch) || exten->has_switch) ) {
  2584. while ((p1 = strstr(prio->appargs, "${EXTEN}"))) {
  2585. p2 = malloc(strlen(prio->appargs)+5);
  2586. *p1 = 0;
  2587. strcpy(p2, prio->appargs);
  2588. strcat(p2, "${~~EXTEN~~}");
  2589. if (*(p1+8))
  2590. strcat(p2, p1+8);
  2591. free(prio->appargs);
  2592. prio->appargs = p2;
  2593. }
  2594. while ((p1 = strstr(prio->appargs, "${EXTEN:"))) {
  2595. p2 = malloc(strlen(prio->appargs)+5);
  2596. *p1 = 0;
  2597. strcpy(p2, prio->appargs);
  2598. strcat(p2, "${~~EXTEN~~:");
  2599. if (*(p1+8))
  2600. strcat(p2, p1+8);
  2601. free(prio->appargs);
  2602. prio->appargs = p2;
  2603. }
  2604. }
  2605. }
  2606. void destroy_extensions(struct ael_extension *exten)
  2607. {
  2608. struct ael_extension *ne, *nen;
  2609. for (ne=exten; ne; ne=nen) {
  2610. struct ael_priority *pe, *pen;
  2611. if (ne->name)
  2612. free(ne->name);
  2613. /* cidmatch fields are allocated with name, and freed when
  2614. the name field is freed. Don't do a free for this field,
  2615. unless you LIKE to see a crash! */
  2616. if (ne->hints)
  2617. free(ne->hints);
  2618. for (pe=ne->plist; pe; pe=pen) {
  2619. pen = pe->next;
  2620. if (pe->app)
  2621. free(pe->app);
  2622. pe->app = 0;
  2623. if (pe->appargs)
  2624. free(pe->appargs);
  2625. pe->appargs = 0;
  2626. pe->origin = 0;
  2627. pe->goto_true = 0;
  2628. pe->goto_false = 0;
  2629. free(pe);
  2630. }
  2631. nen = ne->next_exten;
  2632. ne->next_exten = 0;
  2633. ne->plist =0;
  2634. ne->plist_last = 0;
  2635. ne->next_exten = 0;
  2636. ne->loop_break = 0;
  2637. ne->loop_continue = 0;
  2638. free(ne);
  2639. }
  2640. }
  2641. static int label_inside_case(pval *label)
  2642. {
  2643. pval *p = label;
  2644. while( p && p->type != PV_MACRO && p->type != PV_CONTEXT ) /* early cutout, sort of */ {
  2645. if( p->type == PV_CASE || p->type == PV_DEFAULT || p->type == PV_PATTERN ) {
  2646. return 1;
  2647. }
  2648. p = p->dad;
  2649. }
  2650. return 0;
  2651. }
  2652. static void linkexten(struct ael_extension *exten, struct ael_extension *add)
  2653. {
  2654. add->next_exten = exten->next_exten; /* this will reverse the order. Big deal. */
  2655. exten->next_exten = add;
  2656. }
  2657. static void remove_spaces_before_equals(char *str)
  2658. {
  2659. char *p;
  2660. while( str && *str && *str != '=' )
  2661. {
  2662. if( *str == ' ' || *str == '\n' || *str == '\r' || *str == '\t' )
  2663. {
  2664. p = str;
  2665. while( *p )
  2666. {
  2667. *p = *(p+1);
  2668. p++;
  2669. }
  2670. }
  2671. else
  2672. str++;
  2673. }
  2674. }
  2675. /* =============================================================================================== */
  2676. /* "CODE" GENERATOR -- Convert the AEL representation to asterisk extension language */
  2677. /* =============================================================================================== */
  2678. static void gen_match_to_pattern(char *pattern, char *result)
  2679. {
  2680. /* the result will be a string that will be matched by pattern */
  2681. char *p=pattern, *t=result;
  2682. while (*p) {
  2683. if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
  2684. *t++ = '9';
  2685. else if (*p == '[') {
  2686. char *z = p+1;
  2687. while (*z != ']')
  2688. z++;
  2689. if (*(z+1)== ']')
  2690. z++;
  2691. *t++=*(p+1); /* use the first char in the set */
  2692. p = z;
  2693. } else {
  2694. *t++ = *p;
  2695. }
  2696. p++;
  2697. }
  2698. *t++ = 0; /* cap it off */
  2699. }
  2700. /* ==== a set of routines to search for a switch statement contained in the pval description */
  2701. int find_switch_item(pval *item);
  2702. int contains_switch(pval *item);
  2703. int find_switch_item(pval *item)
  2704. {
  2705. switch ( item->type ) {
  2706. case PV_LOCALVARDEC:
  2707. /* fields: item->u1.str == string associated with this (word). */
  2708. break;
  2709. case PV_WORD:
  2710. /* fields: item->u1.str == string associated with this (word). */
  2711. break;
  2712. case PV_MACRO:
  2713. /* fields: item->u1.str == name of macro
  2714. item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
  2715. item->u2.arglist->u1.str == argument
  2716. item->u2.arglist->next == next arg
  2717. item->u3.macro_statements == pval list of statements in macro body.
  2718. */
  2719. /* had better not see this */
  2720. if (contains_switch(item->u3.macro_statements))
  2721. return 1;
  2722. break;
  2723. case PV_CONTEXT:
  2724. /* fields: item->u1.str == name of context
  2725. item->u2.statements == pval list of statements in context body
  2726. item->u3.abstract == int 1 if an abstract keyword were present
  2727. */
  2728. /* had better not see this */
  2729. if (contains_switch(item->u2.statements))
  2730. return 1;
  2731. break;
  2732. case PV_MACRO_CALL:
  2733. /* fields: item->u1.str == name of macro to call
  2734. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  2735. item->u2.arglist->u1.str == argument
  2736. item->u2.arglist->next == next arg
  2737. */
  2738. break;
  2739. case PV_APPLICATION_CALL:
  2740. /* fields: item->u1.str == name of application to call
  2741. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  2742. item->u2.arglist->u1.str == argument
  2743. item->u2.arglist->next == next arg
  2744. */
  2745. break;
  2746. case PV_CASE:
  2747. /* fields: item->u1.str == value of case
  2748. item->u2.statements == pval list of statements under the case
  2749. */
  2750. /* had better not see this */
  2751. if (contains_switch(item->u2.statements))
  2752. return 1;
  2753. break;
  2754. case PV_PATTERN:
  2755. /* fields: item->u1.str == value of case
  2756. item->u2.statements == pval list of statements under the case
  2757. */
  2758. /* had better not see this */
  2759. if (contains_switch(item->u2.statements))
  2760. return 1;
  2761. break;
  2762. case PV_DEFAULT:
  2763. /* fields:
  2764. item->u2.statements == pval list of statements under the case
  2765. */
  2766. /* had better not see this */
  2767. if (contains_switch(item->u2.statements))
  2768. return 1;
  2769. break;
  2770. case PV_CATCH:
  2771. /* fields: item->u1.str == name of extension to catch
  2772. item->u2.statements == pval list of statements in context body
  2773. */
  2774. /* had better not see this */
  2775. if (contains_switch(item->u2.statements))
  2776. return 1;
  2777. break;
  2778. case PV_SWITCHES:
  2779. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  2780. */
  2781. break;
  2782. case PV_ESWITCHES:
  2783. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  2784. */
  2785. break;
  2786. case PV_INCLUDES:
  2787. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  2788. item->u2.arglist == pval list of 4 PV_WORD elements for time values
  2789. */
  2790. break;
  2791. case PV_STATEMENTBLOCK:
  2792. /* fields: item->u1.list == pval list of statements in block, one per entry in the list
  2793. */
  2794. if (contains_switch(item->u1.list) )
  2795. return 1;
  2796. break;
  2797. case PV_VARDEC:
  2798. /* fields: item->u1.str == variable name
  2799. item->u2.val == variable value to assign
  2800. */
  2801. break;
  2802. case PV_GOTO:
  2803. /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
  2804. item->u1.list->u1.str == where the data on a PV_WORD will always be.
  2805. */
  2806. break;
  2807. case PV_LABEL:
  2808. /* fields: item->u1.str == label name
  2809. */
  2810. break;
  2811. case PV_FOR:
  2812. /* fields: item->u1.for_init == a string containing the initalizer
  2813. item->u2.for_test == a string containing the loop test
  2814. item->u3.for_inc == a string containing the loop increment
  2815. item->u4.for_statements == a pval list of statements in the for ()
  2816. */
  2817. if (contains_switch(item->u4.for_statements))
  2818. return 1;
  2819. break;
  2820. case PV_WHILE:
  2821. /* fields: item->u1.str == the while conditional, as supplied by user
  2822. item->u2.statements == a pval list of statements in the while ()
  2823. */
  2824. if (contains_switch(item->u2.statements))
  2825. return 1;
  2826. break;
  2827. case PV_BREAK:
  2828. /* fields: none
  2829. */
  2830. break;
  2831. case PV_RETURN:
  2832. /* fields: none
  2833. */
  2834. break;
  2835. case PV_CONTINUE:
  2836. /* fields: none
  2837. */
  2838. break;
  2839. case PV_IFTIME:
  2840. /* fields: item->u1.list == there are 4 linked PV_WORDs here.
  2841. item->u2.statements == a pval list of statements in the if ()
  2842. item->u3.else_statements == a pval list of statements in the else
  2843. (could be zero)
  2844. */
  2845. if (contains_switch(item->u2.statements))
  2846. return 1;
  2847. if ( item->u3.else_statements ) {
  2848. if (contains_switch(item->u3.else_statements))
  2849. return 1;
  2850. }
  2851. break;
  2852. case PV_RANDOM:
  2853. /* fields: item->u1.str == the random number expression, as supplied by user
  2854. item->u2.statements == a pval list of statements in the if ()
  2855. item->u3.else_statements == a pval list of statements in the else
  2856. (could be zero)
  2857. */
  2858. if (contains_switch(item->u2.statements))
  2859. return 1;
  2860. if ( item->u3.else_statements ) {
  2861. if (contains_switch(item->u3.else_statements))
  2862. return 1;
  2863. }
  2864. break;
  2865. case PV_IF:
  2866. /* fields: item->u1.str == the if conditional, as supplied by user
  2867. item->u2.statements == a pval list of statements in the if ()
  2868. item->u3.else_statements == a pval list of statements in the else
  2869. (could be zero)
  2870. */
  2871. if (contains_switch(item->u2.statements))
  2872. return 1;
  2873. if ( item->u3.else_statements ) {
  2874. if (contains_switch(item->u3.else_statements))
  2875. return 1;
  2876. }
  2877. break;
  2878. case PV_SWITCH:
  2879. /* fields: item->u1.str == the switch expression
  2880. item->u2.statements == a pval list of statements in the switch,
  2881. (will be case statements, most likely!)
  2882. */
  2883. return 1; /* JACKPOT */
  2884. break;
  2885. case PV_EXTENSION:
  2886. /* fields: item->u1.str == the extension name, label, whatever it's called
  2887. item->u2.statements == a pval list of statements in the extension
  2888. item->u3.hints == a char * hint argument
  2889. item->u4.regexten == an int boolean. non-zero says that regexten was specified
  2890. */
  2891. if (contains_switch(item->u2.statements))
  2892. return 1;
  2893. break;
  2894. case PV_IGNOREPAT:
  2895. /* fields: item->u1.str == the ignorepat data
  2896. */
  2897. break;
  2898. case PV_GLOBALS:
  2899. /* fields: item->u1.statements == pval list of statements, usually vardecs
  2900. */
  2901. break;
  2902. }
  2903. return 0;
  2904. }
  2905. int contains_switch(pval *item)
  2906. {
  2907. pval *i;
  2908. for (i=item; i; i=i->next) {
  2909. if (find_switch_item(i))
  2910. return 1;
  2911. }
  2912. return 0;
  2913. }
  2914. static int gen_prios(struct ael_extension *exten, char *label, pval *statement, struct ael_extension *mother_exten, struct ast_context *this_context )
  2915. {
  2916. pval *p,*p2,*p3;
  2917. struct ael_priority *pr;
  2918. struct ael_priority *for_init, *for_test, *for_inc, *for_loop, *for_end;
  2919. struct ael_priority *while_test, *while_loop, *while_end;
  2920. struct ael_priority *switch_set, *switch_test, *switch_end, *fall_thru, *switch_empty;
  2921. struct ael_priority *if_test, *if_end, *if_skip, *if_false;
  2922. #ifdef OLD_RAND_ACTION
  2923. struct ael_priority *rand_test, *rand_end, *rand_skip;
  2924. #endif
  2925. char *buf1;
  2926. char *buf2;
  2927. char *new_label;
  2928. char *strp, *strp2;
  2929. int default_exists;
  2930. int local_control_statement_count;
  2931. int first;
  2932. struct ael_priority *loop_break_save;
  2933. struct ael_priority *loop_continue_save;
  2934. struct ael_extension *switch_case,*switch_null;
  2935. if (!(buf1 = malloc(BUF_SIZE))) {
  2936. return -1;
  2937. }
  2938. if (!(buf2 = malloc(BUF_SIZE))) {
  2939. return -1;
  2940. }
  2941. if (!(new_label = malloc(BUF_SIZE))) {
  2942. return -1;
  2943. }
  2944. if ((mother_exten && !mother_exten->checked_switch) || (exten && !exten->checked_switch)) {
  2945. if (contains_switch(statement)) { /* only run contains_switch if you haven't checked before */
  2946. if (mother_exten) {
  2947. if (!mother_exten->has_switch) {
  2948. for (first = 1; first >= 0; first--) {
  2949. switch_set = new_prio();
  2950. switch_set->type = AEL_APPCALL;
  2951. if (!ast_compat_app_set) {
  2952. switch_set->app = strdup("MSet");
  2953. } else {
  2954. switch_set->app = strdup("Set");
  2955. }
  2956. /* Are we likely inside a gosub subroutine? */
  2957. if (!strcmp(mother_exten->name, "~~s~~") && first) {
  2958. /* If we're not actually within a gosub, this will fail, but the
  2959. * second time through, it will get set. If we are within gosub,
  2960. * the second time through is redundant, but acceptable. */
  2961. switch_set->appargs = strdup("LOCAL(~~EXTEN~~)=${EXTEN}");
  2962. } else {
  2963. switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
  2964. first = 0;
  2965. }
  2966. linkprio(exten, switch_set, mother_exten);
  2967. mother_exten->has_switch = 1;
  2968. mother_exten->checked_switch = 1;
  2969. if (exten) {
  2970. exten->has_switch = 1;
  2971. exten->checked_switch = 1;
  2972. }
  2973. }
  2974. }
  2975. } else if (exten) {
  2976. if (!exten->has_switch) {
  2977. for (first = 1; first >= 0; first--) {
  2978. switch_set = new_prio();
  2979. switch_set->type = AEL_APPCALL;
  2980. if (!ast_compat_app_set) {
  2981. switch_set->app = strdup("MSet");
  2982. } else {
  2983. switch_set->app = strdup("Set");
  2984. }
  2985. /* Are we likely inside a gosub subroutine? */
  2986. if (!strcmp(exten->name, "~~s~~")) {
  2987. /* If we're not actually within a gosub, this will fail, but the
  2988. * second time through, it will get set. If we are within gosub,
  2989. * the second time through is redundant, but acceptable. */
  2990. switch_set->appargs = strdup("LOCAL(~~EXTEN~~)=${EXTEN}");
  2991. } else {
  2992. switch_set->appargs = strdup("~~EXTEN~~=${EXTEN}");
  2993. first = 0;
  2994. }
  2995. linkprio(exten, switch_set, mother_exten);
  2996. exten->has_switch = 1;
  2997. exten->checked_switch = 1;
  2998. if (mother_exten) {
  2999. mother_exten->has_switch = 1;
  3000. mother_exten->checked_switch = 1;
  3001. }
  3002. }
  3003. }
  3004. }
  3005. } else {
  3006. if (mother_exten) {
  3007. mother_exten->checked_switch = 1;
  3008. }
  3009. if (exten) {
  3010. exten->checked_switch = 1;
  3011. }
  3012. }
  3013. }
  3014. for (p=statement; p; p=p->next) {
  3015. switch (p->type) {
  3016. case PV_VARDEC:
  3017. pr = new_prio();
  3018. pr->type = AEL_APPCALL;
  3019. snprintf(buf1, BUF_SIZE, "%s=$[%s]", p->u1.str, p->u2.val);
  3020. if (!ast_compat_app_set) {
  3021. pr->app = strdup("MSet");
  3022. } else {
  3023. pr->app = strdup("Set");
  3024. }
  3025. remove_spaces_before_equals(buf1);
  3026. pr->appargs = strdup(buf1);
  3027. pr->origin = p;
  3028. linkprio(exten, pr, mother_exten);
  3029. break;
  3030. case PV_LOCALVARDEC:
  3031. pr = new_prio();
  3032. pr->type = AEL_APPCALL;
  3033. snprintf(buf1, BUF_SIZE, "LOCAL(%s)=$[%s]", p->u1.str, p->u2.val);
  3034. if (!ast_compat_app_set) {
  3035. pr->app = strdup("MSet");
  3036. } else {
  3037. pr->app = strdup("Set");
  3038. }
  3039. remove_spaces_before_equals(buf1);
  3040. pr->appargs = strdup(buf1);
  3041. pr->origin = p;
  3042. linkprio(exten, pr, mother_exten);
  3043. break;
  3044. case PV_GOTO:
  3045. pr = new_prio();
  3046. pr->type = AEL_APPCALL;
  3047. p->u2.goto_target = get_goto_target(p);
  3048. if( p->u2.goto_target ) {
  3049. p->u3.goto_target_in_case = label_inside_case(p->u2.goto_target);
  3050. }
  3051. if (!p->u1.list->next) /* just one */ {
  3052. pr->app = strdup("Goto");
  3053. if (!mother_exten)
  3054. pr->appargs = strdup(p->u1.list->u1.str);
  3055. else { /* for the case of simple within-extension gotos in case/pattern/default statement blocks: */
  3056. snprintf(buf1, BUF_SIZE, "%s,%s", mother_exten->name, p->u1.list->u1.str);
  3057. pr->appargs = strdup(buf1);
  3058. }
  3059. } else if (p->u1.list->next && !p->u1.list->next->next) /* two */ {
  3060. snprintf(buf1, BUF_SIZE, "%s,%s", p->u1.list->u1.str, p->u1.list->next->u1.str);
  3061. pr->app = strdup("Goto");
  3062. pr->appargs = strdup(buf1);
  3063. } else if (p->u1.list->next && p->u1.list->next->next) {
  3064. snprintf(buf1, BUF_SIZE, "%s,%s,%s", p->u1.list->u1.str,
  3065. p->u1.list->next->u1.str,
  3066. p->u1.list->next->next->u1.str);
  3067. pr->app = strdup("Goto");
  3068. pr->appargs = strdup(buf1);
  3069. }
  3070. pr->origin = p;
  3071. linkprio(exten, pr, mother_exten);
  3072. break;
  3073. case PV_LABEL:
  3074. pr = new_prio();
  3075. pr->type = AEL_LABEL;
  3076. pr->origin = p;
  3077. p->u3.compiled_label = exten;
  3078. linkprio(exten, pr, mother_exten);
  3079. break;
  3080. case PV_FOR:
  3081. control_statement_count++;
  3082. loop_break_save = exten->loop_break; /* save them, then restore before leaving */
  3083. loop_continue_save = exten->loop_continue;
  3084. snprintf(new_label, BUF_SIZE, "for_%s_%d", label, control_statement_count);
  3085. for_init = new_prio();
  3086. for_inc = new_prio();
  3087. for_test = new_prio();
  3088. for_loop = new_prio();
  3089. for_end = new_prio();
  3090. for_init->type = AEL_APPCALL;
  3091. for_inc->type = AEL_APPCALL;
  3092. for_test->type = AEL_FOR_CONTROL;
  3093. for_test->goto_false = for_end;
  3094. for_loop->type = AEL_CONTROL1; /* simple goto */
  3095. for_end->type = AEL_APPCALL;
  3096. if (!ast_compat_app_set) {
  3097. for_init->app = strdup("MSet");
  3098. } else {
  3099. for_init->app = strdup("Set");
  3100. }
  3101. strcpy(buf2,p->u1.for_init);
  3102. remove_spaces_before_equals(buf2);
  3103. strp = strchr(buf2, '=');
  3104. if (strp) {
  3105. strp2 = strchr(p->u1.for_init, '=');
  3106. *(strp+1) = 0;
  3107. strcat(buf2,"$[");
  3108. strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
  3109. strcat(buf2,"]");
  3110. for_init->appargs = strdup(buf2);
  3111. } else {
  3112. strp2 = p->u1.for_init;
  3113. while (*strp2 && isspace(*strp2))
  3114. strp2++;
  3115. if (*strp2 == '&') { /* itsa macro call */
  3116. char *strp3 = strp2+1;
  3117. while (*strp3 && isspace(*strp3))
  3118. strp3++;
  3119. strcpy(buf2, strp3);
  3120. strp3 = strchr(buf2,'(');
  3121. if (strp3) {
  3122. *strp3 = '|';
  3123. }
  3124. while ((strp3=strchr(buf2,','))) {
  3125. *strp3 = '|';
  3126. }
  3127. strp3 = strrchr(buf2, ')');
  3128. if (strp3)
  3129. *strp3 = 0; /* remove the closing paren */
  3130. for_init->appargs = strdup(buf2);
  3131. free(for_init->app);
  3132. for_init->app = strdup("Macro");
  3133. } else { /* must be a regular app call */
  3134. char *strp3;
  3135. strcpy(buf2, strp2);
  3136. strp3 = strchr(buf2,'(');
  3137. if (strp3) {
  3138. *strp3 = 0;
  3139. free(for_init->app);
  3140. for_init->app = strdup(buf2);
  3141. for_init->appargs = strdup(strp3+1);
  3142. strp3 = strrchr(for_init->appargs, ')');
  3143. if (strp3)
  3144. *strp3 = 0; /* remove the closing paren */
  3145. }
  3146. }
  3147. }
  3148. strcpy(buf2,p->u3.for_inc);
  3149. remove_spaces_before_equals(buf2);
  3150. strp = strchr(buf2, '=');
  3151. if (strp) { /* there's an = in this part; that means an assignment. set it up */
  3152. strp2 = strchr(p->u3.for_inc, '=');
  3153. *(strp+1) = 0;
  3154. strcat(buf2,"$[");
  3155. strncat(buf2,strp2+1, BUF_SIZE-strlen(strp2+1)-2);
  3156. strcat(buf2,"]");
  3157. for_inc->appargs = strdup(buf2);
  3158. if (!ast_compat_app_set) {
  3159. for_inc->app = strdup("MSet");
  3160. } else {
  3161. for_inc->app = strdup("Set");
  3162. }
  3163. } else {
  3164. strp2 = p->u3.for_inc;
  3165. while (*strp2 && isspace(*strp2))
  3166. strp2++;
  3167. if (*strp2 == '&') { /* itsa macro call */
  3168. char *strp3 = strp2+1;
  3169. while (*strp3 && isspace(*strp3))
  3170. strp3++;
  3171. strcpy(buf2, strp3);
  3172. strp3 = strchr(buf2,'(');
  3173. if (strp3) {
  3174. *strp3 = ',';
  3175. }
  3176. strp3 = strrchr(buf2, ')');
  3177. if (strp3)
  3178. *strp3 = 0; /* remove the closing paren */
  3179. for_inc->appargs = strdup(buf2);
  3180. for_inc->app = strdup("Macro");
  3181. } else { /* must be a regular app call */
  3182. char *strp3;
  3183. strcpy(buf2, strp2);
  3184. strp3 = strchr(buf2,'(');
  3185. if (strp3) {
  3186. *strp3 = 0;
  3187. for_inc->app = strdup(buf2);
  3188. for_inc->appargs = strdup(strp3+1);
  3189. strp3 = strrchr(for_inc->appargs, ')');
  3190. if (strp3)
  3191. *strp3 = 0; /* remove the closing paren */
  3192. }
  3193. }
  3194. }
  3195. snprintf(buf1, BUF_SIZE, "$[%s]",p->u2.for_test);
  3196. for_test->app = 0;
  3197. for_test->appargs = strdup(buf1);
  3198. for_loop->goto_true = for_test;
  3199. snprintf(buf1, BUF_SIZE, "Finish for_%s_%d", label, control_statement_count);
  3200. for_end->app = strdup("NoOp");
  3201. for_end->appargs = strdup(buf1);
  3202. /* link & load! */
  3203. linkprio(exten, for_init, mother_exten);
  3204. linkprio(exten, for_test, mother_exten);
  3205. /* now, put the body of the for loop here */
  3206. exten->loop_break = for_end;
  3207. exten->loop_continue = for_inc;
  3208. if (gen_prios(exten, new_label, p->u4.for_statements, mother_exten, this_context)) { /* this will link in all the statements here */
  3209. return -1;
  3210. }
  3211. linkprio(exten, for_inc, mother_exten);
  3212. linkprio(exten, for_loop, mother_exten);
  3213. linkprio(exten, for_end, mother_exten);
  3214. exten->loop_break = loop_break_save;
  3215. exten->loop_continue = loop_continue_save;
  3216. for_loop->origin = p;
  3217. break;
  3218. case PV_WHILE:
  3219. control_statement_count++;
  3220. loop_break_save = exten->loop_break; /* save them, then restore before leaving */
  3221. loop_continue_save = exten->loop_continue;
  3222. snprintf(new_label, BUF_SIZE, "while_%s_%d", label, control_statement_count);
  3223. while_test = new_prio();
  3224. while_loop = new_prio();
  3225. while_end = new_prio();
  3226. while_test->type = AEL_FOR_CONTROL;
  3227. while_test->goto_false = while_end;
  3228. while_loop->type = AEL_CONTROL1; /* simple goto */
  3229. while_end->type = AEL_APPCALL;
  3230. snprintf(buf1, BUF_SIZE, "$[%s]",p->u1.str);
  3231. while_test->app = 0;
  3232. while_test->appargs = strdup(buf1);
  3233. while_loop->goto_true = while_test;
  3234. snprintf(buf1, BUF_SIZE, "Finish while_%s_%d", label, control_statement_count);
  3235. while_end->app = strdup("NoOp");
  3236. while_end->appargs = strdup(buf1);
  3237. linkprio(exten, while_test, mother_exten);
  3238. /* now, put the body of the for loop here */
  3239. exten->loop_break = while_end;
  3240. exten->loop_continue = while_test;
  3241. if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the while body statements here */
  3242. return -1;
  3243. }
  3244. linkprio(exten, while_loop, mother_exten);
  3245. linkprio(exten, while_end, mother_exten);
  3246. exten->loop_break = loop_break_save;
  3247. exten->loop_continue = loop_continue_save;
  3248. while_loop->origin = p;
  3249. break;
  3250. case PV_SWITCH:
  3251. control_statement_count++;
  3252. local_control_statement_count = control_statement_count;
  3253. loop_break_save = exten->loop_break; /* save them, then restore before leaving */
  3254. loop_continue_save = exten->loop_continue;
  3255. snprintf(new_label, BUF_SIZE, "sw_%s_%d", label, control_statement_count);
  3256. switch_test = new_prio();
  3257. switch_end = new_prio();
  3258. switch_test->type = AEL_APPCALL;
  3259. switch_end->type = AEL_APPCALL;
  3260. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", control_statement_count, p->u1.str);
  3261. switch_test->app = strdup("Goto");
  3262. switch_test->appargs = strdup(buf1);
  3263. snprintf(buf1, BUF_SIZE, "Finish switch_%s_%d", label, control_statement_count);
  3264. switch_end->app = strdup("NoOp");
  3265. switch_end->appargs = strdup(buf1);
  3266. switch_end->origin = p;
  3267. switch_end->exten = exten;
  3268. linkprio(exten, switch_test, mother_exten);
  3269. linkprio(exten, switch_end, mother_exten);
  3270. exten->loop_break = switch_end;
  3271. exten->loop_continue = 0;
  3272. default_exists = 0;
  3273. for (p2=p->u2.statements; p2; p2=p2->next) {
  3274. /* now, for each case/default put the body of the for loop here */
  3275. if (p2->type == PV_CASE) {
  3276. /* ok, generate a extension and link it in */
  3277. switch_case = new_exten();
  3278. if (mother_exten && mother_exten->checked_switch) {
  3279. switch_case->has_switch = mother_exten->has_switch;
  3280. switch_case->checked_switch = mother_exten->checked_switch;
  3281. }
  3282. if (exten && exten->checked_switch) {
  3283. switch_case->has_switch = exten->has_switch;
  3284. switch_case->checked_switch = exten->checked_switch;
  3285. }
  3286. switch_case->context = this_context;
  3287. switch_case->is_switch = 1;
  3288. /* the break/continue locations are inherited from parent */
  3289. switch_case->loop_break = exten->loop_break;
  3290. switch_case->loop_continue = exten->loop_continue;
  3291. linkexten(exten,switch_case);
  3292. snprintf(buf1, BUF_SIZE, "sw_%d_%s", local_control_statement_count, p2->u1.str);
  3293. switch_case->name = strdup(buf1);
  3294. snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count);
  3295. if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the case body statements here */
  3296. return -1;
  3297. }
  3298. /* here is where we write code to "fall thru" to the next case... if there is one... */
  3299. for (p3=p2->u2.statements; p3; p3=p3->next) {
  3300. if (!p3->next)
  3301. break;
  3302. }
  3303. /* p3 now points the last statement... */
  3304. if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN) ) {
  3305. /* is there a following CASE/PATTERN/DEFAULT? */
  3306. if (p2->next && p2->next->type == PV_CASE) {
  3307. fall_thru = new_prio();
  3308. fall_thru->type = AEL_APPCALL;
  3309. fall_thru->app = strdup("Goto");
  3310. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
  3311. fall_thru->appargs = strdup(buf1);
  3312. linkprio(switch_case, fall_thru, mother_exten);
  3313. } else if (p2->next && p2->next->type == PV_PATTERN) {
  3314. fall_thru = new_prio();
  3315. fall_thru->type = AEL_APPCALL;
  3316. fall_thru->app = strdup("Goto");
  3317. gen_match_to_pattern(p2->next->u1.str, buf2);
  3318. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
  3319. fall_thru->appargs = strdup(buf1);
  3320. linkprio(switch_case, fall_thru, mother_exten);
  3321. } else if (p2->next && p2->next->type == PV_DEFAULT) {
  3322. fall_thru = new_prio();
  3323. fall_thru->type = AEL_APPCALL;
  3324. fall_thru->app = strdup("Goto");
  3325. snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
  3326. fall_thru->appargs = strdup(buf1);
  3327. linkprio(switch_case, fall_thru, mother_exten);
  3328. } else if (!p2->next) {
  3329. fall_thru = new_prio();
  3330. fall_thru->type = AEL_CONTROL1;
  3331. fall_thru->goto_true = switch_end;
  3332. fall_thru->app = strdup("Goto");
  3333. linkprio(switch_case, fall_thru, mother_exten);
  3334. }
  3335. }
  3336. if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
  3337. char buf[2000];
  3338. struct ael_priority *np2 = new_prio();
  3339. np2->type = AEL_APPCALL;
  3340. np2->app = strdup("NoOp");
  3341. snprintf(buf, BUF_SIZE, "End of Extension %s", switch_case->name);
  3342. np2->appargs = strdup(buf);
  3343. linkprio(switch_case, np2, mother_exten);
  3344. switch_case-> return_target = np2;
  3345. }
  3346. } else if (p2->type == PV_PATTERN) {
  3347. /* ok, generate a extension and link it in */
  3348. switch_case = new_exten();
  3349. if (mother_exten && mother_exten->checked_switch) {
  3350. switch_case->has_switch = mother_exten->has_switch;
  3351. switch_case->checked_switch = mother_exten->checked_switch;
  3352. }
  3353. if (exten && exten->checked_switch) {
  3354. switch_case->has_switch = exten->has_switch;
  3355. switch_case->checked_switch = exten->checked_switch;
  3356. }
  3357. switch_case->context = this_context;
  3358. switch_case->is_switch = 1;
  3359. /* the break/continue locations are inherited from parent */
  3360. switch_case->loop_break = exten->loop_break;
  3361. switch_case->loop_continue = exten->loop_continue;
  3362. linkexten(exten,switch_case);
  3363. snprintf(buf1, BUF_SIZE, "_sw_%d_%s", local_control_statement_count, p2->u1.str);
  3364. switch_case->name = strdup(buf1);
  3365. snprintf(new_label, BUF_SIZE, "sw_%s_%s_%d", label, p2->u1.str, local_control_statement_count);
  3366. if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the while body statements here */
  3367. return -1;
  3368. }
  3369. /* here is where we write code to "fall thru" to the next case... if there is one... */
  3370. for (p3=p2->u2.statements; p3; p3=p3->next) {
  3371. if (!p3->next)
  3372. break;
  3373. }
  3374. /* p3 now points the last statement... */
  3375. if (!p3 || ( p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
  3376. /* is there a following CASE/PATTERN/DEFAULT? */
  3377. if (p2->next && p2->next->type == PV_CASE) {
  3378. fall_thru = new_prio();
  3379. fall_thru->type = AEL_APPCALL;
  3380. fall_thru->app = strdup("Goto");
  3381. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
  3382. fall_thru->appargs = strdup(buf1);
  3383. linkprio(switch_case, fall_thru, mother_exten);
  3384. } else if (p2->next && p2->next->type == PV_PATTERN) {
  3385. fall_thru = new_prio();
  3386. fall_thru->type = AEL_APPCALL;
  3387. fall_thru->app = strdup("Goto");
  3388. gen_match_to_pattern(p2->next->u1.str, buf2);
  3389. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
  3390. fall_thru->appargs = strdup(buf1);
  3391. linkprio(switch_case, fall_thru, mother_exten);
  3392. } else if (p2->next && p2->next->type == PV_DEFAULT) {
  3393. fall_thru = new_prio();
  3394. fall_thru->type = AEL_APPCALL;
  3395. fall_thru->app = strdup("Goto");
  3396. snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
  3397. fall_thru->appargs = strdup(buf1);
  3398. linkprio(switch_case, fall_thru, mother_exten);
  3399. } else if (!p2->next) {
  3400. fall_thru = new_prio();
  3401. fall_thru->type = AEL_CONTROL1;
  3402. fall_thru->goto_true = switch_end;
  3403. fall_thru->app = strdup("Goto");
  3404. linkprio(switch_case, fall_thru, mother_exten);
  3405. }
  3406. }
  3407. if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
  3408. char buf[2000];
  3409. struct ael_priority *np2 = new_prio();
  3410. np2->type = AEL_APPCALL;
  3411. np2->app = strdup("NoOp");
  3412. snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
  3413. np2->appargs = strdup(buf);
  3414. linkprio(switch_case, np2, mother_exten);
  3415. switch_case-> return_target = np2;
  3416. }
  3417. } else if (p2->type == PV_DEFAULT) {
  3418. /* ok, generate a extension and link it in */
  3419. switch_case = new_exten();
  3420. if (mother_exten && mother_exten->checked_switch) {
  3421. switch_case->has_switch = mother_exten->has_switch;
  3422. switch_case->checked_switch = mother_exten->checked_switch;
  3423. }
  3424. if (exten && exten->checked_switch) {
  3425. switch_case->has_switch = exten->has_switch;
  3426. switch_case->checked_switch = exten->checked_switch;
  3427. }
  3428. switch_case->context = this_context;
  3429. switch_case->is_switch = 1;
  3430. /* new: the default case intros a pattern with ., which covers ALMOST everything.
  3431. but it doesn't cover a NULL pattern. So, we'll define a null extension to match
  3432. that goto's the default extension. */
  3433. default_exists++;
  3434. switch_null = new_exten();
  3435. if (mother_exten && mother_exten->checked_switch) {
  3436. switch_null->has_switch = mother_exten->has_switch;
  3437. switch_null->checked_switch = mother_exten->checked_switch;
  3438. }
  3439. if (exten && exten->checked_switch) {
  3440. switch_null->has_switch = exten->has_switch;
  3441. switch_null->checked_switch = exten->checked_switch;
  3442. }
  3443. switch_null->context = this_context;
  3444. switch_null->is_switch = 1;
  3445. switch_empty = new_prio();
  3446. snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
  3447. switch_empty->app = strdup("Goto");
  3448. switch_empty->appargs = strdup(buf1);
  3449. linkprio(switch_null, switch_empty, mother_exten);
  3450. snprintf(buf1, BUF_SIZE, "sw_%d_", local_control_statement_count);
  3451. switch_null->name = strdup(buf1);
  3452. switch_null->loop_break = exten->loop_break;
  3453. switch_null->loop_continue = exten->loop_continue;
  3454. linkexten(exten,switch_null);
  3455. /* the break/continue locations are inherited from parent */
  3456. switch_case->loop_break = exten->loop_break;
  3457. switch_case->loop_continue = exten->loop_continue;
  3458. linkexten(exten,switch_case);
  3459. snprintf(buf1, BUF_SIZE, "_sw_%d_.", local_control_statement_count);
  3460. switch_case->name = strdup(buf1);
  3461. snprintf(new_label, BUF_SIZE, "sw_%s_default_%d", label, local_control_statement_count);
  3462. if (gen_prios(switch_case, new_label, p2->u2.statements, exten, this_context)) { /* this will link in all the default: body statements here */
  3463. return -1;
  3464. }
  3465. /* here is where we write code to "fall thru" to the next case... if there is one... */
  3466. for (p3=p2->u2.statements; p3; p3=p3->next) {
  3467. if (!p3->next)
  3468. break;
  3469. }
  3470. /* p3 now points the last statement... */
  3471. if (!p3 || (p3->type != PV_GOTO && p3->type != PV_BREAK && p3->type != PV_RETURN)) {
  3472. /* is there a following CASE/PATTERN/DEFAULT? */
  3473. if (p2->next && p2->next->type == PV_CASE) {
  3474. fall_thru = new_prio();
  3475. fall_thru->type = AEL_APPCALL;
  3476. fall_thru->app = strdup("Goto");
  3477. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, p2->next->u1.str);
  3478. fall_thru->appargs = strdup(buf1);
  3479. linkprio(switch_case, fall_thru, mother_exten);
  3480. } else if (p2->next && p2->next->type == PV_PATTERN) {
  3481. fall_thru = new_prio();
  3482. fall_thru->type = AEL_APPCALL;
  3483. fall_thru->app = strdup("Goto");
  3484. gen_match_to_pattern(p2->next->u1.str, buf2);
  3485. snprintf(buf1, BUF_SIZE, "sw_%d_%s,10", local_control_statement_count, buf2);
  3486. fall_thru->appargs = strdup(buf1);
  3487. linkprio(switch_case, fall_thru, mother_exten);
  3488. } else if (p2->next && p2->next->type == PV_DEFAULT) {
  3489. fall_thru = new_prio();
  3490. fall_thru->type = AEL_APPCALL;
  3491. fall_thru->app = strdup("Goto");
  3492. snprintf(buf1, BUF_SIZE, "sw_%d_.,10", local_control_statement_count);
  3493. fall_thru->appargs = strdup(buf1);
  3494. linkprio(switch_case, fall_thru, mother_exten);
  3495. } else if (!p2->next) {
  3496. fall_thru = new_prio();
  3497. fall_thru->type = AEL_CONTROL1;
  3498. fall_thru->goto_true = switch_end;
  3499. fall_thru->app = strdup("Goto");
  3500. linkprio(switch_case, fall_thru, mother_exten);
  3501. }
  3502. }
  3503. if (switch_case->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
  3504. char buf[2000];
  3505. struct ael_priority *np2 = new_prio();
  3506. np2->type = AEL_APPCALL;
  3507. np2->app = strdup("NoOp");
  3508. snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
  3509. np2->appargs = strdup(buf);
  3510. linkprio(switch_case, np2, mother_exten);
  3511. switch_case-> return_target = np2;
  3512. }
  3513. } else {
  3514. /* what could it be??? */
  3515. }
  3516. }
  3517. exten->loop_break = loop_break_save;
  3518. exten->loop_continue = loop_continue_save;
  3519. switch_test->origin = p;
  3520. switch_end->origin = p;
  3521. break;
  3522. case PV_MACRO_CALL:
  3523. pr = new_prio();
  3524. pr->type = AEL_APPCALL;
  3525. snprintf(buf1, BUF_SIZE, "%s,~~s~~,1", p->u1.str);
  3526. first = 1;
  3527. for (p2 = p->u2.arglist; p2; p2 = p2->next) {
  3528. if (first)
  3529. {
  3530. strcat(buf1,"(");
  3531. first = 0;
  3532. }
  3533. else
  3534. strcat(buf1,",");
  3535. strcat(buf1,p2->u1.str);
  3536. }
  3537. if (!first)
  3538. strcat(buf1,")");
  3539. pr->app = strdup("Gosub");
  3540. pr->appargs = strdup(buf1);
  3541. pr->origin = p;
  3542. linkprio(exten, pr, mother_exten);
  3543. break;
  3544. case PV_APPLICATION_CALL:
  3545. pr = new_prio();
  3546. pr->type = AEL_APPCALL;
  3547. buf1[0] = 0;
  3548. for (p2 = p->u2.arglist; p2; p2 = p2->next) {
  3549. if (p2 != p->u2.arglist )
  3550. strcat(buf1,",");
  3551. strcat(buf1,p2->u1.str);
  3552. }
  3553. pr->app = strdup(p->u1.str);
  3554. pr->appargs = strdup(buf1);
  3555. pr->origin = p;
  3556. linkprio(exten, pr, mother_exten);
  3557. break;
  3558. case PV_BREAK:
  3559. pr = new_prio();
  3560. pr->type = AEL_CONTROL1; /* simple goto */
  3561. pr->goto_true = exten->loop_break;
  3562. pr->origin = p;
  3563. linkprio(exten, pr, mother_exten);
  3564. break;
  3565. case PV_RETURN: /* hmmmm */
  3566. pr = new_prio();
  3567. pr->type = AEL_RETURN; /* simple Return */
  3568. /* exten->return_needed++; */
  3569. pr->app = strdup("Return");
  3570. pr->appargs = strdup("");
  3571. pr->origin = p;
  3572. linkprio(exten, pr, mother_exten);
  3573. break;
  3574. case PV_CONTINUE:
  3575. pr = new_prio();
  3576. pr->type = AEL_CONTROL1; /* simple goto */
  3577. pr->goto_true = exten->loop_continue;
  3578. pr->origin = p;
  3579. linkprio(exten, pr, mother_exten);
  3580. break;
  3581. case PV_IFTIME:
  3582. control_statement_count++;
  3583. snprintf(new_label, BUF_SIZE, "iftime_%s_%d", label, control_statement_count);
  3584. if_test = new_prio();
  3585. if_test->type = AEL_IFTIME_CONTROL;
  3586. snprintf(buf1, BUF_SIZE, "%s,%s,%s,%s",
  3587. p->u1.list->u1.str,
  3588. p->u1.list->next->u1.str,
  3589. p->u1.list->next->next->u1.str,
  3590. p->u1.list->next->next->next->u1.str);
  3591. if_test->app = 0;
  3592. if_test->appargs = strdup(buf1);
  3593. if_test->origin = p;
  3594. if_end = new_prio();
  3595. if_end->type = AEL_APPCALL;
  3596. snprintf(buf1, BUF_SIZE, "Finish iftime_%s_%d", label, control_statement_count);
  3597. if_end->app = strdup("NoOp");
  3598. if_end->appargs = strdup(buf1);
  3599. if (p->u3.else_statements) {
  3600. if_skip = new_prio();
  3601. if_skip->type = AEL_CONTROL1; /* simple goto */
  3602. if_skip->goto_true = if_end;
  3603. if_skip->origin = p;
  3604. } else {
  3605. if_skip = 0;
  3606. if_test->goto_false = if_end;
  3607. }
  3608. if_false = new_prio();
  3609. if_false->type = AEL_CONTROL1;
  3610. if (p->u3.else_statements) {
  3611. if_false->goto_true = if_skip; /* +1 */
  3612. } else {
  3613. if_false->goto_true = if_end;
  3614. }
  3615. /* link & load! */
  3616. linkprio(exten, if_test, mother_exten);
  3617. linkprio(exten, if_false, mother_exten);
  3618. /* now, put the body of the if here */
  3619. if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */
  3620. return -1;
  3621. }
  3622. if (p->u3.else_statements) {
  3623. linkprio(exten, if_skip, mother_exten);
  3624. if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */
  3625. return -1;
  3626. }
  3627. }
  3628. linkprio(exten, if_end, mother_exten);
  3629. break;
  3630. case PV_RANDOM:
  3631. case PV_IF:
  3632. control_statement_count++;
  3633. snprintf(new_label, BUF_SIZE, "if_%s_%d", label, control_statement_count);
  3634. if_test = new_prio();
  3635. if_end = new_prio();
  3636. if_test->type = AEL_IF_CONTROL;
  3637. if_end->type = AEL_APPCALL;
  3638. if ( p->type == PV_RANDOM )
  3639. snprintf(buf1, BUF_SIZE, "$[${RAND(0,99)} < (%s)]", p->u1.str);
  3640. else
  3641. snprintf(buf1, BUF_SIZE, "$[%s]", p->u1.str);
  3642. if_test->app = 0;
  3643. if_test->appargs = strdup(buf1);
  3644. snprintf(buf1, BUF_SIZE, "Finish if_%s_%d", label, control_statement_count);
  3645. if_end->app = strdup("NoOp");
  3646. if_end->appargs = strdup(buf1);
  3647. if_test->origin = p;
  3648. if (p->u3.else_statements) {
  3649. if_skip = new_prio();
  3650. if_skip->type = AEL_CONTROL1; /* simple goto */
  3651. if_skip->goto_true = if_end;
  3652. if_test->goto_false = if_skip;;
  3653. } else {
  3654. if_skip = 0;
  3655. if_test->goto_false = if_end;;
  3656. }
  3657. /* link & load! */
  3658. linkprio(exten, if_test, mother_exten);
  3659. /* now, put the body of the if here */
  3660. if (gen_prios(exten, new_label, p->u2.statements, mother_exten, this_context)) { /* this will link in all the statements here */
  3661. return -1;
  3662. }
  3663. if (p->u3.else_statements) {
  3664. linkprio(exten, if_skip, mother_exten);
  3665. if (gen_prios(exten, new_label, p->u3.else_statements, mother_exten, this_context)) { /* this will link in all the statements here */
  3666. return -1;
  3667. }
  3668. }
  3669. linkprio(exten, if_end, mother_exten);
  3670. break;
  3671. case PV_STATEMENTBLOCK:
  3672. if (gen_prios(exten, label, p->u1.list, mother_exten, this_context)) { /* recurse into the block */
  3673. return -1;
  3674. }
  3675. break;
  3676. case PV_CATCH:
  3677. control_statement_count++;
  3678. /* generate an extension with name of catch, put all catch stats
  3679. into this exten! */
  3680. switch_case = new_exten();
  3681. if (mother_exten && mother_exten->checked_switch) {
  3682. switch_case->has_switch = mother_exten->has_switch;
  3683. switch_case->checked_switch = mother_exten->checked_switch;
  3684. }
  3685. if (exten && exten->checked_switch) {
  3686. switch_case->has_switch = exten->has_switch;
  3687. switch_case->checked_switch = exten->checked_switch;
  3688. }
  3689. switch_case->context = this_context;
  3690. linkexten(exten,switch_case);
  3691. switch_case->name = strdup(p->u1.str);
  3692. snprintf(new_label, BUF_SIZE, "catch_%s_%d",p->u1.str, control_statement_count);
  3693. if (gen_prios(switch_case, new_label, p->u2.statements, mother_exten,this_context)) { /* this will link in all the catch body statements here */
  3694. return -1;
  3695. }
  3696. if (switch_case->return_needed) { /* returns now generate a Return() app call, no longer a goto to the end of the exten */
  3697. char buf[2000];
  3698. struct ael_priority *np2 = new_prio();
  3699. np2->type = AEL_APPCALL;
  3700. np2->app = strdup("NoOp");
  3701. snprintf(buf,sizeof(buf),"End of Extension %s", switch_case->name);
  3702. np2->appargs = strdup(buf);
  3703. linkprio(switch_case, np2, mother_exten);
  3704. switch_case-> return_target = np2;
  3705. }
  3706. break;
  3707. default:
  3708. break;
  3709. }
  3710. }
  3711. free(buf1);
  3712. free(buf2);
  3713. free(new_label);
  3714. return 0;
  3715. }
  3716. void set_priorities(struct ael_extension *exten)
  3717. {
  3718. int i;
  3719. struct ael_priority *pr;
  3720. do {
  3721. if (exten->is_switch)
  3722. i = 10;
  3723. else if (exten->regexten)
  3724. i=2;
  3725. else
  3726. i=1;
  3727. for (pr=exten->plist; pr; pr=pr->next) {
  3728. pr->priority_num = i;
  3729. if (!pr->origin || (pr->origin && pr->origin->type != PV_LABEL) ) /* Labels don't show up in the dialplan,
  3730. but we want them to point to the right
  3731. priority, which would be the next line
  3732. after the label; */
  3733. i++;
  3734. }
  3735. exten = exten->next_exten;
  3736. } while ( exten );
  3737. }
  3738. void add_extensions(struct ael_extension *exten)
  3739. {
  3740. struct ael_priority *pr;
  3741. char *label=0;
  3742. char realext[AST_MAX_EXTENSION];
  3743. if (!exten) {
  3744. ast_log(LOG_WARNING, "This file is Empty!\n" );
  3745. return;
  3746. }
  3747. do {
  3748. struct ael_priority *last = 0;
  3749. pbx_substitute_variables_helper(NULL, exten->name, realext, sizeof(realext) - 1);
  3750. if (exten->hints) {
  3751. if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, PRIORITY_HINT, NULL, exten->cidmatch,
  3752. exten->hints, NULL, ast_free_ptr, registrar)) {
  3753. ast_log(LOG_WARNING, "Unable to add step at priority 'hint' of extension '%s'\n",
  3754. exten->name);
  3755. }
  3756. }
  3757. for (pr=exten->plist; pr; pr=pr->next) {
  3758. char app[2000];
  3759. char appargs[2000];
  3760. /* before we can add the extension, we need to prep the app/appargs;
  3761. the CONTROL types need to be done after the priority numbers are calculated.
  3762. */
  3763. if (pr->type == AEL_LABEL) /* don't try to put labels in the dialplan! */ {
  3764. last = pr;
  3765. continue;
  3766. }
  3767. if (pr->app)
  3768. strcpy(app, pr->app);
  3769. else
  3770. app[0] = 0;
  3771. if (pr->appargs )
  3772. strcpy(appargs, pr->appargs);
  3773. else
  3774. appargs[0] = 0;
  3775. switch( pr->type ) {
  3776. case AEL_APPCALL:
  3777. /* easy case. Everything is all set up */
  3778. break;
  3779. case AEL_CONTROL1: /* FOR loop, WHILE loop, BREAK, CONTINUE, IF, IFTIME */
  3780. /* simple, unconditional goto. */
  3781. strcpy(app,"Goto");
  3782. if (pr->goto_true->origin && pr->goto_true->origin->type == PV_SWITCH ) {
  3783. snprintf(appargs,sizeof(appargs),"%s,%d", pr->goto_true->exten->name, pr->goto_true->priority_num);
  3784. } else if (pr->goto_true->origin && pr->goto_true->origin->type == PV_IFTIME && pr->goto_true->origin->u3.else_statements ) {
  3785. snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num+1);
  3786. } else
  3787. snprintf(appargs,sizeof(appargs),"%d", pr->goto_true->priority_num);
  3788. break;
  3789. case AEL_FOR_CONTROL: /* WHILE loop test, FOR loop test */
  3790. strcpy(app,"GotoIf");
  3791. snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
  3792. break;
  3793. case AEL_IF_CONTROL:
  3794. strcpy(app,"GotoIf");
  3795. if (pr->origin->u3.else_statements )
  3796. snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num+1);
  3797. else
  3798. snprintf(appargs,sizeof(appargs),"%s?%d:%d", pr->appargs, pr->priority_num+1, pr->goto_false->priority_num);
  3799. break;
  3800. case AEL_RAND_CONTROL:
  3801. strcpy(app,"Random");
  3802. snprintf(appargs,sizeof(appargs),"%s:%d", pr->appargs, pr->goto_true->priority_num+1);
  3803. break;
  3804. case AEL_IFTIME_CONTROL:
  3805. strcpy(app,"GotoIfTime");
  3806. snprintf(appargs,sizeof(appargs),"%s?%d", pr->appargs, pr->priority_num+2);
  3807. break;
  3808. case AEL_RETURN:
  3809. strcpy(app,"Return");
  3810. appargs[0] = 0;
  3811. break;
  3812. default:
  3813. break;
  3814. }
  3815. if (last && last->type == AEL_LABEL ) {
  3816. label = last->origin->u1.str;
  3817. }
  3818. else
  3819. label = 0;
  3820. if (ast_add_extension2(exten->context, 0 /*no replace*/, realext, pr->priority_num, (label?label:NULL), exten->cidmatch,
  3821. app, strdup(appargs), ast_free_ptr, registrar)) {
  3822. ast_log(LOG_WARNING, "Unable to add step at priority '%d' of extension '%s'\n", pr->priority_num,
  3823. exten->name);
  3824. }
  3825. last = pr;
  3826. }
  3827. exten = exten->next_exten;
  3828. } while ( exten );
  3829. }
  3830. static void attach_exten(struct ael_extension **list, struct ael_extension *newmem)
  3831. {
  3832. /* travel to the end of the list... */
  3833. struct ael_extension *lptr;
  3834. if( !*list ) {
  3835. *list = newmem;
  3836. return;
  3837. }
  3838. lptr = *list;
  3839. while( lptr->next_exten ) {
  3840. lptr = lptr->next_exten;
  3841. }
  3842. /* lptr should now pointing to the last element in the list; it has a null next_exten pointer */
  3843. lptr->next_exten = newmem;
  3844. }
  3845. static pval *get_extension_or_contxt(pval *p)
  3846. {
  3847. while( p && p->type != PV_EXTENSION && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
  3848. p = p->dad;
  3849. }
  3850. return p;
  3851. }
  3852. static pval *get_contxt(pval *p)
  3853. {
  3854. while( p && p->type != PV_CONTEXT && p->type != PV_MACRO ) {
  3855. p = p->dad;
  3856. }
  3857. return p;
  3858. }
  3859. static void fix_gotos_in_extensions(struct ael_extension *exten)
  3860. {
  3861. struct ael_extension *e;
  3862. for(e=exten;e;e=e->next_exten) {
  3863. struct ael_priority *p;
  3864. for(p=e->plist;p;p=p->next) {
  3865. if( p->origin && p->origin->type == PV_GOTO && p->origin->u3.goto_target_in_case ) {
  3866. /* fix the extension of the goto target to the actual extension in the post-compiled dialplan */
  3867. pval *target = p->origin->u2.goto_target;
  3868. struct ael_extension *z = target->u3.compiled_label;
  3869. pval *pv2 = p->origin;
  3870. char buf1[500];
  3871. char *apparg_save = p->appargs;
  3872. p->appargs = 0;
  3873. if (!pv2->u1.list->next) /* just one -- it won't hurt to repeat the extension */ {
  3874. snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->u1.str);
  3875. p->appargs = strdup(buf1);
  3876. } else if (pv2->u1.list->next && !pv2->u1.list->next->next) /* two */ {
  3877. snprintf(buf1,sizeof(buf1),"%s,%s", z->name, pv2->u1.list->next->u1.str);
  3878. p->appargs = strdup(buf1);
  3879. } else if (pv2->u1.list->next && pv2->u1.list->next->next) {
  3880. snprintf(buf1,sizeof(buf1),"%s,%s,%s", pv2->u1.list->u1.str,
  3881. z->name,
  3882. pv2->u1.list->next->next->u1.str);
  3883. p->appargs = strdup(buf1);
  3884. }
  3885. else
  3886. printf("WHAT? The goto doesn't fall into one of three cases for GOTO????\n");
  3887. if( apparg_save ) {
  3888. free(apparg_save);
  3889. }
  3890. }
  3891. }
  3892. }
  3893. }
  3894. static int context_used(struct ael_extension *exten_list, struct ast_context *context)
  3895. {
  3896. struct ael_extension *exten;
  3897. /* Check the simple elements first */
  3898. if (ast_walk_context_extensions(context, NULL) || ast_walk_context_includes(context, NULL) || ast_walk_context_ignorepats(context, NULL) || ast_walk_context_switches(context, NULL)) {
  3899. return 1;
  3900. }
  3901. for (exten = exten_list; exten; exten = exten->next_exten) {
  3902. if (exten->context == context) {
  3903. return 1;
  3904. }
  3905. }
  3906. return 0;
  3907. }
  3908. int ast_compile_ael2(struct ast_context **local_contexts, struct ast_hashtab *local_table, struct pval *root)
  3909. {
  3910. pval *p,*p2;
  3911. struct ast_context *context;
  3912. char buf[2000];
  3913. struct ael_extension *exten;
  3914. struct ael_extension *exten_list = 0;
  3915. for (p=root; p; p=p->next ) { /* do the globals first, so they'll be there
  3916. when we try to eval them */
  3917. switch (p->type) {
  3918. case PV_GLOBALS:
  3919. /* just VARDEC elements */
  3920. for (p2=p->u1.list; p2; p2=p2->next) {
  3921. char buf2[2000];
  3922. snprintf(buf2,sizeof(buf2),"%s=%s", p2->u1.str, p2->u2.val);
  3923. pbx_builtin_setvar(NULL, buf2);
  3924. }
  3925. break;
  3926. default:
  3927. break;
  3928. }
  3929. }
  3930. for (p=root; p; p=p->next ) {
  3931. pval *lp;
  3932. int argc;
  3933. switch (p->type) {
  3934. case PV_MACRO:
  3935. context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
  3936. exten = new_exten();
  3937. exten->context = context;
  3938. exten->name = strdup("~~s~~");
  3939. argc = 1;
  3940. for (lp=p->u2.arglist; lp; lp=lp->next) {
  3941. /* for each arg, set up a "Set" command */
  3942. struct ael_priority *np2 = new_prio();
  3943. np2->type = AEL_APPCALL;
  3944. if (!ast_compat_app_set) {
  3945. np2->app = strdup("MSet");
  3946. } else {
  3947. np2->app = strdup("Set");
  3948. }
  3949. snprintf(buf,sizeof(buf),"LOCAL(%s)=${ARG%d}", lp->u1.str, argc++);
  3950. remove_spaces_before_equals(buf);
  3951. np2->appargs = strdup(buf);
  3952. linkprio(exten, np2, NULL);
  3953. }
  3954. /* CONTAINS APPCALLS, CATCH, just like extensions... */
  3955. if (gen_prios(exten, p->u1.str, p->u3.macro_statements, 0, context)) {
  3956. return -1;
  3957. }
  3958. if (exten->return_needed) { /* most likely, this will go away */
  3959. struct ael_priority *np2 = new_prio();
  3960. np2->type = AEL_APPCALL;
  3961. np2->app = strdup("NoOp");
  3962. snprintf(buf,sizeof(buf),"End of Macro %s-%s",p->u1.str, exten->name);
  3963. np2->appargs = strdup(buf);
  3964. linkprio(exten, np2, NULL);
  3965. exten-> return_target = np2;
  3966. }
  3967. set_priorities(exten);
  3968. attach_exten(&exten_list, exten);
  3969. break;
  3970. case PV_GLOBALS:
  3971. /* already done */
  3972. break;
  3973. case PV_CONTEXT:
  3974. context = ast_context_find_or_create(local_contexts, local_table, p->u1.str, registrar);
  3975. /* contexts contain: ignorepat, includes, switches, eswitches, extensions, */
  3976. for (p2=p->u2.statements; p2; p2=p2->next) {
  3977. pval *p3;
  3978. char *s3;
  3979. switch (p2->type) {
  3980. case PV_EXTENSION:
  3981. exten = new_exten();
  3982. exten->name = strdup(p2->u1.str);
  3983. exten->context = context;
  3984. if( (s3=strchr(exten->name, '/') ) != 0 )
  3985. {
  3986. *s3 = 0;
  3987. exten->cidmatch = s3+1;
  3988. }
  3989. if ( p2->u3.hints )
  3990. exten->hints = strdup(p2->u3.hints);
  3991. exten->regexten = p2->u4.regexten;
  3992. if (gen_prios(exten, p->u1.str, p2->u2.statements, 0, context)) {
  3993. return -1;
  3994. }
  3995. if (exten->return_needed) { /* returns don't generate a goto eoe (end of extension) any more, just a Return() app call) */
  3996. struct ael_priority *np2 = new_prio();
  3997. np2->type = AEL_APPCALL;
  3998. np2->app = strdup("NoOp");
  3999. snprintf(buf,sizeof(buf),"End of Extension %s", exten->name);
  4000. np2->appargs = strdup(buf);
  4001. linkprio(exten, np2, NULL);
  4002. exten-> return_target = np2;
  4003. }
  4004. /* is the last priority in the extension a label? Then add a trailing no-op */
  4005. if ( exten->plist_last && exten->plist_last->type == AEL_LABEL ) {
  4006. struct ael_priority *np2 = new_prio();
  4007. np2->type = AEL_APPCALL;
  4008. np2->app = strdup("NoOp");
  4009. snprintf(buf,sizeof(buf),"A NoOp to follow a trailing label %s", exten->plist_last->origin->u1.str);
  4010. np2->appargs = strdup(buf);
  4011. linkprio(exten, np2, NULL);
  4012. }
  4013. set_priorities(exten);
  4014. attach_exten(&exten_list, exten);
  4015. break;
  4016. case PV_IGNOREPAT:
  4017. ast_context_add_ignorepat2(context, p2->u1.str, registrar);
  4018. break;
  4019. case PV_INCLUDES:
  4020. for (p3 = p2->u1.list; p3 ;p3=p3->next) {
  4021. if ( p3->u2.arglist ) {
  4022. snprintf(buf,sizeof(buf), "%s,%s,%s,%s,%s",
  4023. p3->u1.str,
  4024. p3->u2.arglist->u1.str,
  4025. p3->u2.arglist->next->u1.str,
  4026. p3->u2.arglist->next->next->u1.str,
  4027. p3->u2.arglist->next->next->next->u1.str);
  4028. ast_context_add_include2(context, buf, registrar);
  4029. } else
  4030. ast_context_add_include2(context, p3->u1.str, registrar);
  4031. }
  4032. break;
  4033. case PV_SWITCHES:
  4034. for (p3 = p2->u1.list; p3 ;p3=p3->next) {
  4035. char *c = strchr(p3->u1.str, '/');
  4036. if (c) {
  4037. *c = '\0';
  4038. c++;
  4039. } else
  4040. c = "";
  4041. ast_context_add_switch2(context, p3->u1.str, c, 0, registrar);
  4042. }
  4043. break;
  4044. case PV_ESWITCHES:
  4045. for (p3 = p2->u1.list; p3 ;p3=p3->next) {
  4046. char *c = strchr(p3->u1.str, '/');
  4047. if (c) {
  4048. *c = '\0';
  4049. c++;
  4050. } else
  4051. c = "";
  4052. ast_context_add_switch2(context, p3->u1.str, c, 1, registrar);
  4053. }
  4054. break;
  4055. default:
  4056. break;
  4057. }
  4058. }
  4059. break;
  4060. default:
  4061. /* huh? what? */
  4062. break;
  4063. }
  4064. }
  4065. /* Create default "h" bubble context */
  4066. if (ast_custom_function_find("DIALPLAN_EXISTS") && ast_custom_function_find("STACK_PEEK")) {
  4067. int i;
  4068. const char *h_context = "ael-builtin-h-bubble";
  4069. struct ael_priority *np;
  4070. struct {
  4071. int priority;
  4072. const char *app;
  4073. const char *arg;
  4074. } steps[] = {
  4075. /* Start high, to avoid conflict with existing h extensions */
  4076. { 1, "Goto", "9991" },
  4077. /* Save the context, because after the StackPop, it disappears */
  4078. { 9991, "Set", "~~parentcxt~~=${STACK_PEEK(1,c,1)}" },
  4079. /* If we're not in a Gosub frame, exit */
  4080. { 9992, "GotoIf", "$[\"${~~parentcxt~~}\"=\"\"]?9996" },
  4081. /* Check for an "h" extension in that context */
  4082. { 9993, "GotoIf", "${DIALPLAN_EXISTS(${~~parentcxt~~},h,1)}?9994:9996" },
  4083. /* Pop off the stack frame to prevent an infinite loop */
  4084. { 9994, "StackPop", "" },
  4085. /* Finally, go there. */
  4086. { 9995, "Goto", "${~~parentcxt~~},h,1" },
  4087. /* Just an empty priority for jumping out early */
  4088. { 9996, "NoOp", "" }
  4089. };
  4090. context = ast_context_find_or_create(local_contexts, local_table, h_context, registrar);
  4091. if (context_used(exten_list, context)) {
  4092. int found = 0;
  4093. while (!found) {
  4094. /* Pick a new context name that is not used. */
  4095. char h_context_template[] = "/tmp/ael-builtin-h-bubble-XXXXXX";
  4096. int fd = mkstemp(h_context_template);
  4097. unlink(h_context_template);
  4098. close(fd);
  4099. context = ast_context_find_or_create(local_contexts, local_table, h_context_template + 5, registrar);
  4100. found = !context_used(exten_list, context);
  4101. }
  4102. h_context = ast_get_context_name(context);
  4103. }
  4104. exten = new_exten();
  4105. exten->context = context;
  4106. exten->name = strdup("h");
  4107. for (i = 0; i < ARRAY_LEN(steps); i++) {
  4108. np = new_prio();
  4109. np->type = AEL_APPCALL;
  4110. np->priority_num = steps[i].priority;
  4111. np->app = strdup(steps[i].app);
  4112. np->appargs = strdup(steps[i].arg);
  4113. linkprio(exten, np, NULL);
  4114. }
  4115. attach_exten(&exten_list, exten);
  4116. /* Include the default "h" bubble context in each macro context */
  4117. for (exten = exten_list; exten; exten = exten->next_exten) {
  4118. /* All macros contain a "~~s~~" extension, and it's the first created. If
  4119. * we perchance get a non-macro context, it's no big deal; the logic is
  4120. * designed to exit out smoothly if not called from within a Gosub. */
  4121. if (!strcmp(exten->name, "~~s~~")) {
  4122. ast_context_add_include2(exten->context, h_context, registrar);
  4123. }
  4124. }
  4125. }
  4126. /* moved these from being done after a macro or extension were processed,
  4127. to after all processing is done, for the sake of fixing gotos to labels inside cases... */
  4128. /* I guess this would be considered 2nd pass of compiler now... */
  4129. fix_gotos_in_extensions(exten_list); /* find and fix extension ref in gotos to labels that are in case statements */
  4130. add_extensions(exten_list); /* actually makes calls to create priorities in ast_contexts -- feeds dialplan to asterisk */
  4131. destroy_extensions(exten_list); /* all that remains is an empty husk, discard of it as is proper */
  4132. return 0;
  4133. }
  4134. /* DESTROY the PVAL tree ============================================================================ */
  4135. void destroy_pval_item(pval *item)
  4136. {
  4137. if (item == NULL) {
  4138. ast_log(LOG_WARNING, "null item\n");
  4139. return;
  4140. }
  4141. if (item->filename)
  4142. free(item->filename);
  4143. switch (item->type) {
  4144. case PV_WORD:
  4145. /* fields: item->u1.str == string associated with this (word). */
  4146. if (item->u1.str )
  4147. free(item->u1.str);
  4148. if ( item->u2.arglist )
  4149. destroy_pval(item->u2.arglist);
  4150. break;
  4151. case PV_MACRO:
  4152. /* fields: item->u1.str == name of macro
  4153. item->u2.arglist == pval list of PV_WORD arguments of macro, as given by user
  4154. item->u2.arglist->u1.str == argument
  4155. item->u2.arglist->next == next arg
  4156. item->u3.macro_statements == pval list of statements in macro body.
  4157. */
  4158. destroy_pval(item->u2.arglist);
  4159. if (item->u1.str )
  4160. free(item->u1.str);
  4161. destroy_pval(item->u3.macro_statements);
  4162. break;
  4163. case PV_CONTEXT:
  4164. /* fields: item->u1.str == name of context
  4165. item->u2.statements == pval list of statements in context body
  4166. item->u3.abstract == int 1 if an abstract keyword were present
  4167. */
  4168. if (item->u1.str)
  4169. free(item->u1.str);
  4170. destroy_pval(item->u2.statements);
  4171. break;
  4172. case PV_MACRO_CALL:
  4173. /* fields: item->u1.str == name of macro to call
  4174. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  4175. item->u2.arglist->u1.str == argument
  4176. item->u2.arglist->next == next arg
  4177. */
  4178. if (item->u1.str)
  4179. free(item->u1.str);
  4180. destroy_pval(item->u2.arglist);
  4181. break;
  4182. case PV_APPLICATION_CALL:
  4183. /* fields: item->u1.str == name of application to call
  4184. item->u2.arglist == pval list of PV_WORD arguments of macro call, as given by user
  4185. item->u2.arglist->u1.str == argument
  4186. item->u2.arglist->next == next arg
  4187. */
  4188. if (item->u1.str)
  4189. free(item->u1.str);
  4190. destroy_pval(item->u2.arglist);
  4191. break;
  4192. case PV_CASE:
  4193. /* fields: item->u1.str == value of case
  4194. item->u2.statements == pval list of statements under the case
  4195. */
  4196. if (item->u1.str)
  4197. free(item->u1.str);
  4198. destroy_pval(item->u2.statements);
  4199. break;
  4200. case PV_PATTERN:
  4201. /* fields: item->u1.str == value of case
  4202. item->u2.statements == pval list of statements under the case
  4203. */
  4204. if (item->u1.str)
  4205. free(item->u1.str);
  4206. destroy_pval(item->u2.statements);
  4207. break;
  4208. case PV_DEFAULT:
  4209. /* fields:
  4210. item->u2.statements == pval list of statements under the case
  4211. */
  4212. destroy_pval(item->u2.statements);
  4213. break;
  4214. case PV_CATCH:
  4215. /* fields: item->u1.str == name of extension to catch
  4216. item->u2.statements == pval list of statements in context body
  4217. */
  4218. if (item->u1.str)
  4219. free(item->u1.str);
  4220. destroy_pval(item->u2.statements);
  4221. break;
  4222. case PV_SWITCHES:
  4223. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  4224. */
  4225. destroy_pval(item->u1.list);
  4226. break;
  4227. case PV_ESWITCHES:
  4228. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  4229. */
  4230. destroy_pval(item->u1.list);
  4231. break;
  4232. case PV_INCLUDES:
  4233. /* fields: item->u1.list == pval list of PV_WORD elements, one per entry in the list
  4234. item->u2.arglist == pval list of 4 PV_WORD elements for time values
  4235. */
  4236. destroy_pval(item->u1.list);
  4237. break;
  4238. case PV_STATEMENTBLOCK:
  4239. /* fields: item->u1.list == pval list of statements in block, one per entry in the list
  4240. */
  4241. destroy_pval(item->u1.list);
  4242. break;
  4243. case PV_LOCALVARDEC:
  4244. case PV_VARDEC:
  4245. /* fields: item->u1.str == variable name
  4246. item->u2.val == variable value to assign
  4247. */
  4248. if (item->u1.str)
  4249. free(item->u1.str);
  4250. if (item->u2.val)
  4251. free(item->u2.val);
  4252. break;
  4253. case PV_GOTO:
  4254. /* fields: item->u1.list == pval list of PV_WORD target names, up to 3, in order as given by user.
  4255. item->u1.list->u1.str == where the data on a PV_WORD will always be.
  4256. */
  4257. destroy_pval(item->u1.list);
  4258. break;
  4259. case PV_LABEL:
  4260. /* fields: item->u1.str == label name
  4261. */
  4262. if (item->u1.str)
  4263. free(item->u1.str);
  4264. break;
  4265. case PV_FOR:
  4266. /* fields: item->u1.for_init == a string containing the initalizer
  4267. item->u2.for_test == a string containing the loop test
  4268. item->u3.for_inc == a string containing the loop increment
  4269. item->u4.for_statements == a pval list of statements in the for ()
  4270. */
  4271. if (item->u1.for_init)
  4272. free(item->u1.for_init);
  4273. if (item->u2.for_test)
  4274. free(item->u2.for_test);
  4275. if (item->u3.for_inc)
  4276. free(item->u3.for_inc);
  4277. destroy_pval(item->u4.for_statements);
  4278. break;
  4279. case PV_WHILE:
  4280. /* fields: item->u1.str == the while conditional, as supplied by user
  4281. item->u2.statements == a pval list of statements in the while ()
  4282. */
  4283. if (item->u1.str)
  4284. free(item->u1.str);
  4285. destroy_pval(item->u2.statements);
  4286. break;
  4287. case PV_BREAK:
  4288. /* fields: none
  4289. */
  4290. break;
  4291. case PV_RETURN:
  4292. /* fields: none
  4293. */
  4294. break;
  4295. case PV_CONTINUE:
  4296. /* fields: none
  4297. */
  4298. break;
  4299. case PV_IFTIME:
  4300. /* fields: item->u1.list == the 4 time values, in PV_WORD structs, linked list
  4301. item->u2.statements == a pval list of statements in the if ()
  4302. item->u3.else_statements == a pval list of statements in the else
  4303. (could be zero)
  4304. */
  4305. destroy_pval(item->u1.list);
  4306. destroy_pval(item->u2.statements);
  4307. if (item->u3.else_statements) {
  4308. destroy_pval(item->u3.else_statements);
  4309. }
  4310. break;
  4311. case PV_RANDOM:
  4312. /* fields: item->u1.str == the random percentage, as supplied by user
  4313. item->u2.statements == a pval list of statements in the true part ()
  4314. item->u3.else_statements == a pval list of statements in the else
  4315. (could be zero)
  4316. fall thru to If */
  4317. case PV_IF:
  4318. /* fields: item->u1.str == the if conditional, as supplied by user
  4319. item->u2.statements == a pval list of statements in the if ()
  4320. item->u3.else_statements == a pval list of statements in the else
  4321. (could be zero)
  4322. */
  4323. if (item->u1.str)
  4324. free(item->u1.str);
  4325. destroy_pval(item->u2.statements);
  4326. if (item->u3.else_statements) {
  4327. destroy_pval(item->u3.else_statements);
  4328. }
  4329. break;
  4330. case PV_SWITCH:
  4331. /* fields: item->u1.str == the switch expression
  4332. item->u2.statements == a pval list of statements in the switch,
  4333. (will be case statements, most likely!)
  4334. */
  4335. if (item->u1.str)
  4336. free(item->u1.str);
  4337. destroy_pval(item->u2.statements);
  4338. break;
  4339. case PV_EXTENSION:
  4340. /* fields: item->u1.str == the extension name, label, whatever it's called
  4341. item->u2.statements == a pval list of statements in the extension
  4342. item->u3.hints == a char * hint argument
  4343. item->u4.regexten == an int boolean. non-zero says that regexten was specified
  4344. */
  4345. if (item->u1.str)
  4346. free(item->u1.str);
  4347. if (item->u3.hints)
  4348. free(item->u3.hints);
  4349. destroy_pval(item->u2.statements);
  4350. break;
  4351. case PV_IGNOREPAT:
  4352. /* fields: item->u1.str == the ignorepat data
  4353. */
  4354. if (item->u1.str)
  4355. free(item->u1.str);
  4356. break;
  4357. case PV_GLOBALS:
  4358. /* fields: item->u1.statements == pval list of statements, usually vardecs
  4359. */
  4360. destroy_pval(item->u1.statements);
  4361. break;
  4362. }
  4363. free(item);
  4364. }
  4365. void destroy_pval(pval *item)
  4366. {
  4367. pval *i,*nxt;
  4368. for (i=item; i; i=nxt) {
  4369. nxt = i->next;
  4370. destroy_pval_item(i);
  4371. }
  4372. }
  4373. #ifdef AAL_ARGCHECK
  4374. static char *ael_funclist[] =
  4375. {
  4376. "AGENT",
  4377. "ARRAY",
  4378. "BASE64_DECODE",
  4379. "BASE64_ENCODE",
  4380. "CALLERID",
  4381. "CDR",
  4382. "CHANNEL",
  4383. "CHECKSIPDOMAIN",
  4384. "CHECK_MD5",
  4385. "CURL",
  4386. "CUT",
  4387. "DB",
  4388. "DB_EXISTS",
  4389. "DUNDILOOKUP",
  4390. "ENUMLOOKUP",
  4391. "ENV",
  4392. "EVAL",
  4393. "EXISTS",
  4394. "FIELDQTY",
  4395. "FILTER",
  4396. "GROUP",
  4397. "GROUP_COUNT",
  4398. "GROUP_LIST",
  4399. "GROUP_MATCH_COUNT",
  4400. "IAXPEER",
  4401. "IF",
  4402. "IFTIME",
  4403. "ISNULL",
  4404. "KEYPADHASH",
  4405. "LANGUAGE",
  4406. "LEN",
  4407. "MATH",
  4408. "MD5",
  4409. "MUSICCLASS",
  4410. "QUEUEAGENTCOUNT",
  4411. "QUEUE_MEMBER_COUNT",
  4412. "QUEUE_MEMBER_LIST",
  4413. "QUOTE",
  4414. "RAND",
  4415. "REGEX",
  4416. "SET",
  4417. "SHA1",
  4418. "SIPCHANINFO",
  4419. "SIPPEER",
  4420. "SIP_HEADER",
  4421. "SORT",
  4422. "STAT",
  4423. "STRFTIME",
  4424. "STRPTIME",
  4425. "TIMEOUT",
  4426. "TXTCIDNAME",
  4427. "URIDECODE",
  4428. "URIENCODE",
  4429. "VMCOUNT"
  4430. };
  4431. int ael_is_funcname(char *name)
  4432. {
  4433. int s,t;
  4434. t = sizeof(ael_funclist)/sizeof(char*);
  4435. s = 0;
  4436. while ((s < t) && strcasecmp(name, ael_funclist[s]))
  4437. s++;
  4438. if ( s < t )
  4439. return 1;
  4440. else
  4441. return 0;
  4442. }
  4443. #endif
  4444. /* PVAL PI */
  4445. /* ----------------- implementation ------------------- */
  4446. int pvalCheckType( pval *p, char *funcname, pvaltype type )
  4447. {
  4448. if (p->type != type)
  4449. {
  4450. ast_log(LOG_ERROR, "Func: %s the pval passed is not appropriate for this function!\n", funcname);
  4451. return 0;
  4452. }
  4453. return 1;
  4454. }
  4455. pval *pvalCreateNode( pvaltype type )
  4456. {
  4457. pval *p = calloc(1,sizeof(pval)); /* why, oh why, don't I use ast_calloc? Way, way, way too messy if I do! */
  4458. p->type = type; /* remember, this can be used externally or internally to asterisk */
  4459. return p;
  4460. }
  4461. pvaltype pvalObjectGetType( pval *p )
  4462. {
  4463. return p->type;
  4464. }
  4465. void pvalWordSetString( pval *p, char *str)
  4466. {
  4467. if (!pvalCheckType(p, "pvalWordSetString", PV_WORD))
  4468. return;
  4469. p->u1.str = str;
  4470. }
  4471. char *pvalWordGetString( pval *p )
  4472. {
  4473. if (!pvalCheckType(p, "pvalWordGetString", PV_WORD))
  4474. return 0;
  4475. return p->u1.str;
  4476. }
  4477. void pvalMacroSetName( pval *p, char *name)
  4478. {
  4479. if (!pvalCheckType(p, "pvalMacroSetName", PV_MACRO))
  4480. return;
  4481. p->u1.str = name;
  4482. }
  4483. char *pvalMacroGetName( pval *p )
  4484. {
  4485. if (!pvalCheckType(p, "pvalMacroGetName", PV_MACRO))
  4486. return 0;
  4487. return p->u1.str;
  4488. }
  4489. void pvalMacroSetArglist( pval *p, pval *arglist )
  4490. {
  4491. if (!pvalCheckType(p, "pvalMacroSetArglist", PV_MACRO))
  4492. return;
  4493. p->u2.arglist = arglist;
  4494. }
  4495. void pvalMacroAddArg( pval *p, pval *arg ) /* single arg only! */
  4496. {
  4497. if (!pvalCheckType(p, "pvalMacroAddArg", PV_MACRO))
  4498. return;
  4499. if (!p->u2.arglist)
  4500. p->u2.arglist = arg;
  4501. else
  4502. linku1(p->u2.arglist, arg);
  4503. }
  4504. pval *pvalMacroWalkArgs( pval *p, pval **arg )
  4505. {
  4506. if (!pvalCheckType(p, "pvalMacroWalkArgs", PV_MACRO))
  4507. return 0;
  4508. if (!(*arg))
  4509. *arg = p->u2.arglist;
  4510. else {
  4511. *arg = (*arg)->next;
  4512. }
  4513. return *arg;
  4514. }
  4515. void pvalMacroAddStatement( pval *p, pval *statement )
  4516. {
  4517. if (!pvalCheckType(p, "pvalMacroAddStatement", PV_MACRO))
  4518. return;
  4519. if (!p->u3.macro_statements)
  4520. p->u3.macro_statements = statement;
  4521. else
  4522. linku1(p->u3.macro_statements, statement);
  4523. }
  4524. pval *pvalMacroWalkStatements( pval *p, pval **next_statement )
  4525. {
  4526. if (!pvalCheckType(p, "pvalMacroWalkStatements", PV_MACRO))
  4527. return 0;
  4528. if (!(*next_statement))
  4529. *next_statement = p->u3.macro_statements;
  4530. else {
  4531. *next_statement = (*next_statement)->next;
  4532. }
  4533. return *next_statement;
  4534. }
  4535. void pvalContextSetName( pval *p, char *name)
  4536. {
  4537. if (!pvalCheckType(p, "pvalContextSetName", PV_CONTEXT))
  4538. return;
  4539. p->u1.str = name;
  4540. }
  4541. char *pvalContextGetName( pval *p )
  4542. {
  4543. if (!pvalCheckType(p, "pvalContextGetName", PV_CONTEXT))
  4544. return 0;
  4545. return p->u1.str;
  4546. }
  4547. void pvalContextSetAbstract( pval *p )
  4548. {
  4549. if (!pvalCheckType(p, "pvalContextSetAbstract", PV_CONTEXT))
  4550. return;
  4551. p->u3.abstract = 1;
  4552. }
  4553. void pvalContextUnsetAbstract( pval *p )
  4554. {
  4555. if (!pvalCheckType(p, "pvalContextUnsetAbstract", PV_CONTEXT))
  4556. return;
  4557. p->u3.abstract = 0;
  4558. }
  4559. int pvalContextGetAbstract( pval *p )
  4560. {
  4561. if (!pvalCheckType(p, "pvalContextGetAbstract", PV_CONTEXT))
  4562. return 0;
  4563. return p->u3.abstract;
  4564. }
  4565. void pvalContextAddStatement( pval *p, pval *statement) /* this includes SWITCHES, INCLUDES, IGNOREPAT, etc */
  4566. {
  4567. if (!pvalCheckType(p, "pvalContextAddStatement", PV_CONTEXT))
  4568. return;
  4569. if (!p->u2.statements)
  4570. p->u2.statements = statement;
  4571. else
  4572. linku1(p->u2.statements, statement);
  4573. }
  4574. pval *pvalContextWalkStatements( pval *p, pval **statements )
  4575. {
  4576. if (!pvalCheckType(p, "pvalContextWalkStatements", PV_CONTEXT))
  4577. return 0;
  4578. if (!(*statements))
  4579. *statements = p->u2.statements;
  4580. else {
  4581. *statements = (*statements)->next;
  4582. }
  4583. return *statements;
  4584. }
  4585. void pvalMacroCallSetMacroName( pval *p, char *name )
  4586. {
  4587. if (!pvalCheckType(p, "pvalMacroCallSetMacroName", PV_MACRO_CALL))
  4588. return;
  4589. p->u1.str = name;
  4590. }
  4591. char* pvalMacroCallGetMacroName( pval *p )
  4592. {
  4593. if (!pvalCheckType(p, "pvalMacroCallGetMacroName", PV_MACRO_CALL))
  4594. return 0;
  4595. return p->u1.str;
  4596. }
  4597. void pvalMacroCallSetArglist( pval *p, pval *arglist )
  4598. {
  4599. if (!pvalCheckType(p, "pvalMacroCallSetArglist", PV_MACRO_CALL))
  4600. return;
  4601. p->u2.arglist = arglist;
  4602. }
  4603. void pvalMacroCallAddArg( pval *p, pval *arg )
  4604. {
  4605. if (!pvalCheckType(p, "pvalMacroCallGetAddArg", PV_MACRO_CALL))
  4606. return;
  4607. if (!p->u2.arglist)
  4608. p->u2.arglist = arg;
  4609. else
  4610. linku1(p->u2.arglist, arg);
  4611. }
  4612. pval *pvalMacroCallWalkArgs( pval *p, pval **args )
  4613. {
  4614. if (!pvalCheckType(p, "pvalMacroCallWalkArgs", PV_MACRO_CALL))
  4615. return 0;
  4616. if (!(*args))
  4617. *args = p->u2.arglist;
  4618. else {
  4619. *args = (*args)->next;
  4620. }
  4621. return *args;
  4622. }
  4623. void pvalAppCallSetAppName( pval *p, char *name )
  4624. {
  4625. if (!pvalCheckType(p, "pvalAppCallSetAppName", PV_APPLICATION_CALL))
  4626. return;
  4627. p->u1.str = name;
  4628. }
  4629. char* pvalAppCallGetAppName( pval *p )
  4630. {
  4631. if (!pvalCheckType(p, "pvalAppCallGetAppName", PV_APPLICATION_CALL))
  4632. return 0;
  4633. return p->u1.str;
  4634. }
  4635. void pvalAppCallSetArglist( pval *p, pval *arglist )
  4636. {
  4637. if (!pvalCheckType(p, "pvalAppCallSetArglist", PV_APPLICATION_CALL))
  4638. return;
  4639. p->u2.arglist = arglist;
  4640. }
  4641. void pvalAppCallAddArg( pval *p, pval *arg )
  4642. {
  4643. if (!pvalCheckType(p, "pvalAppCallAddArg", PV_APPLICATION_CALL))
  4644. return;
  4645. if (!p->u2.arglist)
  4646. p->u2.arglist = arg;
  4647. else
  4648. linku1(p->u2.arglist, arg);
  4649. }
  4650. pval *pvalAppCallWalkArgs( pval *p, pval **args )
  4651. {
  4652. if (!pvalCheckType(p, "pvalAppCallWalkArgs", PV_APPLICATION_CALL))
  4653. return 0;
  4654. if (!(*args))
  4655. *args = p->u2.arglist;
  4656. else {
  4657. *args = (*args)->next;
  4658. }
  4659. return *args;
  4660. }
  4661. void pvalCasePatSetVal( pval *p, char *val )
  4662. {
  4663. if (!pvalCheckType(p, "pvalAppCallWalkArgs", PV_APPLICATION_CALL))
  4664. return;
  4665. p->u1.str = val;
  4666. }
  4667. char* pvalCasePatGetVal( pval *p )
  4668. {
  4669. return p->u1.str;
  4670. }
  4671. void pvalCasePatDefAddStatement( pval *p, pval *statement )
  4672. {
  4673. if (!p->u2.arglist)
  4674. p->u2.statements = statement;
  4675. else
  4676. linku1(p->u2.statements, statement);
  4677. }
  4678. pval *pvalCasePatDefWalkStatements( pval *p, pval **statement )
  4679. {
  4680. if (!(*statement))
  4681. *statement = p->u2.statements;
  4682. else {
  4683. *statement = (*statement)->next;
  4684. }
  4685. return *statement;
  4686. }
  4687. void pvalCatchSetExtName( pval *p, char *name )
  4688. {
  4689. if (!pvalCheckType(p, "pvalCatchSetExtName", PV_CATCH))
  4690. return;
  4691. p->u1.str = name;
  4692. }
  4693. char* pvalCatchGetExtName( pval *p )
  4694. {
  4695. if (!pvalCheckType(p, "pvalCatchGetExtName", PV_CATCH))
  4696. return 0;
  4697. return p->u1.str;
  4698. }
  4699. void pvalCatchSetStatement( pval *p, pval *statement )
  4700. {
  4701. if (!pvalCheckType(p, "pvalCatchSetStatement", PV_CATCH))
  4702. return;
  4703. p->u2.statements = statement;
  4704. }
  4705. pval *pvalCatchGetStatement( pval *p )
  4706. {
  4707. if (!pvalCheckType(p, "pvalCatchGetStatement", PV_CATCH))
  4708. return 0;
  4709. return p->u2.statements;
  4710. }
  4711. void pvalSwitchesAddSwitch( pval *p, char *name )
  4712. {
  4713. pval *s;
  4714. if (!pvalCheckType(p, "pvalSwitchesAddSwitch", PV_SWITCHES))
  4715. return;
  4716. s = pvalCreateNode(PV_WORD);
  4717. s->u1.str = name;
  4718. p->u1.list = linku1(p->u1.list, s);
  4719. }
  4720. char* pvalSwitchesWalkNames( pval *p, pval **next_item )
  4721. {
  4722. if (!pvalCheckType(p, "pvalSwitchesWalkNames", PV_SWITCHES))
  4723. return 0;
  4724. if (!(*next_item))
  4725. *next_item = p->u1.list;
  4726. else {
  4727. *next_item = (*next_item)->next;
  4728. }
  4729. return (*next_item)->u1.str;
  4730. }
  4731. void pvalESwitchesAddSwitch( pval *p, char *name )
  4732. {
  4733. pval *s;
  4734. if (!pvalCheckType(p, "pvalESwitchesAddSwitch", PV_ESWITCHES))
  4735. return;
  4736. s = pvalCreateNode(PV_WORD);
  4737. s->u1.str = name;
  4738. p->u1.list = linku1(p->u1.list, s);
  4739. }
  4740. char* pvalESwitchesWalkNames( pval *p, pval **next_item )
  4741. {
  4742. if (!pvalCheckType(p, "pvalESwitchesWalkNames", PV_ESWITCHES))
  4743. return 0;
  4744. if (!(*next_item))
  4745. *next_item = p->u1.list;
  4746. else {
  4747. *next_item = (*next_item)->next;
  4748. }
  4749. return (*next_item)->u1.str;
  4750. }
  4751. void pvalIncludesAddInclude( pval *p, const char *include )
  4752. {
  4753. pval *s;
  4754. if (!pvalCheckType(p, "pvalIncludesAddSwitch", PV_INCLUDES))
  4755. return;
  4756. s = pvalCreateNode(PV_WORD);
  4757. s->u1.str = (char *)include;
  4758. p->u1.list = linku1(p->u1.list, s);
  4759. }
  4760. /* an include is a WORD with string set to path */
  4761. void pvalIncludesAddIncludeWithTimeConstraints( pval *p, const char *include, char *hour_range, char *dom_range, char *dow_range, char *month_range )
  4762. {
  4763. pval *hr = pvalCreateNode(PV_WORD);
  4764. pval *dom = pvalCreateNode(PV_WORD);
  4765. pval *dow = pvalCreateNode(PV_WORD);
  4766. pval *mon = pvalCreateNode(PV_WORD);
  4767. pval *s = pvalCreateNode(PV_WORD);
  4768. if (!pvalCheckType(p, "pvalIncludeAddIncludeWithTimeConstraints", PV_INCLUDES))
  4769. return;
  4770. s->u1.str = (char *)include;
  4771. p->u1.list = linku1(p->u1.list, s);
  4772. hr->u1.str = hour_range;
  4773. dom->u1.str = dom_range;
  4774. dow->u1.str = dow_range;
  4775. mon->u1.str = month_range;
  4776. s->u2.arglist = hr;
  4777. hr->next = dom;
  4778. dom->next = dow;
  4779. dow->next = mon;
  4780. mon->next = 0;
  4781. }
  4782. /* is this right??? come back and correct it */ /*the ptr is to the WORD */
  4783. void pvalIncludeGetTimeConstraints( pval *p, char **hour_range, char **dom_range, char **dow_range, char **month_range )
  4784. {
  4785. if (!pvalCheckType(p, "pvalIncludeGetTimeConstraints", PV_WORD))
  4786. return;
  4787. if (p->u2.arglist) {
  4788. *hour_range = p->u2.arglist->u1.str;
  4789. *dom_range = p->u2.arglist->next->u1.str;
  4790. *dow_range = p->u2.arglist->next->next->u1.str;
  4791. *month_range = p->u2.arglist->next->next->next->u1.str;
  4792. } else {
  4793. *hour_range = 0;
  4794. *dom_range = 0;
  4795. *dow_range = 0;
  4796. *month_range = 0;
  4797. }
  4798. }
  4799. /* is this right??? come back and correct it */ /*the ptr is to the WORD */
  4800. char* pvalIncludesWalk( pval *p, pval **next_item )
  4801. {
  4802. if (!pvalCheckType(p, "pvalIncludesWalk", PV_INCLUDES))
  4803. return 0;
  4804. if (!(*next_item))
  4805. *next_item = p->u1.list;
  4806. else {
  4807. *next_item = (*next_item)->next;
  4808. }
  4809. return (*next_item)->u1.str;
  4810. }
  4811. void pvalStatementBlockAddStatement( pval *p, pval *statement)
  4812. {
  4813. if (!pvalCheckType(p, "pvalStatementBlockAddStatement", PV_STATEMENTBLOCK))
  4814. return;
  4815. p->u1.list = linku1(p->u1.list, statement);
  4816. }
  4817. pval *pvalStatementBlockWalkStatements( pval *p, pval **next_statement)
  4818. {
  4819. if (!pvalCheckType(p, "pvalStatementBlockWalkStatements", PV_STATEMENTBLOCK))
  4820. return 0;
  4821. if (!(*next_statement))
  4822. *next_statement = p->u1.list;
  4823. else {
  4824. *next_statement = (*next_statement)->next;
  4825. }
  4826. return *next_statement;
  4827. }
  4828. void pvalVarDecSetVarname( pval *p, char *name )
  4829. {
  4830. if (!pvalCheckType(p, "pvalVarDecSetVarname", PV_VARDEC))
  4831. return;
  4832. p->u1.str = name;
  4833. }
  4834. void pvalVarDecSetValue( pval *p, char *value )
  4835. {
  4836. if (!pvalCheckType(p, "pvalVarDecSetValue", PV_VARDEC))
  4837. return;
  4838. p->u2.val = value;
  4839. }
  4840. char* pvalVarDecGetVarname( pval *p )
  4841. {
  4842. if (!pvalCheckType(p, "pvalVarDecGetVarname", PV_VARDEC))
  4843. return 0;
  4844. return p->u1.str;
  4845. }
  4846. char* pvalVarDecGetValue( pval *p )
  4847. {
  4848. if (!pvalCheckType(p, "pvalVarDecGetValue", PV_VARDEC))
  4849. return 0;
  4850. return p->u2.val;
  4851. }
  4852. void pvalGotoSetTarget( pval *p, char *context, char *exten, char *label )
  4853. {
  4854. pval *con, *ext, *pri;
  4855. if (!pvalCheckType(p, "pvalGotoSetTarget", PV_GOTO))
  4856. return;
  4857. if (context && strlen(context)) {
  4858. con = pvalCreateNode(PV_WORD);
  4859. ext = pvalCreateNode(PV_WORD);
  4860. pri = pvalCreateNode(PV_WORD);
  4861. con->u1.str = context;
  4862. ext->u1.str = exten;
  4863. pri->u1.str = label;
  4864. con->next = ext;
  4865. ext->next = pri;
  4866. p->u1.list = con;
  4867. } else if (exten && strlen(exten)) {
  4868. ext = pvalCreateNode(PV_WORD);
  4869. pri = pvalCreateNode(PV_WORD);
  4870. ext->u1.str = exten;
  4871. pri->u1.str = label;
  4872. ext->next = pri;
  4873. p->u1.list = ext;
  4874. } else {
  4875. pri = pvalCreateNode(PV_WORD);
  4876. pri->u1.str = label;
  4877. p->u1.list = pri;
  4878. }
  4879. }
  4880. void pvalGotoGetTarget( pval *p, char **context, char **exten, char **label )
  4881. {
  4882. if (!pvalCheckType(p, "pvalGotoGetTarget", PV_GOTO))
  4883. return;
  4884. if (p->u1.list && p->u1.list->next && p->u1.list->next->next) {
  4885. *context = p->u1.list->u1.str;
  4886. *exten = p->u1.list->next->u1.str;
  4887. *label = p->u1.list->next->next->u1.str;
  4888. } else if (p->u1.list && p->u1.list->next ) {
  4889. *exten = p->u1.list->u1.str;
  4890. *label = p->u1.list->next->u1.str;
  4891. *context = 0;
  4892. } else if (p->u1.list) {
  4893. *label = p->u1.list->u1.str;
  4894. *context = 0;
  4895. *exten = 0;
  4896. } else {
  4897. *context = 0;
  4898. *exten = 0;
  4899. *label = 0;
  4900. }
  4901. }
  4902. void pvalLabelSetName( pval *p, char *name )
  4903. {
  4904. if (!pvalCheckType(p, "pvalLabelSetName", PV_LABEL))
  4905. return;
  4906. p->u1.str = name;
  4907. }
  4908. char* pvalLabelGetName( pval *p )
  4909. {
  4910. if (!pvalCheckType(p, "pvalLabelGetName", PV_LABEL))
  4911. return 0;
  4912. return p->u1.str;
  4913. }
  4914. void pvalForSetInit( pval *p, char *init )
  4915. {
  4916. if (!pvalCheckType(p, "pvalForSetInit", PV_FOR))
  4917. return;
  4918. p->u1.for_init = init;
  4919. }
  4920. void pvalForSetTest( pval *p, char *test )
  4921. {
  4922. if (!pvalCheckType(p, "pvalForSetTest", PV_FOR))
  4923. return;
  4924. p->u2.for_test = test;
  4925. }
  4926. void pvalForSetInc( pval *p, char *inc )
  4927. {
  4928. if (!pvalCheckType(p, "pvalForSetInc", PV_FOR))
  4929. return;
  4930. p->u3.for_inc = inc;
  4931. }
  4932. void pvalForSetStatement( pval *p, pval *statement )
  4933. {
  4934. if (!pvalCheckType(p, "pvalForSetStatement", PV_FOR))
  4935. return;
  4936. p->u4.for_statements = statement;
  4937. }
  4938. char* pvalForGetInit( pval *p )
  4939. {
  4940. if (!pvalCheckType(p, "pvalForGetInit", PV_FOR))
  4941. return 0;
  4942. return p->u1.for_init;
  4943. }
  4944. char* pvalForGetTest( pval *p )
  4945. {
  4946. if (!pvalCheckType(p, "pvalForGetTest", PV_FOR))
  4947. return 0;
  4948. return p->u2.for_test;
  4949. }
  4950. char* pvalForGetInc( pval *p )
  4951. {
  4952. if (!pvalCheckType(p, "pvalForGetInc", PV_FOR))
  4953. return 0;
  4954. return p->u3.for_inc;
  4955. }
  4956. pval* pvalForGetStatement( pval *p )
  4957. {
  4958. if (!pvalCheckType(p, "pvalForGetStatement", PV_FOR))
  4959. return 0;
  4960. return p->u4.for_statements;
  4961. }
  4962. void pvalIfSetCondition( pval *p, char *expr )
  4963. {
  4964. if (!pvalCheckType(p, "pvalIfSetCondition", PV_IF))
  4965. return;
  4966. p->u1.str = expr;
  4967. }
  4968. char* pvalIfGetCondition( pval *p )
  4969. {
  4970. if (!pvalCheckType(p, "pvalIfGetCondition", PV_IFTIME))
  4971. return 0;
  4972. return p->u1.str;
  4973. }
  4974. void pvalIfTimeSetCondition( pval *p, char *hour_range, char *dow_range, char *dom_range, char *mon_range ) /* time range format: 24-hour format begin-end|dow range|dom range|month range */
  4975. {
  4976. pval *hr = pvalCreateNode(PV_WORD);
  4977. pval *dow = pvalCreateNode(PV_WORD);
  4978. pval *dom = pvalCreateNode(PV_WORD);
  4979. pval *mon = pvalCreateNode(PV_WORD);
  4980. if (!pvalCheckType(p, "pvalIfTimeSetCondition", PV_IFTIME))
  4981. return;
  4982. pvalWordSetString(hr, hour_range);
  4983. pvalWordSetString(dow, dow_range);
  4984. pvalWordSetString(dom, dom_range);
  4985. pvalWordSetString(mon, mon_range);
  4986. dom->next = mon;
  4987. dow->next = dom;
  4988. hr->next = dow;
  4989. p->u1.list = hr;
  4990. }
  4991. /* is this right??? come back and correct it */
  4992. void pvalIfTimeGetCondition( pval *p, char **hour_range, char **dow_range, char **dom_range, char **month_range )
  4993. {
  4994. if (!pvalCheckType(p, "pvalIfTimeGetCondition", PV_IFTIME))
  4995. return;
  4996. *hour_range = p->u1.list->u1.str;
  4997. *dow_range = p->u1.list->next->u1.str;
  4998. *dom_range = p->u1.list->next->next->u1.str;
  4999. *month_range = p->u1.list->next->next->next->u1.str;
  5000. }
  5001. void pvalRandomSetCondition( pval *p, char *percent )
  5002. {
  5003. if (!pvalCheckType(p, "pvalRandomSetCondition", PV_RANDOM))
  5004. return;
  5005. p->u1.str = percent;
  5006. }
  5007. char* pvalRandomGetCondition( pval *p )
  5008. {
  5009. if (!pvalCheckType(p, "pvalRandomGetCondition", PV_RANDOM))
  5010. return 0;
  5011. return p->u1.str;
  5012. }
  5013. void pvalConditionalSetThenStatement( pval *p, pval *statement )
  5014. {
  5015. p->u2.statements = statement;
  5016. }
  5017. void pvalConditionalSetElseStatement( pval *p, pval *statement )
  5018. {
  5019. p->u3.else_statements = statement;
  5020. }
  5021. pval* pvalConditionalGetThenStatement( pval *p )
  5022. {
  5023. return p->u2.statements;
  5024. }
  5025. pval* pvalConditionalGetElseStatement( pval *p )
  5026. {
  5027. return p->u3.else_statements;
  5028. }
  5029. void pvalSwitchSetTestexpr( pval *p, char *expr )
  5030. {
  5031. if (!pvalCheckType(p, "pvalSwitchSetTestexpr", PV_SWITCH))
  5032. return;
  5033. p->u1.str = expr;
  5034. }
  5035. char* pvalSwitchGetTestexpr( pval *p )
  5036. {
  5037. if (!pvalCheckType(p, "pvalSwitchGetTestexpr", PV_SWITCH))
  5038. return 0;
  5039. return p->u1.str;
  5040. }
  5041. void pvalSwitchAddCase( pval *p, pval *Case )
  5042. {
  5043. if (!pvalCheckType(p, "pvalSwitchAddCase", PV_SWITCH))
  5044. return;
  5045. if (!pvalCheckType(Case, "pvalSwitchAddCase", PV_CASE))
  5046. return;
  5047. if (!p->u2.statements)
  5048. p->u2.statements = Case;
  5049. else
  5050. linku1(p->u2.statements, Case);
  5051. }
  5052. pval* pvalSwitchWalkCases( pval *p, pval **next_case )
  5053. {
  5054. if (!pvalCheckType(p, "pvalSwitchWalkCases", PV_SWITCH))
  5055. return 0;
  5056. if (!(*next_case))
  5057. *next_case = p->u2.statements;
  5058. else {
  5059. *next_case = (*next_case)->next;
  5060. }
  5061. return *next_case;
  5062. }
  5063. void pvalExtenSetName( pval *p, char *name )
  5064. {
  5065. if (!pvalCheckType(p, "pvalExtenSetName", PV_EXTENSION))
  5066. return;
  5067. p->u1.str = name;
  5068. }
  5069. char* pvalExtenGetName( pval *p )
  5070. {
  5071. if (!pvalCheckType(p, "pvalExtenGetName", PV_EXTENSION))
  5072. return 0;
  5073. return p->u1.str;
  5074. }
  5075. void pvalExtenSetRegexten( pval *p )
  5076. {
  5077. if (!pvalCheckType(p, "pvalExtenSetRegexten", PV_EXTENSION))
  5078. return;
  5079. p->u4.regexten = 1;
  5080. }
  5081. void pvalExtenUnSetRegexten( pval *p )
  5082. {
  5083. if (!pvalCheckType(p, "pvalExtenUnSetRegexten", PV_EXTENSION))
  5084. return;
  5085. p->u4.regexten = 0;
  5086. }
  5087. int pvalExtenGetRegexten( pval *p )
  5088. {
  5089. if (!pvalCheckType(p, "pvalExtenGetRegexten", PV_EXTENSION))
  5090. return 0;
  5091. return p->u4.regexten;
  5092. }
  5093. void pvalExtenSetHints( pval *p, char *hints )
  5094. {
  5095. if (!pvalCheckType(p, "pvalExtenSetHints", PV_EXTENSION))
  5096. return;
  5097. p->u3.hints = hints;
  5098. }
  5099. char* pvalExtenGetHints( pval *p )
  5100. {
  5101. if (!pvalCheckType(p, "pvalExtenGetHints", PV_EXTENSION))
  5102. return 0;
  5103. return p->u3.hints;
  5104. }
  5105. void pvalExtenSetStatement( pval *p, pval *statement )
  5106. {
  5107. if (!pvalCheckType(p, "pvalExtenSetStatement", PV_EXTENSION))
  5108. return;
  5109. p->u2.statements = statement;
  5110. }
  5111. pval* pvalExtenGetStatement( pval *p )
  5112. {
  5113. if (!pvalCheckType(p, "pvalExtenGetStatement", PV_EXTENSION))
  5114. return 0;
  5115. return p->u2.statements;
  5116. }
  5117. void pvalIgnorePatSetPattern( pval *p, char *pat )
  5118. {
  5119. if (!pvalCheckType(p, "pvalIgnorePatSetPattern", PV_IGNOREPAT))
  5120. return;
  5121. p->u1.str = pat;
  5122. }
  5123. char* pvalIgnorePatGetPattern( pval *p )
  5124. {
  5125. if (!pvalCheckType(p, "pvalIgnorePatGetPattern", PV_IGNOREPAT))
  5126. return 0;
  5127. return p->u1.str;
  5128. }
  5129. void pvalGlobalsAddStatement( pval *p, pval *statement )
  5130. {
  5131. if (p->type != PV_GLOBALS) {
  5132. ast_log(LOG_ERROR, "pvalGlobalsAddStatement called where first arg is not a Globals!\n");
  5133. } else {
  5134. if (!p->u1.statements) {
  5135. p->u1.statements = statement;
  5136. } else {
  5137. p->u1.statements = linku1(p->u1.statements,statement);
  5138. }
  5139. }
  5140. }
  5141. pval* pvalGlobalsWalkStatements( pval *p, pval **next_statement )
  5142. {
  5143. if (!pvalCheckType(p, "pvalGlobalsWalkStatements", PV_GLOBALS))
  5144. return 0;
  5145. if (!*next_statement) {
  5146. *next_statement = p;
  5147. return p;
  5148. } else {
  5149. *next_statement = (*next_statement)->next;
  5150. return (*next_statement)->next;
  5151. }
  5152. }
  5153. void pvalTopLevAddObject( pval *p, pval *contextOrObj )
  5154. {
  5155. if (p) {
  5156. linku1(p,contextOrObj);
  5157. } else {
  5158. ast_log(LOG_ERROR, "First arg to pvalTopLevel is NULL!\n");
  5159. }
  5160. }
  5161. pval *pvalTopLevWalkObjects(pval *p, pval **next_obj )
  5162. {
  5163. if (!*next_obj) {
  5164. *next_obj = p;
  5165. return p;
  5166. } else {
  5167. *next_obj = (*next_obj)->next;
  5168. return (*next_obj)->next;
  5169. }
  5170. }
  5171. /* append second element to the list in the first one via next pointers */
  5172. pval * linku1(pval *head, pval *tail)
  5173. {
  5174. if (!head)
  5175. return tail;
  5176. if (tail) {
  5177. if (!head->next) {
  5178. head->next = tail;
  5179. } else {
  5180. head->u1_last->next = tail;
  5181. }
  5182. head->u1_last = tail;
  5183. tail->prev = head; /* the dad link only points to containers */
  5184. }
  5185. return head;
  5186. }