12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096 |
- /*
- * Asterisk -- A telephony toolkit for Linux.
- *
- * Core PBX routines.
- *
- * Copyright (C) 1999, Mark Spencer
- *
- * Mark Spencer <markster@digium.com>
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License
- */
- #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/channel_pvt.h>
- #include <asterisk/linkedlists.h>
- #include <asterisk/say.h>
- #include <asterisk/utils.h>
- #include <string.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <setjmp.h>
- #include <ctype.h>
- #include <errno.h>
- #include <time.h>
- #include <sys/time.h>
- #include "asterisk.h"
- /*
- * 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
- struct ast_context;
- /* ast_exten: An extension */
- struct ast_exten {
- char exten[AST_MAX_EXTENSION]; /* Extension name */
- int matchcid; /* Match caller id ? */
- char cidmatch[AST_MAX_EXTENSION]; /* Caller id to match for this extension */
- int priority; /* Priority */
- struct ast_context *parent; /* An extension */
- char app[AST_MAX_EXTENSION]; /* Application to execute */
- void *data; /* Data to use */
- void (*datad)(void *); /* Data destructor */
- struct ast_exten *peer; /* Next higher priority with our extension */
- char *registrar; /* Registrar */
- struct ast_exten *next; /* Extension with a greater ID */
- };
- /* ast_include: include= support in extensions.conf */
- struct ast_include {
- char name[AST_MAX_EXTENSION];
- char rname[AST_MAX_EXTENSION]; /* Context to include */
- char *registrar; /* Registrar */
- int hastime; /* If time construct exists */
- unsigned int monthmask; /* Mask for month */
- unsigned int daymask; /* Mask for date */
- unsigned int dowmask; /* Mask for day of week (mon-sun) */
- unsigned int minmask[24]; /* Mask for minute */
- struct ast_include *next; /* Link them together */
- };
- /* ast_sw: Switch statement in extensions.conf */
- struct ast_sw {
- char name[AST_MAX_EXTENSION];
- char *registrar; /* Registrar */
- char data[AST_MAX_EXTENSION]; /* Data load */
- struct ast_sw *next; /* Link them together */
- };
- struct ast_ignorepat {
- char pattern[AST_MAX_EXTENSION];
- char *registrar;
- struct ast_ignorepat *next;
- };
- /* ast_context: An extension context */
- struct ast_context {
- char name[AST_MAX_EXTENSION]; /* Name of the 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 */
- char *registrar; /* Registrar */
- struct ast_sw *alts; /* Alternative switches */
- };
- /* ast_app: An application */
- struct ast_app {
- char name[AST_MAX_APP]; /* Name of the application */
- int (*execute)(struct ast_channel *chan, void *data);
- char *synopsis; /* Synopsis text for 'show applications' */
- char *description; /* Description (help text) for 'show application <name>' */
- struct ast_app *next; /* Next app in list */
- };
- /* ast_state_cb: An extension state notify */
- struct ast_state_cb {
- int id;
- void *data;
- ast_state_cb_type callback;
- struct ast_state_cb *next;
- };
-
- struct ast_hint {
- struct ast_exten *exten;
- int laststate;
- struct ast_state_cb *callbacks;
- struct ast_hint *next;
- };
- static int pbx_builtin_prefix(struct ast_channel *, void *);
- static int pbx_builtin_suffix(struct ast_channel *, void *);
- static int pbx_builtin_stripmsd(struct ast_channel *, 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_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 *);
- int pbx_builtin_setvar(struct ast_channel *, void *);
- void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
- char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
- static struct varshead globals;
- 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): Set the absolute maximum amount of time permitted\n"
- "for a call. A setting of 0 disables the timeout. Always returns 0.\n"
- },
- { "Answer", pbx_builtin_answer,
- "Answer a channel if ringing",
- " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
- "Returns 0 unless it tries to answer the channel and fails.\n"
- },
- { "BackGround", pbx_builtin_background,
- "Play a file while awaiting extension",
- " Background(filename[|options[|langoverride]]): Plays a given file, while simultaneously\n"
- "waiting for the user to begin typing an extension. The timeouts do not\n"
- "count until the last BackGround application has ended.\n"
- "Options may also be included following a pipe symbol. The 'skip'\n"
- "option causes the playback of the message to be skipped if the channel\n"
- "is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
- "specified, the application will return immediately should the channel not be\n"
- "off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
- "be answered before the sound is played. Not all channels support playing\n"
- "messages while still hook. The 'langoverride' may be a language to use for\n"
- "playing the prompt which differs from the current language of the channel\n"
- "Returns -1 if the channel was hung up, or if the file does not exist. \n"
- "Returns 0 otherwise.\n"
- },
- { "Busy", pbx_builtin_busy,
- "Indicate busy condition and stop",
- " Busy([timeout]): Requests that the channel indicate busy condition and\n"
- "then waits for the user to hang up or the optional timeout to expire.\n"
- "Always returns -1."
- },
- { "Congestion", pbx_builtin_congestion,
- "Indicate congestion and stop",
- " Congestion([timeout]): Requests that the channel indicate congestion\n"
- "and then waits for the user to hang up or for the optional timeout to\n"
- "expire. Always returns -1."
- },
- { "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"
- "Always returns 0.\n"
- },
- { "Goto", pbx_builtin_goto,
- "Goto a particular priority, extension, or context",
- " Goto([[context|]extension|]priority): Set the priority to the specified\n"
- "value, optionally setting the extension and optionally the context as well.\n"
- "The extension BYEXTENSION is special in that it uses the current extension,\n"
- "thus permitting you to go to a different context, without specifying a\n"
- "specific extension. Always returns 0, even if the given context, extension,\n"
- "or priority is invalid.\n"
- },
- { "GotoIf", pbx_builtin_gotoif,
- "Conditional goto",
- " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
- "true, to label2 if condition is false. Either label1 or label2 may be\n"
- "omitted (in that case, we just don't take the particular branch) but not\n"
- "both. Look for the condition syntax in examples or documentation."
- },
- { "GotoIfTime", pbx_builtin_gotoiftime,
- "Conditional goto on current time",
- " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
- "If the current time matches the specified time, then branch to the specified\n"
- "extension. Each of the elements may be specified either as '*' (for always)\n"
- "or as a range. See the 'include' syntax for details."
- },
-
- { "Hangup", pbx_builtin_hangup,
- "Unconditional hangup",
- " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n"
- },
- { "NoOp", pbx_builtin_noop,
- "No operation",
- " NoOp(): No-operation; Does nothing."
- },
- { "Prefix", pbx_builtin_prefix,
- "Prepend leading digits",
- " Prefix(digits): Prepends the digit string specified by digits to the\n"
- "channel's associated extension. For example, the number 1212 when prefixed\n"
- "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
- "continue processing at the next priority for the *new* extension.\n"
- " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n"
- "executed will be priority 4 of 5551212. If you switch into an extension\n"
- "which has no first step, the PBX will treat it as though the user dialed an\n"
- "invalid extension.\n"
- },
- { "Progress", pbx_builtin_progress,
- "Indicate progress",
- " Progress(): Request that the channel indicate in-band progress is \n"
- "available to the user.\nAlways returns 0.\n"
- },
- { "ResetCDR", pbx_builtin_resetcdr,
- "Resets the Call Data Record",
- " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n"
- "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
- "record WILL be stored.\nAlways returns 0.\n"
- },
- { "ResponseTimeout", pbx_builtin_rtimeout,
- "Set maximum timeout awaiting response",
- " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
- "falling through a series of priorities for a channel in which the user may\n"
- "begin typing an extension. If the user does not type an extension in this\n"
- "amount of time, control will pass to the 't' extension if it exists, and\n"
- "if not the call would be terminated. The default timeout is 10 seconds.\n"
- "Always returns 0.\n"
- },
- { "Ringing", pbx_builtin_ringing,
- "Indicate ringing tone",
- " Ringing(): Request that the channel indicate ringing tone to the user.\n"
- "Always returns 0.\n"
- },
- { "SayNumber", pbx_builtin_saynumber,
- "Say Number",
- " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n"
- "the current language setting for the channel. (See app SetLanguage).\n"
- },
- { "SayDigits", pbx_builtin_saydigits,
- "Say Digits",
- " SayDigits(digits): Says the passed digits. SayDigits is using the\n"
- "current language setting for the channel. (See app setLanguage)\n"
- },
- { "SayAlpha", pbx_builtin_saycharacters,
- "Say Alpha",
- " SayAlpha(string): Spells the passed string\n"
- },
- { "SayPhonetic", pbx_builtin_sayphonetic,
- "Say Phonetic",
- " SayPhonetic(string): Spells the passed string with phonetic alphabet\n"
- },
- { "SetAccount", pbx_builtin_setaccount,
- "Sets account code",
- " SetAccount([account]): Set the channel account code for billing\n"
- "purposes. Always returns 0.\n"
- },
- { "SetAMAFlags", pbx_builtin_setamaflags,
- "Sets AMA Flags",
- " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n"
- "purposes. Always returns 0.\n"
- },
- { "SetGlobalVar", pbx_builtin_setglobalvar,
- "Set global variable to value",
- " SetGlobalVar(#n=value): Sets global variable n to value. Global\n"
- "variable are available across channels.\n"
- },
- { "SetLanguage", pbx_builtin_setlanguage,
- "Sets user language",
- " SetLanguage(language): Set the channel language to 'language'. This\n"
- "information is used for the syntax in generation of numbers, and to choose\n"
- "a natural language file when 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, and if not will play the normal 'demo-congrats'.\n"
- "Always returns 0.\n"
- },
- { "SetVar", pbx_builtin_setvar,
- "Set variable to value",
- " Setvar(#n=value): Sets channel specific variable n to value"
- },
- { "StripMSD", pbx_builtin_stripmsd,
- "Strip leading digits",
- " StripMSD(count): Strips the leading 'count' digits from the channel's\n"
- "associated extension. For example, the number 5551212 when stripped with a\n"
- "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
- "will continue processing at the next priority for the *new* extension.\n"
- " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
- "executed will be priority 4 of 1212. If you switch into an extension which\n"
- "has no first step, the PBX will treat it as though the user dialed an\n"
- "invalid extension.\n"
- },
- { "Suffix", pbx_builtin_suffix,
- "Append trailing digits",
- " Suffix(digits): Appends the digit string specified by digits to the\n"
- "channel's associated extension. For example, the number 555 when suffixed\n"
- "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
- "continue processing at the next priority for the *new* extension.\n"
- " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n"
- "executed will be priority 4 of 5551212. If you switch into an extension\n"
- "which has no first step, the PBX will treat it as though the user dialed an\n"
- "invalid extension.\n"
- },
- { "Wait", pbx_builtin_wait,
- "Waits for some time",
- " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
- "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
- },
- { "WaitExten", pbx_builtin_waitexten,
- "Waits for some time",
- " Wait(seconds): Waits for the user to enter a new extension for the \n"
- "specified number of seconds, then returns 0. Seconds can be passed with\n"
- "fractions of a second. (eg: 1.5 = 1.5 seconds)\n"
- },
- };
- AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */
- 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(switchlock); /* Lock for switches */
- struct ast_switch *switches = NULL;
- 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;
- int pbx_exec(struct ast_channel *c, /* Channel */
- struct ast_app *app, /* Application */
- void *data, /* Data for execution */
- int newstack) /* Force stack increment */
- {
- /* 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 res;
-
- char *saved_c_appl;
- char *saved_c_data;
-
- int stack = c->stack;
- int (*execute)(struct ast_channel *chan, void *data) = app->execute;
- if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
- /* Don't allow us to go over the max number of stacks we
- permit saving. */
- ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
- return -1;
- }
- if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
- /* Okay, here's where it gets weird. If newstack is non-zero,
- then we increase the stack increment, but setjmp is not going
- to return until longjmp is called -- when the application
- exec'd is finished running. */
- if (res == 1)
- res = 0;
- if (c->stack != stack + 1)
- ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
- else if (c->app[c->stack])
- ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
- c->stack = stack;
- return res;
- } else {
- 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;
- /* Any application that returns, we longjmp back, just in case. */
- if (c->stack != stack + 1)
- ast_log(LOG_WARNING, "Stack is not at expected value\n");
- longjmp(c->jmp[stack+1], res);
- /* Never returns */
- }
- }
- /* 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
- struct ast_app *pbx_findapp(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(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)
- {
- struct tm tm;
- time_t t;
- if (!i->hastime)
- return 1;
- 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;
- }
- 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 ' ':\
- case '-':\
- /* Ignore these characters */\
- data--;\
- break;\
- default:\
- if (*data != *pattern)\
- match =0;\
- }\
- data++;\
- pattern++;\
- }\
- }
- int ast_extension_match(char *pattern, 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;
- }
- static int extension_close(char *pattern, 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, return non-zero, otlherwise it's a miss */
- if (!needmore || *pattern) {
- return match;
- } else
- return 0;
- }
- struct ast_context *ast_context_find(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_SUCCESS 4
- static int matchcid(char *cidpattern, char *callerid)
- {
- char tmp[AST_MAX_EXTENSION];
- int failresult;
- char *name, *num;
-
- /* 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;
- /* Copy original Caller*ID */
- strncpy(tmp, callerid, sizeof(tmp)-1);
- /* Parse Number */
- if (ast_callerid_parse(tmp, &name, &num))
- return failresult;
- if (!num)
- return failresult;
- ast_shrink_phone_number(num);
- return ast_extension_match(cidpattern, num);
- }
- static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data)
- {
- 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;
- }
- tmp = contexts;
- while(tmp) {
- /* Match context */
- if (!strcmp(tmp->name, context)) {
- if (*status < STATUS_NO_EXTENSION)
- *status = STATUS_NO_EXTENSION;
- eroot = tmp->root;
- while(eroot) {
- /* Match extension */
- if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
- ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
- ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
- (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
- e = eroot;
- if (*status < STATUS_NO_PRIORITY)
- *status = STATUS_NO_PRIORITY;
- while(e) {
- /* Match priority */
- if (e->priority == priority) {
- *status = STATUS_SUCCESS;
- return e;
- }
- e = e->peer;
- }
- }
- eroot = eroot->next;
- }
- /* Check alternative switches */
- sw = tmp->alts;
- while(sw) {
- if ((asw = pbx_findswitch(sw->name))) {
- if (action == HELPER_CANMATCH)
- res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
- else if (action == HELPER_MATCHMORE)
- res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
- else
- res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
- if (res) {
- /* Got a match */
- *swo = asw;
- *data = sw->data;
- 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, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data)))
- return e;
- if (*swo)
- return NULL;
- }
- i = i->next;
- }
- }
- tmp = tmp->next;
- }
- return NULL;
- }
- /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
- functions in the dialplan
- ---*/
- static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
- {
- char *first,*second;
- char tmpvar[80] = "";
- time_t thistime;
- struct tm brokentime;
- int offset,offset2;
- struct ast_var_t *variables;
- char *name, *num; /* for callerid name + num variables */
- struct varshead *headp=NULL;
- if (c)
- headp=&c->varshead;
-
- *ret=NULL;
-
- if (!strncasecmp(var,"LEN(",4)) { /* ${LEN(<string>)} */
- char *endparen, *string = ast_strdupa(var + 4);
- int len = 0;
- if (!string) {
- ast_log(LOG_WARNING, "Out of memory!\n");
- return;
- }
- if ((endparen = strrchr(string,')'))) {
- *endparen = '\0';
- len = strlen(string);
- }
- sprintf(workspace, "%d", len);
- *ret = workspace;
- } else if ((first=strchr(var,':'))) { /* : Remove characters counting from end or start of string */
- strncpy(tmpvar, var, sizeof(tmpvar) - 1);
- first = strchr(tmpvar, ':');
- if (!first)
- first = tmpvar + strlen(tmpvar);
- *first='\0';
- pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
- if (!(*ret))
- return;
- offset=atoi(first+1); /* The number of characters,
- positive: remove # of chars from start
- negative: keep # of chars from end */
-
- if ((second=strchr(first+1,':'))) {
- *second='\0';
- offset2 = atoi(second+1); /* Number of chars to copy */
- } else if (offset >= 0) {
- offset2 = strlen(*ret)-offset; /* Rest of string */
- } else {
- offset2 = abs(offset);
- }
- if (abs(offset) > strlen(*ret)) { /* Offset beyond string */
- if (offset >= 0)
- offset=strlen(*ret);
- else
- offset=-strlen(*ret);
- }
- if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
- if (offset >= 0)
- offset2=strlen(*ret)-offset;
- else
- offset2=strlen(*ret)+offset;
- }
- if (offset >= 0)
- *ret += offset;
- else
- *ret += strlen(*ret)+offset;
- (*ret)[offset2] = '\0'; /* Cut at offset2 position */
- } else if (c && !strcmp(var, "CALLERIDNUM")) {
- if (c->callerid)
- strncpy(workspace, c->callerid, workspacelen - 1);
- ast_callerid_parse(workspace, &name, &num);
- if (num) {
- ast_shrink_phone_number(num);
- *ret = num;
- } else
- *ret = workspace;
- } else if (c && !strcmp(var, "CALLERIDNAME")) {
- if (c->callerid)
- strncpy(workspace, c->callerid, workspacelen - 1);
- ast_callerid_parse(workspace, &name, &num);
- if (name)
- *ret = name;
- else
- *ret = workspace;
- } else if (c && !strcmp(var, "CALLERID")) {
- if (c->callerid) {
- strncpy(workspace, c->callerid, workspacelen - 1);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (c && !strcmp(var, "DNID")) {
- if (c->dnid) {
- strncpy(workspace, c->dnid, workspacelen - 1);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (c && !strcmp(var, "HINT")) {
- if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
- *ret = NULL;
- else
- *ret = workspace;
- } else if (c && !strcmp(var, "EXTEN")) {
- strncpy(workspace, c->exten, workspacelen - 1);
- *ret = workspace;
- } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) &&
- /* XXX Remove me eventually */
- (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
- if (offset < 0)
- offset=0;
- if (offset > strlen(c->exten))
- offset = strlen(c->exten);
- strncpy(workspace, c->exten + offset, workspacelen - 1);
- *ret = workspace;
- ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
- } else if (c && !strcmp(var, "RDNIS")) {
- if (c->rdnis) {
- strncpy(workspace, c->rdnis, workspacelen - 1);
- *ret = workspace;
- } else
- *ret = NULL;
- } else if (c && !strcmp(var, "CONTEXT")) {
- strncpy(workspace, c->context, workspacelen - 1);
- *ret = workspace;
- } else if (c && !strcmp(var, "PRIORITY")) {
- snprintf(workspace, workspacelen, "%d", c->priority);
- *ret = workspace;
- } else if (c && !strcmp(var, "CALLINGPRES")) {
- snprintf(workspace, workspacelen, "%d", c->callingpres);
- *ret = workspace;
- } else if (c && !strcmp(var, "CHANNEL")) {
- strncpy(workspace, c->name, workspacelen - 1);
- *ret = workspace;
- } else if (c && !strcmp(var, "EPOCH")) {
- snprintf(workspace, workspacelen, "%u",(int)time(NULL));
- *ret = workspace;
- } else if (c && !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 (c && !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, "%i", c->hangupcause);
- *ret = workspace;
- } else if (c && !strcmp(var, "ACCOUNTCODE")) {
- strncpy(workspace, c->accountcode, workspacelen - 1);
- *ret = workspace;
- } else if (c && !strcmp(var, "LANGUAGE")) {
- strncpy(workspace, c->language, workspacelen - 1);
- *ret = workspace;
- } else {
- if (c) {
- 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) {
- strncpy(workspace, *ret, workspacelen - 1);
- *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) {
- strncpy(workspace, *ret, workspacelen - 1);
- *ret = workspace;
- }
- }
- }
- }
- if (!(*ret)) {
- int len=strlen(var);
- int len_env=strlen("ENV(");
- if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
- char cp3[80] = "";
- strncpy(cp3, var, sizeof(cp3) - 1);
- cp3[len-1]='\0';
- *ret=getenv(cp3+len_env);
- if (*ret) {
- strncpy(workspace, *ret, workspacelen - 1);
- *ret = workspace;
- }
- }
- }
- }
- }
- void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
- {
- char *cp4;
- const char *tmp, *whereweare;
- int length;
- char workspace[4096];
- char ltmp[4096], var[4096];
- char *nextvar, *nextexp;
- 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);
- /* Look for a variable */
- nextvar = strstr(whereweare, "${");
-
- /* Look for an expression */
- nextexp = strstr(whereweare, "$[");
-
- /* Pick the first one only */
- if (nextvar && nextexp) {
- if (nextvar < nextexp)
- nextexp = NULL;
- else
- nextvar = NULL;
- }
-
- /* If there is one, we only go that far */
- if (nextvar)
- pos = nextvar - whereweare;
- else if (nextexp)
- pos = nextexp - whereweare;
-
- /* 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 name */
- whereweare += ( len + 3);
-
- /* Store variable name (and truncate) */
- memset(var, 0, sizeof(var));
- strncpy(var, vars, sizeof(var) - 1);
- var[len] = '\0';
-
- /* Substitute if necessary */
- if (needsub) {
- memset(ltmp, 0, sizeof(ltmp));
- pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
- vars = ltmp;
- } else {
- vars = var;
- }
-
- /* Retrieve variable value */
- workspace[0] = '\0';
- pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
- if (cp4) {
- 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 variable name */
- whereweare += ( len + 3);
-
- /* Store variable name (and truncate) */
- memset(var, 0, sizeof(var));
- strncpy(var, vars, sizeof(var) - 1);
- var[len] = '\0';
-
- /* Substitute if necessary */
- if (needsub) {
- memset(ltmp, 0, sizeof(ltmp));
- pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
- vars = ltmp;
- } else {
- vars = var;
- }
- /* Evaluate expression */
- cp4 = ast_expr(vars);
-
- ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
-
- if (cp4) {
- length = strlen(cp4);
- if (length > count)
- length = count;
- memcpy(cp2, cp4, length);
- count -= length;
- cp2 += length;
- free(cp4);
- }
-
- } else
- break;
- }
- }
- 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 (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
- strncpy(passdata, e->data, datalen - 1);
- passdata[datalen-1] = '\0';
- return;
- }
-
- pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
- }
- static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action)
- {
- struct ast_exten *e;
- struct ast_app *app;
- struct ast_switch *sw;
- char *data;
- 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];
- 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, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
- if (e) {
- 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_SPAWN:
- newstack++;
- /* Fall through */
- case HELPER_EXEC:
- app = pbx_findapp(e->app);
- ast_mutex_unlock(&conlock);
- if (app) {
- if (c->context != context)
- strncpy(c->context, context, sizeof(c->context)-1);
- if (c->exten != exten)
- strncpy(c->exten, exten, sizeof(c->exten)-1);
- c->priority = priority;
- pbx_substitute_variables(passdata, sizeof(passdata), c, e);
- if (option_debug)
- ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
- 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_SPAWN:
- newstack++;
- /* Fall through */
- case HELPER_EXEC:
- ast_mutex_unlock(&conlock);
- if (sw->exec)
- res = sw->exec(c, 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;
- default:
- ast_log(LOG_DEBUG, "Shouldn't happen!\n");
- }
-
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
- return -1;
- else
- return 0;
- }
- }
- static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
- {
- struct ast_exten *e;
- struct ast_switch *sw;
- char *data;
- 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, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
- ast_mutex_unlock(&conlock);
- return e;
- }
- 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;
- strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
-
- cur = hint;
- 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:
- return AST_EXTENSION_INUSE;
- 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 (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;
- }
- int ast_extension_state(struct ast_channel *c, char *context, char *exten)
- {
- struct ast_exten *e;
- e = ast_hint_extension(c, context, exten);
- if (!e)
- return -1;
- return ast_extension_state2(e);
- }
- int ast_device_state_changed(const char *fmt, ...)
- {
- struct ast_hint *list;
- struct ast_state_cb *cblist;
- char hint[AST_MAX_EXTENSION] = "";
- char device[AST_MAX_EXTENSION];
- char *cur, *rest;
- int state;
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(device, sizeof(device), fmt, ap);
- va_end(ap);
- rest = strchr(device, '-');
- if (rest) {
- *rest = 0;
- }
- ast_mutex_lock(&hintlock);
- list = hints;
- while (list) {
- strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
- cur = hint;
- do {
- rest = strchr(cur, '&');
- if (rest) {
- *rest = 0;
- rest++;
- }
-
- if (!strcmp(cur, device)) {
- /* Found extension execute callbacks */
- state = ast_extension_state2(list->exten);
- if ((state != -1) && (state != list->laststate)) {
- /* For general callbacks */
- cblist = statecbs;
- while (cblist) {
- cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
- cblist = cblist->next;
- }
- /* For extension callbacks */
- cblist = list->callbacks;
- while (cblist) {
- cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
- cblist = cblist->next;
- }
-
- list->laststate = state;
- }
- break;
- }
- cur = rest;
- } while (cur);
- list = list->next;
- }
- ast_mutex_unlock(&hintlock);
- return 1;
- }
-
- int ast_extension_state_add(char *context, char *exten,
- ast_state_cb_type callback, void *data)
- {
- struct ast_hint *list;
- struct ast_state_cb *cblist;
- struct ast_exten *e;
- /* 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 */
- e = ast_hint_extension(NULL, context, exten);
- if (!e) {
- return -1;
- }
-
- ast_mutex_lock(&hintlock);
- list = hints;
-
- while (list) {
- if (list->exten == e)
- break;
- list = list->next;
- }
- if (!list) {
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- /* Now inserts 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 = stateid++;
- cblist->callback = callback;
- cblist->data = data;
- cblist->next = list->callbacks;
- list->callbacks = cblist;
- ast_mutex_unlock(&hintlock);
- return cblist->id;
- }
- 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 */
- 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;
- }
- 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);
- return -1;
- }
- list = list->next;
- }
- list = malloc(sizeof(struct ast_hint));
- if (!list) {
- ast_mutex_unlock(&hintlock);
- return -1;
- }
- /* Initialize and insert new item */
- 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;
- }
- 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;
- }
- 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, -1, 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;
- }
- int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, char *context, char *exten)
- {
- struct ast_exten *e;
- e = ast_hint_extension(c, context, exten);
- if (e) {
- strncpy(hint, ast_get_extension_app(e), hintsize - 1);
- return -1;
- }
- return 0;
- }
- int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
- {
- return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
- }
- int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
- {
- return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
- }
- int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
- {
- return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
- }
- int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
- {
- return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
- }
- int ast_pbx_run(struct ast_channel *c)
- {
- int firstpass = 1;
- int digit;
- char exten[256];
- int pos;
- int waittime;
- int res=0;
- /* 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) {
- ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
- } else {
- 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;
- /* Start by trying whatever the channel is set to */
- if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
- /* JK02: If not successfull 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);
- strncpy(c->exten, "s", sizeof(c->exten)-1);
- if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
- /* 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);
- strncpy(c->context, "default", sizeof(c->context)-1);
- }
- c->priority = 1;
- }
- if (c->cdr)
- ast_cdr_start(c->cdr);
- for(;;) {
- pos = 0;
- digit = 0;
- while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
- memset(exten, 0, sizeof(exten));
- if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
- /* 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->callerid))) {
- strncpy(c->exten,"T",sizeof(c->exten) - 1);
- /* 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->callerid)) {
- /* It's not a valid extension anymore */
- if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
- 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);
- strncpy(c->exten, "i", sizeof(c->exten)-1);
- 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 */
- if (digit)
- waittime = c->pbx->dtimeout;
- else
- waittime = c->pbx->rtimeout;
- while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
- /* 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->callerid)) {
- /* Prepare the next cycle */
- strncpy(c->exten, exten, sizeof(c->exten)-1);
- 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->callerid)) {
- 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);
- strncpy(c->exten, "i", sizeof(c->exten)-1);
- 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->callerid)) {
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
- strncpy(c->exten, "t", sizeof(c->exten)-1);
- 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);
- }
- }
- }
- 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->callerid)) {
- c->exten[0] = 'h';
- c->exten[1] = '\0';
- c->priority = 1;
- while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
- if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
- /* 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++;
- }
- }
- pbx_destroy(c->pbx);
- c->pbx = NULL;
- if (res != AST_PBX_KEEPALIVE)
- ast_hangup(c);
- return 0;
- }
- 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. The setjmp stuff is fairly
- confusing, but necessary to get smooth transitions between
- the execution of different applications (without the use of
- additional threads) */
- struct ast_channel *c = data;
- ast_pbx_run(c);
- pthread_exit(NULL);
- return NULL;
- }
- int 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 -1;
- }
-
- /* 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 -1;
- }
- return 0;
- }
- /*
- * 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(char *context, char *include, 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, char *include, 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;
- }
- /*
- * 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(char *context, char *sw, char *data, 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;
- }
- /*
- * 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 switch, unlock context and
- * return.
- */
- int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, 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;
- }
- /*
- * 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(char *context, char *extension, int priority, 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;
- }
- /*
- * 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.
- *
- * 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.
- */
- int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, 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;
- }
- int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
- {
- struct ast_app *tmp, *prev, *cur;
- char tmps[80];
- 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(sizeof(struct ast_app));
- if (tmp) {
- memset(tmp, 0, sizeof(struct ast_app));
- strncpy(tmp->name, app, sizeof(tmp->name)-1);
- 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_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";
- /*
- * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
- *
- */
- /*
- * '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;
- }
- 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;
- /* 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;
- if (like) {
- if (ast_strcasestr(a->name, argv[3])) {
- printapp = 1;
- }
- } else if (describing) {
- if (a->description) {
- /* Match all words on command line */
- int i;
- printapp = 1;
- for (i=3;i<argc;i++) {
- if (! ast_strcasestr(a->description, argv[i])) {
- printapp = 0;
- }
- }
- }
- } else {
- printapp = 1;
- }
- if (printapp) {
- ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
- }
- }
- /* ... 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;
- }
- static int handle_show_dialplan(int fd, int argc, char *argv[])
- {
- struct ast_context *c;
- char *exten = NULL, *context = NULL;
- int context_existence = 0, extension_existence = 0;
- if (argc != 3 && argc != 2) return -1;
- /* we obtain [exten@]context? if yes, split them ... */
- if (argc == 3) {
- char *splitter = argv[2];
- /* is there a '@' character? */
- if (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;
- } else
- {
- /* no '@' char, only context given */
- context = argv[2];
- if (ast_strlen_zero(context)) context = NULL;
- }
- }
- /* try to lock contexts */
- if (ast_lock_contexts()) {
- ast_log(LOG_WARNING, "Failed to lock contexts list\n");
- return RESULT_FAILURE;
- }
- /* walk all contexts ... */
- c = ast_walk_contexts(NULL);
- while (c) {
- /* show this context? */
- if (!context ||
- !strcmp(ast_get_context_name(c), context)) {
- 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) {
- 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 ... */
- e = ast_walk_context_extensions(c, NULL);
- while (e) {
- struct ast_exten *p;
- int prio;
- /* looking for extension? is this our extension? */
- if (exten &&
- strcmp(ast_get_extension_name(e), exten))
- {
- /* we are looking for extension and it's not our
- * extension, so skip to next extension */
- e = ast_walk_context_extensions(c, e);
- continue;
- }
- extension_existence = 1;
- /* may we print context info? */
- if (!context_info_printed) {
- ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
- ast_get_context_name(c),
- ast_get_context_registrar(c));
- context_info_printed = 1;
- }
- /* 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));
- /* walk next extension peers */
- p = ast_walk_extension_priorities(e, e);
- while (p) {
- bzero((void *)buf2, sizeof(buf2));
- 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",
- "", buf2,
- ast_get_extension_registrar(p));
- p = ast_walk_extension_priorities(e, p);
- }
- e = ast_walk_context_extensions(c, e);
- }
- /* include & ignorepat we all printing if we are not
- * looking for exact extension
- */
- if (!exten) {
- if (ast_walk_context_extensions(c, NULL))
- ast_cli(fd, "\n");
- /* walk included and write info ... */
- i = ast_walk_context_includes(c, NULL);
- while (i) {
- bzero(buf, sizeof(buf));
- snprintf(buf, sizeof(buf), "'%s'",
- ast_get_include_name(i));
- ast_cli(fd, " Include => %-45s [%s]\n",
- buf, ast_get_include_registrar(i));
- i = ast_walk_context_includes(c, i);
- }
- /* walk ignore patterns and write info ... */
- ip = ast_walk_context_ignorepats(c, NULL);
- while (ip) {
- bzero(buf, sizeof(buf));
- snprintf(buf, sizeof(buf), "'%s'",
- ast_get_ignorepat_name(ip));
- ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
- buf, ast_get_ignorepat_registrar(ip));
- ip = ast_walk_context_ignorepats(c, ip);
- }
- sw = ast_walk_context_switches(c, NULL);
- while(sw) {
- bzero(buf, sizeof(buf));
- 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));
- sw = ast_walk_context_switches(c, sw);
- }
- }
-
- ast_unlock_context(c);
- /* if we print something in context, make an empty line */
- if (context_info_printed) ast_cli(fd, "\n");
- }
- }
- c = ast_walk_contexts(c);
- }
- ast_unlock_contexts();
- /* check for input failure and throw some error messages */
- if (context && !context_existence) {
- ast_cli(fd, "There is no existence of '%s' context\n",
- context);
- return RESULT_FAILURE;
- }
- if (exten && !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;
- }
- /* everything ok */
- return RESULT_SUCCESS;
- }
- /*
- * CLI entries for upper commands ...
- */
- static struct ast_cli_entry show_applications_cli =
- { { "show", "applications", NULL },
- handle_show_applications, "Shows registered applications",
- show_applications_help, complete_show_applications };
- static struct ast_cli_entry show_application_cli =
- { { "show", "application", NULL },
- handle_show_application, "Describe a specific application",
- show_application_help, complete_show_application };
- static struct ast_cli_entry show_dialplan_cli =
- { { "show", "dialplan", NULL },
- handle_show_dialplan, "Show dialplan",
- show_dialplan_help, complete_show_dialplan_context };
- static struct ast_cli_entry show_switches_cli =
- { { "show", "switches", NULL },
- handle_show_switches, "Show alternative switches",
- show_switches_help, NULL };
- int ast_unregister_application(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, char *name, char *registrar)
- {
- struct ast_context *tmp, **local_contexts;
- 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(sizeof(struct ast_context));
- if (tmp) {
- memset(tmp, 0, sizeof(struct ast_context));
- ast_mutex_init(&tmp->lock);
- strncpy(tmp->name, name, sizeof(tmp->name)-1);
- 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, char *registrar);
- void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
- struct ast_context *tmp, *lasttmp = NULL;
- 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);
- return;
- }
- /*
- * errno values
- * EBUSY - can't lock
- * ENOENT - no existence of context
- */
- int ast_context_add_include(char *context, char *include, 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_include *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",
- };
- 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;
- }
- static void build_timing(struct ast_include *i, char *info)
- {
- char *c;
- /* Check for empty just in case */
- if (ast_strlen_zero(info))
- return;
- i->hastime = 1;
- /* 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;
- FIND_NEXT;
- /* Now check for day of week */
- i->dowmask = get_dow(info);
- info = c;
- if (!info)
- return;
- FIND_NEXT;
- /* Now check for the day of the month */
- i->daymask = get_day(info);
- info = c;
- if (!info)
- return;
- FIND_NEXT;
- /* And finally go for the month */
- i->monthmask = get_month(info);
- }
- /*
- * 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, char *value,
- char *registrar)
- {
- struct ast_include *new_include;
- char *c;
- struct ast_include *i, *il = NULL; /* include, include_last */
- /* allocate new include structure ... */
- if (!(new_include = malloc(sizeof(struct ast_include)))) {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
-
- /* ... fill in this structure ... */
- memset(new_include, 0, sizeof(struct ast_include));
- strncpy(new_include->name, value, sizeof(new_include->name)-1);
- strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
- c = new_include->rname;
- /* Strip off timing info */
- while(*c && (*c != '|')) c++;
- /* Process if it's there */
- if (*c) {
- build_timing(new_include, 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(char *context, char *sw, char *data, 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, 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, char *value,
- char *data, char *registrar)
- {
- struct ast_sw *new_sw;
- struct ast_sw *i, *il = NULL; /* sw, sw_last */
- /* allocate new sw structure ... */
- if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
-
- /* ... fill in this structure ... */
- memset(new_sw, 0, sizeof(struct ast_sw));
- strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
- if (data)
- strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
- else
- strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
- new_sw->next = NULL;
- 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(char *context, char *ignorepat, 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, char *ignorepat, 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(char *con, char *value, 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, char *value, char *registrar)
- {
- struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
- ignorepat = malloc(sizeof(struct ast_ignorepat));
- if (!ignorepat) {
- ast_log(LOG_ERROR, "Out of memory\n");
- errno = ENOMEM;
- return -1;
- }
- memset(ignorepat, 0, sizeof(struct ast_ignorepat));
- strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
- 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(char *context, 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(char *context, int replace, char *extension, int priority, char *callerid,
- char *application, void *data, void (*datad)(void *), 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, callerid,
- application, data, datad, registrar);
- ast_unlock_contexts();
- return ret;
- }
- c = ast_walk_contexts(c);
- }
- ast_unlock_contexts();
- errno = ENOENT;
- return -1;
- }
- int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority)
- {
- int res = 0;
- ast_mutex_lock(&chan->lock);
- if (chan->pbx) {
- /* This channel is currently in the PBX */
- if (context && !ast_strlen_zero(context))
- strncpy(chan->context, context, sizeof(chan->context) - 1);
- if (exten && !ast_strlen_zero(exten))
- strncpy(chan->exten, exten, sizeof(chan->context) - 1);
- if (priority)
- chan->priority = priority - 1;
- 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 */
- if (context && !ast_strlen_zero(context))
- strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
- else
- strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
- if (exten && !ast_strlen_zero(exten))
- strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
- else
- strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
- if (priority)
- tmpchan->priority = priority;
- else
- tmpchan->priority = chan->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(char *channame, char *context, char *exten, int priority)
- {
- struct ast_channel *chan;
- int res = -1;
- chan = ast_channel_walk_locked(NULL);
- while(chan) {
- if (!strcasecmp(channame, chan->name))
- break;
- ast_mutex_unlock(&chan->lock);
- chan = ast_channel_walk_locked(chan);
- }
-
- if (chan) {
- res = ast_async_goto(chan, context, exten, priority);
- ast_mutex_unlock(&chan->lock);
- }
- return res;
- }
- static void ext_strncpy(char *dst, 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';
- }
- /*
- * 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, char *extension, int priority, char *callerid,
- char *application, void *data, void (*datad)(void *),
- 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;
- /* Be optimistic: Build the extension structure first */
- tmp = malloc(sizeof(struct ast_exten));
- if (tmp) {
- memset(tmp, 0, sizeof(struct ast_exten));
- ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
- tmp->priority = priority;
- if (callerid) {
- ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
- tmp->matchcid = 1;
- } else {
- tmp->cidmatch[0] = '\0';
- tmp->matchcid = 0;
- }
- strncpy(tmp->app, application, sizeof(tmp->app)-1);
- 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_EXTENSION];
- 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))
- strncpy(chan->context, as->context, sizeof(chan->context) - 1);
- if (!ast_strlen_zero(as->exten))
- strncpy(chan->exten, as->exten, sizeof(chan->exten) - 1);
- 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;
- }
- int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable, char *account)
- {
- struct ast_channel *chan;
- struct async_stat *as;
- int res = -1;
- char *var, *tmp;
- struct outgoing_helper oh;
- pthread_attr_t attr;
-
- if (sync) {
- LOAD_OH(oh);
- chan = __ast_request_and_dial(type, format, data, timeout, reason, callerid, &oh);
- if (chan) {
- pbx_builtin_setaccount(chan, account);
- 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 (ast_pbx_run(chan)) {
- ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
- ast_hangup(chan);
- res = -1;
- }
- } else {
- if (ast_pbx_start(chan)) {
- ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
- ast_hangup(chan);
- res = -1;
- }
- }
- } else {
- if (option_verbose > 3)
- ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
- ast_hangup(chan);
- }
- }
- if(res < 0) { /* the call failed for some reason */
- /* 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) {
- strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1);
- if (context && !ast_strlen_zero(context))
- strncpy(chan->context, context, sizeof(chan->context) - 1);
- strncpy(chan->exten, "failed", sizeof(chan->exten) - 1);
- chan->priority = 1;
- if (variable) {
- tmp = ast_strdupa(variable);
- for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) {
- pbx_builtin_setvar( chan, var );
- }
- }
- 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)
- return -1;
- memset(as, 0, sizeof(struct async_stat));
- chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
- if (!chan) {
- free(as);
- return -1;
- }
- pbx_builtin_setaccount(chan, account);
- as->chan = chan;
- strncpy(as->context, context, sizeof(as->context) - 1);
- strncpy(as->exten, exten, sizeof(as->exten) - 1);
- as->priority = priority;
- as->timeout = timeout;
- if (variable) {
- tmp = ast_strdupa(variable);
- for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp))
- pbx_builtin_setvar( chan, var );
- }
- 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);
- ast_hangup(chan);
- return -1;
- }
- res = 0;
- }
- 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(char *type, int format, void *data, int timeout, char *app, char *appdata, int *reason, int sync, char *callerid, char *variable, char *account)
- {
- struct ast_channel *chan;
- struct async_stat *as;
- struct app_tmp *tmp;
- char *var, *vartmp;
- int res = -1;
- pthread_attr_t attr;
-
- if (!app || ast_strlen_zero(app))
- return -1;
- if (sync) {
- chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
- if (chan) {
- pbx_builtin_setaccount(chan, account);
- if (variable) {
- vartmp = ast_strdupa(variable);
- for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) {
- pbx_builtin_setvar( chan, var );
- }
- }
- 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));
- strncpy(tmp->app, app, sizeof(tmp->app) - 1);
- strncpy(tmp->data, appdata, sizeof(tmp->data) - 1);
- tmp->chan = chan;
- if (sync > 1) {
- ast_pbx_run_app(tmp);
- } else {
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- 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);
- ast_hangup(chan);
- res = -1;
- }
- }
- } 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);
- ast_hangup(chan);
- }
- }
- } else {
- as = malloc(sizeof(struct async_stat));
- if (!as)
- return -1;
- memset(as, 0, sizeof(struct async_stat));
- chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
- if (!chan) {
- free(as);
- return -1;
- }
- pbx_builtin_setaccount(chan, account);
- as->chan = chan;
- strncpy(as->app, app, sizeof(as->app) - 1);
- if (appdata)
- strncpy(as->appdata, appdata, sizeof(as->appdata) - 1);
- as->timeout = timeout;
- if (variable) {
- vartmp = ast_strdupa(variable);
- for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp))
- pbx_builtin_setvar( chan, var );
- }
- /* 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(&as->p, &attr, async_wait, as)) {
- ast_log(LOG_WARNING, "Failed to start async wait\n");
- free(as);
- ast_hangup(chan);
- return -1;
- }
- res = 0;
- }
- 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, 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, 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 (!data || !strlen(data) || (sscanf(data, "%i", &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);
- }
- static int pbx_builtin_progress(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_PROGRESS);
- return 0;
- }
- static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_RINGING);
- return 0;
- }
- static int pbx_builtin_busy(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_BUSY);
- wait_for_hangup(chan, data);
- return -1;
- }
- static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
- {
- ast_indicate(chan, AST_CONTROL_CONGESTION);
- wait_for_hangup(chan, data);
- return -1;
- }
- static int pbx_builtin_answer(struct ast_channel *chan, void *data)
- {
- return ast_answer(chan);
- }
- static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
- {
- /* Copy the language as specified */
- if (data)
- strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
- return 0;
- }
- static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
- {
- int flags = 0;
- /* Reset the CDR as specified */
- if(data) {
- if(strchr((char *)data, 'w'))
- flags |= AST_CDR_FLAG_POSTED;
- if(strchr((char *)data, 'a'))
- flags |= AST_CDR_FLAG_LOCKED;
- }
- ast_cdr_reset(chan->cdr, flags);
- return 0;
- }
- 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;
- }
- 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;
- }
- static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
- {
- /* Just return non-zero and it will hang up */
- return -1;
- }
- static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
- {
- char newexten[AST_MAX_EXTENSION] = "";
- if (!data || !atoi(data)) {
- ast_log(LOG_DEBUG, "Ignoring, since number of digits to strip is 0\n");
- return 0;
- }
- if (strlen(chan->exten) > atoi(data)) {
- strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1);
- }
- strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
- return 0;
- }
- static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
- {
- char newexten[AST_MAX_EXTENSION] = "";
- if (!data || ast_strlen_zero(data)) {
- ast_log(LOG_DEBUG, "Ignoring, since there is no prefix to add\n");
- return 0;
- }
- snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
- strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
- return 0;
- }
- static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
- {
- char newexten[AST_MAX_EXTENSION] = "";
- if (!data || ast_strlen_zero(data)) {
- ast_log(LOG_DEBUG, "Ignoring, since there is no suffix to add\n");
- return 0;
- }
- snprintf(newexten, sizeof(newexten), "%s%s", chan->exten, (char *)data);
- strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
- if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Appended suffix, new extension is %s\n", chan->exten);
- return 0;
- }
- static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
- {
- int res=0;
- char *s, *ts;
- struct ast_include include;
- if (!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;
- }
- s = strdup((char *) data);
- ts = s;
- /* Separate the Goto path */
- strsep(&ts,"?");
- /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
- build_timing(&include, s);
- if (include_valid(&include))
- res = pbx_builtin_goto(chan, (void *)ts);
- free(s);
- return res;
- }
- 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;
- }
- static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
- {
- int ms;
- /* Wait for "n" seconds */
- if (data && atof((char *)data)) {
- ms = atof((char *)data) * 1000;
- return ast_waitfordigit(chan, ms);
- }
- return 0;
- }
- static int pbx_builtin_background(struct ast_channel *chan, void *data)
- {
- int res = 0;
- int option_skip = 0;
- int option_noanswer = 0;
- char filename[256] = "";
- char* stringp;
- char* options;
- char *lang = NULL;
- if (!data || ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Background requires an argument(filename)\n");
- return -1;
- }
- strncpy(filename, (char*)data, sizeof(filename) - 1);
- stringp = filename;
- strsep(&stringp, "|");
- options = strsep(&stringp, "|");
- if (options)
- lang = strsep(&stringp, "|");
- if (!lang)
- lang = chan->language;
- if (options && !strcasecmp(options, "skip"))
- option_skip = 1;
- if (options && !strcasecmp(options, "noanswer"))
- option_noanswer = 1;
- /* Answer if need be */
- if (chan->_state != AST_STATE_UP) {
- if (option_skip) {
- return 0;
- } else if (!option_noanswer) {
- res = ast_answer(chan);
- }
- }
- if (!res) {
- /* Stop anything playing */
- ast_stopstream(chan);
- /* Stream a file */
- res = ast_streamfile(chan, filename, lang);
- if (!res) {
- 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;
- }
- }
- return res;
- }
- static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
- {
- int x = atoi((char *) data);
- /* 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;
- }
- static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
- {
- /* 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;
- }
- static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
- {
- /* 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;
- }
- static int pbx_builtin_goto(struct ast_channel *chan, void *data)
- {
- char *s;
- char *exten, *pri, *context;
- char *stringp=NULL;
- if (!data || ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
- return -1;
- }
- s = ast_strdupa((void *) data);
- 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 (atoi(pri) < 0) {
- ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
- return -1;
- }
- /* At this point we have a priority and maybe an extension and a context */
- chan->priority = atoi(pri) - 1;
- if (exten && strcasecmp(exten, "BYEXTENSION"))
- strncpy(chan->exten, exten, sizeof(chan->exten)-1);
- if (context)
- strncpy(chan->context, context, sizeof(chan->context)-1);
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
- ast_cdr_update(chan);
- return 0;
- }
- char *pbx_builtin_getvar_helper(struct ast_channel *chan, 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_setvar_helper(struct ast_channel *chan, char *name, char *value)
- {
- struct ast_var_t *newvariable;
- struct varshead *headp;
- if (chan)
- headp=&chan->varshead;
- else
- headp=&globals;
-
- AST_LIST_TRAVERSE (headp,newvariable,entries) {
- if (strcasecmp(ast_var_name(newvariable),name)==0) {
- /* there is already such a variable, delete it */
- AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries);
- ast_var_delete(newvariable);
- break;
- }
- }
-
- if (value) {
- if ((option_verbose > 1) && (headp == &globals))
- ast_verbose(VERBOSE_PREFIX_3 "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(struct ast_channel *chan, void *data)
- {
- char *name;
- char *value;
- char *stringp=NULL;
-
- if (!data || 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(chan,name,value);
-
- return(0);
- }
- static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
- {
- char *name;
- char *value;
- char *stringp=NULL;
-
- if (!data || 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_FIRST(&globals);
- AST_LIST_REMOVE_HEAD(&globals, entries);
- ast_var_delete(vardata);
- }
- }
- static int pbx_checkcondition(char *condition)
- {
- return condition ? atoi(condition) : 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 (!data || 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 ((branch==NULL) || 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 (!data || ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
- return -1;
- }
- strncpy(tmp, (char *)data, sizeof(tmp)-1);
- 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(&globals);
- ast_cli_register(&show_applications_cli);
- ast_cli_register(&show_application_cli);
- ast_cli_register(&show_dialplan_cli);
- ast_cli_register(&show_switches_cli);
- /* 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 ...
- */
- char *ast_get_context_name(struct ast_context *con)
- {
- return con ? con->name : NULL;
- }
- char *ast_get_extension_name(struct ast_exten *exten)
- {
- return exten ? exten->exten : NULL;
- }
- char *ast_get_include_name(struct ast_include *inc)
- {
- return inc ? inc->name : NULL;
- }
- 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 ...
- */
- char *ast_get_context_registrar(struct ast_context *c)
- {
- return c ? c->registrar : NULL;
- }
- char *ast_get_extension_registrar(struct ast_exten *e)
- {
- return e ? e->registrar : NULL;
- }
- char *ast_get_include_registrar(struct ast_include *i)
- {
- return i ? i->registrar : NULL;
- }
- 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;
- }
- char *ast_get_extension_cidmatch(struct ast_exten *e)
- {
- return e ? e->cidmatch : NULL;
- }
- 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;
- }
- char *ast_get_switch_name(struct ast_sw *sw)
- {
- return sw ? sw->name : NULL;
- }
- char *ast_get_switch_data(struct ast_sw *sw)
- {
- return sw ? sw->data : NULL;
- }
- 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;
- }
|