1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469 |
- /*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster@digium.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- */
- /*! \file
- *
- * \brief Core PBX routines.
- *
- */
- #include <sys/types.h>
- #include <string.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <errno.h>
- #include <time.h>
- #include <sys/time.h>
- #include "asterisk.h"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
- #include "asterisk/lock.h"
- #include "asterisk/cli.h"
- #include "asterisk/pbx.h"
- #include "asterisk/channel.h"
- #include "asterisk/options.h"
- #include "asterisk/logger.h"
- #include "asterisk/file.h"
- #include "asterisk/callerid.h"
- #include "asterisk/cdr.h"
- #include "asterisk/config.h"
- #include "asterisk/term.h"
- #include "asterisk/manager.h"
- #include "asterisk/ast_expr.h"
- #include "asterisk/linkedlists.h"
- #include "asterisk/say.h"
- #include "asterisk/utils.h"
- #include "asterisk/causes.h"
- #include "asterisk/musiconhold.h"
- #include "asterisk/app.h"
- #include "asterisk/devicestate.h"
- #include "asterisk/compat.h"
- /*!
- * \note I M P O R T A N T :
- *
- * The speed of extension handling will likely be among the most important
- * aspects of this PBX. The switching scheme as it exists right now isn't
- * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
- * of priorities, but a constant search time here would be great ;-)
- *
- */
- #ifdef LOW_MEMORY
- #define EXT_DATA_SIZE 256
- #else
- #define EXT_DATA_SIZE 8192
- #endif
- #define SWITCH_DATA_LENGTH 256
- #define VAR_BUF_SIZE 4096
- #define VAR_NORMAL 1
- #define VAR_SOFTTRAN 2
- #define VAR_HARDTRAN 3
- #define BACKGROUND_SKIP (1 << 0)
- #define BACKGROUND_NOANSWER (1 << 1)
- #define BACKGROUND_MATCHEXTEN (1 << 2)
- #define BACKGROUND_PLAYBACK (1 << 3)
- AST_APP_OPTIONS(background_opts, {
- AST_APP_OPTION('s', BACKGROUND_SKIP),
- AST_APP_OPTION('n', BACKGROUND_NOANSWER),
- AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
- AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
- });
- #define WAITEXTEN_MOH (1 << 0)
- AST_APP_OPTIONS(waitexten_opts, {
- AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
- });
- struct ast_context;
- /*!\brief ast_exten: An extension
- The dialplan is saved as a linked list with each context
- having it's own linked list of extensions - one item per
- priority.
- */
- struct ast_exten {
- char *exten; /* Extension name */
- int matchcid; /* Match caller id ? */
- char *cidmatch; /* Caller id to match for this extension */
- int priority; /* Priority */
- char *label; /* Label */
- struct ast_context *parent; /* The context this extension belongs to */
- char *app; /* Application to execute */
- void *data; /* Data to use (arguments) */
- void (*datad)(void *); /* Data destructor */
- struct ast_exten *peer; /* Next higher priority with our extension */
- const char *registrar; /* Registrar */
- struct ast_exten *next; /* Extension with a greater ID */
- char stuff[0];
- };
- /*! \brief ast_include: include= support in extensions.conf */
- struct ast_include {
- char *name;
- char *rname; /* Context to include */
- const char *registrar; /* Registrar */
- int hastime; /* If time construct exists */
- struct ast_timing timing; /* time construct */
- struct ast_include *next; /* Link them together */
- char stuff[0];
- };
- /*! \brief ast_sw: Switch statement in extensions.conf */
- struct ast_sw {
- char *name;
- const char *registrar; /* Registrar */
- char *data; /* Data load */
- int eval;
- struct ast_sw *next; /* Link them together */
- char *tmpdata;
- char stuff[0];
- };
- /*! \brief ast_ignorepat: Ignore patterns in dial plan */
- struct ast_ignorepat {
- const char *registrar;
- struct ast_ignorepat *next;
- char pattern[0];
- };
- /*! \brief ast_context: An extension context */
- struct ast_context {
- ast_mutex_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
- struct ast_exten *root; /*!< The root of the list of extensions */
- struct ast_context *next; /*!< Link them together */
- struct ast_include *includes; /*!< Include other contexts */
- struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
- const char *registrar; /*!< Registrar */
- struct ast_sw *alts; /*!< Alternative switches */
- char name[0]; /*!< Name of the context */
- };
- /*! \brief ast_app: A registered application */
- struct ast_app {
- int (*execute)(struct ast_channel *chan, void *data);
- const char *synopsis; /* Synopsis text for 'show applications' */
- const char *description; /* Description (help text) for 'show application <name>' */
- struct ast_app *next; /* Next app in list */
- char name[0]; /* Name of the application */
- };
- /*! \brief ast_state_cb: An extension state notify register item */
- struct ast_state_cb {
- int id;
- void *data;
- ast_state_cb_type callback;
- struct ast_state_cb *next;
- };
-
- /*! \brief Structure for dial plan hints
- Hints are pointers from an extension in the dialplan to one or
- more devices (tech/name) */
- struct ast_hint {
- struct ast_exten *exten; /*!< Extension */
- int laststate; /*!< Last known state */
- struct ast_state_cb *callbacks; /*!< Callback list for this extension */
- struct ast_hint *next; /*!< Pointer to next hint in list */
- };
- int ast_pbx_outgoing_cdr_failed(void);
- static int pbx_builtin_answer(struct ast_channel *, void *);
- static int pbx_builtin_goto(struct ast_channel *, void *);
- static int pbx_builtin_hangup(struct ast_channel *, void *);
- static int pbx_builtin_background(struct ast_channel *, void *);
- static int pbx_builtin_dtimeout(struct ast_channel *, void *);
- static int pbx_builtin_rtimeout(struct ast_channel *, void *);
- static int pbx_builtin_atimeout(struct ast_channel *, void *);
- static int pbx_builtin_wait(struct ast_channel *, void *);
- static int pbx_builtin_waitexten(struct ast_channel *, void *);
- static int pbx_builtin_setlanguage(struct ast_channel *, void *);
- static int pbx_builtin_resetcdr(struct ast_channel *, void *);
- static int pbx_builtin_setaccount(struct ast_channel *, void *);
- static int pbx_builtin_setamaflags(struct ast_channel *, void *);
- static int pbx_builtin_ringing(struct ast_channel *, void *);
- static int pbx_builtin_progress(struct ast_channel *, void *);
- static int pbx_builtin_congestion(struct ast_channel *, void *);
- static int pbx_builtin_busy(struct ast_channel *, void *);
- static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
- static int pbx_builtin_noop(struct ast_channel *, void *);
- static int pbx_builtin_gotoif(struct ast_channel *, void *);
- static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
- static int pbx_builtin_execiftime(struct ast_channel *, void *);
- static int pbx_builtin_saynumber(struct ast_channel *, void *);
- static int pbx_builtin_saydigits(struct ast_channel *, void *);
- static int pbx_builtin_saycharacters(struct ast_channel *, void *);
- static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
- static int pbx_builtin_setvar_old(struct ast_channel *, void *);
- int pbx_builtin_setvar(struct ast_channel *, void *);
- static int pbx_builtin_importvar(struct ast_channel *, void *);
- static struct varshead globals;
- static int autofallthrough = 0;
- AST_MUTEX_DEFINE_STATIC(maxcalllock);
- static int countcalls = 0;
- AST_MUTEX_DEFINE_STATIC(acflock); /*!< Lock for the custom function list */
- static struct ast_custom_function *acf_root = NULL;
- /*! \brief Declaration of builtin applications */
- static struct pbx_builtin {
- char name[AST_MAX_APP];
- int (*execute)(struct ast_channel *chan, void *data);
- char *synopsis;
- char *description;
- } builtins[] =
- {
- /* These applications are built into the PBX core and do not
- need separate modules */
- { "AbsoluteTimeout", pbx_builtin_atimeout,
- "Set absolute maximum time of call",
- " AbsoluteTimeout(seconds): This application will set the absolute maximum\n"
- "amount of time permitted for a call. A setting of 0 disables the timeout.\n"
- " AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
- },
- { "Answer", pbx_builtin_answer,
- "Answer a channel if ringing",
- " Answer([delay]): If the call has not been answered, this application will\n"
- "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
- "Asterisk will wait this number of milliseconds before answering the call.\n"
- },
- { "BackGround", pbx_builtin_background,
- "Play a file while awaiting extension",
- " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
- "This application will play the given list of files while waiting for an\n"
- "extension to be dialed by the calling channel. To continue waiting for digits\n"
- "after this application has finished playing files, the WaitExten application\n"
- "should be used. The 'langoverride' option explicity specifies which language\n"
- "to attempt to use for the requested sound files. If a 'context' is specified,\n"
- "this is the dialplan context that this application will use when exiting to a\n"
- "dialed extension."
- " If one of the requested sound files does not exist, call processing will be\n"
- "terminated.\n"
- " Options:\n"
- " s - causes the playback of the message to be skipped\n"
- " if the channel is not in the 'up' state (i.e. it\n"
- " hasn't been answered yet.) If this happens, the\n"
- " application will return immediately.\n"
- " n - don't answer the channel before playing the files\n"
- " m - only break if a digit hit matches a one digit\n"
- " extension in the destination context\n"
- },
- { "Busy", pbx_builtin_busy,
- "Indicate the Busy condition",
- " Busy([timeout]): This application will indicate the busy condition to\n"
- "the calling channel. If the optional timeout is specified, the calling channel\n"
- "will be hung up after the specified number of seconds. Otherwise, this\n"
- "application will wait until the calling channel hangs up.\n"
- },
- { "Congestion", pbx_builtin_congestion,
- "Indicate the Congestion condition",
- " Congestion([timeout]): This application will indicate the congenstion\n"
- "condition to the calling channel. If the optional timeout is specified, the\n"
- "calling channel will be hung up after the specified number of seconds.\n"
- "Otherwise, this application will wait until the calling channel hangs up.\n"
- },
- { "DigitTimeout", pbx_builtin_dtimeout,
- "Set maximum timeout between digits",
- " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
- "digits when the user is typing in an extension. When this timeout expires,\n"
- "after the user has started to type in an extension, the extension will be\n"
- "considered complete, and will be interpreted. Note that if an extension\n"
- "typed in is valid, it will not have to timeout to be tested, so typically\n"
- "at the expiry of this timeout, the extension will be considered invalid\n"
- "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
- "exist the call would be terminated). The default timeout is 5 seconds.\n"
- " DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout)\n"
- },
- { "Goto", pbx_builtin_goto,
- "Jump to a particular priority, extension, or context",
- " Goto([[context|]extension|]priority): This application will cause the\n"
- "calling channel to continue dialplan execution at the specified priority.\n"
- "If no specific extension, or extension and context, are specified, then this\n"
- "application will jump to the specified priority of the current extension.\n"
- " If the attempt to jump to another location in the dialplan is not successful,\n"
- "then the channel will continue at the next priority of the current extension.\n"
- },
- { "GotoIf", pbx_builtin_gotoif,
- "Conditional goto",
- " GotoIf(Condition?[label1]:[label2]): This application will cause the calling\n"
- "channel to jump to the speicifed location in the dialplan based on the\n"
- "evaluation of the given condition. The channel will continue at 'label1' if the\n"
- "condition is true, or 'label2' if the condition is false. The labels are\n"
- "specified in the same syntax that is used with the Goto application.\n"
- },
- { "GotoIfTime", pbx_builtin_gotoiftime,
- "Conditional Goto based on the current time",
- " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
- "This application will have the calling channel jump to the speicified location\n"
- "int the dialplan if the current time matches the given time specification.\n"
- "Further information on the time specification can be found in examples\n"
- "illustrating how to do time-based context includes in the dialplan.\n"
- },
- { "ExecIfTime", pbx_builtin_execiftime,
- "Conditional application execution based on the current time",
- " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
- "This application will execute the specified dialplan application, with optional\n"
- "arguments, if the current time matches the given time specification. Further\n"
- "information on the time speicification can be found in examples illustrating\n"
- "how to do time-based context includes in the dialplan.\n"
- },
-
- { "Hangup", pbx_builtin_hangup,
- "Hang up the calling channel",
- " Hangup(): This application will hang up the calling channel.\n"
- },
- { "NoOp", pbx_builtin_noop,
- "Do Nothing",
- " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
- "purposes. Any text that is provided as arguments to this application can be\n"
- "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
- "variables or functions without having any effect."
- },
- { "Progress", pbx_builtin_progress,
- "Indicate progress",
- " Progress(): This application will request that in-band progress information\n"
- "be provided to the calling channel.\n"
- },
- { "ResetCDR", pbx_builtin_resetcdr,
- "Resets the Call Data Record",
- " ResetCDR([options]): This application causes the Call Data Record to be\n"
- "reset.\n"
- " Options:\n"
- " w -- Store the current CDR record before resetting it.\n"
- " a -- Store any stacked records.\n"
- " v -- Save CDR variables.\n"
- },
- { "ResponseTimeout", pbx_builtin_rtimeout,
- "Set maximum timeout awaiting response",
- " ResponseTimeout(seconds): This will set the maximum amount of time permitted\n"
- "to wait for an extension to dialed (see the WaitExten application), before the\n"
- "timeout occurs. If this timeout is reached, dialplan execution will continue at\n"
- "the 't' extension, if it exists.\n"
- " ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout)\n"
- },
- { "Ringing", pbx_builtin_ringing,
- "Indicate ringing tone",
- " Ringing(): This application will request that the channel indicate a ringing\n"
- "tone to the user.\n"
- },
- { "SayNumber", pbx_builtin_saynumber,
- "Say Number",
- " SayNumber(digits[,gender]): This application will play the sounds that\n"
- "correspond to the given number. Optionally, a gender may be specified.\n"
- "This will use the language that is currently set for the channel. See the\n"
- "LANGUAGE function for more information on setting the language for the channel.\n"
- },
- { "SayDigits", pbx_builtin_saydigits,
- "Say Digits",
- " SayDigits(digits): This application will play the sounds that correspond\n"
- "to the digits of the given number. This will use the language that is currently\n"
- "set for the channel. See the LANGUAGE function for more information on setting\n"
- "the language for the channel.\n"
- },
- { "SayAlpha", pbx_builtin_saycharacters,
- "Say Alpha",
- " SayAlpha(string): This application will play the sounds that correspond to\n"
- "the letters of the given string.\n"
- },
- { "SayPhonetic", pbx_builtin_sayphonetic,
- "Say Phonetic",
- " SayPhonetic(string): This application will play the sounds from the phonetic\n"
- "alphabet that correspond to the letters in the given string.\n"
- },
- { "SetAccount", pbx_builtin_setaccount,
- "Set the CDR Account Code",
- " SetAccount([account]): This application will set the channel account code for\n"
- "billing purposes.\n"
- " SetAccount has been deprecated in favor of the Set(CDR(accountcode)=account).\n"
- },
- { "SetAMAFlags", pbx_builtin_setamaflags,
- "Set the AMA Flags",
- " SetAMAFlags([flag]): This channel will set the channel's AMA Flags for billing\n"
- "purposes.\n"
- },
- { "SetGlobalVar", pbx_builtin_setglobalvar,
- "Set a global variable to a given value",
- " SetGlobalVar(variable=value): This application sets a given global variable to\n"
- "the specified value.\n"
- },
- { "SetLanguage", pbx_builtin_setlanguage,
- "Set the channel's preferred language",
- " SetLanguage(language): This will set the channel language to the given value.\n"
- "This information is used for the syntax in generation of numbers, and to choose\n"
- "a sound file in the given language, when it is available.\n"
- " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
- "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
- "it will play that file. If not, it will play the normal 'demo-congrats'.\n"
- "For some language codes, SetLanguage also changes the syntax of some\n"
- "Asterisk functions, like SayNumber.\n"
- " SetLanguage has been deprecated in favor of Set(LANGUAGE()=language)\n"
- },
- { "Set", pbx_builtin_setvar,
- "Set channel variable(s) or function value(s)",
- " Set(name1=value1|name2=value2|..[|options])\n"
- "This function can be used to set the value of channel variables or dialplan\n"
- "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
- "if the variable name is prefixed with _, the variable will be inherited into\n"
- "channels created from the current channel. If the variable name is prefixed\n"
- "with __, the variable will be inherited into channels created from the current\n"
- "channel and all children channels.\n"
- " Options:\n"
- " g - Set variable globally instead of on the channel\n"
- " (applies only to variables, not functions)\n"
- },
- { "SetVar", pbx_builtin_setvar_old,
- "Set channel variable(s)",
- " SetVar(name1=value1|name2=value2|..[|options]): This application has been\n"
- "deprecated in favor of using the Set application.\n"
- },
- { "ImportVar", pbx_builtin_importvar,
- "Import a variable from a channel into a new variable",
- " ImportVar(newvar=channelname|variable): This application imports a variable\n"
- "from the specified channel (as opposed to the current one) and stores it as\n"
- "a variable in the current channel (the channel that is calling this\n"
- "application). Variables created by this application have the same inheritance\n"
- "properties as those created with the Set application. See the documentation for\n"
- "Set for more information.\n"
- },
- { "Wait", pbx_builtin_wait,
- "Waits for some time",
- " Wait(seconds): This application waits for a specified number of seconds.\n"
- "Then, dialplan execution will continue at the next priority.\n"
- " Note that the seconds can be passed with fractions of a second. For example,\n"
- "'1.5' will ask the application to wait for 1.5 seconds.\n"
- },
- { "WaitExten", pbx_builtin_waitexten,
- "Waits for an extension to be entered",
- " WaitExten([seconds][|options]): This application waits for the user to enter\n"
- "a new extension for a specified number of seconds.\n"
- " Note that the seconds can be passed with fractions of a second. For example,\n"
- "'1.5' will ask the application to wait for 1.5 seconds.\n"
- " Options:\n"
- " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
- " Optionally, specify the class for music on hold within parenthesis.\n"
- },
- };
- static struct ast_context *contexts = NULL;
- AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */
- static struct ast_app *apps = NULL;
- AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
- struct ast_switch *switches = NULL;
- AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */
- AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */
- static int stateid = 1;
- struct ast_hint *hints = NULL;
- struct ast_state_cb *statecbs = NULL;
- /*
- \note This function is special. It saves the stack so that no matter
- how many times it is called, it returns to the same place */
- int pbx_exec(struct ast_channel *c, /*!< Channel */
- struct ast_app *app, /*!< Application */
- void *data, /*!< Data for execution */
- int newstack) /*!< Force stack increment */
- {
- int res;
-
- char *saved_c_appl;
- char *saved_c_data;
-
- int (*execute)(struct ast_channel *chan, void *data) = app->execute;
- if (newstack) {
- if (c->cdr)
- ast_cdr_setapp(c->cdr, app->name, data);
- /* save channel values */
- saved_c_appl= c->appl;
- saved_c_data= c->data;
- c->appl = app->name;
- c->data = data;
- res = execute(c, data);
- /* restore channel values */
- c->appl= saved_c_appl;
- c->data= saved_c_data;
- return res;
- } else
- ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
- return -1;
- }
- /*! Go no deeper than this through includes (not counting loops) */
- #define AST_PBX_MAX_STACK 128
- #define HELPER_EXISTS 0
- #define HELPER_SPAWN 1
- #define HELPER_EXEC 2
- #define HELPER_CANMATCH 3
- #define HELPER_MATCHMORE 4
- #define HELPER_FINDLABEL 5
- /*! \brief Find application handle in linked list
- */
- struct ast_app *pbx_findapp(const char *app)
- {
- struct ast_app *tmp;
- if (ast_mutex_lock(&applock)) {
- ast_log(LOG_WARNING, "Unable to obtain application lock\n");
- return NULL;
- }
- tmp = apps;
- while(tmp) {
- if (!strcasecmp(tmp->name, app))
- break;
- tmp = tmp->next;
- }
- ast_mutex_unlock(&applock);
- return tmp;
- }
- static struct ast_switch *pbx_findswitch(const char *sw)
- {
- struct ast_switch *asw;
- if (ast_mutex_lock(&switchlock)) {
- ast_log(LOG_WARNING, "Unable to obtain application lock\n");
- return NULL;
- }
- asw = switches;
- while(asw) {
- if (!strcasecmp(asw->name, sw))
- break;
- asw = asw->next;
- }
- ast_mutex_unlock(&switchlock);
- return asw;
- }
- static inline int include_valid(struct ast_include *i)
- {
- if (!i->hastime)
- return 1;
- return ast_check_timing(&(i->timing));
- }
- static void pbx_destroy(struct ast_pbx *p)
- {
- free(p);
- }
- #define EXTENSION_MATCH_CORE(data,pattern,match) {\
- /* All patterns begin with _ */\
- if (pattern[0] != '_') \
- return 0;\
- /* Start optimistic */\
- match=1;\
- pattern++;\
- while(match && *data && *pattern && (*pattern != '/')) {\
- while (*data == '-' && (*(data+1) != '\0')) data++;\
- switch(toupper(*pattern)) {\
- case '[': \
- {\
- int i,border=0;\
- char *where;\
- match=0;\
- pattern++;\
- where=strchr(pattern,']');\
- if (where)\
- border=(int)(where-pattern);\
- if (!where || border > strlen(pattern)) {\
- ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
- return match;\
- }\
- for (i=0; i<border; i++) {\
- int res=0;\
- if (i+2<border)\
- if (pattern[i+1]=='-') {\
- if (*data >= pattern[i] && *data <= pattern[i+2]) {\
- res=1;\
- } else {\
- i+=2;\
- continue;\
- }\
- }\
- if (res==1 || *data==pattern[i]) {\
- match = 1;\
- break;\
- }\
- }\
- pattern+=border;\
- break;\
- }\
- case 'N':\
- if ((*data < '2') || (*data > '9'))\
- match=0;\
- break;\
- case 'X':\
- if ((*data < '0') || (*data > '9'))\
- match = 0;\
- break;\
- case 'Z':\
- if ((*data < '1') || (*data > '9'))\
- match = 0;\
- break;\
- case '.':\
- /* Must match */\
- return 1;\
- case '!':\
- /* Early match */\
- return 2;\
- case ' ':\
- case '-':\
- /* Ignore these characters */\
- data--;\
- break;\
- default:\
- if (*data != *pattern)\
- match =0;\
- }\
- data++;\
- pattern++;\
- }\
- /* If we ran off the end of the data and the pattern ends in '!', match */\
- if (match && !*data && (*pattern == '!'))\
- return 2;\
- }
- int ast_extension_match(const char *pattern, const char *data)
- {
- int match;
- /* If they're the same return */
- if (!strcmp(pattern, data))
- return 1;
- EXTENSION_MATCH_CORE(data,pattern,match);
- /* Must be at the end of both */
- if (*data || (*pattern && (*pattern != '/')))
- match = 0;
- return match;
- }
- int ast_extension_close(const char *pattern, const char *data, int needmore)
- {
- int match;
- /* If "data" is longer, it can'be a subset of pattern unless
- pattern is a pattern match */
- if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
- return 0;
-
- if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
- (!needmore || (strlen(pattern) > strlen(data)))) {
- return 1;
- }
- EXTENSION_MATCH_CORE(data,pattern,match);
- /* If there's more or we don't care about more, or if it's a possible early match,
- return non-zero; otherwise it's a miss */
- if (!needmore || *pattern || match == 2) {
- return match;
- } else
- return 0;
- }
- struct ast_context *ast_context_find(const char *name)
- {
- struct ast_context *tmp;
- ast_mutex_lock(&conlock);
- if (name) {
- tmp = contexts;
- while(tmp) {
- if (!strcasecmp(name, tmp->name))
- break;
- tmp = tmp->next;
- }
- } else
- tmp = contexts;
- ast_mutex_unlock(&conlock);
- return tmp;
- }
- #define STATUS_NO_CONTEXT 1
- #define STATUS_NO_EXTENSION 2
- #define STATUS_NO_PRIORITY 3
- #define STATUS_NO_LABEL 4
- #define STATUS_SUCCESS 5
- static int matchcid(const char *cidpattern, const char *callerid)
- {
- int failresult;
-
- /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
- failing to get a number should count as a match, otherwise not */
- if (!ast_strlen_zero(cidpattern))
- failresult = 0;
- else
- failresult = 1;
- if (!callerid)
- return failresult;
- return ast_extension_match(cidpattern, callerid);
- }
- static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data, const char **foundcontext)
- {
- int x, res;
- struct ast_context *tmp;
- struct ast_exten *e, *eroot;
- struct ast_include *i;
- struct ast_sw *sw;
- struct ast_switch *asw;
- /* Initialize status if appropriate */
- if (!*stacklen) {
- *status = STATUS_NO_CONTEXT;
- *swo = NULL;
- *data = NULL;
- }
- /* Check for stack overflow */
- if (*stacklen >= AST_PBX_MAX_STACK) {
- ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
- return NULL;
- }
- /* Check first to see if we've already been checked */
- for (x=0; x<*stacklen; x++) {
- if (!strcasecmp(incstack[x], context))
- return NULL;
- }
- if (bypass)
- tmp = bypass;
- else
- tmp = contexts;
- while(tmp) {
- /* Match context */
- if (bypass || !strcmp(tmp->name, context)) {
- struct ast_exten *earlymatch = NULL;
- if (*status < STATUS_NO_EXTENSION)
- *status = STATUS_NO_EXTENSION;
- for (eroot = tmp->root; eroot; eroot=eroot->next) {
- int match = 0;
- /* Match extension */
- if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
- ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
- ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
- (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
- if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
- /* It matched an extension ending in a '!' wildcard
- So ignore it for now, unless there's a better match */
- earlymatch = eroot;
- } else {
- e = eroot;
- if (*status < STATUS_NO_PRIORITY)
- *status = STATUS_NO_PRIORITY;
- while(e) {
- /* Match priority */
- if (action == HELPER_FINDLABEL) {
- if (*status < STATUS_NO_LABEL)
- *status = STATUS_NO_LABEL;
- if (label && e->label && !strcmp(label, e->label)) {
- *status = STATUS_SUCCESS;
- *foundcontext = context;
- return e;
- }
- } else if (e->priority == priority) {
- *status = STATUS_SUCCESS;
- *foundcontext = context;
- return e;
- }
- e = e->peer;
- }
- }
- }
- }
- if (earlymatch) {
- /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
- of the loop waiting for more digits, and _then_ match (normally)
- the extension we ended up with. We got an early-matching wildcard
- pattern, so return NULL to break out of the loop. */
- return NULL;
- }
- /* Check alternative switches */
- sw = tmp->alts;
- while(sw) {
- if ((asw = pbx_findswitch(sw->name))) {
- /* Substitute variables now */
- if (sw->eval)
- pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
- if (action == HELPER_CANMATCH)
- res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
- else if (action == HELPER_MATCHMORE)
- res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
- else
- res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
- if (res) {
- /* Got a match */
- *swo = asw;
- *data = sw->eval ? sw->tmpdata : sw->data;
- *foundcontext = context;
- return NULL;
- }
- } else {
- ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
- }
- sw = sw->next;
- }
- /* Setup the stack */
- incstack[*stacklen] = tmp->name;
- (*stacklen)++;
- /* Now try any includes we have in this context */
- i = tmp->includes;
- while(i) {
- if (include_valid(i)) {
- if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
- return e;
- if (*swo)
- return NULL;
- }
- i = i->next;
- }
- break;
- }
- tmp = tmp->next;
- }
- return NULL;
- }
- /* Note that it's negative -- that's important later. */
- #define DONT_HAVE_LENGTH 0x80000000
- static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
- {
- char *varchar, *offsetchar = NULL;
- int parens=0;
- *offset = 0;
- *length = DONT_HAVE_LENGTH;
- *isfunc = 0;
- for (varchar=var; *varchar; varchar++) {
- switch (*varchar) {
- case '(':
- (*isfunc)++;
- parens++;
- break;
- case ')':
- parens--;
- break;
- case ':':
- if (parens == 0) {
- offsetchar = varchar + 1;
- *varchar = '\0';
- goto pvn_endfor;
- }
- }
- }
- pvn_endfor:
- if (offsetchar) {
- sscanf(offsetchar, "%d:%d", offset, length);
- return 1;
- } else {
- return 0;
- }
- }
- static char *substring(char *value, int offset, int length, char *workspace, size_t workspace_len)
- {
- char *ret = workspace;
- /* No need to do anything */
- if (offset == 0 && length==-1) {
- return value;
- }
- ast_copy_string(workspace, value, workspace_len);
- if (abs(offset) > strlen(ret)) { /* Offset beyond string */
- if (offset >= 0)
- offset = strlen(ret);
- else
- offset =- strlen(ret);
- }
- /* Detect too-long length */
- if ((offset < 0 && length > -offset) || (offset >= 0 && offset+length > strlen(ret))) {
- if (offset >= 0)
- length = strlen(ret)-offset;
- else
- length = strlen(ret)+offset;
- }
- /* Bounce up to the right offset */
- if (offset >= 0)
- ret += offset;
- else
- ret += strlen(ret)+offset;
- /* Chop off at the requisite length */
- if (length >= 0)
- ret[length] = '\0';
- return ret;
- }
- /*! \brief pbx_retrieve_variable: Support for Asterisk built-in variables and
- functions in the dialplan
- ---*/
- void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
- {
- char tmpvar[80];
- time_t thistime;
- struct tm brokentime;
- int offset, offset2, isfunc;
- struct ast_var_t *variables;
- if (c)
- headp=&c->varshead;
- *ret=NULL;
- ast_copy_string(tmpvar, var, sizeof(tmpvar));
- if (parse_variable_name(tmpvar, &offset, &offset2, &isfunc)) {
- pbx_retrieve_variable(c, tmpvar, ret, workspace, workspacelen, headp);
- if (!(*ret))
- return;
- *ret = substring(*ret, offset, offset2, workspace, workspacelen);
- } else if (c && !strncmp(var, "CALL", 4)) {
- if (!strncmp(var + 4, "ER", 2)) {
- if (!strncmp(var + 6, "ID", 2)) {
- if (!var[8]) { /* CALLERID */
- if (c->cid.cid_num) {
- if (c->cid.cid_name) {
- snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
- } else {
- ast_copy_string(workspace, c->cid.cid_num, workspacelen);
- }
- *ret = workspace;
- } else if (c->cid.cid_name) {
- ast_copy_string(workspace, c->cid.cid_name, workspacelen);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (!strcmp(var + 8, "NUM")) {
- /* CALLERIDNUM */
- if (c->cid.cid_num) {
- ast_copy_string(workspace, c->cid.cid_num, workspacelen);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (!strcmp(var + 8, "NAME")) {
- /* CALLERIDNAME */
- if (c->cid.cid_name) {
- ast_copy_string(workspace, c->cid.cid_name, workspacelen);
- *ret = workspace;
- } else
- *ret = NULL;
- }
- } else if (!strcmp(var + 6, "ANI")) {
- /* CALLERANI */
- if (c->cid.cid_ani) {
- ast_copy_string(workspace, c->cid.cid_ani, workspacelen);
- *ret = workspace;
- } else
- *ret = NULL;
- } else
- goto icky;
- } else if (!strncmp(var + 4, "ING", 3)) {
- if (!strcmp(var + 7, "PRES")) {
- /* CALLINGPRES */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
- *ret = workspace;
- } else if (!strcmp(var + 7, "ANI2")) {
- /* CALLINGANI2 */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
- *ret = workspace;
- } else if (!strcmp(var + 7, "TON")) {
- /* CALLINGTON */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
- *ret = workspace;
- } else if (!strcmp(var + 7, "TNS")) {
- /* CALLINGTNS */
- snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
- *ret = workspace;
- } else
- goto icky;
- } else
- goto icky;
- } else if (c && !strcmp(var, "DNID")) {
- if (c->cid.cid_dnid) {
- ast_copy_string(workspace, c->cid.cid_dnid, workspacelen);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (c && !strcmp(var, "HINT")) {
- if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
- *ret = NULL;
- else
- *ret = workspace;
- } else if (c && !strcmp(var, "HINTNAME")) {
- if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
- *ret = NULL;
- else
- *ret = workspace;
- } else if (c && !strcmp(var, "EXTEN")) {
- ast_copy_string(workspace, c->exten, workspacelen);
- *ret = workspace;
- } else if (c && !strcmp(var, "RDNIS")) {
- if (c->cid.cid_rdnis) {
- ast_copy_string(workspace, c->cid.cid_rdnis, workspacelen);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (c && !strcmp(var, "CONTEXT")) {
- ast_copy_string(workspace, c->context, workspacelen);
- *ret = workspace;
- } else if (c && !strcmp(var, "PRIORITY")) {
- snprintf(workspace, workspacelen, "%d", c->priority);
- *ret = workspace;
- } else if (c && !strcmp(var, "CHANNEL")) {
- ast_copy_string(workspace, c->name, workspacelen);
- *ret = workspace;
- } else if (!strcmp(var, "EPOCH")) {
- snprintf(workspace, workspacelen, "%u",(int)time(NULL));
- *ret = workspace;
- } else if (!strcmp(var, "DATETIME")) {
- thistime=time(NULL);
- localtime_r(&thistime, &brokentime);
- snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
- brokentime.tm_mday,
- brokentime.tm_mon+1,
- brokentime.tm_year+1900,
- brokentime.tm_hour,
- brokentime.tm_min,
- brokentime.tm_sec
- );
- *ret = workspace;
- } else if (!strcmp(var, "TIMESTAMP")) {
- thistime=time(NULL);
- localtime_r(&thistime, &brokentime);
- /* 20031130-150612 */
- snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
- brokentime.tm_year+1900,
- brokentime.tm_mon+1,
- brokentime.tm_mday,
- brokentime.tm_hour,
- brokentime.tm_min,
- brokentime.tm_sec
- );
- *ret = workspace;
- } else if (c && !strcmp(var, "UNIQUEID")) {
- snprintf(workspace, workspacelen, "%s", c->uniqueid);
- *ret = workspace;
- } else if (c && !strcmp(var, "HANGUPCAUSE")) {
- snprintf(workspace, workspacelen, "%d", c->hangupcause);
- *ret = workspace;
- } else if (c && !strcmp(var, "ACCOUNTCODE")) {
- ast_copy_string(workspace, c->accountcode, workspacelen);
- *ret = workspace;
- } else if (c && !strcmp(var, "LANGUAGE")) {
- ast_copy_string(workspace, c->language, workspacelen);
- *ret = workspace;
- } else {
- icky:
- if (headp) {
- AST_LIST_TRAVERSE(headp,variables,entries) {
- #if 0
- ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
- #endif
- if (strcasecmp(ast_var_name(variables),var)==0) {
- *ret=ast_var_value(variables);
- if (*ret) {
- ast_copy_string(workspace, *ret, workspacelen);
- *ret = workspace;
- }
- break;
- }
- }
- }
- if (!(*ret)) {
- /* Try globals */
- AST_LIST_TRAVERSE(&globals,variables,entries) {
- #if 0
- ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
- #endif
- if (strcasecmp(ast_var_name(variables),var)==0) {
- *ret = ast_var_value(variables);
- if (*ret) {
- ast_copy_string(workspace, *ret, workspacelen);
- *ret = workspace;
- }
- }
- }
- }
- }
- }
- /*! \brief CLI function to show installed custom functions
- \addtogroup CLI_functions
- */
- static int handle_show_functions(int fd, int argc, char *argv[])
- {
- struct ast_custom_function *acf;
- int count_acf = 0;
- ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
- for (acf = acf_root ; acf; acf = acf->next) {
- ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
- count_acf++;
- }
- ast_cli(fd, "%d custom functions installed.\n", count_acf);
- return 0;
- }
- static int handle_show_function(int fd, int argc, char *argv[])
- {
- struct ast_custom_function *acf;
- /* Maximum number of characters added by terminal coloring is 22 */
- char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
- char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
- char stxtitle[40], *syntax = NULL;
- int synopsis_size, description_size, syntax_size;
- if (argc < 3) return RESULT_SHOWUSAGE;
- if (!(acf = ast_custom_function_find(argv[2]))) {
- ast_cli(fd, "No function by that name registered.\n");
- return RESULT_FAILURE;
- }
- if (acf->synopsis)
- synopsis_size = strlen(acf->synopsis) + 23;
- else
- synopsis_size = strlen("Not available") + 23;
- synopsis = alloca(synopsis_size);
-
- if (acf->desc)
- description_size = strlen(acf->desc) + 23;
- else
- description_size = strlen("Not available") + 23;
- description = alloca(description_size);
- if (acf->syntax)
- syntax_size = strlen(acf->syntax) + 23;
- else
- syntax_size = strlen("Not available") + 23;
- syntax = alloca(syntax_size);
- snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
- term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
- term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
- term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
- term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
- term_color(syntax,
- acf->syntax ? acf->syntax : "Not available",
- COLOR_CYAN, 0, syntax_size);
- term_color(synopsis,
- acf->synopsis ? acf->synopsis : "Not available",
- COLOR_CYAN, 0, synopsis_size);
- term_color(description,
- acf->desc ? acf->desc : "Not available",
- COLOR_CYAN, 0, description_size);
-
- ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
- return RESULT_SUCCESS;
- }
- static char *complete_show_function(char *line, char *word, int pos, int state)
- {
- struct ast_custom_function *acf;
- int which = 0;
- /* try to lock functions list ... */
- if (ast_mutex_lock(&acflock)) {
- ast_log(LOG_ERROR, "Unable to lock function list\n");
- return NULL;
- }
- acf = acf_root;
- while (acf) {
- if (!strncasecmp(word, acf->name, strlen(word))) {
- if (++which > state) {
- char *ret = strdup(acf->name);
- ast_mutex_unlock(&acflock);
- return ret;
- }
- }
- acf = acf->next;
- }
- ast_mutex_unlock(&acflock);
- return NULL;
- }
- struct ast_custom_function* ast_custom_function_find(char *name)
- {
- struct ast_custom_function *acfptr;
- /* try to lock functions list ... */
- if (ast_mutex_lock(&acflock)) {
- ast_log(LOG_ERROR, "Unable to lock function list\n");
- return NULL;
- }
- for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
- if (!strcmp(name, acfptr->name)) {
- break;
- }
- }
- ast_mutex_unlock(&acflock);
-
- return acfptr;
- }
- int ast_custom_function_unregister(struct ast_custom_function *acf)
- {
- struct ast_custom_function *acfptr, *lastacf = NULL;
- int res = -1;
- if (!acf)
- return -1;
- /* try to lock functions list ... */
- if (ast_mutex_lock(&acflock)) {
- ast_log(LOG_ERROR, "Unable to lock function list\n");
- return -1;
- }
- for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
- if (acfptr == acf) {
- if (lastacf) {
- lastacf->next = acf->next;
- } else {
- acf_root = acf->next;
- }
- res = 0;
- break;
- }
- lastacf = acfptr;
- }
- ast_mutex_unlock(&acflock);
- if (!res && (option_verbose > 1))
- ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
- return res;
- }
- int ast_custom_function_register(struct ast_custom_function *acf)
- {
- if (!acf)
- return -1;
- /* try to lock functions list ... */
- if (ast_mutex_lock(&acflock)) {
- ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
- return -1;
- }
- if (ast_custom_function_find(acf->name)) {
- ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
- ast_mutex_unlock(&acflock);
- return -1;
- }
- acf->next = acf_root;
- acf_root = acf;
- ast_mutex_unlock(&acflock);
- if (option_verbose > 1)
- ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
- return 0;
- }
- char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
- {
- char *args = NULL, *function, *p;
- char *ret = "0";
- struct ast_custom_function *acfptr;
- function = ast_strdupa(in);
- if (!function) {
- ast_log(LOG_ERROR, "Out of memory\n");
- return ret;
- }
- if ((args = strchr(function, '('))) {
- *args = '\0';
- args++;
- if ((p = strrchr(args, ')'))) {
- *p = '\0';
- } else {
- ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
- }
- } else {
- ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
- }
- if ((acfptr = ast_custom_function_find(function))) {
- /* run the custom function */
- if (acfptr->read) {
- return acfptr->read(chan, function, args, workspace, len);
- } else {
- ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
- }
- } else {
- ast_log(LOG_ERROR, "Function %s not registered\n", function);
- }
- return ret;
- }
- void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
- {
- char *args = NULL, *function, *p;
- struct ast_custom_function *acfptr;
- function = ast_strdupa(in);
- if (!function) {
- ast_log(LOG_ERROR, "Out of memory\n");
- return;
- }
- if ((args = strchr(function, '('))) {
- *args = '\0';
- args++;
- if ((p = strrchr(args, ')'))) {
- *p = '\0';
- } else {
- ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
- }
- } else {
- ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
- }
- if ((acfptr = ast_custom_function_find(function))) {
- /* run the custom function */
- if (acfptr->write) {
- acfptr->write(chan, function, args, value);
- } else {
- ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
- }
- } else {
- ast_log(LOG_ERROR, "Function %s not registered\n", function);
- }
- }
- static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
- {
- char *cp4;
- const char *tmp, *whereweare;
- int length, offset, offset2, isfunction;
- char *workspace = NULL;
- char *ltmp = NULL, *var = NULL;
- char *nextvar, *nextexp, *nextthing;
- char *vars, *vare;
- int pos, brackets, needsub, len;
-
- /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
- zero-filled */
- whereweare=tmp=cp1;
- while(!ast_strlen_zero(whereweare) && count) {
- /* Assume we're copying the whole remaining string */
- pos = strlen(whereweare);
- nextvar = NULL;
- nextexp = NULL;
- nextthing = strchr(whereweare, '$');
- if (nextthing) {
- switch(nextthing[1]) {
- case '{':
- nextvar = nextthing;
- pos = nextvar - whereweare;
- break;
- case '[':
- nextexp = nextthing;
- pos = nextexp - whereweare;
- break;
- }
- }
- if (pos) {
- /* Can't copy more than 'count' bytes */
- if (pos > count)
- pos = count;
-
- /* Copy that many bytes */
- memcpy(cp2, whereweare, pos);
-
- count -= pos;
- cp2 += pos;
- whereweare += pos;
- }
-
- if (nextvar) {
- /* We have a variable. Find the start and end, and determine
- if we are going to have to recursively call ourselves on the
- contents */
- vars = vare = nextvar + 2;
- brackets = 1;
- needsub = 0;
- /* Find the end of it */
- while(brackets && *vare) {
- if ((vare[0] == '$') && (vare[1] == '{')) {
- needsub++;
- brackets++;
- } else if (vare[0] == '}') {
- brackets--;
- } else if ((vare[0] == '$') && (vare[1] == '['))
- needsub++;
- vare++;
- }
- if (brackets)
- ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
- len = vare - vars - 1;
- /* Skip totally over variable string */
- whereweare += (len + 3);
- if (!var)
- var = alloca(VAR_BUF_SIZE);
- /* Store variable name (and truncate) */
- ast_copy_string(var, vars, len + 1);
- /* Substitute if necessary */
- if (needsub) {
- if (!ltmp)
- ltmp = alloca(VAR_BUF_SIZE);
- memset(ltmp, 0, VAR_BUF_SIZE);
- pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
- vars = ltmp;
- } else {
- vars = var;
- }
- if (!workspace)
- workspace = alloca(VAR_BUF_SIZE);
- workspace[0] = '\0';
- parse_variable_name(vars, &offset, &offset2, &isfunction);
- if (isfunction) {
- /* Evaluate function */
- cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE);
- ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
- } else {
- /* Retrieve variable value */
- pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
- }
- if (cp4) {
- cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
- length = strlen(cp4);
- if (length > count)
- length = count;
- memcpy(cp2, cp4, length);
- count -= length;
- cp2 += length;
- }
- } else if (nextexp) {
- /* We have an expression. Find the start and end, and determine
- if we are going to have to recursively call ourselves on the
- contents */
- vars = vare = nextexp + 2;
- brackets = 1;
- needsub = 0;
- /* Find the end of it */
- while(brackets && *vare) {
- if ((vare[0] == '$') && (vare[1] == '[')) {
- needsub++;
- brackets++;
- vare++;
- } else if (vare[0] == '[') {
- brackets++;
- } else if (vare[0] == ']') {
- brackets--;
- } else if ((vare[0] == '$') && (vare[1] == '{')) {
- needsub++;
- vare++;
- }
- vare++;
- }
- if (brackets)
- ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
- len = vare - vars - 1;
-
- /* Skip totally over expression */
- whereweare += (len + 3);
-
- if (!var)
- var = alloca(VAR_BUF_SIZE);
- /* Store variable name (and truncate) */
- ast_copy_string(var, vars, len + 1);
-
- /* Substitute if necessary */
- if (needsub) {
- if (!ltmp)
- ltmp = alloca(VAR_BUF_SIZE);
- memset(ltmp, 0, VAR_BUF_SIZE);
- pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
- vars = ltmp;
- } else {
- vars = var;
- }
- length = ast_expr(vars, cp2, count);
- if (length) {
- ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
- count -= length;
- cp2 += length;
- }
- } else
- break;
- }
- }
- void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
- {
- pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
- }
- void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
- {
- pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
- }
- static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
- {
- memset(passdata, 0, datalen);
-
- /* No variables or expressions in e->data, so why scan it? */
- if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
- ast_copy_string(passdata, e->data, datalen);
- return;
- }
-
- pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
- }
- static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
- {
- struct ast_exten *e;
- struct ast_app *app;
- struct ast_switch *sw;
- char *data;
- const char *foundcontext=NULL;
- int newstack = 0;
- int res;
- int status = 0;
- char *incstack[AST_PBX_MAX_STACK];
- char passdata[EXT_DATA_SIZE];
- int stacklen = 0;
- char tmp[80];
- char tmp2[80];
- char tmp3[EXT_DATA_SIZE];
- char atmp[80];
- char atmp2[EXT_DATA_SIZE+100];
- if (ast_mutex_lock(&conlock)) {
- ast_log(LOG_WARNING, "Unable to obtain lock\n");
- if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
- return 0;
- else
- return -1;
- }
- e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
- if (e) {
- switch(action) {
- case HELPER_CANMATCH:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_EXISTS:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_FINDLABEL:
- res = e->priority;
- ast_mutex_unlock(&conlock);
- return res;
- case HELPER_MATCHMORE:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_SPAWN:
- newstack++;
- /* Fall through */
- case HELPER_EXEC:
- app = pbx_findapp(e->app);
- ast_mutex_unlock(&conlock);
- if (app) {
- if (c->context != context)
- ast_copy_string(c->context, context, sizeof(c->context));
- if (c->exten != exten)
- ast_copy_string(c->exten, exten, sizeof(c->exten));
- c->priority = priority;
- pbx_substitute_variables(passdata, sizeof(passdata), c, e);
- if (option_debug) {
- ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
- snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
- snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
- pbx_builtin_setvar_helper(c, atmp, atmp2);
- }
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
- term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
- term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
- term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
- (newstack ? "in new stack" : "in same stack"));
- manager_event(EVENT_FLAG_CALL, "Newexten",
- "Channel: %s\r\n"
- "Context: %s\r\n"
- "Extension: %s\r\n"
- "Priority: %d\r\n"
- "Application: %s\r\n"
- "AppData: %s\r\n"
- "Uniqueid: %s\r\n",
- c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
- res = pbx_exec(c, app, passdata, newstack);
- return res;
- } else {
- ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
- return -1;
- }
- default:
- ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
- }
- } else if (sw) {
- switch(action) {
- case HELPER_CANMATCH:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_EXISTS:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_MATCHMORE:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_FINDLABEL:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_SPAWN:
- newstack++;
- /* Fall through */
- case HELPER_EXEC:
- ast_mutex_unlock(&conlock);
- if (sw->exec)
- res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
- else {
- ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
- res = -1;
- }
- return res;
- default:
- ast_log(LOG_WARNING, "Huh (%d)?\n", action);
- return -1;
- }
- } else {
- ast_mutex_unlock(&conlock);
- switch(status) {
- case STATUS_NO_CONTEXT:
- if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
- ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
- break;
- case STATUS_NO_EXTENSION:
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
- ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
- break;
- case STATUS_NO_PRIORITY:
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
- ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
- break;
- case STATUS_NO_LABEL:
- if (context)
- ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
- break;
- default:
- ast_log(LOG_DEBUG, "Shouldn't happen!\n");
- }
-
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
- return -1;
- else
- return 0;
- }
- }
- /*! \brief ast_hint_extension: Find hint for given extension in context */
- static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
- {
- struct ast_exten *e;
- struct ast_switch *sw;
- char *data;
- const char *foundcontext = NULL;
- int status = 0;
- char *incstack[AST_PBX_MAX_STACK];
- int stacklen = 0;
- if (ast_mutex_lock(&conlock)) {
- ast_log(LOG_WARNING, "Unable to obtain lock\n");
- return NULL;
- }
- e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
- ast_mutex_unlock(&conlock);
- return e;
- }
- /*! \brief ast_extensions_state2: Check state of extension by using hints */
- static int ast_extension_state2(struct ast_exten *e)
- {
- char hint[AST_MAX_EXTENSION] = "";
- char *cur, *rest;
- int res = -1;
- int allunavailable = 1, allbusy = 1, allfree = 1;
- int busy = 0, inuse = 0, ring = 0;
- if (!e)
- return -1;
- ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
- cur = hint; /* On or more devices separated with a & character */
- do {
- rest = strchr(cur, '&');
- if (rest) {
- *rest = 0;
- rest++;
- }
-
- res = ast_device_state(cur);
- switch (res) {
- case AST_DEVICE_NOT_INUSE:
- allunavailable = 0;
- allbusy = 0;
- break;
- case AST_DEVICE_INUSE:
- inuse = 1;
- allunavailable = 0;
- allfree = 0;
- break;
- case AST_DEVICE_RINGING:
- ring = 1;
- allunavailable = 0;
- allfree = 0;
- break;
- case AST_DEVICE_BUSY:
- allunavailable = 0;
- allfree = 0;
- busy = 1;
- break;
- case AST_DEVICE_UNAVAILABLE:
- case AST_DEVICE_INVALID:
- allbusy = 0;
- allfree = 0;
- break;
- default:
- allunavailable = 0;
- allbusy = 0;
- allfree = 0;
- }
- cur = rest;
- } while (cur);
- if (!inuse && ring)
- return AST_EXTENSION_RINGING;
- if (inuse && ring)
- return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
- if (inuse)
- return AST_EXTENSION_INUSE;
- if (allfree)
- return AST_EXTENSION_NOT_INUSE;
- if (allbusy)
- return AST_EXTENSION_BUSY;
- if (allunavailable)
- return AST_EXTENSION_UNAVAILABLE;
- if (busy)
- return AST_EXTENSION_INUSE;
-
- return AST_EXTENSION_NOT_INUSE;
- }
- /*! \brief ast_extension_state2str: Return extension_state as string */
- const char *ast_extension_state2str(int extension_state)
- {
- int i;
- for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
- if (extension_states[i].extension_state == extension_state) {
- return extension_states[i].text;
- }
- }
- return "Unknown";
- }
- /*! \brief ast_extension_state: Check extension state for an extension by using hint */
- int ast_extension_state(struct ast_channel *c, char *context, char *exten)
- {
- struct ast_exten *e;
- e = ast_hint_extension(c, context, exten); /* Do we have a hint for this extension ? */
- if (!e)
- return -1; /* No hint, return -1 */
- return ast_extension_state2(e); /* Check all devices in the hint */
- }
- void ast_hint_state_changed(const char *device)
- {
- struct ast_hint *hint;
- struct ast_state_cb *cblist;
- char buf[AST_MAX_EXTENSION];
- char *parse;
- char *cur;
- int state;
- ast_mutex_lock(&hintlock);
- for (hint = hints; hint; hint = hint->next) {
- ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
- parse = buf;
- for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
- if (strcmp(cur, device))
- continue;
- /* Get device state for this hint */
- state = ast_extension_state2(hint->exten);
-
- if ((state == -1) || (state == hint->laststate))
- continue;
- /* Device state changed since last check - notify the watchers */
-
- /* For general callbacks */
- for (cblist = statecbs; cblist; cblist = cblist->next)
- cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
-
- /* For extension callbacks */
- for (cblist = hint->callbacks; cblist; cblist = cblist->next)
- cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
-
- hint->laststate = state;
- break;
- }
- }
- ast_mutex_unlock(&hintlock);
- }
-
- /*! \brief ast_extension_state_add: Add watcher for extension states */
- int ast_extension_state_add(const char *context, const char *exten,
- ast_state_cb_type callback, void *data)
- {
- struct ast_hint *list;
- struct ast_state_cb *cblist;
- struct ast_exten *e;
- /* If there's no context and extension: add callback to statecbs list */
- if (!context && !exten) {
- ast_mutex_lock(&hintlock);
- cblist = statecbs;
- while (cblist) {
- if (cblist->callback == callback) {
- cblist->data = data;
- ast_mutex_unlock(&hintlock);
- return 0;
- }
- cblist = cblist->next;
- }
-
- /* Now insert the callback */
- cblist = malloc(sizeof(struct ast_state_cb));
- if (!cblist) {
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- memset(cblist, 0, sizeof(struct ast_state_cb));
- cblist->id = 0;
- cblist->callback = callback;
- cblist->data = data;
-
- cblist->next = statecbs;
- statecbs = cblist;
- ast_mutex_unlock(&hintlock);
- return 0;
- }
- if (!context || !exten)
- return -1;
- /* This callback type is for only one hint, so get the hint */
- e = ast_hint_extension(NULL, context, exten);
- if (!e) {
- return -1;
- }
- /* Find the hint in the list of hints */
- ast_mutex_lock(&hintlock);
- list = hints;
- while (list) {
- if (list->exten == e)
- break;
- list = list->next;
- }
- if (!list) {
- /* We have no hint, sorry */
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- /* Now insert the callback in the callback list */
- cblist = malloc(sizeof(struct ast_state_cb));
- if (!cblist) {
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- memset(cblist, 0, sizeof(struct ast_state_cb));
- cblist->id = stateid++; /* Unique ID for this callback */
- cblist->callback = callback; /* Pointer to callback routine */
- cblist->data = data; /* Data for the callback */
- cblist->next = list->callbacks;
- list->callbacks = cblist;
- ast_mutex_unlock(&hintlock);
- return cblist->id;
- }
- /*! \brief ast_extension_state_del: Remove a watcher from the callback list */
- int ast_extension_state_del(int id, ast_state_cb_type callback)
- {
- struct ast_hint *list;
- struct ast_state_cb *cblist, *cbprev;
- if (!id && !callback)
- return -1;
- ast_mutex_lock(&hintlock);
- /* id is zero is a callback without extension */
- if (!id) {
- cbprev = NULL;
- cblist = statecbs;
- while (cblist) {
- if (cblist->callback == callback) {
- if (!cbprev)
- statecbs = cblist->next;
- else
- cbprev->next = cblist->next;
- free(cblist);
- ast_mutex_unlock(&hintlock);
- return 0;
- }
- cbprev = cblist;
- cblist = cblist->next;
- }
- ast_mutex_lock(&hintlock);
- return -1;
- }
- /* id greater than zero is a callback with extension */
- /* Find the callback based on ID */
- list = hints;
- while (list) {
- cblist = list->callbacks;
- cbprev = NULL;
- while (cblist) {
- if (cblist->id==id) {
- if (!cbprev)
- list->callbacks = cblist->next;
- else
- cbprev->next = cblist->next;
-
- free(cblist);
-
- ast_mutex_unlock(&hintlock);
- return 0;
- }
- cbprev = cblist;
- cblist = cblist->next;
- }
- list = list->next;
- }
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- /*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
- static int ast_add_hint(struct ast_exten *e)
- {
- struct ast_hint *list;
- if (!e)
- return -1;
- ast_mutex_lock(&hintlock);
- list = hints;
- /* Search if hint exists, do nothing */
- while (list) {
- if (list->exten == e) {
- ast_mutex_unlock(&hintlock);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
- return -1;
- }
- list = list->next;
- }
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
- list = malloc(sizeof(struct ast_hint));
- if (!list) {
- ast_mutex_unlock(&hintlock);
- if (option_debug > 1)
- ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
- return -1;
- }
- /* Initialize and insert new item at the top */
- memset(list, 0, sizeof(struct ast_hint));
- list->exten = e;
- list->laststate = ast_extension_state2(e);
- list->next = hints;
- hints = list;
- ast_mutex_unlock(&hintlock);
- return 0;
- }
- /*! \brief ast_change_hint: Change hint for an extension */
- static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
- {
- struct ast_hint *list;
- ast_mutex_lock(&hintlock);
- list = hints;
- while(list) {
- if (list->exten == oe) {
- list->exten = ne;
- ast_mutex_unlock(&hintlock);
- return 0;
- }
- list = list->next;
- }
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- /*! \brief ast_remove_hint: Remove hint from extension */
- static int ast_remove_hint(struct ast_exten *e)
- {
- /* Cleanup the Notifys if hint is removed */
- struct ast_hint *list, *prev = NULL;
- struct ast_state_cb *cblist, *cbprev;
- if (!e)
- return -1;
- ast_mutex_lock(&hintlock);
- list = hints;
- while(list) {
- if (list->exten==e) {
- cbprev = NULL;
- cblist = list->callbacks;
- while (cblist) {
- /* Notify with -1 and remove all callbacks */
- cbprev = cblist;
- cblist = cblist->next;
- cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
- free(cbprev);
- }
- list->callbacks = NULL;
- if (!prev)
- hints = list->next;
- else
- prev->next = list->next;
- free(list);
-
- ast_mutex_unlock(&hintlock);
- return 0;
- } else {
- prev = list;
- list = list->next;
- }
- }
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- /*! \brief ast_get_hint: Get hint for channel */
- int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
- {
- struct ast_exten *e;
- void *tmp;
- e = ast_hint_extension(c, context, exten);
- if (e) {
- if (hint)
- ast_copy_string(hint, ast_get_extension_app(e), hintsize);
- if (name) {
- tmp = ast_get_extension_app_data(e);
- if (tmp)
- ast_copy_string(name, (char *) tmp, namesize);
- }
- return -1;
- }
- return 0;
- }
- int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
- {
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
- }
- int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
- {
- return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
- }
- int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
- {
- return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
- }
- int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
- {
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
- }
- int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
- {
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
- }
- int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
- {
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
- }
- int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
- {
- return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
- }
- static int __ast_pbx_run(struct ast_channel *c)
- {
- int firstpass = 1;
- int digit;
- char exten[256];
- int pos;
- int waittime;
- int res=0;
- int autoloopflag;
- /* A little initial setup here */
- if (c->pbx)
- ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
- c->pbx = malloc(sizeof(struct ast_pbx));
- if (!c->pbx) {
- ast_log(LOG_ERROR, "Out of memory\n");
- return -1;
- }
- if (c->amaflags) {
- if (!c->cdr) {
- c->cdr = ast_cdr_alloc();
- if (!c->cdr) {
- ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
- free(c->pbx);
- return -1;
- }
- ast_cdr_init(c->cdr, c);
- }
- }
- memset(c->pbx, 0, sizeof(struct ast_pbx));
- /* Set reasonable defaults */
- c->pbx->rtimeout = 10;
- c->pbx->dtimeout = 5;
- autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
- ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
- /* Start by trying whatever the channel is set to */
- if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
- /* If not successful fall back to 's' */
- if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
- ast_copy_string(c->exten, "s", sizeof(c->exten));
- if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
- /* JK02: And finally back to default if everything else failed */
- if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
- ast_copy_string(c->context, "default", sizeof(c->context));
- }
- c->priority = 1;
- }
- if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
- ast_cdr_start(c->cdr);
- for(;;) {
- pos = 0;
- digit = 0;
- while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
- memset(exten, 0, sizeof(exten));
- if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
- /* Something bad happened, or a hangup has been requested. */
- if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
- (res == '*') || (res == '#')) {
- ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
- memset(exten, 0, sizeof(exten));
- pos = 0;
- exten[pos++] = digit = res;
- break;
- }
- switch(res) {
- case AST_PBX_KEEPALIVE:
- if (option_debug)
- ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
- else if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
- goto out;
- break;
- default:
- if (option_debug)
- ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
- else if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
- if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
- c->_softhangup =0;
- break;
- }
- /* atimeout */
- if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
- break;
- }
- if (c->cdr) {
- ast_cdr_update(c);
- }
- goto out;
- }
- }
- if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
- ast_copy_string(c->exten, "T", sizeof(c->exten));
- /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
- c->whentohangup = 0;
- c->priority = 0;
- c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
- } else if (c->_softhangup) {
- ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
- c->exten, c->priority);
- goto out;
- }
- firstpass = 0;
- c->priority++;
- }
- if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
- /* It's not a valid extension anymore */
- if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
- pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
- ast_copy_string(c->exten, "i", sizeof(c->exten));
- c->priority = 1;
- } else {
- ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
- c->name, c->exten, c->context);
- goto out;
- }
- } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
- /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
- c->_softhangup = 0;
- } else {
- /* Done, wait for an extension */
- waittime = 0;
- if (digit)
- waittime = c->pbx->dtimeout;
- else if (!autofallthrough)
- waittime = c->pbx->rtimeout;
- if (waittime) {
- while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
- /* As long as we're willing to wait, and as long as it's not defined,
- keep reading digits until we can't possibly get a right answer anymore. */
- digit = ast_waitfordigit(c, waittime * 1000);
- if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
- c->_softhangup = 0;
- } else {
- if (!digit)
- /* No entry */
- break;
- if (digit < 0)
- /* Error, maybe a hangup */
- goto out;
- exten[pos++] = digit;
- waittime = c->pbx->dtimeout;
- }
- }
- if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
- /* Prepare the next cycle */
- ast_copy_string(c->exten, exten, sizeof(c->exten));
- c->priority = 1;
- } else {
- /* No such extension */
- if (!ast_strlen_zero(exten)) {
- /* An invalid extension */
- if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
- pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
- ast_copy_string(c->exten, "i", sizeof(c->exten));
- c->priority = 1;
- } else {
- ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
- goto out;
- }
- } else {
- /* A simple timeout */
- if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
- ast_copy_string(c->exten, "t", sizeof(c->exten));
- c->priority = 1;
- } else {
- ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
- goto out;
- }
- }
- }
- if (c->cdr) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
- ast_cdr_update(c);
- }
- } else {
- char *status;
- status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
- if (!status)
- status = "UNKNOWN";
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
- if (!strcasecmp(status, "CONGESTION"))
- res = pbx_builtin_congestion(c, "10");
- else if (!strcasecmp(status, "CHANUNAVAIL"))
- res = pbx_builtin_congestion(c, "10");
- else if (!strcasecmp(status, "BUSY"))
- res = pbx_builtin_busy(c, "10");
- goto out;
- }
- }
- }
- if (firstpass)
- ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
- out:
- if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
- c->exten[0] = 'h';
- c->exten[1] = '\0';
- c->priority = 1;
- while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
- if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
- /* Something bad happened, or a hangup has been requested. */
- if (option_debug)
- ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
- else if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
- break;
- }
- c->priority++;
- }
- }
- ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
- pbx_destroy(c->pbx);
- c->pbx = NULL;
- if (res != AST_PBX_KEEPALIVE)
- ast_hangup(c);
- return 0;
- }
- /* Returns 0 on success, non-zero if call limit was reached */
- static int increase_call_count(const struct ast_channel *c)
- {
- int failed = 0;
- double curloadavg;
- ast_mutex_lock(&maxcalllock);
- if (option_maxcalls) {
- if (countcalls >= option_maxcalls) {
- ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
- failed = -1;
- }
- }
- if (option_maxload) {
- getloadavg(&curloadavg, 1);
- if (curloadavg >= option_maxload) {
- ast_log(LOG_NOTICE, "Maximum loadavg limit of %lf load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
- failed = -1;
- }
- }
- if (!failed)
- countcalls++;
- ast_mutex_unlock(&maxcalllock);
- return failed;
- }
- static void decrease_call_count(void)
- {
- ast_mutex_lock(&maxcalllock);
- if (countcalls > 0)
- countcalls--;
- ast_mutex_unlock(&maxcalllock);
- }
- static void *pbx_thread(void *data)
- {
- /* Oh joyeous kernel, we're a new thread, with nothing to do but
- answer this channel and get it going.
- */
- /* NOTE:
- The launcher of this function _MUST_ increment 'countcalls'
- before invoking the function; it will be decremented when the
- PBX has finished running on the channel
- */
- struct ast_channel *c = data;
- __ast_pbx_run(c);
- decrease_call_count();
- pthread_exit(NULL);
- return NULL;
- }
- enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
- {
- pthread_t t;
- pthread_attr_t attr;
- if (!c) {
- ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
- return AST_PBX_FAILED;
- }
-
- if (increase_call_count(c))
- return AST_PBX_CALL_LIMIT;
- /* Start a new thread, and get something handling this channel. */
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
- ast_log(LOG_WARNING, "Failed to create new channel thread\n");
- return AST_PBX_FAILED;
- }
- return AST_PBX_SUCCESS;
- }
- enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
- {
- enum ast_pbx_result res = AST_PBX_SUCCESS;
- if (increase_call_count(c))
- return AST_PBX_CALL_LIMIT;
- res = __ast_pbx_run(c);
- decrease_call_count();
- return res;
- }
- int ast_active_calls(void)
- {
- return countcalls;
- }
- int pbx_set_autofallthrough(int newval)
- {
- int oldval;
- oldval = autofallthrough;
- if (oldval != newval)
- autofallthrough = newval;
- return oldval;
- }
- /*
- * This function locks contexts list by &conlist, search for the right context
- * structure, leave context list locked and call ast_context_remove_include2
- * which removes include, unlock contexts list and return ...
- */
- int ast_context_remove_include(const char *context, const char *include, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) return -1;
- /* walk contexts and search for the right one ...*/
- c = ast_walk_contexts(NULL);
- while (c) {
- /* we found one ... */
- if (!strcmp(ast_get_context_name(c), context)) {
- int ret;
- /* remove include from this context ... */
- ret = ast_context_remove_include2(c, include, registrar);
- ast_unlock_contexts();
- /* ... return results */
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- /* we can't find the right one context */
- ast_unlock_contexts();
- return -1;
- }
- /*
- * When we call this function, &conlock lock must be locked, because when
- * we giving *con argument, some process can remove/change this context
- * and after that there can be segfault.
- *
- * This function locks given context, removes include, unlock context and
- * return.
- */
- int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
- {
- struct ast_include *i, *pi = NULL;
- if (ast_mutex_lock(&con->lock)) return -1;
- /* walk includes */
- i = con->includes;
- while (i) {
- /* find our include */
- if (!strcmp(i->name, include) &&
- (!registrar || !strcmp(i->registrar, registrar))) {
- /* remove from list */
- if (pi)
- pi->next = i->next;
- else
- con->includes = i->next;
- /* free include and return */
- free(i);
- ast_mutex_unlock(&con->lock);
- return 0;
- }
- pi = i;
- i = i->next;
- }
- /* we can't find the right include */
- ast_mutex_unlock(&con->lock);
- return -1;
- }
- /*!
- * \note This function locks contexts list by &conlist, search for the rigt context
- * structure, leave context list locked and call ast_context_remove_switch2
- * which removes switch, unlock contexts list and return ...
- */
- int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) return -1;
- /* walk contexts and search for the right one ...*/
- c = ast_walk_contexts(NULL);
- while (c) {
- /* we found one ... */
- if (!strcmp(ast_get_context_name(c), context)) {
- int ret;
- /* remove switch from this context ... */
- ret = ast_context_remove_switch2(c, sw, data, registrar);
- ast_unlock_contexts();
- /* ... return results */
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- /* we can't find the right one context */
- ast_unlock_contexts();
- return -1;
- }
- /*!
- * \brief This function locks given context, removes switch, unlock context and
- * return.
- * \note When we call this function, &conlock lock must be locked, because when
- * we giving *con argument, some process can remove/change this context
- * and after that there can be segfault.
- *
- */
- int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
- {
- struct ast_sw *i, *pi = NULL;
- if (ast_mutex_lock(&con->lock)) return -1;
- /* walk switchs */
- i = con->alts;
- while (i) {
- /* find our switch */
- if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
- (!registrar || !strcmp(i->registrar, registrar))) {
- /* remove from list */
- if (pi)
- pi->next = i->next;
- else
- con->alts = i->next;
- /* free switch and return */
- free(i);
- ast_mutex_unlock(&con->lock);
- return 0;
- }
- pi = i;
- i = i->next;
- }
- /* we can't find the right switch */
- ast_mutex_unlock(&con->lock);
- return -1;
- }
- /*
- * \note This functions lock contexts list, search for the right context,
- * call ast_context_remove_extension2, unlock contexts list and return.
- * In this function we are using
- */
- int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) return -1;
- /* walk contexts ... */
- c = ast_walk_contexts(NULL);
- while (c) {
- /* ... search for the right one ... */
- if (!strcmp(ast_get_context_name(c), context)) {
- /* ... remove extension ... */
- int ret = ast_context_remove_extension2(c, extension, priority,
- registrar);
- /* ... unlock contexts list and return */
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- /* we can't find the right context */
- ast_unlock_contexts();
- return -1;
- }
- /*!
- * \brief This functionc locks given context, search for the right extension and
- * fires out all peer in this extensions with given priority. If priority
- * is set to 0, all peers are removed. After that, unlock context and
- * return.
- * \note When do you want to call this function, make sure that &conlock is locked,
- * because some process can handle with your *con context before you lock
- * it.
- *
- */
- int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
- {
- struct ast_exten *exten, *prev_exten = NULL;
- if (ast_mutex_lock(&con->lock)) return -1;
- /* go through all extensions in context and search the right one ... */
- exten = con->root;
- while (exten) {
- /* look for right extension */
- if (!strcmp(exten->exten, extension) &&
- (!registrar || !strcmp(exten->registrar, registrar))) {
- struct ast_exten *peer;
- /* should we free all peers in this extension? (priority == 0)? */
- if (priority == 0) {
- /* remove this extension from context list */
- if (prev_exten)
- prev_exten->next = exten->next;
- else
- con->root = exten->next;
- /* fire out all peers */
- peer = exten;
- while (peer) {
- exten = peer->peer;
-
- if (!peer->priority==PRIORITY_HINT)
- ast_remove_hint(peer);
- peer->datad(peer->data);
- free(peer);
- peer = exten;
- }
- ast_mutex_unlock(&con->lock);
- return 0;
- } else {
- /* remove only extension with exten->priority == priority */
- struct ast_exten *previous_peer = NULL;
- peer = exten;
- while (peer) {
- /* is this our extension? */
- if (peer->priority == priority &&
- (!registrar || !strcmp(peer->registrar, registrar) )) {
- /* we are first priority extension? */
- if (!previous_peer) {
- /* exists previous extension here? */
- if (prev_exten) {
- /* yes, so we must change next pointer in
- * previous connection to next peer
- */
- if (peer->peer) {
- prev_exten->next = peer->peer;
- peer->peer->next = exten->next;
- } else
- prev_exten->next = exten->next;
- } else {
- /* no previous extension, we are first
- * extension, so change con->root ...
- */
- if (peer->peer)
- con->root = peer->peer;
- else
- con->root = exten->next;
- }
- } else {
- /* we are not first priority in extension */
- previous_peer->peer = peer->peer;
- }
- /* now, free whole priority extension */
- if (peer->priority==PRIORITY_HINT)
- ast_remove_hint(peer);
- peer->datad(peer->data);
- free(peer);
- ast_mutex_unlock(&con->lock);
- return 0;
- } else {
- /* this is not right extension, skip to next peer */
- previous_peer = peer;
- peer = peer->peer;
- }
- }
- ast_mutex_unlock(&con->lock);
- return -1;
- }
- }
- prev_exten = exten;
- exten = exten->next;
- }
- /* we can't find right extension */
- ast_mutex_unlock(&con->lock);
- return -1;
- }
- /*! \brief Dynamically register a new dial plan application */
- int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
- {
- struct ast_app *tmp, *prev, *cur;
- char tmps[80];
- int length;
- length = sizeof(struct ast_app);
- length += strlen(app) + 1;
- if (ast_mutex_lock(&applock)) {
- ast_log(LOG_ERROR, "Unable to lock application list\n");
- return -1;
- }
- tmp = apps;
- while(tmp) {
- if (!strcasecmp(app, tmp->name)) {
- ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
- ast_mutex_unlock(&applock);
- return -1;
- }
- tmp = tmp->next;
- }
- tmp = malloc(length);
- if (tmp) {
- memset(tmp, 0, length);
- strcpy(tmp->name, app);
- tmp->execute = execute;
- tmp->synopsis = synopsis;
- tmp->description = description;
- /* Store in alphabetical order */
- cur = apps;
- prev = NULL;
- while(cur) {
- if (strcasecmp(tmp->name, cur->name) < 0)
- break;
- prev = cur;
- cur = cur->next;
- }
- if (prev) {
- tmp->next = prev->next;
- prev->next = tmp;
- } else {
- tmp->next = apps;
- apps = tmp;
- }
- } else {
- ast_log(LOG_ERROR, "Out of memory\n");
- ast_mutex_unlock(&applock);
- return -1;
- }
- if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
- ast_mutex_unlock(&applock);
- return 0;
- }
- int ast_register_switch(struct ast_switch *sw)
- {
- struct ast_switch *tmp, *prev=NULL;
- if (ast_mutex_lock(&switchlock)) {
- ast_log(LOG_ERROR, "Unable to lock switch lock\n");
- return -1;
- }
- tmp = switches;
- while(tmp) {
- if (!strcasecmp(tmp->name, sw->name))
- break;
- prev = tmp;
- tmp = tmp->next;
- }
- if (tmp) {
- ast_mutex_unlock(&switchlock);
- ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
- return -1;
- }
- sw->next = NULL;
- if (prev)
- prev->next = sw;
- else
- switches = sw;
- ast_mutex_unlock(&switchlock);
- return 0;
- }
- void ast_unregister_switch(struct ast_switch *sw)
- {
- struct ast_switch *tmp, *prev=NULL;
- if (ast_mutex_lock(&switchlock)) {
- ast_log(LOG_ERROR, "Unable to lock switch lock\n");
- return;
- }
- tmp = switches;
- while(tmp) {
- if (tmp == sw) {
- if (prev)
- prev->next = tmp->next;
- else
- switches = tmp->next;
- tmp->next = NULL;
- break;
- }
- prev = tmp;
- tmp = tmp->next;
- }
- ast_mutex_unlock(&switchlock);
- }
- /*
- * Help for CLI commands ...
- */
- static char show_application_help[] =
- "Usage: show application <application> [<application> [<application> [...]]]\n"
- " Describes a particular application.\n";
- static char show_functions_help[] =
- "Usage: show functions\n"
- " List builtin functions accessable as $(function args)\n";
- static char show_function_help[] =
- "Usage: show function <function>\n"
- " Describe a particular dialplan function.\n";
- static char show_applications_help[] =
- "Usage: show applications [{like|describing} <text>]\n"
- " List applications which are currently available.\n"
- " If 'like', <text> will be a substring of the app name\n"
- " If 'describing', <text> will be a substring of the description\n";
- static char show_dialplan_help[] =
- "Usage: show dialplan [exten@][context]\n"
- " Show dialplan\n";
- static char show_switches_help[] =
- "Usage: show switches\n"
- " Show registered switches\n";
- static char show_hints_help[] =
- "Usage: show hints\n"
- " Show registered hints\n";
- /*
- * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
- *
- */
- /*
- * \brief 'show application' CLI command implementation functions ...
- */
- /*
- * There is a possibility to show informations about more than one
- * application at one time. You can type 'show application Dial Echo' and
- * you will see informations about these two applications ...
- */
- static char *complete_show_application(char *line, char *word,
- int pos, int state)
- {
- struct ast_app *a;
- int which = 0;
- /* try to lock applications list ... */
- if (ast_mutex_lock(&applock)) {
- ast_log(LOG_ERROR, "Unable to lock application list\n");
- return NULL;
- }
- /* ... walk all applications ... */
- a = apps;
- while (a) {
- /* ... check if word matches this application ... */
- if (!strncasecmp(word, a->name, strlen(word))) {
- /* ... if this is right app serve it ... */
- if (++which > state) {
- char *ret = strdup(a->name);
- ast_mutex_unlock(&applock);
- return ret;
- }
- }
- a = a->next;
- }
- /* no application match */
- ast_mutex_unlock(&applock);
- return NULL;
- }
- static int handle_show_application(int fd, int argc, char *argv[])
- {
- struct ast_app *a;
- int app, no_registered_app = 1;
- if (argc < 3) return RESULT_SHOWUSAGE;
- /* try to lock applications list ... */
- if (ast_mutex_lock(&applock)) {
- ast_log(LOG_ERROR, "Unable to lock application list\n");
- return -1;
- }
- /* ... go through all applications ... */
- a = apps;
- while (a) {
- /* ... compare this application name with all arguments given
- * to 'show application' command ... */
- for (app = 2; app < argc; app++) {
- if (!strcasecmp(a->name, argv[app])) {
- /* Maximum number of characters added by terminal coloring is 22 */
- char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
- char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
- int synopsis_size, description_size;
- no_registered_app = 0;
- if (a->synopsis)
- synopsis_size = strlen(a->synopsis) + 23;
- else
- synopsis_size = strlen("Not available") + 23;
- synopsis = alloca(synopsis_size);
- if (a->description)
- description_size = strlen(a->description) + 23;
- else
- description_size = strlen("Not available") + 23;
- description = alloca(description_size);
- if (synopsis && description) {
- snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
- term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
- term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
- term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
- term_color(synopsis,
- a->synopsis ? a->synopsis : "Not available",
- COLOR_CYAN, 0, synopsis_size);
- term_color(description,
- a->description ? a->description : "Not available",
- COLOR_CYAN, 0, description_size);
- ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
- } else {
- /* ... one of our applications, show info ...*/
- ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
- "[Synopsis]\n %s\n\n"
- "[Description]\n%s\n",
- a->name,
- a->synopsis ? a->synopsis : "Not available",
- a->description ? a->description : "Not available");
- }
- }
- }
- a = a->next;
- }
- ast_mutex_unlock(&applock);
- /* we found at least one app? no? */
- if (no_registered_app) {
- ast_cli(fd, "Your application(s) is (are) not registered\n");
- return RESULT_FAILURE;
- }
- return RESULT_SUCCESS;
- }
- /*! \brief handle_show_hints: CLI support for listing registred dial plan hints */
- static int handle_show_hints(int fd, int argc, char *argv[])
- {
- struct ast_hint *hint;
- int num = 0;
- int watchers;
- struct ast_state_cb *watcher;
- if (!hints) {
- ast_cli(fd, "There are no registered dialplan hints\n");
- return RESULT_SUCCESS;
- }
- /* ... we have hints ... */
- ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
- if (ast_mutex_lock(&hintlock)) {
- ast_log(LOG_ERROR, "Unable to lock hints\n");
- return -1;
- }
- hint = hints;
- while (hint) {
- watchers = 0;
- for (watcher = hint->callbacks; watcher; watcher = watcher->next)
- watchers++;
- ast_cli(fd, " %-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
- ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten),
- ast_extension_state2str(hint->laststate), watchers);
- num++;
- hint = hint->next;
- }
- ast_cli(fd, "----------------\n");
- ast_cli(fd, "- %d hints registered\n", num);
- ast_mutex_unlock(&hintlock);
- return RESULT_SUCCESS;
- }
- /*! \brief handle_show_switches: CLI support for listing registred dial plan switches */
- static int handle_show_switches(int fd, int argc, char *argv[])
- {
- struct ast_switch *sw;
- if (!switches) {
- ast_cli(fd, "There are no registered alternative switches\n");
- return RESULT_SUCCESS;
- }
- /* ... we have applications ... */
- ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
- if (ast_mutex_lock(&switchlock)) {
- ast_log(LOG_ERROR, "Unable to lock switches\n");
- return -1;
- }
- sw = switches;
- while (sw) {
- ast_cli(fd, "%s: %s\n", sw->name, sw->description);
- sw = sw->next;
- }
- ast_mutex_unlock(&switchlock);
- return RESULT_SUCCESS;
- }
- /*
- * 'show applications' CLI command implementation functions ...
- */
- static int handle_show_applications(int fd, int argc, char *argv[])
- {
- struct ast_app *a;
- int like=0, describing=0;
- int total_match = 0; /* Number of matches in like clause */
- int total_apps = 0; /* Number of apps registered */
-
- /* try to lock applications list ... */
- if (ast_mutex_lock(&applock)) {
- ast_log(LOG_ERROR, "Unable to lock application list\n");
- return -1;
- }
- /* ... have we got at least one application (first)? no? */
- if (!apps) {
- ast_cli(fd, "There are no registered applications\n");
- ast_mutex_unlock(&applock);
- return -1;
- }
- /* show applications like <keyword> */
- if ((argc == 4) && (!strcmp(argv[2], "like"))) {
- like = 1;
- } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
- describing = 1;
- }
- /* show applications describing <keyword1> [<keyword2>] [...] */
- if ((!like) && (!describing)) {
- ast_cli(fd, " -= Registered Asterisk Applications =-\n");
- } else {
- ast_cli(fd, " -= Matching Asterisk Applications =-\n");
- }
- /* ... go through all applications ... */
- for (a = apps; a; a = a->next) {
- /* ... show informations about applications ... */
- int printapp=0;
- total_apps++;
- if (like) {
- if (strcasestr(a->name, argv[3])) {
- printapp = 1;
- total_match++;
- }
- } else if (describing) {
- if (a->description) {
- /* Match all words on command line */
- int i;
- printapp = 1;
- for (i=3; i<argc; i++) {
- if (!strcasestr(a->description, argv[i])) {
- printapp = 0;
- } else {
- total_match++;
- }
- }
- }
- } else {
- printapp = 1;
- }
- if (printapp) {
- ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
- }
- }
- if ((!like) && (!describing)) {
- ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
- } else {
- ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
- }
-
- /* ... unlock and return */
- ast_mutex_unlock(&applock);
- return RESULT_SUCCESS;
- }
- static char *complete_show_applications(char *line, char *word, int pos, int state)
- {
- if (pos == 2) {
- if (ast_strlen_zero(word)) {
- switch (state) {
- case 0:
- return strdup("like");
- case 1:
- return strdup("describing");
- default:
- return NULL;
- }
- } else if (! strncasecmp(word, "like", strlen(word))) {
- if (state == 0) {
- return strdup("like");
- } else {
- return NULL;
- }
- } else if (! strncasecmp(word, "describing", strlen(word))) {
- if (state == 0) {
- return strdup("describing");
- } else {
- return NULL;
- }
- }
- }
- return NULL;
- }
- /*
- * 'show dialplan' CLI command implementation functions ...
- */
- static char *complete_show_dialplan_context(char *line, char *word, int pos,
- int state)
- {
- struct ast_context *c;
- int which = 0;
- /* we are do completion of [exten@]context on second position only */
- if (pos != 2) return NULL;
- /* try to lock contexts list ... */
- if (ast_lock_contexts()) {
- ast_log(LOG_ERROR, "Unable to lock context list\n");
- return NULL;
- }
- /* ... walk through all contexts ... */
- c = ast_walk_contexts(NULL);
- while(c) {
- /* ... word matches context name? yes? ... */
- if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
- /* ... for serve? ... */
- if (++which > state) {
- /* ... yes, serve this context name ... */
- char *ret = strdup(ast_get_context_name(c));
- ast_unlock_contexts();
- return ret;
- }
- }
- c = ast_walk_contexts(c);
- }
- /* ... unlock and return */
- ast_unlock_contexts();
- return NULL;
- }
- struct dialplan_counters {
- int total_context;
- int total_exten;
- int total_prio;
- int context_existence;
- int extension_existence;
- };
- static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, char *includes[])
- {
- struct ast_context *c;
- int res=0, old_total_exten = dpc->total_exten;
- /* try to lock contexts */
- if (ast_lock_contexts()) {
- ast_log(LOG_WARNING, "Failed to lock contexts list\n");
- return -1;
- }
- /* walk all contexts ... */
- for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
- /* show this context? */
- if (!context ||
- !strcmp(ast_get_context_name(c), context)) {
- dpc->context_existence = 1;
- /* try to lock context before walking in ... */
- if (!ast_lock_context(c)) {
- struct ast_exten *e;
- struct ast_include *i;
- struct ast_ignorepat *ip;
- struct ast_sw *sw;
- char buf[256], buf2[256];
- int context_info_printed = 0;
- /* are we looking for exten too? if yes, we print context
- * if we our extension only
- */
- if (!exten) {
- dpc->total_context++;
- ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
- ast_get_context_name(c), ast_get_context_registrar(c));
- context_info_printed = 1;
- }
- /* walk extensions ... */
- for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
- struct ast_exten *p;
- int prio;
- /* looking for extension? is this our extension? */
- if (exten &&
- !ast_extension_match(ast_get_extension_name(e), exten))
- {
- /* we are looking for extension and it's not our
- * extension, so skip to next extension */
- continue;
- }
- dpc->extension_existence = 1;
- /* may we print context info? */
- if (!context_info_printed) {
- dpc->total_context++;
- if (rinclude) {
- /* TODO Print more info about rinclude */
- ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
- ast_get_context_name(c),
- ast_get_context_registrar(c));
- } else {
- ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
- ast_get_context_name(c),
- ast_get_context_registrar(c));
- }
- context_info_printed = 1;
- }
- dpc->total_prio++;
- /* write extension name and first peer */
- bzero(buf, sizeof(buf));
- snprintf(buf, sizeof(buf), "'%s' =>",
- ast_get_extension_name(e));
- prio = ast_get_extension_priority(e);
- if (prio == PRIORITY_HINT) {
- snprintf(buf2, sizeof(buf2),
- "hint: %s",
- ast_get_extension_app(e));
- } else {
- snprintf(buf2, sizeof(buf2),
- "%d. %s(%s)",
- prio,
- ast_get_extension_app(e),
- (char *)ast_get_extension_app_data(e));
- }
- ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
- ast_get_extension_registrar(e));
- dpc->total_exten++;
- /* walk next extension peers */
- for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
- dpc->total_prio++;
- bzero((void *)buf2, sizeof(buf2));
- bzero((void *)buf, sizeof(buf));
- if (ast_get_extension_label(p))
- snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
- prio = ast_get_extension_priority(p);
- if (prio == PRIORITY_HINT) {
- snprintf(buf2, sizeof(buf2),
- "hint: %s",
- ast_get_extension_app(p));
- } else {
- snprintf(buf2, sizeof(buf2),
- "%d. %s(%s)",
- prio,
- ast_get_extension_app(p),
- (char *)ast_get_extension_app_data(p));
- }
- ast_cli(fd," %-17s %-45s [%s]\n",
- buf, buf2,
- ast_get_extension_registrar(p));
- }
- }
- /* walk included and write info ... */
- for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
- bzero(buf, sizeof(buf));
- snprintf(buf, sizeof(buf), "'%s'",
- ast_get_include_name(i));
- if (exten) {
- /* Check all includes for the requested extension */
- if (includecount >= AST_PBX_MAX_STACK) {
- ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
- } else {
- int dupe=0;
- int x;
- for (x=0;x<includecount;x++) {
- if (!strcasecmp(includes[x], ast_get_include_name(i))) {
- dupe++;
- break;
- }
- }
- if (!dupe) {
- includes[includecount] = (char *)ast_get_include_name(i);
- show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
- } else {
- ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
- }
- }
- } else {
- ast_cli(fd, " Include => %-45s [%s]\n",
- buf, ast_get_include_registrar(i));
- }
- }
- /* walk ignore patterns and write info ... */
- for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
- const char *ipname = ast_get_ignorepat_name(ip);
- char ignorepat[AST_MAX_EXTENSION];
- snprintf(buf, sizeof(buf), "'%s'", ipname);
- snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
- if ((!exten) || ast_extension_match(ignorepat, exten)) {
- ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
- buf, ast_get_ignorepat_registrar(ip));
- }
- }
- if (!rinclude) {
- for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
- snprintf(buf, sizeof(buf), "'%s/%s'",
- ast_get_switch_name(sw),
- ast_get_switch_data(sw));
- ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
- buf, ast_get_switch_registrar(sw));
- }
- }
-
- ast_unlock_context(c);
- /* if we print something in context, make an empty line */
- if (context_info_printed) ast_cli(fd, "\r\n");
- }
- }
- }
- ast_unlock_contexts();
- if (dpc->total_exten == old_total_exten) {
- /* Nothing new under the sun */
- return -1;
- } else {
- return res;
- }
- }
- static int handle_show_dialplan(int fd, int argc, char *argv[])
- {
- char *exten = NULL, *context = NULL;
- /* Variables used for different counters */
- struct dialplan_counters counters;
- char *incstack[AST_PBX_MAX_STACK];
- memset(&counters, 0, sizeof(counters));
- if (argc != 2 && argc != 3)
- return RESULT_SHOWUSAGE;
- /* we obtain [exten@]context? if yes, split them ... */
- if (argc == 3) {
- char *splitter = ast_strdupa(argv[2]);
- /* is there a '@' character? */
- if (splitter && strchr(argv[2], '@')) {
- /* yes, split into exten & context ... */
- exten = strsep(&splitter, "@");
- context = splitter;
- /* check for length and change to NULL if ast_strlen_zero() */
- if (ast_strlen_zero(exten))
- exten = NULL;
- if (ast_strlen_zero(context))
- context = NULL;
- show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
- } else {
- /* no '@' char, only context given */
- context = argv[2];
- if (ast_strlen_zero(context))
- context = NULL;
- show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
- }
- } else {
- /* Show complete dial plan */
- show_dialplan_helper(fd, NULL, NULL, &counters, NULL, 0, incstack);
- }
- /* check for input failure and throw some error messages */
- if (context && !counters.context_existence) {
- ast_cli(fd, "There is no existence of '%s' context\n", context);
- return RESULT_FAILURE;
- }
- if (exten && !counters.extension_existence) {
- if (context)
- ast_cli(fd, "There is no existence of %s@%s extension\n",
- exten, context);
- else
- ast_cli(fd,
- "There is no existence of '%s' extension in all contexts\n",
- exten);
- return RESULT_FAILURE;
- }
- ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
- counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
- counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
- counters.total_context, counters.total_context == 1 ? "context" : "contexts");
- /* everything ok */
- return RESULT_SUCCESS;
- }
- /*
- * CLI entries for upper commands ...
- */
- static struct ast_cli_entry pbx_cli[] = {
- { { "show", "applications", NULL }, handle_show_applications,
- "Shows registered dialplan applications", show_applications_help, complete_show_applications },
- { { "show", "functions", NULL }, handle_show_functions,
- "Shows registered dialplan functions", show_functions_help },
- { { "show" , "function", NULL }, handle_show_function,
- "Describe a specific dialplan function", show_function_help, complete_show_function },
- { { "show", "application", NULL }, handle_show_application,
- "Describe a specific dialplan application", show_application_help, complete_show_application },
- { { "show", "dialplan", NULL }, handle_show_dialplan,
- "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
- { { "show", "switches", NULL }, handle_show_switches,
- "Show alternative switches", show_switches_help },
- { { "show", "hints", NULL }, handle_show_hints,
- "Show dialplan hints", show_hints_help },
- };
- int ast_unregister_application(const char *app)
- {
- struct ast_app *tmp, *tmpl = NULL;
- if (ast_mutex_lock(&applock)) {
- ast_log(LOG_ERROR, "Unable to lock application list\n");
- return -1;
- }
- tmp = apps;
- while(tmp) {
- if (!strcasecmp(app, tmp->name)) {
- if (tmpl)
- tmpl->next = tmp->next;
- else
- apps = tmp->next;
- if (option_verbose > 1)
- ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
- free(tmp);
- ast_mutex_unlock(&applock);
- return 0;
- }
- tmpl = tmp;
- tmp = tmp->next;
- }
- ast_mutex_unlock(&applock);
- return -1;
- }
- struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
- {
- struct ast_context *tmp, **local_contexts;
- int length;
- length = sizeof(struct ast_context);
- length += strlen(name) + 1;
- if (!extcontexts) {
- local_contexts = &contexts;
- ast_mutex_lock(&conlock);
- } else
- local_contexts = extcontexts;
- tmp = *local_contexts;
- while(tmp) {
- if (!strcasecmp(tmp->name, name)) {
- ast_mutex_unlock(&conlock);
- ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
- if (!extcontexts)
- ast_mutex_unlock(&conlock);
- return NULL;
- }
- tmp = tmp->next;
- }
- tmp = malloc(length);
- if (tmp) {
- memset(tmp, 0, length);
- ast_mutex_init(&tmp->lock);
- strcpy(tmp->name, name);
- tmp->root = NULL;
- tmp->registrar = registrar;
- tmp->next = *local_contexts;
- tmp->includes = NULL;
- tmp->ignorepats = NULL;
- *local_contexts = tmp;
- if (option_debug)
- ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
- else if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
- } else
- ast_log(LOG_ERROR, "Out of memory\n");
-
- if (!extcontexts)
- ast_mutex_unlock(&conlock);
- return tmp;
- }
- void __ast_context_destroy(struct ast_context *con, const char *registrar);
- struct store_hint {
- char *context;
- char *exten;
- struct ast_state_cb *callbacks;
- int laststate;
- AST_LIST_ENTRY(store_hint) list;
- char data[1];
- };
- AST_LIST_HEAD(store_hints, store_hint);
- void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
- {
- struct ast_context *tmp, *lasttmp = NULL;
- struct store_hints store;
- struct store_hint *this;
- struct ast_hint *hint;
- struct ast_exten *exten;
- int length;
- struct ast_state_cb *thiscb, *prevcb;
- /* preserve all watchers for hints associated with this registrar */
- AST_LIST_HEAD_INIT(&store);
- ast_mutex_lock(&hintlock);
- for (hint = hints; hint; hint = hint->next) {
- if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
- length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
- this = calloc(1, length);
- if (!this) {
- ast_log(LOG_WARNING, "Could not allocate memory to preserve hint\n");
- continue;
- }
- this->callbacks = hint->callbacks;
- hint->callbacks = NULL;
- this->laststate = hint->laststate;
- this->context = this->data;
- strcpy(this->data, hint->exten->parent->name);
- this->exten = this->data + strlen(this->context) + 1;
- strcpy(this->exten, hint->exten->exten);
- AST_LIST_INSERT_HEAD(&store, this, list);
- }
- }
- ast_mutex_unlock(&hintlock);
- tmp = *extcontexts;
- ast_mutex_lock(&conlock);
- if (registrar) {
- __ast_context_destroy(NULL,registrar);
- while (tmp) {
- lasttmp = tmp;
- tmp = tmp->next;
- }
- } else {
- while (tmp) {
- __ast_context_destroy(tmp,tmp->registrar);
- lasttmp = tmp;
- tmp = tmp->next;
- }
- }
- if (lasttmp) {
- lasttmp->next = contexts;
- contexts = *extcontexts;
- *extcontexts = NULL;
- } else
- ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
- ast_mutex_unlock(&conlock);
- /* restore the watchers for hints that can be found; notify those that
- cannot be restored
- */
- while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
- exten = ast_hint_extension(NULL, this->context, this->exten);
- /* Find the hint in the list of hints */
- ast_mutex_lock(&hintlock);
- for (hint = hints; hint; hint = hint->next) {
- if (hint->exten == exten)
- break;
- }
- if (!exten || !hint) {
- /* this hint has been removed, notify the watchers */
- prevcb = NULL;
- thiscb = this->callbacks;
- while (thiscb) {
- prevcb = thiscb;
- thiscb = thiscb->next;
- prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
- free(prevcb);
- }
- } else {
- thiscb = this->callbacks;
- while (thiscb->next)
- thiscb = thiscb->next;
- thiscb->next = hint->callbacks;
- hint->callbacks = this->callbacks;
- hint->laststate = this->laststate;
- }
- ast_mutex_unlock(&hintlock);
- free(this);
- }
- return;
- }
- /*
- * errno values
- * EBUSY - can't lock
- * ENOENT - no existence of context
- */
- int ast_context_add_include(const char *context, const char *include, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) {
- errno = EBUSY;
- return -1;
- }
- /* walk contexts ... */
- c = ast_walk_contexts(NULL);
- while (c) {
- /* ... search for the right one ... */
- if (!strcmp(ast_get_context_name(c), context)) {
- int ret = ast_context_add_include2(c, include, registrar);
- /* ... unlock contexts list and return */
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- /* we can't find the right context */
- ast_unlock_contexts();
- errno = ENOENT;
- return -1;
- }
- #define FIND_NEXT \
- do { \
- c = info; \
- while(*c && (*c != '|')) c++; \
- if (*c) { *c = '\0'; c++; } else c = NULL; \
- } while(0)
- static void get_timerange(struct ast_timing *i, char *times)
- {
- char *e;
- int x;
- int s1, s2;
- int e1, e2;
- /* int cth, ctm; */
- /* start disabling all times, fill the fields with 0's, as they may contain garbage */
- memset(i->minmask, 0, sizeof(i->minmask));
-
- /* Star is all times */
- if (ast_strlen_zero(times) || !strcmp(times, "*")) {
- for (x=0; x<24; x++)
- i->minmask[x] = (1 << 30) - 1;
- return;
- }
- /* Otherwise expect a range */
- e = strchr(times, '-');
- if (!e) {
- ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
- return;
- }
- *e = '\0';
- e++;
- while(*e && !isdigit(*e))
- e++;
- if (!*e) {
- ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
- return;
- }
- if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
- ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
- return;
- }
- if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
- ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
- return;
- }
- #if 1
- s1 = s1 * 30 + s2/2;
- if ((s1 < 0) || (s1 >= 24*30)) {
- ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
- return;
- }
- e1 = e1 * 30 + e2/2;
- if ((e1 < 0) || (e1 >= 24*30)) {
- ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
- return;
- }
- /* Go through the time and enable each appropriate bit */
- for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
- i->minmask[x/30] |= (1 << (x % 30));
- }
- /* Do the last one */
- i->minmask[x/30] |= (1 << (x % 30));
- #else
- for (cth=0; cth<24; cth++) {
- /* Initialize masks to blank */
- i->minmask[cth] = 0;
- for (ctm=0; ctm<30; ctm++) {
- if (
- /* First hour with more than one hour */
- (((cth == s1) && (ctm >= s2)) &&
- ((cth < e1)))
- /* Only one hour */
- || (((cth == s1) && (ctm >= s2)) &&
- ((cth == e1) && (ctm <= e2)))
- /* In between first and last hours (more than 2 hours) */
- || ((cth > s1) &&
- (cth < e1))
- /* Last hour with more than one hour */
- || ((cth > s1) &&
- ((cth == e1) && (ctm <= e2)))
- )
- i->minmask[cth] |= (1 << (ctm / 2));
- }
- }
- #endif
- /* All done */
- return;
- }
- static char *days[] =
- {
- "sun",
- "mon",
- "tue",
- "wed",
- "thu",
- "fri",
- "sat",
- };
- /*! \brief get_dow: Get day of week */
- static unsigned int get_dow(char *dow)
- {
- char *c;
- /* The following line is coincidence, really! */
- int s, e, x;
- unsigned int mask;
- /* Check for all days */
- if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
- return (1 << 7) - 1;
- /* Get start and ending days */
- c = strchr(dow, '-');
- if (c) {
- *c = '\0';
- c++;
- } else
- c = NULL;
- /* Find the start */
- s = 0;
- while((s < 7) && strcasecmp(dow, days[s])) s++;
- if (s >= 7) {
- ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
- return 0;
- }
- if (c) {
- e = 0;
- while((e < 7) && strcasecmp(c, days[e])) e++;
- if (e >= 7) {
- ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
- return 0;
- }
- } else
- e = s;
- mask = 0;
- for (x=s; x != e; x = (x + 1) % 7) {
- mask |= (1 << x);
- }
- /* One last one */
- mask |= (1 << x);
- return mask;
- }
- static unsigned int get_day(char *day)
- {
- char *c;
- /* The following line is coincidence, really! */
- int s, e, x;
- unsigned int mask;
- /* Check for all days */
- if (ast_strlen_zero(day) || !strcmp(day, "*")) {
- mask = (1 << 30) + ((1 << 30) - 1);
- return mask;
- }
- /* Get start and ending days */
- c = strchr(day, '-');
- if (c) {
- *c = '\0';
- c++;
- }
- /* Find the start */
- if (sscanf(day, "%d", &s) != 1) {
- ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
- return 0;
- }
- if ((s < 1) || (s > 31)) {
- ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
- return 0;
- }
- s--;
- if (c) {
- if (sscanf(c, "%d", &e) != 1) {
- ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
- return 0;
- }
- if ((e < 1) || (e > 31)) {
- ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
- return 0;
- }
- e--;
- } else
- e = s;
- mask = 0;
- for (x=s; x!=e; x = (x + 1) % 31) {
- mask |= (1 << x);
- }
- mask |= (1 << x);
- return mask;
- }
- static char *months[] =
- {
- "jan",
- "feb",
- "mar",
- "apr",
- "may",
- "jun",
- "jul",
- "aug",
- "sep",
- "oct",
- "nov",
- "dec",
- };
- static unsigned int get_month(char *mon)
- {
- char *c;
- /* The following line is coincidence, really! */
- int s, e, x;
- unsigned int mask;
- /* Check for all days */
- if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
- return (1 << 12) - 1;
- /* Get start and ending days */
- c = strchr(mon, '-');
- if (c) {
- *c = '\0';
- c++;
- }
- /* Find the start */
- s = 0;
- while((s < 12) && strcasecmp(mon, months[s])) s++;
- if (s >= 12) {
- ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
- return 0;
- }
- if (c) {
- e = 0;
- while((e < 12) && strcasecmp(mon, months[e])) e++;
- if (e >= 12) {
- ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
- return 0;
- }
- } else
- e = s;
- mask = 0;
- for (x=s; x!=e; x = (x + 1) % 12) {
- mask |= (1 << x);
- }
- /* One last one */
- mask |= (1 << x);
- return mask;
- }
- int ast_build_timing(struct ast_timing *i, char *info_in)
- {
- char info_save[256];
- char *info;
- char *c;
- /* Check for empty just in case */
- if (ast_strlen_zero(info_in))
- return 0;
- /* make a copy just in case we were passed a static string */
- ast_copy_string(info_save, info_in, sizeof(info_save));
- info = info_save;
- /* Assume everything except time */
- i->monthmask = (1 << 12) - 1;
- i->daymask = (1 << 30) - 1 + (1 << 30);
- i->dowmask = (1 << 7) - 1;
- /* Avoid using str tok */
- FIND_NEXT;
- /* Info has the time range, start with that */
- get_timerange(i, info);
- info = c;
- if (!info)
- return 1;
- FIND_NEXT;
- /* Now check for day of week */
- i->dowmask = get_dow(info);
- info = c;
- if (!info)
- return 1;
- FIND_NEXT;
- /* Now check for the day of the month */
- i->daymask = get_day(info);
- info = c;
- if (!info)
- return 1;
- FIND_NEXT;
- /* And finally go for the month */
- i->monthmask = get_month(info);
- return 1;
- }
- int ast_check_timing(struct ast_timing *i)
- {
- struct tm tm;
- time_t t;
- time(&t);
- localtime_r(&t,&tm);
- /* If it's not the right month, return */
- if (!(i->monthmask & (1 << tm.tm_mon))) {
- return 0;
- }
- /* If it's not that time of the month.... */
- /* Warning, tm_mday has range 1..31! */
- if (!(i->daymask & (1 << (tm.tm_mday-1))))
- return 0;
- /* If it's not the right day of the week */
- if (!(i->dowmask & (1 << tm.tm_wday)))
- return 0;
- /* Sanity check the hour just to be safe */
- if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
- ast_log(LOG_WARNING, "Insane time...\n");
- return 0;
- }
- /* Now the tough part, we calculate if it fits
- in the right time based on min/hour */
- if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
- return 0;
- /* If we got this far, then we're good */
- return 1;
- }
- /*
- * errno values
- * ENOMEM - out of memory
- * EBUSY - can't lock
- * EEXIST - already included
- * EINVAL - there is no existence of context for inclusion
- */
- int ast_context_add_include2(struct ast_context *con, const char *value,
- const char *registrar)
- {
- struct ast_include *new_include;
- char *c;
- struct ast_include *i, *il = NULL; /* include, include_last */
- int length;
- char *p;
-
- length = sizeof(struct ast_include);
- length += 2 * (strlen(value) + 1);
- /* allocate new include structure ... */
- if (!(new_include = malloc(length))) {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
-
- /* ... fill in this structure ... */
- memset(new_include, 0, length);
- p = new_include->stuff;
- new_include->name = p;
- strcpy(new_include->name, value);
- p += strlen(value) + 1;
- new_include->rname = p;
- strcpy(new_include->rname, value);
- c = new_include->rname;
- /* Strip off timing info */
- while(*c && (*c != '|'))
- c++;
- /* Process if it's there */
- if (*c) {
- new_include->hastime = ast_build_timing(&(new_include->timing), c+1);
- *c = '\0';
- }
- new_include->next = NULL;
- new_include->registrar = registrar;
- /* ... try to lock this context ... */
- if (ast_mutex_lock(&con->lock)) {
- free(new_include);
- errno = EBUSY;
- return -1;
- }
- /* ... go to last include and check if context is already included too... */
- i = con->includes;
- while (i) {
- if (!strcasecmp(i->name, new_include->name)) {
- free(new_include);
- ast_mutex_unlock(&con->lock);
- errno = EEXIST;
- return -1;
- }
- il = i;
- i = i->next;
- }
- /* ... include new context into context list, unlock, return */
- if (il)
- il->next = new_include;
- else
- con->includes = new_include;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
- ast_mutex_unlock(&con->lock);
- return 0;
- }
- /*
- * errno values
- * EBUSY - can't lock
- * ENOENT - no existence of context
- */
- int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) {
- errno = EBUSY;
- return -1;
- }
- /* walk contexts ... */
- c = ast_walk_contexts(NULL);
- while (c) {
- /* ... search for the right one ... */
- if (!strcmp(ast_get_context_name(c), context)) {
- int ret = ast_context_add_switch2(c, sw, data, eval, registrar);
- /* ... unlock contexts list and return */
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- /* we can't find the right context */
- ast_unlock_contexts();
- errno = ENOENT;
- return -1;
- }
- /*
- * errno values
- * ENOMEM - out of memory
- * EBUSY - can't lock
- * EEXIST - already included
- * EINVAL - there is no existence of context for inclusion
- */
- int ast_context_add_switch2(struct ast_context *con, const char *value,
- const char *data, int eval, const char *registrar)
- {
- struct ast_sw *new_sw;
- struct ast_sw *i, *il = NULL; /* sw, sw_last */
- int length;
- char *p;
-
- length = sizeof(struct ast_sw);
- length += strlen(value) + 1;
- if (data)
- length += strlen(data);
- length++;
- if (eval) {
- /* Create buffer for evaluation of variables */
- length += SWITCH_DATA_LENGTH;
- length++;
- }
- /* allocate new sw structure ... */
- if (!(new_sw = malloc(length))) {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
-
- /* ... fill in this structure ... */
- memset(new_sw, 0, length);
- p = new_sw->stuff;
- new_sw->name = p;
- strcpy(new_sw->name, value);
- p += strlen(value) + 1;
- new_sw->data = p;
- if (data) {
- strcpy(new_sw->data, data);
- p += strlen(data) + 1;
- } else {
- strcpy(new_sw->data, "");
- p++;
- }
- if (eval)
- new_sw->tmpdata = p;
- new_sw->next = NULL;
- new_sw->eval = eval;
- new_sw->registrar = registrar;
- /* ... try to lock this context ... */
- if (ast_mutex_lock(&con->lock)) {
- free(new_sw);
- errno = EBUSY;
- return -1;
- }
- /* ... go to last sw and check if context is already swd too... */
- i = con->alts;
- while (i) {
- if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
- free(new_sw);
- ast_mutex_unlock(&con->lock);
- errno = EEXIST;
- return -1;
- }
- il = i;
- i = i->next;
- }
- /* ... sw new context into context list, unlock, return */
- if (il)
- il->next = new_sw;
- else
- con->alts = new_sw;
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
- ast_mutex_unlock(&con->lock);
- return 0;
- }
- /*
- * EBUSY - can't lock
- * ENOENT - there is not context existence
- */
- int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) {
- errno = EBUSY;
- return -1;
- }
- c = ast_walk_contexts(NULL);
- while (c) {
- if (!strcmp(ast_get_context_name(c), context)) {
- int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- ast_unlock_contexts();
- errno = ENOENT;
- return -1;
- }
- int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
- {
- struct ast_ignorepat *ip, *ipl = NULL;
- if (ast_mutex_lock(&con->lock)) {
- errno = EBUSY;
- return -1;
- }
- ip = con->ignorepats;
- while (ip) {
- if (!strcmp(ip->pattern, ignorepat) &&
- (!registrar || (registrar == ip->registrar))) {
- if (ipl) {
- ipl->next = ip->next;
- free(ip);
- } else {
- con->ignorepats = ip->next;
- free(ip);
- }
- ast_mutex_unlock(&con->lock);
- return 0;
- }
- ipl = ip; ip = ip->next;
- }
- ast_mutex_unlock(&con->lock);
- errno = EINVAL;
- return -1;
- }
- /*
- * EBUSY - can't lock
- * ENOENT - there is no existence of context
- */
- int ast_context_add_ignorepat(const char *con, const char *value, const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) {
- errno = EBUSY;
- return -1;
- }
- c = ast_walk_contexts(NULL);
- while (c) {
- if (!strcmp(ast_get_context_name(c), con)) {
- int ret = ast_context_add_ignorepat2(c, value, registrar);
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- ast_unlock_contexts();
- errno = ENOENT;
- return -1;
- }
- int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
- {
- struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
- int length;
- length = sizeof(struct ast_ignorepat);
- length += strlen(value) + 1;
- ignorepat = malloc(length);
- if (!ignorepat) {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
- memset(ignorepat, 0, length);
- strcpy(ignorepat->pattern, value);
- ignorepat->next = NULL;
- ignorepat->registrar = registrar;
- ast_mutex_lock(&con->lock);
- ignorepatc = con->ignorepats;
- while(ignorepatc) {
- ignorepatl = ignorepatc;
- if (!strcasecmp(ignorepatc->pattern, value)) {
- /* Already there */
- ast_mutex_unlock(&con->lock);
- errno = EEXIST;
- return -1;
- }
- ignorepatc = ignorepatc->next;
- }
- if (ignorepatl)
- ignorepatl->next = ignorepat;
- else
- con->ignorepats = ignorepat;
- ast_mutex_unlock(&con->lock);
- return 0;
-
- }
- int ast_ignore_pattern(const char *context, const char *pattern)
- {
- struct ast_context *con;
- struct ast_ignorepat *pat;
- con = ast_context_find(context);
- if (con) {
- pat = con->ignorepats;
- while (pat) {
- if (ast_extension_match(pat->pattern, pattern))
- return 1;
- pat = pat->next;
- }
- }
- return 0;
- }
- /*
- * EBUSY - can't lock
- * ENOENT - no existence of context
- *
- */
- int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid,
- const char *application, void *data, void (*datad)(void *), const char *registrar)
- {
- struct ast_context *c;
- if (ast_lock_contexts()) {
- errno = EBUSY;
- return -1;
- }
- c = ast_walk_contexts(NULL);
- while (c) {
- if (!strcmp(context, ast_get_context_name(c))) {
- int ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
- application, data, datad, registrar);
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- ast_unlock_contexts();
- errno = ENOENT;
- return -1;
- }
- int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
- {
- if (!chan)
- return -1;
- if (!ast_strlen_zero(context))
- ast_copy_string(chan->context, context, sizeof(chan->context));
- if (!ast_strlen_zero(exten))
- ast_copy_string(chan->exten, exten, sizeof(chan->exten));
- if (priority > -1) {
- chan->priority = priority;
- /* see flag description in channel.h for explanation */
- if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
- chan->priority--;
- }
-
- return 0;
- }
- int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
- {
- int res = 0;
- ast_mutex_lock(&chan->lock);
- if (chan->pbx) {
- /* This channel is currently in the PBX */
- ast_explicit_goto(chan, context, exten, priority);
- ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
- } else {
- /* In order to do it when the channel doesn't really exist within
- the PBX, we have to make a new channel, masquerade, and start the PBX
- at the new location */
- struct ast_channel *tmpchan;
- tmpchan = ast_channel_alloc(0);
- if (tmpchan) {
- snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
- ast_setstate(tmpchan, chan->_state);
- /* Make formats okay */
- tmpchan->readformat = chan->readformat;
- tmpchan->writeformat = chan->writeformat;
- /* Setup proper location */
- ast_explicit_goto(tmpchan,
- (!ast_strlen_zero(context)) ? context : chan->context,
- (!ast_strlen_zero(exten)) ? exten : chan->exten,
- priority);
- /* Masquerade into temp channel */
- ast_channel_masquerade(tmpchan, chan);
-
- /* Grab the locks and get going */
- ast_mutex_lock(&tmpchan->lock);
- ast_do_masquerade(tmpchan);
- ast_mutex_unlock(&tmpchan->lock);
- /* Start the PBX going on our stolen channel */
- if (ast_pbx_start(tmpchan)) {
- ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
- ast_hangup(tmpchan);
- res = -1;
- }
- } else {
- res = -1;
- }
- }
- ast_mutex_unlock(&chan->lock);
- return res;
- }
- int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
- {
- struct ast_channel *chan;
- int res = -1;
- chan = ast_get_channel_by_name_locked(channame);
- if (chan) {
- res = ast_async_goto(chan, context, exten, priority);
- ast_mutex_unlock(&chan->lock);
- }
- return res;
- }
- static int ext_strncpy(char *dst, const char *src, int len)
- {
- int count=0;
- while(*src && (count < len - 1)) {
- switch(*src) {
- case ' ':
- /* otherwise exten => [a-b],1,... doesn't work */
- /* case '-': */
- /* Ignore */
- break;
- default:
- *dst = *src;
- dst++;
- }
- src++;
- count++;
- }
- *dst = '\0';
- return count;
- }
- static void null_datad(void *foo)
- {
- }
- /*
- * EBUSY - can't lock
- * EEXIST - extension with the same priority exist and no replace is set
- *
- */
- int ast_add_extension2(struct ast_context *con,
- int replace, const char *extension, int priority, const char *label, const char *callerid,
- const char *application, void *data, void (*datad)(void *),
- const char *registrar)
- {
- #define LOG do { if (option_debug) {\
- if (tmp->matchcid) { \
- ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
- } else { \
- ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
- } \
- } else if (option_verbose > 2) { \
- if (tmp->matchcid) { \
- ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
- } else { \
- ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
- } \
- } } while(0)
- /*
- * This is a fairly complex routine. Different extensions are kept
- * in order by the extension number. Then, extensions of different
- * priorities (same extension) are kept in a list, according to the
- * peer pointer.
- */
- struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
- int res;
- int length;
- char *p;
- length = sizeof(struct ast_exten);
- length += strlen(extension) + 1;
- length += strlen(application) + 1;
- if (label)
- length += strlen(label) + 1;
- if (callerid)
- length += strlen(callerid) + 1;
- else
- length ++;
- /* Be optimistic: Build the extension structure first */
- if (datad == NULL)
- datad = null_datad;
- tmp = malloc(length);
- if (tmp) {
- memset(tmp, 0, length);
- p = tmp->stuff;
- if (label) {
- tmp->label = p;
- strcpy(tmp->label, label);
- p += strlen(label) + 1;
- }
- tmp->exten = p;
- p += ext_strncpy(tmp->exten, extension, strlen(extension) + 1) + 1;
- tmp->priority = priority;
- tmp->cidmatch = p;
- if (callerid) {
- p += ext_strncpy(tmp->cidmatch, callerid, strlen(callerid) + 1) + 1;
- tmp->matchcid = 1;
- } else {
- tmp->cidmatch[0] = '\0';
- tmp->matchcid = 0;
- p++;
- }
- tmp->app = p;
- strcpy(tmp->app, application);
- tmp->parent = con;
- tmp->data = data;
- tmp->datad = datad;
- tmp->registrar = registrar;
- tmp->peer = NULL;
- tmp->next = NULL;
- } else {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
- if (ast_mutex_lock(&con->lock)) {
- free(tmp);
- /* And properly destroy the data */
- datad(data);
- ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
- errno = EBUSY;
- return -1;
- }
- e = con->root;
- while(e) {
- /* Make sure patterns are always last! */
- if ((e->exten[0] != '_') && (extension[0] == '_'))
- res = -1;
- else if ((e->exten[0] == '_') && (extension[0] != '_'))
- res = 1;
- else
- res= strcmp(e->exten, extension);
- if (!res) {
- if (!e->matchcid && !tmp->matchcid)
- res = 0;
- else if (tmp->matchcid && !e->matchcid)
- res = 1;
- else if (e->matchcid && !tmp->matchcid)
- res = -1;
- else
- res = strcasecmp(e->cidmatch, tmp->cidmatch);
- }
- if (res == 0) {
- /* We have an exact match, now we find where we are
- and be sure there's no duplicates */
- while(e) {
- if (e->priority == tmp->priority) {
- /* Can't have something exactly the same. Is this a
- replacement? If so, replace, otherwise, bonk. */
- if (replace) {
- if (ep) {
- /* We're in the peer list, insert ourselves */
- ep->peer = tmp;
- tmp->peer = e->peer;
- } else if (el) {
- /* We're the first extension. Take over e's functions */
- el->next = tmp;
- tmp->next = e->next;
- tmp->peer = e->peer;
- } else {
- /* We're the very first extension. */
- con->root = tmp;
- tmp->next = e->next;
- tmp->peer = e->peer;
- }
- if (tmp->priority == PRIORITY_HINT)
- ast_change_hint(e,tmp);
- /* Destroy the old one */
- e->datad(e->data);
- free(e);
- ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_change_hint(e, tmp);
- /* And immediately return success. */
- LOG;
- return 0;
- } else {
- ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
- tmp->datad(tmp->data);
- free(tmp);
- ast_mutex_unlock(&con->lock);
- errno = EEXIST;
- return -1;
- }
- } else if (e->priority > tmp->priority) {
- /* Slip ourselves in just before e */
- if (ep) {
- /* Easy enough, we're just in the peer list */
- ep->peer = tmp;
- tmp->peer = e;
- } else if (el) {
- /* We're the first extension in this peer list */
- el->next = tmp;
- tmp->next = e->next;
- e->next = NULL;
- tmp->peer = e;
- } else {
- /* We're the very first extension altogether */
- tmp->next = con->root->next;
- /* Con->root must always exist or we couldn't get here */
- tmp->peer = con->root;
- con->root = tmp;
- }
- ast_mutex_unlock(&con->lock);
- /* And immediately return success. */
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
-
- LOG;
- return 0;
- }
- ep = e;
- e = e->peer;
- }
- /* If we make it here, then it's time for us to go at the very end.
- ep *must* be defined or we couldn't have gotten here. */
- ep->peer = tmp;
- ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
-
- /* And immediately return success. */
- LOG;
- return 0;
-
- } else if (res > 0) {
- /* Insert ourselves just before 'e'. We're the first extension of
- this kind */
- tmp->next = e;
- if (el) {
- /* We're in the list somewhere */
- el->next = tmp;
- } else {
- /* We're at the top of the list */
- con->root = tmp;
- }
- ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
- /* And immediately return success. */
- LOG;
- return 0;
- }
-
- el = e;
- e = e->next;
- }
- /* If we fall all the way through to here, then we need to be on the end. */
- if (el)
- el->next = tmp;
- else
- con->root = tmp;
- ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
- LOG;
- return 0;
- }
- struct async_stat {
- pthread_t p;
- struct ast_channel *chan;
- char context[AST_MAX_CONTEXT];
- char exten[AST_MAX_EXTENSION];
- int priority;
- int timeout;
- char app[AST_MAX_EXTENSION];
- char appdata[1024];
- };
- static void *async_wait(void *data)
- {
- struct async_stat *as = data;
- struct ast_channel *chan = as->chan;
- int timeout = as->timeout;
- int res;
- struct ast_frame *f;
- struct ast_app *app;
-
- while(timeout && (chan->_state != AST_STATE_UP)) {
- res = ast_waitfor(chan, timeout);
- if (res < 1)
- break;
- if (timeout > -1)
- timeout = res;
- f = ast_read(chan);
- if (!f)
- break;
- if (f->frametype == AST_FRAME_CONTROL) {
- if ((f->subclass == AST_CONTROL_BUSY) ||
- (f->subclass == AST_CONTROL_CONGESTION) )
- break;
- }
- ast_frfree(f);
- }
- if (chan->_state == AST_STATE_UP) {
- if (!ast_strlen_zero(as->app)) {
- app = pbx_findapp(as->app);
- if (app) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
- pbx_exec(chan, app, as->appdata, 1);
- } else
- ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
- } else {
- if (!ast_strlen_zero(as->context))
- ast_copy_string(chan->context, as->context, sizeof(chan->context));
- if (!ast_strlen_zero(as->exten))
- ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
- if (as->priority > 0)
- chan->priority = as->priority;
- /* Run the PBX */
- if (ast_pbx_run(chan)) {
- ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
- } else {
- /* PBX will have taken care of this */
- chan = NULL;
- }
- }
-
- }
- free(as);
- if (chan)
- ast_hangup(chan);
- return NULL;
- }
- /*! Function to update the cdr after a spool call fails.
- *
- * This function updates the cdr for a failed spool call
- * and takes the channel of the failed call as an argument.
- *
- */
- int ast_pbx_outgoing_cdr_failed(void)
- {
- /* allocate a channel */
- struct ast_channel *chan = ast_channel_alloc(0);
- if(!chan) {
- /* allocation of the channel failed, let some peeps know */
- ast_log(LOG_WARNING, "Unable to allocate channel structure for CDR record\n");
- return -1; /* failure */
- }
- chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
- if(!chan->cdr) {
- /* allocation of the cdr failed */
- ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
- ast_channel_free(chan); /* free the channel */
- return -1; /* return failure */
- }
-
- /* allocation of the cdr was successful */
- ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
- ast_cdr_start(chan->cdr); /* record the start and stop time */
- ast_cdr_end(chan->cdr);
- ast_cdr_failed(chan->cdr); /* set the status to failed */
- ast_cdr_detach(chan->cdr); /* post and free the record */
- ast_channel_free(chan); /* free the channel */
-
- return 0; /* success */
- }
- int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **channel)
- {
- struct ast_channel *chan;
- struct async_stat *as;
- int res = -1, cdr_res = -1;
- struct outgoing_helper oh;
- pthread_attr_t attr;
- if (sync) {
- LOAD_OH(oh);
- chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
- if (channel) {
- *channel = chan;
- if (chan)
- ast_mutex_lock(&chan->lock);
- }
- if (chan) {
- if(chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
- ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
- } else {
- chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
- if (!chan->cdr) {
- /* allocation of the cdr failed */
- ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
- free(chan->pbx);
- res = -1;
- goto outgoing_exten_cleanup;
- }
- /* allocation of the cdr was successful */
- ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
- ast_cdr_start(chan->cdr);
- }
- if (chan->_state == AST_STATE_UP) {
- res = 0;
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
- if (sync > 1) {
- if (channel)
- ast_mutex_unlock(&chan->lock);
- if (ast_pbx_run(chan)) {
- ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
- if (channel)
- *channel = NULL;
- ast_hangup(chan);
- res = -1;
- }
- } else {
- if (ast_pbx_start(chan)) {
- ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
- if (channel)
- *channel = NULL;
- ast_hangup(chan);
- res = -1;
- }
- }
- } else {
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
- if(chan->cdr) { /* update the cdr */
- /* here we update the status of the call, which sould be busy.
- * if that fails then we set the status to failed */
- if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
- ast_cdr_failed(chan->cdr);
- }
-
- if (channel)
- *channel = NULL;
- ast_hangup(chan);
- }
- }
- if(res < 0) { /* the call failed for some reason */
- if (*reason == 0) { /* if the call failed (not busy or no answer)
- * update the cdr with the failed message */
- cdr_res = ast_pbx_outgoing_cdr_failed();
- if (cdr_res != 0) {
- res = cdr_res;
- goto outgoing_exten_cleanup;
- }
- }
-
- /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
- /* check if "failed" exists */
- if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
- chan = ast_channel_alloc(0);
- if (chan) {
- ast_copy_string(chan->name, "OutgoingSpoolFailed", sizeof(chan->name));
- if (!ast_strlen_zero(context))
- ast_copy_string(chan->context, context, sizeof(chan->context));
- ast_copy_string(chan->exten, "failed", sizeof(chan->exten));
- chan->priority = 1;
- ast_set_variables(chan, vars);
- ast_pbx_run(chan);
- } else
- ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
- }
- }
- } else {
- as = malloc(sizeof(struct async_stat));
- if (!as) {
- res = -1;
- goto outgoing_exten_cleanup;
- }
- memset(as, 0, sizeof(struct async_stat));
- chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
- if (channel) {
- *channel = chan;
- if (chan)
- ast_mutex_lock(&chan->lock);
- }
- if (!chan) {
- free(as);
- res = -1;
- goto outgoing_exten_cleanup;
- }
- as->chan = chan;
- ast_copy_string(as->context, context, sizeof(as->context));
- ast_copy_string(as->exten, exten, sizeof(as->exten));
- as->priority = priority;
- as->timeout = timeout;
- ast_set_variables(chan, vars);
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
- ast_log(LOG_WARNING, "Failed to start async wait\n");
- free(as);
- if (channel)
- *channel = NULL;
- ast_hangup(chan);
- res = -1;
- goto outgoing_exten_cleanup;
- }
- res = 0;
- }
- outgoing_exten_cleanup:
- ast_variables_destroy(vars);
- return res;
- }
- struct app_tmp {
- char app[256];
- char data[256];
- struct ast_channel *chan;
- pthread_t t;
- };
- static void *ast_pbx_run_app(void *data)
- {
- struct app_tmp *tmp = data;
- struct ast_app *app;
- app = pbx_findapp(tmp->app);
- if (app) {
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
- pbx_exec(tmp->chan, app, tmp->data, 1);
- } else
- ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
- ast_hangup(tmp->chan);
- free(tmp);
- return NULL;
- }
- int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, struct ast_channel **locked_channel)
- {
- struct ast_channel *chan;
- struct async_stat *as;
- struct app_tmp *tmp;
- int res = -1, cdr_res = -1;
- struct outgoing_helper oh;
- pthread_attr_t attr;
-
- memset(&oh, 0, sizeof(oh));
- oh.vars = vars;
- if (locked_channel)
- *locked_channel = NULL;
- if (ast_strlen_zero(app)) {
- res = -1;
- goto outgoing_app_cleanup;
- }
- if (sync) {
- chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
- if (chan) {
- if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
- ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
- } else {
- chan->cdr = ast_cdr_alloc(); /* allocate a cdr for the channel */
- if(!chan->cdr) {
- /* allocation of the cdr failed */
- ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
- free(chan->pbx);
- res = -1;
- goto outgoing_app_cleanup;
- }
- /* allocation of the cdr was successful */
- ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
- ast_cdr_start(chan->cdr);
- }
- ast_set_variables(chan, vars);
- if (chan->_state == AST_STATE_UP) {
- res = 0;
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
- tmp = malloc(sizeof(struct app_tmp));
- if (tmp) {
- memset(tmp, 0, sizeof(struct app_tmp));
- ast_copy_string(tmp->app, app, sizeof(tmp->app));
- if (appdata)
- ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
- tmp->chan = chan;
- if (sync > 1) {
- if (locked_channel)
- ast_mutex_unlock(&chan->lock);
- ast_pbx_run_app(tmp);
- } else {
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (locked_channel)
- ast_mutex_lock(&chan->lock);
- if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
- ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
- free(tmp);
- if (locked_channel)
- ast_mutex_unlock(&chan->lock);
- ast_hangup(chan);
- res = -1;
- } else {
- if (locked_channel)
- *locked_channel = chan;
- }
- }
- } else {
- ast_log(LOG_ERROR, "Out of memory :(\n");
- res = -1;
- }
- } else {
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
- if (chan->cdr) { /* update the cdr */
- /* here we update the status of the call, which sould be busy.
- * if that fails then we set the status to failed */
- if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
- ast_cdr_failed(chan->cdr);
- }
- ast_hangup(chan);
- }
- }
-
- if (res < 0) { /* the call failed for some reason */
- if (*reason == 0) { /* if the call failed (not busy or no answer)
- * update the cdr with the failed message */
- cdr_res = ast_pbx_outgoing_cdr_failed();
- if (cdr_res != 0) {
- res = cdr_res;
- goto outgoing_app_cleanup;
- }
- }
- }
- } else {
- as = malloc(sizeof(struct async_stat));
- if (!as) {
- res = -1;
- goto outgoing_app_cleanup;
- }
- memset(as, 0, sizeof(struct async_stat));
- chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
- if (!chan) {
- free(as);
- res = -1;
- goto outgoing_app_cleanup;
- }
- as->chan = chan;
- ast_copy_string(as->app, app, sizeof(as->app));
- if (appdata)
- ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
- as->timeout = timeout;
- ast_set_variables(chan, vars);
- /* Start a new thread, and get something handling this channel. */
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- if (locked_channel)
- ast_mutex_lock(&chan->lock);
- if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
- ast_log(LOG_WARNING, "Failed to start async wait\n");
- free(as);
- if (locked_channel)
- ast_mutex_unlock(&chan->lock);
- ast_hangup(chan);
- res = -1;
- goto outgoing_app_cleanup;
- } else {
- if (locked_channel)
- *locked_channel = chan;
- }
- res = 0;
- }
- outgoing_app_cleanup:
- ast_variables_destroy(vars);
- return res;
- }
- static void destroy_exten(struct ast_exten *e)
- {
- if (e->priority == PRIORITY_HINT)
- ast_remove_hint(e);
- if (e->datad)
- e->datad(e->data);
- free(e);
- }
- void __ast_context_destroy(struct ast_context *con, const char *registrar)
- {
- struct ast_context *tmp, *tmpl=NULL;
- struct ast_include *tmpi, *tmpil= NULL;
- struct ast_sw *sw, *swl= NULL;
- struct ast_exten *e, *el, *en;
- struct ast_ignorepat *ipi, *ipl = NULL;
- ast_mutex_lock(&conlock);
- tmp = contexts;
- while(tmp) {
- if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
- (!registrar || !strcasecmp(registrar, tmp->registrar))) {
- /* Okay, let's lock the structure to be sure nobody else
- is searching through it. */
- if (ast_mutex_lock(&tmp->lock)) {
- ast_log(LOG_WARNING, "Unable to lock context lock\n");
- return;
- }
- if (tmpl)
- tmpl->next = tmp->next;
- else
- contexts = tmp->next;
- /* Okay, now we're safe to let it go -- in a sense, we were
- ready to let it go as soon as we locked it. */
- ast_mutex_unlock(&tmp->lock);
- for (tmpi = tmp->includes; tmpi; ) {
- /* Free includes */
- tmpil = tmpi;
- tmpi = tmpi->next;
- free(tmpil);
- }
- for (ipi = tmp->ignorepats; ipi; ) {
- /* Free ignorepats */
- ipl = ipi;
- ipi = ipi->next;
- free(ipl);
- }
- for (sw = tmp->alts; sw; ) {
- /* Free switches */
- swl = sw;
- sw = sw->next;
- free(swl);
- swl = sw;
- }
- for (e = tmp->root; e;) {
- for (en = e->peer; en;) {
- el = en;
- en = en->peer;
- destroy_exten(el);
- }
- el = e;
- e = e->next;
- destroy_exten(el);
- }
- ast_mutex_destroy(&tmp->lock);
- free(tmp);
- if (!con) {
- /* Might need to get another one -- restart */
- tmp = contexts;
- tmpl = NULL;
- tmpil = NULL;
- continue;
- }
- ast_mutex_unlock(&conlock);
- return;
- }
- tmpl = tmp;
- tmp = tmp->next;
- }
- ast_mutex_unlock(&conlock);
- }
- void ast_context_destroy(struct ast_context *con, const char *registrar)
- {
- __ast_context_destroy(con,registrar);
- }
- static void wait_for_hangup(struct ast_channel *chan, void *data)
- {
- int res;
- struct ast_frame *f;
- int waittime;
-
- if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
- waittime = -1;
- if (waittime > -1) {
- ast_safe_sleep(chan, waittime * 1000);
- } else do {
- res = ast_waitfor(chan, -1);
- if (res < 0)
- return;
- f = ast_read(chan);
- if (f)
- ast_frfree(f);
- } while(f);
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_progress(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_PROGRESS);
- return 0;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_RINGING);
- return 0;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_busy(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_BUSY);
- ast_setstate(chan, AST_STATE_BUSY);
- wait_for_hangup(chan, data);
- return -1;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_CONGESTION);
- ast_setstate(chan, AST_STATE_BUSY);
- wait_for_hangup(chan, data);
- return -1;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_answer(struct ast_channel *chan, void *data)
- {
- int delay = 0;
- int res;
- if (chan->_state == AST_STATE_UP)
- delay = 0;
- else if (!ast_strlen_zero(data))
- delay = atoi(data);
- res = ast_answer(chan);
- if (res)
- return res;
- if (delay)
- res = ast_safe_sleep(chan, delay);
- return res;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
- {
- static int deprecation_warning = 0;
- if (!deprecation_warning) {
- ast_log(LOG_WARNING, "SetLanguage is deprecated, please use Set(LANGUAGE()=language) instead.\n");
- deprecation_warning = 1;
- }
- /* Copy the language as specified */
- if (!ast_strlen_zero(data))
- ast_copy_string(chan->language, data, sizeof(chan->language));
- return 0;
- }
- AST_APP_OPTIONS(resetcdr_opts, {
- AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
- AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
- AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
- });
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
- {
- char *args;
- struct ast_flags flags = { 0 };
-
- if (!ast_strlen_zero(data)) {
- args = ast_strdupa(data);
- if (!args) {
- ast_log(LOG_ERROR, "Out of memory!\n");
- return -1;
- }
- ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
- }
- ast_cdr_reset(chan->cdr, &flags);
- return 0;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
- {
- /* Copy the account code as specified */
- if (data)
- ast_cdr_setaccount(chan, (char *)data);
- else
- ast_cdr_setaccount(chan, "");
- return 0;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
- {
- /* Copy the AMA Flags as specified */
- if (data)
- ast_cdr_setamaflags(chan, (char *)data);
- else
- ast_cdr_setamaflags(chan, "");
- return 0;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
- {
- /* Just return non-zero and it will hang up */
- return -1;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
- {
- int res=0;
- char *s, *ts;
- struct ast_timing timing;
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
- return -1;
- }
- if ((s = ast_strdupa((char *) data))) {
- ts = s;
- /* Separate the Goto path */
- strsep(&ts,"?");
- /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
- if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
- res = pbx_builtin_goto(chan, (void *)ts);
- } else {
- ast_log(LOG_ERROR, "Memory Error!\n");
- }
- return res;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
- {
- int res = 0;
- char *ptr1, *ptr2;
- struct ast_timing timing;
- struct ast_app *app;
- const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "%s\n", usage);
- return -1;
- }
- ptr1 = ast_strdupa(data);
- if (!ptr1) {
- ast_log(LOG_ERROR, "Out of Memory!\n");
- return -1;
- }
- ptr2 = ptr1;
- /* Separate the Application data ptr1 is the time spec ptr2 is the app|data */
- strsep(&ptr2,"?");
- if(!ast_build_timing(&timing, ptr1)) {
- ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", ptr1, usage);
- res = -1;
- }
-
- if (!res && ast_check_timing(&timing)) {
- if (!ptr2) {
- ast_log(LOG_WARNING, "%s\n", usage);
- }
- /* ptr2 is now the app name
- we're done with ptr1 now so recycle it and use it to point to the app args */
- if((ptr1 = strchr(ptr2, '|'))) {
- *ptr1 = '\0';
- ptr1++;
- }
-
- if ((app = pbx_findapp(ptr2))) {
- res = pbx_exec(chan, app, ptr1 ? ptr1 : "", 1);
- } else {
- ast_log(LOG_WARNING, "Cannot locate application %s\n", ptr2);
- res = -1;
- }
- }
-
- return res;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_wait(struct ast_channel *chan, void *data)
- {
- int ms;
- /* Wait for "n" seconds */
- if (data && atof((char *)data)) {
- ms = atof((char *)data) * 1000;
- return ast_safe_sleep(chan, ms);
- }
- return 0;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
- {
- int ms, res, argc;
- char *args;
- char *argv[2];
- char *options = NULL;
- char *timeout = NULL;
- struct ast_flags flags = {0};
- char *opts[1] = { NULL };
- args = ast_strdupa(data);
- if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
- if (argc > 0) {
- timeout = argv[0];
- if (argc > 1)
- options = argv[1];
- }
- }
- if (options)
- ast_app_parse_options(waitexten_opts, &flags, opts, options);
-
- if (ast_test_flag(&flags, WAITEXTEN_MOH))
- ast_moh_start(chan, opts[0]);
- /* Wait for "n" seconds */
- if (timeout && atof((char *)timeout))
- ms = atof((char *)timeout) * 1000;
- else if (chan->pbx)
- ms = chan->pbx->rtimeout * 1000;
- else
- ms = 10000;
- res = ast_waitfordigit(chan, ms);
- if (!res) {
- if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
- } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
- ast_copy_string(chan->exten, "t", sizeof(chan->exten));
- chan->priority = 0;
- } else {
- ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
- res = -1;
- }
- }
- if (ast_test_flag(&flags, WAITEXTEN_MOH))
- ast_moh_stop(chan);
- return res;
- }
- /*!
- * \ingroup applications
- */
- static int pbx_builtin_background(struct ast_channel *chan, void *data)
- {
- int res = 0;
- int argc;
- char *parse;
- char *argv[4];
- char *options = NULL;
- char *filename = NULL;
- char *front = NULL, *back = NULL;
- char *lang = NULL;
- char *context = NULL;
- struct ast_flags flags = {0};
- parse = ast_strdupa(data);
- if ((argc = ast_app_separate_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
- switch (argc) {
- case 4:
- context = argv[3];
- case 3:
- lang = argv[2];
- case 2:
- options = argv[1];
- case 1:
- filename = argv[0];
- break;
- default:
- ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
- break;
- }
- }
- if (!lang)
- lang = chan->language;
- if (!context)
- context = chan->context;
- if (options) {
- if (!strcasecmp(options, "skip"))
- flags.flags = BACKGROUND_SKIP;
- else if (!strcasecmp(options, "noanswer"))
- flags.flags = BACKGROUND_NOANSWER;
- else
- ast_app_parse_options(background_opts, &flags, NULL, options);
- }
- /* Answer if need be */
- if (chan->_state != AST_STATE_UP) {
- if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
- return 0;
- } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
- res = ast_answer(chan);
- }
- }
- if (!res) {
- /* Stop anything playing */
- ast_stopstream(chan);
- /* Stream a file */
- front = filename;
- while(!res && front) {
- if((back = strchr(front, '&'))) {
- *back = '\0';
- back++;
- }
- res = ast_streamfile(chan, front, lang);
- if (!res) {
- if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
- res = ast_waitstream(chan, "");
- } else {
- if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
- res = ast_waitstream_exten(chan, context);
- } else {
- res = ast_waitstream(chan, AST_DIGIT_ANY);
- }
- }
- ast_stopstream(chan);
- } else {
- ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
- res = 0;
- break;
- }
- front = back;
- }
- }
- if (context != chan->context && res) {
- snprintf(chan->exten, sizeof(chan->exten), "%c", res);
- ast_copy_string(chan->context, context, sizeof(chan->context));
- chan->priority = 0;
- return 0;
- } else {
- return res;
- }
- }
- /*! AbsoluteTimeout
- * \ingroup applications
- * \todo Remove in 1.3 dev
- */
- static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
- {
- static int deprecation_warning = 0;
- int x = atoi((char *) data);
- if (!deprecation_warning) {
- ast_log(LOG_WARNING, "AbsoluteTimeout is deprecated, please use Set(TIMEOUT(absolute)=timeout) instead.\n");
- deprecation_warning = 1;
- }
-
- /* Set the absolute maximum time how long a call can be connected */
- ast_channel_setwhentohangup(chan,x);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
- return 0;
- }
- /*! ResponseTimeout
- * \ingroup applications
- * \todo Remove in 1.3 dev
- */
- static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
- {
- static int deprecation_warning = 0;
- if (!deprecation_warning) {
- ast_log(LOG_WARNING, "ResponseTimeout is deprecated, please use Set(TIMEOUT(response)=timeout) instead.\n");
- deprecation_warning = 1;
- }
- /* If the channel is not in a PBX, return now */
- if (!chan->pbx)
- return 0;
- /* Set the timeout for how long to wait between digits */
- chan->pbx->rtimeout = atoi((char *)data);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
- return 0;
- }
- /*! DigitTimeout
- * \ingroup applications
- * \todo Remove in 1.3 dev
- */
- static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
- {
- static int deprecation_warning = 0;
- if (!deprecation_warning) {
- ast_log(LOG_WARNING, "DigitTimeout is deprecated, please use Set(TIMEOUT(digit)=timeout) instead.\n");
- deprecation_warning = 1;
- }
- /* If the channel is not in a PBX, return now */
- if (!chan->pbx)
- return 0;
- /* Set the timeout for how long to wait between digits */
- chan->pbx->dtimeout = atoi((char *)data);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
- return 0;
- }
- /*! Goto
- * \ingroup applications
- */
- static int pbx_builtin_goto(struct ast_channel *chan, void *data)
- {
- int res;
- res = ast_parseable_goto(chan, (const char *) data);
- if (!res && (option_verbose > 2))
- ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
- return res;
- }
- int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
- {
- struct ast_var_t *variables;
- char *var, *val;
- int total = 0;
- if (!chan)
- return 0;
- memset(buf, 0, size);
- AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
- if(variables &&
- (var=ast_var_name(variables)) && (val=ast_var_value(variables)) &&
- !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
- if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
- ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
- break;
- } else
- total++;
- } else
- break;
- }
-
- return total;
- }
- char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
- {
- struct ast_var_t *variables;
- struct varshead *headp;
- if (chan)
- headp=&chan->varshead;
- else
- headp=&globals;
- if (name) {
- AST_LIST_TRAVERSE(headp,variables,entries) {
- if (!strcmp(name, ast_var_name(variables)))
- return ast_var_value(variables);
- }
- if (headp != &globals) {
- /* Check global variables if we haven't already */
- headp = &globals;
- AST_LIST_TRAVERSE(headp,variables,entries) {
- if (!strcmp(name, ast_var_name(variables)))
- return ast_var_value(variables);
- }
- }
- }
- return NULL;
- }
- void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
- {
- struct ast_var_t *newvariable;
- struct varshead *headp;
- if (name[strlen(name)-1] == ')') {
- ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
- return ast_func_write(chan, name, value);
- }
- headp = (chan) ? &chan->varshead : &globals;
- if (value) {
- if ((option_verbose > 1) && (headp == &globals))
- ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
- newvariable = ast_var_assign(name, value);
- AST_LIST_INSERT_HEAD(headp, newvariable, entries);
- }
- }
- void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
- {
- struct ast_var_t *newvariable;
- struct varshead *headp;
- const char *nametail = name;
- if (name[strlen(name)-1] == ')')
- return ast_func_write(chan, name, value);
- headp = (chan) ? &chan->varshead : &globals;
- /* For comparison purposes, we have to strip leading underscores */
- if (*nametail == '_') {
- nametail++;
- if (*nametail == '_')
- nametail++;
- }
- AST_LIST_TRAVERSE (headp, newvariable, entries) {
- if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
- /* there is already such a variable, delete it */
- AST_LIST_REMOVE(headp, newvariable, entries);
- ast_var_delete(newvariable);
- break;
- }
- }
- if (value) {
- if ((option_verbose > 1) && (headp == &globals))
- ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
- newvariable = ast_var_assign(name, value);
- AST_LIST_INSERT_HEAD(headp, newvariable, entries);
- }
- }
- int pbx_builtin_setvar_old(struct ast_channel *chan, void *data)
- {
- static int deprecation_warning = 0;
- if (!deprecation_warning) {
- ast_log(LOG_WARNING, "SetVar is deprecated, please use Set instead.\n");
- deprecation_warning = 1;
- }
- return pbx_builtin_setvar(chan, data);
- }
- int pbx_builtin_setvar(struct ast_channel *chan, void *data)
- {
- char *name, *value, *mydata;
- int argc;
- char *argv[24]; /* this will only support a maximum of 24 variables being set in a single operation */
- int global = 0;
- int x;
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
- return 0;
- }
- mydata = ast_strdupa(data);
- argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
- /* check for a trailing flags argument */
- if ((argc > 1) && !strchr(argv[argc-1], '=')) {
- argc--;
- if (strchr(argv[argc], 'g'))
- global = 1;
- }
- for (x = 0; x < argc; x++) {
- name = argv[x];
- if ((value = strchr(name, '='))) {
- *value = '\0';
- value++;
- pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
- } else
- ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
- }
- return(0);
- }
- int pbx_builtin_importvar(struct ast_channel *chan, void *data)
- {
- char *name;
- char *value;
- char *stringp=NULL;
- char *channel;
- struct ast_channel *chan2;
- char tmp[VAR_BUF_SIZE]="";
- char *s;
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
- return 0;
- }
- stringp = ast_strdupa(data);
- name = strsep(&stringp,"=");
- channel = strsep(&stringp,"|");
- value = strsep(&stringp,"\0");
- if (channel && value && name) {
- chan2 = ast_get_channel_by_name_locked(channel);
- if (chan2) {
- s = alloca(strlen(value) + 4);
- if (s) {
- sprintf(s, "${%s}", value);
- pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
- }
- ast_mutex_unlock(&chan2->lock);
- }
- pbx_builtin_setvar_helper(chan, name, tmp);
- }
- return(0);
- }
- static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
- {
- char *name;
- char *value;
- char *stringp = NULL;
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
- return 0;
- }
- stringp = data;
- name = strsep(&stringp, "=");
- value = strsep(&stringp, "\0");
- pbx_builtin_setvar_helper(NULL, name, value);
- return(0);
- }
- static int pbx_builtin_noop(struct ast_channel *chan, void *data)
- {
- return 0;
- }
- void pbx_builtin_clear_globals(void)
- {
- struct ast_var_t *vardata;
- while (!AST_LIST_EMPTY(&globals)) {
- vardata = AST_LIST_REMOVE_HEAD(&globals, entries);
- ast_var_delete(vardata);
- }
- }
- static int pbx_checkcondition(char *condition)
- {
- if (condition) {
- if (*condition == '\0') {
- /* Empty strings are false */
- return 0;
- } else if (*condition >= '0' && *condition <= '9') {
- /* Numbers are evaluated for truth */
- return atoi(condition);
- } else {
- /* Strings are true */
- return 1;
- }
- } else {
- /* NULL is also false */
- return 0;
- }
- }
- static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
- {
- char *condition, *branch1, *branch2, *branch;
- char *s;
- int rc;
- char *stringp=NULL;
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
- return 0;
- }
-
- s = ast_strdupa(data);
- stringp = s;
- condition = strsep(&stringp,"?");
- branch1 = strsep(&stringp,":");
- branch2 = strsep(&stringp,"");
- branch = pbx_checkcondition(condition) ? branch1 : branch2;
-
- if (ast_strlen_zero(branch)) {
- ast_log(LOG_DEBUG, "Not taking any branch\n");
- return 0;
- }
-
- rc = pbx_builtin_goto(chan, branch);
- return rc;
- }
- static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
- {
- int res = 0;
- char tmp[256];
- char *number = (char *) NULL;
- char *options = (char *) NULL;
-
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
- return -1;
- }
- ast_copy_string(tmp, (char *) data, sizeof(tmp));
- number=tmp;
- strsep(&number, "|");
- options = strsep(&number, "|");
- if (options) {
- if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
- strcasecmp(options, "c") && strcasecmp(options, "n") ) {
- ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
- return -1;
- }
- }
- return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
- }
- static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
- {
- int res = 0;
- if (data)
- res = ast_say_digit_str(chan, (char *)data, "", chan->language);
- return res;
- }
-
- static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
- {
- int res = 0;
- if (data)
- res = ast_say_character_str(chan, (char *)data, "", chan->language);
- return res;
- }
-
- static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
- {
- int res = 0;
- if (data)
- res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
- return res;
- }
-
- int load_pbx(void)
- {
- int x;
- /* Initialize the PBX */
- if (option_verbose) {
- ast_verbose( "Asterisk PBX Core Initializing\n");
- ast_verbose( "Registering builtin applications:\n");
- }
- AST_LIST_HEAD_INIT_NOLOCK(&globals);
- ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
- /* Register builtin applications */
- for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
- if (option_verbose)
- ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
- if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
- ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
- return -1;
- }
- }
- return 0;
- }
- /*
- * Lock context list functions ...
- */
- int ast_lock_contexts()
- {
- return ast_mutex_lock(&conlock);
- }
- int ast_unlock_contexts()
- {
- return ast_mutex_unlock(&conlock);
- }
- /*
- * Lock context ...
- */
- int ast_lock_context(struct ast_context *con)
- {
- return ast_mutex_lock(&con->lock);
- }
- int ast_unlock_context(struct ast_context *con)
- {
- return ast_mutex_unlock(&con->lock);
- }
- /*
- * Name functions ...
- */
- const char *ast_get_context_name(struct ast_context *con)
- {
- return con ? con->name : NULL;
- }
- const char *ast_get_extension_name(struct ast_exten *exten)
- {
- return exten ? exten->exten : NULL;
- }
- const char *ast_get_extension_label(struct ast_exten *exten)
- {
- return exten ? exten->label : NULL;
- }
- const char *ast_get_include_name(struct ast_include *inc)
- {
- return inc ? inc->name : NULL;
- }
- const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
- {
- return ip ? ip->pattern : NULL;
- }
- int ast_get_extension_priority(struct ast_exten *exten)
- {
- return exten ? exten->priority : -1;
- }
- /*
- * Registrar info functions ...
- */
- const char *ast_get_context_registrar(struct ast_context *c)
- {
- return c ? c->registrar : NULL;
- }
- const char *ast_get_extension_registrar(struct ast_exten *e)
- {
- return e ? e->registrar : NULL;
- }
- const char *ast_get_include_registrar(struct ast_include *i)
- {
- return i ? i->registrar : NULL;
- }
- const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
- {
- return ip ? ip->registrar : NULL;
- }
- int ast_get_extension_matchcid(struct ast_exten *e)
- {
- return e ? e->matchcid : 0;
- }
- const char *ast_get_extension_cidmatch(struct ast_exten *e)
- {
- return e ? e->cidmatch : NULL;
- }
- const char *ast_get_extension_app(struct ast_exten *e)
- {
- return e ? e->app : NULL;
- }
- void *ast_get_extension_app_data(struct ast_exten *e)
- {
- return e ? e->data : NULL;
- }
- const char *ast_get_switch_name(struct ast_sw *sw)
- {
- return sw ? sw->name : NULL;
- }
- const char *ast_get_switch_data(struct ast_sw *sw)
- {
- return sw ? sw->data : NULL;
- }
- const char *ast_get_switch_registrar(struct ast_sw *sw)
- {
- return sw ? sw->registrar : NULL;
- }
- /*
- * Walking functions ...
- */
- struct ast_context *ast_walk_contexts(struct ast_context *con)
- {
- if (!con)
- return contexts;
- else
- return con->next;
- }
- struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
- struct ast_exten *exten)
- {
- if (!exten)
- return con ? con->root : NULL;
- else
- return exten->next;
- }
- struct ast_sw *ast_walk_context_switches(struct ast_context *con,
- struct ast_sw *sw)
- {
- if (!sw)
- return con ? con->alts : NULL;
- else
- return sw->next;
- }
- struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
- struct ast_exten *priority)
- {
- if (!priority)
- return exten;
- else
- return priority->peer;
- }
- struct ast_include *ast_walk_context_includes(struct ast_context *con,
- struct ast_include *inc)
- {
- if (!inc)
- return con ? con->includes : NULL;
- else
- return inc->next;
- }
- struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
- struct ast_ignorepat *ip)
- {
- if (!ip)
- return con ? con->ignorepats : NULL;
- else
- return ip->next;
- }
- int ast_context_verify_includes(struct ast_context *con)
- {
- struct ast_include *inc;
- int res = 0;
- for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
- if (!ast_context_find(inc->rname)) {
- res = -1;
- ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
- ast_get_context_name(con), inc->rname);
- }
- return res;
- }
- static int __ast_goto_if_exists(struct ast_channel *chan, char *context, char *exten, int priority, int async)
- {
- int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
- if (!chan)
- return -2;
- goto_func = (async) ? ast_async_goto : ast_explicit_goto;
- if (ast_exists_extension(chan, context ? context : chan->context,
- exten ? exten : chan->exten, priority,
- chan->cid.cid_num))
- return goto_func(chan, context ? context : chan->context,
- exten ? exten : chan->exten, priority);
- else
- return -3;
- }
- int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
- return __ast_goto_if_exists(chan, context, exten, priority, 0);
- }
- int ast_async_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
- return __ast_goto_if_exists(chan, context, exten, priority, 1);
- }
- int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
- {
- char *s;
- char *exten, *pri, *context;
- char *stringp=NULL;
- int ipri;
- int mode = 0;
- if (ast_strlen_zero(goto_string)) {
- ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
- return -1;
- }
- s = ast_strdupa(goto_string);
- stringp=s;
- context = strsep(&stringp, "|");
- exten = strsep(&stringp, "|");
- if (!exten) {
- /* Only a priority in this one */
- pri = context;
- exten = NULL;
- context = NULL;
- } else {
- pri = strsep(&stringp, "|");
- if (!pri) {
- /* Only an extension and priority in this one */
- pri = exten;
- exten = context;
- context = NULL;
- }
- }
- if (*pri == '+') {
- mode = 1;
- pri++;
- } else if (*pri == '-') {
- mode = -1;
- pri++;
- }
- if (sscanf(pri, "%d", &ipri) != 1) {
- if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten,
- pri, chan->cid.cid_num)) < 1) {
- ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
- return -1;
- } else
- mode = 0;
- }
- /* At this point we have a priority and maybe an extension and a context */
- if (exten && !strcasecmp(exten, "BYEXTENSION"))
- exten = NULL;
- if (mode)
- ipri = chan->priority + (ipri * mode);
- ast_explicit_goto(chan, context, exten, ipri);
- ast_cdr_update(chan);
- return 0;
- }
|