123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117 |
- /*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (C) 2004 - 2006, Christian Richter
- *
- * Christian Richter <crich@beronet.com>
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE file
- * at the top of the source tree.
- *
- */
- /*!
- * \file
- *
- * \brief the chan_misdn channel driver for Asterisk
- *
- * \author Christian Richter <crich@beronet.com>
- *
- * \extref MISDN http://www.misdn.org/
- *
- * \ingroup channel_drivers
- */
- /*** MODULEINFO
- <depend>isdnnet</depend>
- <depend>misdn</depend>
- <depend>suppserv</depend>
- ***/
- #include "asterisk.h"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
- #include <pthread.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <arpa/inet.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <signal.h>
- #include <sys/file.h>
- #include <semaphore.h>
- #include "asterisk/channel.h"
- #include "asterisk/config.h"
- #include "asterisk/module.h"
- #include "asterisk/pbx.h"
- #include "asterisk/io.h"
- #include "asterisk/frame.h"
- #include "asterisk/translate.h"
- #include "asterisk/cli.h"
- #include "asterisk/musiconhold.h"
- #include "asterisk/dsp.h"
- #include "asterisk/file.h"
- #include "asterisk/callerid.h"
- #include "asterisk/indications.h"
- #include "asterisk/app.h"
- #include "asterisk/features.h"
- #include "asterisk/term.h"
- #include "asterisk/sched.h"
- #include "asterisk/stringfields.h"
- #include "asterisk/abstract_jb.h"
- #include "asterisk/causes.h"
- #include "chan_misdn_config.h"
- #include "isdn_lib.h"
- char global_tracefile[BUFFERSIZE + 1];
- static int g_config_initialized = 0;
- struct misdn_jb{
- int size;
- int upper_threshold;
- char *samples, *ok;
- int wp,rp;
- int state_empty;
- int state_full;
- int state_buffer;
- int bytes_wrote;
- ast_mutex_t mutexjb;
- };
- /*! \brief allocates the jb-structure and initialize the elements */
- struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
- /*! \brief frees the data and destroys the given jitterbuffer struct */
- void misdn_jb_destroy(struct misdn_jb *jb);
- /*! \brief fills the jitterbuffer with len data returns < 0 if there was an
- error (buffer overrun). */
- int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
- /*! \brief gets len bytes out of the jitterbuffer if available, else only the
- available data is returned and the return value indicates the number
- of data. */
- int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
- static char *complete_ch(struct ast_cli_args *a);
- static char *complete_debug_port(struct ast_cli_args *a);
- static char *complete_show_config(struct ast_cli_args *a);
- /* BEGIN: chan_misdn.h */
- ast_mutex_t release_lock;
- enum misdn_chan_state {
- MISDN_NOTHING=0, /*!< at beginning */
- MISDN_WAITING4DIGS, /*!< when waiting for infos */
- MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */
- MISDN_INCOMING_SETUP, /*!< for incoming setups*/
- MISDN_DIALING, /*!< when pbx_start */
- MISDN_PROGRESS, /*!< we got a progress */
- MISDN_PROCEEDING, /*!< we got a progress */
- MISDN_CALLING, /*!< when misdn_call is called */
- MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
- MISDN_ALERTING, /*!< when Alerting */
- MISDN_BUSY, /*!< when BUSY */
- MISDN_CONNECTED, /*!< when connected */
- MISDN_DISCONNECTED, /*!< when connected */
- MISDN_CLEANING, /*!< when hangup from * but we were connected before */
- };
- #define ORG_AST 1
- #define ORG_MISDN 2
- enum misdn_hold_state {
- MISDN_HOLD_IDLE, /*!< HOLD not active */
- MISDN_HOLD_ACTIVE, /*!< Call is held */
- MISDN_HOLD_TRANSFER, /*!< Held call is being transferred */
- MISDN_HOLD_DISCONNECT, /*!< Held call is being disconnected */
- };
- struct hold_info {
- /*!
- * \brief Call HOLD state.
- */
- enum misdn_hold_state state;
- /*!
- * \brief Logical port the channel call record is HELD on
- * because the B channel is no longer associated.
- */
- int port;
- /*!
- * \brief Original B channel number the HELD call was using.
- * \note Used only for debug display messages.
- */
- int channel;
- };
- /*!
- * \brief Channel call record structure
- */
- struct chan_list {
- /*!
- * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
- */
- char allowed_bearers[BUFFERSIZE + 1];
-
- /*!
- * \brief State of the channel
- */
- enum misdn_chan_state state;
- /*!
- * \brief TRUE if a hangup needs to be queued
- * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
- */
- int need_queue_hangup;
- /*!
- * \brief TRUE if a channel can be hung up by calling asterisk directly when done.
- */
- int need_hangup;
- /*!
- * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
- */
- int need_busy;
-
- /*!
- * \brief Who originally created this channel. ORG_AST or ORG_MISDN
- */
- int originator;
- /*!
- * \brief TRUE of we are not to respond immediately to a SETUP message. Check the dialplan first.
- * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
- */
- int noautorespond_on_setup;
-
- int norxtone; /* Boolean assigned values but the value is not used. */
- /*!
- * \brief TRUE if we are not to generate tones (Playtones)
- */
- int notxtone;
- /*!
- * \brief TRUE if echo canceller is enabled. Value is toggled.
- */
- int toggle_ec;
-
- /*!
- * \brief TRUE if you want to send Tone Indications to an incoming
- * ISDN channel on a TE Port.
- * \note The "incoming_early_audio" boolean read in from /etc/asterisk/misdn.conf
- */
- int incoming_early_audio;
- /*!
- * \brief TRUE if DTMF digits are to be passed inband only.
- * \note It is settable by the misdn_set_opt() application.
- */
- int ignore_dtmf;
- /*!
- * \brief Pipe file descriptor handles array.
- * Read from pipe[0], write to pipe[1]
- */
- int pipe[2];
- /*!
- * \brief Read buffer for inbound audio from pipe[0]
- */
- char ast_rd_buf[4096];
- /*!
- * \brief Inbound audio frame returned by misdn_read().
- */
- struct ast_frame frame;
- /*!
- * \brief Fax detection option. (0:no 1:yes 2:yes+nojump)
- * \note The "faxdetect" option string read in from /etc/asterisk/misdn.conf
- * \note It is settable by the misdn_set_opt() application.
- */
- int faxdetect;
- /*!
- * \brief Number of seconds to detect a Fax machine when detection enabled.
- * \note 0 disables the timeout.
- * \note The "faxdetect_timeout" value read in from /etc/asterisk/misdn.conf
- */
- int faxdetect_timeout;
- /*!
- * \brief Starting time of fax detection with timeout when nonzero.
- */
- struct timeval faxdetect_tv;
- /*!
- * \brief TRUE if a fax has been detected.
- */
- int faxhandled;
- /*!
- * \brief TRUE if we will use the Asterisk DSP to detect DTMF/Fax
- * \note The "astdtmf" boolean read in from /etc/asterisk/misdn.conf
- */
- int ast_dsp;
- /*!
- * \brief Jitterbuffer length
- * \note The "jitterbuffer" value read in from /etc/asterisk/misdn.conf
- */
- int jb_len;
- /*!
- * \brief Jitterbuffer upper threshold
- * \note The "jitterbuffer_upper_threshold" value read in from /etc/asterisk/misdn.conf
- */
- int jb_upper_threshold;
- /*!
- * \brief Allocated jitterbuffer controller
- * \note misdn_jb_init() creates the jitterbuffer.
- * \note Must use misdn_jb_destroy() to clean up.
- */
- struct misdn_jb *jb;
-
- /*!
- * \brief Allocated DSP controller
- * \note ast_dsp_new() creates the DSP controller.
- * \note Must use ast_dsp_free() to clean up.
- */
- struct ast_dsp *dsp;
- /*!
- * \brief Associated Asterisk channel structure.
- */
- struct ast_channel * ast;
- //int dummy; /* Not used */
-
- /*!
- * \brief Associated B channel structure.
- */
- struct misdn_bchannel *bc;
- /*!
- * \brief HELD channel call information
- */
- struct hold_info hold;
- /*!
- * \brief From associated B channel: Layer 3 process ID
- * \note Used to find the HELD channel call record when retrieving a call.
- */
- unsigned int l3id;
- /*!
- * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
- * \note Used only for debug display messages.
- */
- int addr;
- /*!
- * \brief Incoming call dialplan context identifier.
- * \note The "context" string read in from /etc/asterisk/misdn.conf
- */
- char context[AST_MAX_CONTEXT];
- /*!
- * \brief The configured music-on-hold class to use for this call.
- * \note The "musicclass" string read in from /etc/asterisk/misdn.conf
- */
- char mohinterpret[MAX_MUSICCLASS];
- //int zero_read_cnt; /* Not used */
- /*!
- * \brief Number of outgoing audio frames dropped since last debug gripe message.
- */
- int dropped_frame_cnt;
- /*!
- * \brief TRUE if we must do the ringback tones.
- * \note The "far_alerting" boolean read in from /etc/asterisk/misdn.conf
- */
- int far_alerting;
- /*!
- * \brief TRUE if NT should disconnect an overlap dialing call when a timeout occurs.
- * \note The "nttimeout" boolean read in from /etc/asterisk/misdn.conf
- */
- int nttimeout;
- /*!
- * \brief Other channel call record PID
- * \note Value imported from Asterisk environment variable MISDN_PID
- */
- int other_pid;
- /*!
- * \brief Bridged other channel call record
- * \note Pointer set when other_pid imported from Asterisk environment
- * variable MISDN_PID by either side.
- */
- struct chan_list *other_ch;
- /*!
- * \brief Tone zone sound used for dialtone generation.
- * \note Used as a boolean. Non-NULL to prod generation if enabled.
- */
- const struct tone_zone_sound *ts;
-
- /*!
- * \brief Enables overlap dialing for the set amount of seconds. (0 = Disabled)
- * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
- */
- int overlap_dial;
- /*!
- * \brief Overlap dialing timeout Task ID. -1 if not running.
- */
- int overlap_dial_task;
- /*!
- * \brief overlap_tv access lock.
- */
- ast_mutex_t overlap_tv_lock;
- /*!
- * \brief Overlap timer start time. Timer restarted for every digit received.
- */
- struct timeval overlap_tv;
-
- //struct chan_list *peer; /* Not used */
- /*!
- * \brief Next channel call record in the list.
- */
- struct chan_list *next;
- //struct chan_list *prev; /* Not used */
- //struct chan_list *first; /* Not used */
- };
- void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
- void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
- struct robin_list {
- char *group;
- int port;
- int channel;
- struct robin_list *next;
- struct robin_list *prev;
- };
- static struct robin_list *robin = NULL;
- static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
- static void free_robin_list(void)
- {
- struct robin_list *r;
- struct robin_list *next;
- for (r = robin, robin = NULL; r; r = next) {
- next = r->next;
- ast_free(r->group);
- ast_free(r);
- }
- }
- static struct robin_list* get_robin_position (char *group)
- {
- struct robin_list *new;
- struct robin_list *iter = robin;
- for (; iter; iter = iter->next) {
- if (!strcasecmp(iter->group, group)) {
- return iter;
- }
- }
- new = ast_calloc(1, sizeof(*new));
- if (!new) {
- return NULL;
- }
- new->group = ast_strdup(group);
- if (!new->group) {
- ast_free(new);
- return NULL;
- }
- new->channel = 1;
- if (robin) {
- new->next = robin;
- robin->prev = new;
- }
- robin = new;
- return robin;
- }
- /*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
- static struct sched_context *misdn_tasks = NULL;
- static pthread_t misdn_tasks_thread;
- static int *misdn_ports;
- static void chan_misdn_log(int level, int port, char *tmpl, ...)
- __attribute__((format(printf, 3, 4)));
- static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);
- static void send_digit_to_chan(struct chan_list *cl, char digit );
- static int pbx_start_chan(struct chan_list *ch);
- #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
- #define MISDN_ASTERISK_PVT(ast) 1
- #include "asterisk/strings.h"
- /* #define MISDN_DEBUG 1 */
- static const char misdn_type[] = "mISDN";
- static int tracing = 0 ;
- /*! \brief Only alaw and mulaw is allowed for now */
- static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */
- static int *misdn_debug;
- static int *misdn_debug_only;
- static int max_ports;
- static int *misdn_in_calls;
- static int *misdn_out_calls;
- struct chan_list dummy_cl;
- /*!
- * \brief Global channel call record list head.
- */
- struct chan_list *cl_te=NULL;
- ast_mutex_t cl_te_lock;
- static enum event_response_e
- cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
- static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);
- static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);
- static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);
- static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);
- static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);
- static int dialtone_indicate(struct chan_list *cl);
- static void hanguptone_indicate(struct chan_list *cl);
- static int stop_indicate(struct chan_list *cl);
- static int start_bc_tones(struct chan_list *cl);
- static int stop_bc_tones(struct chan_list *cl);
- static void release_chan_early(struct chan_list *ch);
- static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
- static int misdn_check_l2l1(struct ast_channel *chan, void *data);
- static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
- static int misdn_facility_exec(struct ast_channel *chan, void *data);
- int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
- void debug_numplan(int port, int numplan, char *type);
- int add_out_calls(int port);
- int add_in_calls(int port);
- #ifdef MISDN_1_2
- static int update_pipeline_config(struct misdn_bchannel *bc);
- #else
- static int update_ec_config(struct misdn_bchannel *bc);
- #endif
- /*************** Helpers *****************/
- static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
- {
- struct chan_list *tmp;
-
- for (tmp=cl_te; tmp; tmp = tmp->next) {
- if ( tmp->ast == ast ) return tmp;
- }
-
- return NULL;
- }
- static struct chan_list * get_chan_by_ast_name(char *name)
- {
- struct chan_list *tmp;
-
- for (tmp=cl_te; tmp; tmp = tmp->next) {
- if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp;
- }
-
- return NULL;
- }
- struct allowed_bearers {
- char *name; /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
- char *display; /*!< Bearer capability displayable name */
- int cap; /*!< SETUP message bearer capability field code value */
- int deprecated; /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
- };
- /* *INDENT-OFF* */
- static const struct allowed_bearers allowed_bearers_array[]= {
- /* Name, Displayable Name Bearer Capability, Deprecated */
- { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
- { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
- { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
- { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 },
- { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 }, /* Allow misspelling for backwards compatibility */
- { "video", "Video", INFO_CAPABILITY_VIDEO, 0 }
- };
- /* *INDENT-ON* */
- static const char *bearer2str(int cap)
- {
- unsigned index;
- for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
- if (allowed_bearers_array[index].cap == cap) {
- return allowed_bearers_array[index].display;
- }
- }
- return "Unknown Bearer";
- }
- static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc)
- {
- switch (fac->Function) {
- #ifdef HAVE_MISDN_FAC_RESULT
- case Fac_RESULT:
- chan_misdn_log(0, bc->port," --> Received RESULT Operation\n");
- break;
- #endif
- #ifdef HAVE_MISDN_FAC_ERROR
- case Fac_ERROR:
- chan_misdn_log(0, bc->port," --> Received Error Operation\n");
- chan_misdn_log(0, bc->port," --> Value:%d Error:%s\n",fac->u.ERROR.errorValue, fac->u.ERROR.error);
- break;
- #endif
- case Fac_CD:
- chan_misdn_log(1,bc->port," --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
- fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
- break;
- case Fac_AOCDCurrency:
- if (fac->u.AOCDcur.chargeNotAvailable)
- chan_misdn_log(1,bc->port," --> AOCD currency: charge not available\n");
- else if (fac->u.AOCDcur.freeOfCharge)
- chan_misdn_log(1,bc->port," --> AOCD currency: free of charge\n");
- else if (fac->u.AOCDchu.billingId >= 0)
- chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
- fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
- (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
- else
- chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
- fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
- (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
- break;
- case Fac_AOCDChargingUnit:
- if (fac->u.AOCDchu.chargeNotAvailable)
- chan_misdn_log(1,bc->port," --> AOCD charging unit: charge not available\n");
- else if (fac->u.AOCDchu.freeOfCharge)
- chan_misdn_log(1,bc->port," --> AOCD charging unit: free of charge\n");
- else if (fac->u.AOCDchu.billingId >= 0)
- chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
- fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
- else
- chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
- fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
- break;
- case Fac_None:
- default:
- chan_misdn_log(1,bc->port," --> unknown facility\n");
- break;
- }
- }
- static void print_bearer(struct misdn_bchannel *bc)
- {
-
- chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability));
-
- switch(bc->law) {
- case INFO_CODEC_ALAW:
- chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
- break;
- case INFO_CODEC_ULAW:
- chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
- break;
- }
- }
- static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
- {
- char buf[128];
- if (!bc->AOCD_need_export || !ast)
- return;
- if (originator == ORG_AST) {
- ast = ast_bridged_channel(ast);
- if (!ast)
- return;
- }
- switch (bc->AOCDtype) {
- case Fac_AOCDCurrency:
- pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
- if (bc->AOCD.currency.chargeNotAvailable)
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
- if (bc->AOCD.currency.freeOfCharge)
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
- if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
- pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
- if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf))
- pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
- }
- }
- }
- break;
- case Fac_AOCDChargingUnit:
- pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
- if (bc->AOCD.chargingUnit.chargeNotAvailable)
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
- if (bc->AOCD.chargingUnit.freeOfCharge)
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
- else {
- pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
- if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
- pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
- if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf))
- pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
- }
- }
- }
- break;
- default:
- break;
- }
-
- bc->AOCD_need_export = 0;
- }
- /*************** Helpers END *************/
- static void sighandler(int sig)
- {}
- static void* misdn_tasks_thread_func (void *data)
- {
- int wait;
- struct sigaction sa;
- sa.sa_handler = sighandler;
- sa.sa_flags = SA_NODEFER;
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGUSR1);
- sigaction(SIGUSR1, &sa, NULL);
-
- sem_post((sem_t *)data);
- while (1) {
- wait = ast_sched_wait(misdn_tasks);
- if (wait < 0)
- wait = 8000;
- if (poll(NULL, 0, wait) < 0)
- chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
- ast_sched_runq(misdn_tasks);
- }
- return NULL;
- }
- static void misdn_tasks_init (void)
- {
- sem_t blocker;
- int i = 5;
- if (sem_init(&blocker, 0, 0)) {
- perror("chan_misdn: Failed to initialize semaphore!");
- exit(1);
- }
- chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
-
- misdn_tasks = sched_context_create();
- pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
- while (sem_wait(&blocker) && --i);
- sem_destroy(&blocker);
- }
- static void misdn_tasks_destroy (void)
- {
- if (misdn_tasks) {
- chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
- if ( pthread_cancel(misdn_tasks_thread) == 0 ) {
- cb_log(4, 0, "Joining misdn_tasks thread\n");
- pthread_join(misdn_tasks_thread, NULL);
- }
- sched_context_destroy(misdn_tasks);
- }
- }
- static inline void misdn_tasks_wakeup (void)
- {
- pthread_kill(misdn_tasks_thread, SIGUSR1);
- }
- static inline int _misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data, int variable)
- {
- int task_id;
- if (!misdn_tasks) {
- misdn_tasks_init();
- }
- task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
- misdn_tasks_wakeup();
- return task_id;
- }
- static int misdn_tasks_add (int timeout, ast_sched_cb callback, const void *data)
- {
- return _misdn_tasks_add_variable(timeout, callback, data, 0);
- }
- static int misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data)
- {
- return _misdn_tasks_add_variable(timeout, callback, data, 1);
- }
- static void misdn_tasks_remove (int task_id)
- {
- AST_SCHED_DEL(misdn_tasks, task_id);
- }
- static int misdn_l1_task (const void *data)
- {
- misdn_lib_isdn_l1watcher(*(int *)data);
- chan_misdn_log(5, *(int *)data, "L1watcher timeout\n");
- return 1;
- }
- static int misdn_overlap_dial_task (const void *data)
- {
- struct timeval tv_end, tv_now;
- int diff;
- struct chan_list *ch = (struct chan_list *)data;
- chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
- if (ch->state != MISDN_WAITING4DIGS) {
- ch->overlap_dial_task = -1;
- return 0;
- }
-
- ast_mutex_lock(&ch->overlap_tv_lock);
- tv_end = ch->overlap_tv;
- ast_mutex_unlock(&ch->overlap_tv_lock);
-
- tv_end.tv_sec += ch->overlap_dial;
- tv_now = ast_tvnow();
- diff = ast_tvdiff_ms(tv_end, tv_now);
- if (diff <= 100) {
- char *dad=ch->bc->dad, sexten[]="s";
- /* if we are 100ms near the timeout, we are satisfied.. */
- stop_indicate(ch);
-
- if (ast_strlen_zero(ch->bc->dad)) {
- dad=sexten;
- strcpy(ch->ast->exten, sexten);
- }
- if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
- ch->state=MISDN_DIALING;
- if (pbx_start_chan(ch) < 0) {
- chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
- goto misdn_overlap_dial_task_disconnect;
- }
- } else {
- misdn_overlap_dial_task_disconnect:
- hanguptone_indicate(ch);
- ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
- ch->state=MISDN_CLEANING;
- misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
- }
- ch->overlap_dial_task = -1;
- return 0;
- } else
- return diff;
- }
- static void send_digit_to_chan(struct chan_list *cl, char digit )
- {
- static const char* dtmf_tones[] = {
- "!941+1336/100,!0/100", /* 0 */
- "!697+1209/100,!0/100", /* 1 */
- "!697+1336/100,!0/100", /* 2 */
- "!697+1477/100,!0/100", /* 3 */
- "!770+1209/100,!0/100", /* 4 */
- "!770+1336/100,!0/100", /* 5 */
- "!770+1477/100,!0/100", /* 6 */
- "!852+1209/100,!0/100", /* 7 */
- "!852+1336/100,!0/100", /* 8 */
- "!852+1477/100,!0/100", /* 9 */
- "!697+1633/100,!0/100", /* A */
- "!770+1633/100,!0/100", /* B */
- "!852+1633/100,!0/100", /* C */
- "!941+1633/100,!0/100", /* D */
- "!941+1209/100,!0/100", /* * */
- "!941+1477/100,!0/100" }; /* # */
- struct ast_channel *chan=cl->ast;
-
- if (digit >= '0' && digit <='9')
- ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
- else if (digit >= 'A' && digit <= 'D')
- ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
- else if (digit == '*')
- ast_playtones_start(chan,0,dtmf_tones[14], 0);
- else if (digit == '#')
- ast_playtones_start(chan,0,dtmf_tones[15], 0);
- else {
- /* not handled */
- ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
- }
- }
- /*** CLI HANDLING ***/
- static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int level;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn set debug";
- e->usage =
- "Usage: misdn set debug <level> [only] | [port <port> [only]]\n"
- " Set the debug level of the mISDN channel.\n";
- return NULL;
- case CLI_GENERATE:
- return complete_debug_port(a);
- }
- if (a->argc < 4 || a->argc > 7)
- return CLI_SHOWUSAGE;
- level = atoi(a->argv[3]);
- switch (a->argc) {
- case 4:
- case 5:
- {
- int i;
- int only = 0;
- if (a->argc == 5) {
- if (strncasecmp(a->argv[4], "only", strlen(a->argv[4])))
- return CLI_SHOWUSAGE;
- else
- only = 1;
- }
-
- for (i = 0; i <= max_ports; i++) {
- misdn_debug[i] = level;
- misdn_debug_only[i] = only;
- }
- ast_cli(a->fd, "changing debug level for all ports to %d%s\n",misdn_debug[0], only?" (only)":"");
- }
- break;
- case 6:
- case 7:
- {
- int port;
- if (strncasecmp(a->argv[4], "port", strlen(a->argv[4])))
- return CLI_SHOWUSAGE;
- port = atoi(a->argv[5]);
- if (port <= 0 || port > max_ports) {
- switch (max_ports) {
- case 0:
- ast_cli(a->fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
- break;
- case 1:
- ast_cli(a->fd, "port number not valid! only port 1 is available.\n");
- break;
- default:
- ast_cli(a->fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
- }
- return 0;
- }
- if (a->argc == 7) {
- if (strncasecmp(a->argv[6], "only", strlen(a->argv[6])))
- return CLI_SHOWUSAGE;
- else
- misdn_debug_only[port] = 1;
- } else
- misdn_debug_only[port] = 0;
- misdn_debug[port] = level;
- ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port]?" (only)":"", port);
- }
- }
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_set_crypt_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn set crypt debug";
- e->usage =
- "Usage: misdn set crypt debug <level>\n"
- " Set the crypt debug level of the mISDN channel. Level\n"
- " must be 1 or 2.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 5)
- return CLI_SHOWUSAGE;
- /* Is this supposed to not do anything? */
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_port_block(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn port block";
- e->usage =
- "Usage: misdn port block <port>\n"
- " Block the specified port by <port>.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- misdn_lib_port_block(atoi(a->argv[3]));
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_port_unblock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn port unblock";
- e->usage =
- "Usage: misdn port unblock <port>\n"
- " Unblock the port specified by <port>.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- misdn_lib_port_unblock(atoi(a->argv[3]));
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_restart_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn restart port";
- e->usage =
- "Usage: misdn restart port <port>\n"
- " Restart the given port.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- misdn_lib_port_restart(atoi(a->argv[3]));
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_restart_pid(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn restart pid";
- e->usage =
- "Usage: misdn restart pid <pid>\n"
- " Restart the given pid\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- misdn_lib_pid_restart(atoi(a->argv[3]));
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_port_up(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn port up";
- e->usage =
- "Usage: misdn port up <port>\n"
- " Try to establish L1 on the given port.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- misdn_lib_get_port_up(atoi(a->argv[3]));
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_port_down(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn port down";
- e->usage =
- "Usage: misdn port down <port>\n"
- " Try to deactivate the L1 on the given port.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- misdn_lib_get_port_down(atoi(a->argv[3]));
- return CLI_SUCCESS;
- }
- static inline void show_config_description(int fd, enum misdn_cfg_elements elem)
- {
- char section[BUFFERSIZE];
- char name[BUFFERSIZE];
- char desc[BUFFERSIZE];
- char def[BUFFERSIZE];
- char tmp[BUFFERSIZE];
- misdn_cfg_get_name(elem, tmp, sizeof(tmp));
- term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
- misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
- if (elem < MISDN_CFG_LAST)
- term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
- else
- term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
- if (*def)
- ast_cli(fd, "[%s] %s (Default: %s)\n\t%s\n", section, name, def, desc);
- else
- ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
- }
- static char *handle_cli_misdn_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- char buffer[BUFFERSIZE];
- enum misdn_cfg_elements elem;
- int linebreak;
- int onlyport = -1;
- int ok = 0;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn show config";
- e->usage =
- "Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]]\n"
- " Use 0 for <port> to only print the general config.\n";
- return NULL;
- case CLI_GENERATE:
- return complete_show_config(a);
- }
- if (a->argc >= 4) {
- if (!strcmp(a->argv[3], "description")) {
- if (a->argc == 5) {
- enum misdn_cfg_elements elem = misdn_cfg_get_elem(a->argv[4]);
- if (elem == MISDN_CFG_FIRST)
- ast_cli(a->fd, "Unknown element: %s\n", a->argv[4]);
- else
- show_config_description(a->fd, elem);
- return CLI_SUCCESS;
- }
- return CLI_SHOWUSAGE;
- } else if (!strcmp(a->argv[3], "descriptions")) {
- if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "general"))) {
- for (elem = MISDN_GEN_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
- show_config_description(a->fd, elem);
- ast_cli(a->fd, "\n");
- }
- ok = 1;
- }
- if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "ports"))) {
- for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_CFG_LAST - 1 /* the ptp hack, remove the -1 when ptp is gone */; ++elem) {
- show_config_description(a->fd, elem);
- ast_cli(a->fd, "\n");
- }
- ok = 1;
- }
- return ok ? CLI_SUCCESS : CLI_SHOWUSAGE;
- } else if (!sscanf(a->argv[3], "%5d", &onlyport) || onlyport < 0) {
- ast_cli(a->fd, "Unknown option: %s\n", a->argv[3]);
- return CLI_SHOWUSAGE;
- }
- } else if (a->argc == 3 || onlyport == 0) {
- ast_cli(a->fd, "mISDN General-Config:\n");
- for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
- misdn_cfg_get_config_string(0, elem, buffer, sizeof(buffer));
- ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
- }
- ast_cli(a->fd, "\n");
- }
- if (onlyport < 0) {
- int port = misdn_cfg_get_next_port(0);
- for (; port > 0; port = misdn_cfg_get_next_port(port)) {
- ast_cli(a->fd, "\n[PORT %d]\n", port);
- for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
- misdn_cfg_get_config_string(port, elem, buffer, sizeof(buffer));
- ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
- }
- ast_cli(a->fd, "\n");
- }
- }
-
- if (onlyport > 0) {
- if (misdn_cfg_is_port_valid(onlyport)) {
- ast_cli(a->fd, "[PORT %d]\n", onlyport);
- for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
- misdn_cfg_get_config_string(onlyport, elem, buffer, sizeof(buffer));
- ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
- }
- ast_cli(a->fd, "\n");
- } else {
- ast_cli(a->fd, "Port %d is not active!\n", onlyport);
- }
- }
- return CLI_SUCCESS;
- }
- struct state_struct {
- enum misdn_chan_state state;
- char txt[255];
- };
- static struct state_struct state_array[] = {
- {MISDN_NOTHING,"NOTHING"}, /* at beginning */
- {MISDN_WAITING4DIGS,"WAITING4DIGS"}, /* when waiting for infos */
- {MISDN_EXTCANTMATCH,"EXTCANTMATCH"}, /* when asterisk couldn't match our ext */
- {MISDN_INCOMING_SETUP,"INCOMING SETUP"}, /* when pbx_start */
- {MISDN_DIALING,"DIALING"}, /* when pbx_start */
- {MISDN_PROGRESS,"PROGRESS"}, /* when pbx_start */
- {MISDN_PROCEEDING,"PROCEEDING"}, /* when pbx_start */
- {MISDN_CALLING,"CALLING"}, /* when misdn_call is called */
- {MISDN_CALLING_ACKNOWLEDGE,"CALLING_ACKNOWLEDGE"}, /* when misdn_call is called */
- {MISDN_ALERTING,"ALERTING"}, /* when Alerting */
- {MISDN_BUSY,"BUSY"}, /* when BUSY */
- {MISDN_CONNECTED,"CONNECTED"}, /* when connected */
- {MISDN_DISCONNECTED,"DISCONNECTED"}, /* when connected */
- {MISDN_CLEANING,"CLEANING"}, /* when hangup from * but we were connected before */
- };
- static const char *misdn_get_ch_state(struct chan_list *p)
- {
- int i;
- static char state[8];
-
- if( !p) return NULL;
-
- for (i = 0; i < sizeof(state_array) / sizeof(struct state_struct); i++) {
- if (state_array[i].state == p->state)
- return state_array[i].txt;
- }
- snprintf(state, sizeof(state), "%d", p->state) ;
- return state;
- }
- static void reload_config(void)
- {
- int i, cfg_debug;
- if (!g_config_initialized) {
- ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
- return ;
- }
-
- free_robin_list();
- misdn_cfg_reload();
- misdn_cfg_update_ptp();
- misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
- misdn_cfg_get(0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(cfg_debug));
- for (i = 0; i <= max_ports; i++) {
- misdn_debug[i] = cfg_debug;
- misdn_debug_only[i] = 0;
- }
- }
- static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn reload";
- e->usage =
- "Usage: misdn reload\n"
- " Reload internal mISDN config, read from the config\n"
- " file.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 2)
- return CLI_SHOWUSAGE;
- ast_cli(a->fd, "Reloading mISDN configuration\n");
- reload_config();
- return CLI_SUCCESS;
- }
- static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc)
- {
- struct ast_channel *ast = help->ast;
- ast_cli(fd,
- "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n",
- bc->pid, bc->port, bc->channel,
- bc->nt ? "NT" : "TE",
- help->originator == ORG_AST ? "*" : "I",
- ast ? ast->exten : NULL,
- ast ? ast->cid.cid_num : NULL,
- bc->rad,
- ast ? ast->context : NULL,
- misdn_get_ch_state(help)
- );
- if (misdn_debug[bc->port] > 0)
- ast_cli(fd,
- " --> astname: %s\n"
- " --> ch_l3id: %x\n"
- " --> ch_addr: %x\n"
- " --> bc_addr: %x\n"
- " --> bc_l3id: %x\n"
- " --> display: %s\n"
- " --> activated: %d\n"
- " --> state: %s\n"
- " --> capability: %s\n"
- #ifdef MISDN_1_2
- " --> pipeline: %s\n"
- #else
- " --> echo_cancel: %d\n"
- #endif
- " --> notone : rx %d tx:%d\n"
- " --> bc_hold: %d\n",
- help->ast->name,
- help->l3id,
- help->addr,
- bc->addr,
- bc ? bc->l3_id : -1,
- bc->display,
-
- bc->active,
- bc_state2str(bc->bc_state),
- bearer2str(bc->capability),
- #ifdef MISDN_1_2
- bc->pipeline,
- #else
- bc->ec_enable,
- #endif
- help->norxtone, help->notxtone,
- bc->holded
- );
- }
- static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct chan_list *help;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn show channels";
- e->usage =
- "Usage: misdn show channels\n"
- " Show the internal mISDN channel list\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 3)
- return CLI_SHOWUSAGE;
- help = cl_te;
-
- ast_cli(a->fd, "Channel List: %p\n", cl_te);
- for (; help; help = help->next) {
- struct misdn_bchannel *bc = help->bc;
- struct ast_channel *ast = help->ast;
- if (!ast) {
- if (!bc) {
- ast_cli(a->fd, "chan_list obj. with l3id:%x has no bc and no ast Leg\n", help->l3id);
- continue;
- }
- ast_cli(a->fd, "bc with pid:%d has no Ast Leg\n", bc->pid);
- continue;
- }
- if (misdn_debug[0] > 2)
- ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast);
- if (bc) {
- print_bc_info(a->fd, help, bc);
- } else {
- if (help->hold.state != MISDN_HOLD_IDLE) {
- ast_cli(a->fd, "ITS A HELD CALL BC:\n");
- ast_cli(a->fd, " --> l3_id: %x\n"
- " --> dad:%s oad:%s\n"
- " --> hold_port: %d\n"
- " --> hold_channel: %d\n",
- help->l3id,
- ast->exten,
- ast->cid.cid_num,
- help->hold.port,
- help->hold.channel
- );
- } else {
- ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
- }
- }
- }
- misdn_dump_chanlist();
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- struct chan_list *help;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn show channel";
- e->usage =
- "Usage: misdn show channel <channel>\n"
- " Show an internal mISDN channel\n.";
- return NULL;
- case CLI_GENERATE:
- return complete_ch(a);
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- help = cl_te;
- for (; help; help = help->next) {
- struct misdn_bchannel *bc = help->bc;
- struct ast_channel *ast = help->ast;
-
- if (bc && ast) {
- if (!strcasecmp(ast->name, a->argv[3])) {
- print_bc_info(a->fd, help, bc);
- break;
- }
- }
- }
- return CLI_SUCCESS;
- }
- ast_mutex_t lock;
- int MAXTICS = 8;
- static char *handle_cli_misdn_set_tics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn set tics";
- e->usage =
- "Usage: misdn set tics <value>\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- MAXTICS = atoi(a->argv[3]);
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_show_stacks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int port;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn show stacks";
- e->usage =
- "Usage: misdn show stacks\n"
- " Show internal mISDN stack_list.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 3)
- return CLI_SHOWUSAGE;
- ast_cli(a->fd, "BEGIN STACK_LIST:\n");
- for (port = misdn_cfg_get_next_port(0); port > 0;
- port = misdn_cfg_get_next_port(port)) {
- char buf[128];
- get_show_stack_details(port, buf);
- ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
- }
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_show_ports_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int port;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn show ports stats";
- e->usage =
- "Usage: misdn show ports stats\n"
- " Show mISDNs channel's call statistics per port.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
- for (port = misdn_cfg_get_next_port(0); port > 0;
- port = misdn_cfg_get_next_port(port)) {
- ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
- }
- ast_cli(a->fd, "\n");
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_show_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int port;
- char buf[128];
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn show port";
- e->usage =
- "Usage: misdn show port <port>\n"
- " Show detailed information for given port.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- port = atoi(a->argv[3]);
- ast_cli(a->fd, "BEGIN STACK_LIST:\n");
- get_show_stack_details(port, buf);
- ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- char *channame;
- char *nr;
- struct chan_list *tmp;
- int port;
- char *served_nr;
- struct misdn_bchannel dummy, *bc=&dummy;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn send facility";
- e->usage = "Usage: misdn send facility <type> <channel|port> \"<args>\" \n"
- "\t type is one of:\n"
- "\t - calldeflect\n"
- "\t - CFActivate\n"
- "\t - CFDeactivate\n";
- return NULL;
- case CLI_GENERATE:
- return complete_ch(a);
- }
- if (a->argc < 5)
- return CLI_SHOWUSAGE;
-
- if (strstr(a->argv[3], "calldeflect")) {
- if (a->argc < 6) {
- ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
- return 0;
- }
- channame = a->argv[4];
- nr = a->argv[5];
- ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame);
- tmp = get_chan_by_ast_name(channame);
- if (!tmp) {
- ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n",nr, channame);
- return 0;
- }
- if (strlen(nr) >= 15) {
- ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to 15 digits are allowed).\n",nr, channame);
- return 0;
- }
- tmp->bc->fac_out.Function = Fac_CD;
- ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
- misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
- } else if (strstr(a->argv[3],"CFActivate")) {
- if (a->argc < 7) {
- ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n");
- return 0;
- }
- port = atoi(a->argv[4]);
- served_nr = a->argv[5];
- nr = a->argv[6];
- misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
- ast_verbose("Sending CFActivate Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);
- bc->fac_out.Function = Fac_CFActivate;
- bc->fac_out.u.CFActivate.BasicService = 0; //All Services
- bc->fac_out.u.CFActivate.Procedure = 0; //Unconditional
- ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
- ast_copy_string((char *)bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber));
- misdn_lib_send_event(bc, EVENT_FACILITY);
- } else if (strstr(a->argv[3],"CFDeactivate")) {
- if (a->argc < 6) {
- ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
- return 0;
- }
- port = atoi(a->argv[4]);
- served_nr = a->argv[5];
-
- misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
- ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr);
- bc->fac_out.Function = Fac_CFDeactivate;
- bc->fac_out.u.CFDeactivate.BasicService = 0; //All Services
- bc->fac_out.u.CFDeactivate.Procedure = 0; //Unconditional
-
- ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
- misdn_lib_send_event(bc, EVENT_FACILITY);
- }
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_send_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- int port;
- int channel;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn send restart";
- e->usage =
- "Usage: misdn send restart [port [channel]]\n"
- " Send a restart for every bchannel on the given port.\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
- if (a->argc < 4 || a->argc > 5)
- return CLI_SHOWUSAGE;
- port = atoi(a->argv[3]);
- if (a->argc == 5) {
- channel = atoi(a->argv[4]);
- misdn_lib_send_restart(port, channel);
- } else {
- misdn_lib_send_restart(port, -1);
- }
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- char *channame;
- char *msg;
- struct chan_list *tmp;
- int i, msglen;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn send digit";
- e->usage =
- "Usage: misdn send digit <channel> \"<msg>\" \n"
- " Send <digit> to <channel> as DTMF Tone\n"
- " when channel is a mISDN channel\n";
- return NULL;
- case CLI_GENERATE:
- return complete_ch(a);
- }
- if (a->argc != 5)
- return CLI_SHOWUSAGE;
- channame = a->argv[3];
- msg = a->argv[4];
- msglen = strlen(msg);
- ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
- tmp = get_chan_by_ast_name(channame);
- if (!tmp) {
- ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
- return CLI_SUCCESS;
- }
- #if 1
- for (i = 0; i < msglen; i++) {
- ast_cli(a->fd, "Sending: %c\n", msg[i]);
- send_digit_to_chan(tmp, msg[i]);
- /* res = ast_safe_sleep(tmp->ast, 250); */
- usleep(250000);
- /* res = ast_waitfor(tmp->ast,100); */
- }
- #else
- ast_dtmf_stream(tmp->ast, NULL, msg, 250);
- #endif
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_toggle_echocancel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- char *channame;
- struct chan_list *tmp;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn toggle echocancel";
- e->usage =
- "Usage: misdn toggle echocancel <channel>\n"
- " Toggle EchoCancel on mISDN Channel.\n";
- return NULL;
- case CLI_GENERATE:
- return complete_ch(a);
- }
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- channame = a->argv[3];
-
- ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
-
- tmp = get_chan_by_ast_name(channame);
- if (!tmp) {
- ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
- return CLI_SUCCESS;
- }
- tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;
- if (tmp->toggle_ec) {
- #ifdef MISDN_1_2
- update_pipeline_config(tmp->bc);
- #else
- update_ec_config(tmp->bc);
- #endif
- manager_ec_enable(tmp->bc);
- } else {
- manager_ec_disable(tmp->bc);
- }
- return CLI_SUCCESS;
- }
- static char *handle_cli_misdn_send_display(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
- {
- char *channame;
- char *msg;
- struct chan_list *tmp;
- switch (cmd) {
- case CLI_INIT:
- e->command = "misdn send display";
- e->usage =
- "Usage: misdn send display <channel> \"<msg>\" \n"
- " Send <msg> to <channel> as Display Message\n"
- " when channel is a mISDN channel\n";
- return NULL;
- case CLI_GENERATE:
- return complete_ch(a);
- }
- if (a->argc != 5)
- return CLI_SHOWUSAGE;
- channame = a->argv[3];
- msg = a->argv[4];
- ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
- tmp = get_chan_by_ast_name(channame);
-
- if (tmp && tmp->bc) {
- ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
- misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
- } else {
- ast_cli(a->fd, "No such channel %s\n", channame);
- return CLI_SUCCESS;
- }
- return CLI_SUCCESS;
- }
- static char *complete_ch(struct ast_cli_args *a)
- {
- return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
- }
- static char *complete_debug_port (struct ast_cli_args *a)
- {
- if (a->n)
- return NULL;
- switch (a->pos) {
- case 4:
- if (a->word[0] == 'p')
- return ast_strdup("port");
- else if (a->word[0] == 'o')
- return ast_strdup("only");
- break;
- case 6:
- if (a->word[0] == 'o')
- return ast_strdup("only");
- break;
- }
- return NULL;
- }
- static char *complete_show_config(struct ast_cli_args *a)
- {
- char buffer[BUFFERSIZE];
- enum misdn_cfg_elements elem;
- int wordlen = strlen(a->word);
- int which = 0;
- int port = 0;
- switch (a->pos) {
- case 3:
- if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n))
- return ast_strdup("description");
- if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n))
- return ast_strdup("descriptions");
- if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n))
- return ast_strdup("0");
- while ((port = misdn_cfg_get_next_port(port)) != -1) {
- snprintf(buffer, sizeof(buffer), "%d", port);
- if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) {
- return ast_strdup(buffer);
- }
- }
- break;
- case 4:
- if (strstr(a->line, "description ")) {
- for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
- if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST))
- continue;
- misdn_cfg_get_name(elem, buffer, sizeof(buffer));
- if (!wordlen || !strncmp(a->word, buffer, wordlen)) {
- if (++which > a->n)
- return ast_strdup(buffer);
- }
- }
- } else if (strstr(a->line, "descriptions ")) {
- if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n))
- return ast_strdup("general");
- if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n))
- return ast_strdup("ports");
- }
- break;
- }
- return NULL;
- }
- static struct ast_cli_entry chan_misdn_clis[] = {
- AST_CLI_DEFINE(handle_cli_misdn_port_block, "Block the given port"),
- AST_CLI_DEFINE(handle_cli_misdn_port_down, "Try to deactivate the L1 on the given port"),
- AST_CLI_DEFINE(handle_cli_misdn_port_unblock, "Unblock the given port"),
- AST_CLI_DEFINE(handle_cli_misdn_port_up, "Try to establish L1 on the given port"),
- AST_CLI_DEFINE(handle_cli_misdn_reload, "Reload internal mISDN config, read from the config file"),
- AST_CLI_DEFINE(handle_cli_misdn_restart_pid, "Restart the given pid"),
- AST_CLI_DEFINE(handle_cli_misdn_restart_port, "Restart the given port"),
- AST_CLI_DEFINE(handle_cli_misdn_show_channel, "Show an internal mISDN channel"),
- AST_CLI_DEFINE(handle_cli_misdn_show_channels, "Show the internal mISDN channel list"),
- AST_CLI_DEFINE(handle_cli_misdn_show_config, "Show internal mISDN config, read from the config file"),
- AST_CLI_DEFINE(handle_cli_misdn_show_port, "Show detailed information for given port"),
- AST_CLI_DEFINE(handle_cli_misdn_show_ports_stats, "Show mISDNs channel's call statistics per port"),
- AST_CLI_DEFINE(handle_cli_misdn_show_stacks, "Show internal mISDN stack_list"),
- AST_CLI_DEFINE(handle_cli_misdn_send_facility, "Sends a Facility Message to the mISDN Channel"),
- AST_CLI_DEFINE(handle_cli_misdn_send_digit, "Send DTMF digit to mISDN Channel"),
- AST_CLI_DEFINE(handle_cli_misdn_send_display, "Send Text to mISDN Channel"),
- AST_CLI_DEFINE(handle_cli_misdn_send_restart, "Send a restart for every bchannel on the given port"),
- AST_CLI_DEFINE(handle_cli_misdn_set_crypt_debug, "Set CryptDebuglevel of chan_misdn, at the moment, level={1,2}"),
- AST_CLI_DEFINE(handle_cli_misdn_set_debug, "Set Debuglevel of chan_misdn"),
- AST_CLI_DEFINE(handle_cli_misdn_set_tics, "???"),
- AST_CLI_DEFINE(handle_cli_misdn_toggle_echocancel, "Toggle EchoCancel on mISDN Channel"),
- };
- /*! \brief Updates caller ID information from config */
- static int update_config(struct chan_list *ch, int orig)
- {
- struct ast_channel *ast;
- struct misdn_bchannel *bc;
- int port, hdlc = 0;
- int pres, screen;
- if (!ch) {
- ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
- return -1;
- }
- ast = ch->ast;
- bc = ch->bc;
- if (! ast || ! bc) {
- ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
- return -1;
- }
- port = bc->port;
- chan_misdn_log(7, port, "update_config: Getting Config\n");
- misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
-
- if (hdlc) {
- switch (bc->capability) {
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- case INFO_CAPABILITY_DIGITAL_RESTRICTED:
- chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
- bc->hdlc = 1;
- break;
- }
- }
- misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
- misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
- chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
-
- if (pres < 0 || screen < 0) {
- chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres);
-
- switch (ast->cid.cid_pres & 0x60) {
- case AST_PRES_RESTRICTED:
- bc->pres = 1;
- chan_misdn_log(2, port, " --> PRES: Restricted (1)\n");
- break;
- case AST_PRES_UNAVAILABLE:
- bc->pres = 2;
- chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n");
- break;
- default:
- bc->pres = 0;
- chan_misdn_log(2, port, " --> PRES: Allowed (0)\n");
- break;
- }
- switch (ast->cid.cid_pres & 0x3) {
- default:
- case AST_PRES_USER_NUMBER_UNSCREENED:
- bc->screen = 0;
- chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n");
- break;
- case AST_PRES_USER_NUMBER_PASSED_SCREEN:
- bc->screen = 1;
- chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n");
- break;
- case AST_PRES_USER_NUMBER_FAILED_SCREEN:
- bc->screen = 2;
- chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n");
- break;
- case AST_PRES_NETWORK_NUMBER:
- bc->screen = 3;
- chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n");
- break;
- }
- } else {
- bc->screen = screen;
- bc->pres = pres;
- }
- return 0;
- }
- static void config_jitterbuffer(struct chan_list *ch)
- {
- struct misdn_bchannel *bc = ch->bc;
- int len = ch->jb_len, threshold = ch->jb_upper_threshold;
-
- chan_misdn_log(5, bc->port, "config_jb: Called\n");
-
- if (! len) {
- chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
- bc->nojitter=1;
- } else {
- if (len <= 100 || len > 8000) {
- chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
- len = 1000;
- }
- if ( threshold > len ) {
- chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
- }
- if ( ch->jb) {
- cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
- misdn_jb_destroy(ch->jb);
- ch->jb = NULL;
- }
- ch->jb=misdn_jb_init(len, threshold);
- if (!ch->jb )
- bc->nojitter = 1;
- }
- }
- void debug_numplan(int port, int numplan, char *type)
- {
- switch (numplan) {
- case NUMPLAN_INTERNATIONAL:
- chan_misdn_log(2, port, " --> %s: International\n", type);
- break;
- case NUMPLAN_NATIONAL:
- chan_misdn_log(2, port, " --> %s: National\n", type);
- break;
- case NUMPLAN_SUBSCRIBER:
- chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
- break;
- case NUMPLAN_UNKNOWN:
- chan_misdn_log(2, port, " --> %s: Unknown\n", type);
- break;
- /* Maybe we should cut off the prefix if present ? */
- default:
- chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
- break;
- }
- }
- #ifdef MISDN_1_2
- static int update_pipeline_config(struct misdn_bchannel *bc)
- {
- int ec;
- misdn_cfg_get(bc->port, MISDN_CFG_PIPELINE, bc->pipeline, sizeof(bc->pipeline));
- if (*bc->pipeline)
- return 0;
- misdn_cfg_get(bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
- if (ec == 1)
- ast_copy_string(bc->pipeline, "mg2ec", sizeof(bc->pipeline));
- else if (ec > 1)
- snprintf(bc->pipeline, sizeof(bc->pipeline), "mg2ec(deftaps=%d)", ec);
- return 0;
- }
- #else
- static int update_ec_config(struct misdn_bchannel *bc)
- {
- int ec;
- int port = bc->port;
- misdn_cfg_get(port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
- if (ec == 1) {
- bc->ec_enable = 1;
- } else if (ec > 1) {
- bc->ec_enable = 1;
- bc->ec_deftaps = ec;
- }
- return 0;
- }
- #endif
- static int read_config(struct chan_list *ch, int orig)
- {
- struct ast_channel *ast;
- struct misdn_bchannel *bc;
- int port;
- int hdlc = 0;
- char lang[BUFFERSIZE + 1];
- char faxdetect[BUFFERSIZE + 1];
- char buf[256];
- char buf2[256];
- ast_group_t pg;
- ast_group_t cg;
- if (!ch) {
- ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
- return -1;
- }
- ast = ch->ast;
- bc = ch->bc;
- if (! ast || ! bc) {
- ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
- return -1;
- }
-
- port = bc->port;
- chan_misdn_log(1, port, "read_config: Getting Config\n");
- misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang));
- ast_string_field_set(ast, language, lang);
- misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));
- misdn_cfg_get(port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(bc->txgain));
- misdn_cfg_get(port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(bc->rxgain));
- misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(ch->incoming_early_audio));
- misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));
- misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
- if (ch->ast_dsp) {
- ch->ignore_dtmf = 1;
- }
- misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(bc->need_more_infos));
- misdn_cfg_get(port, MISDN_CFG_NTTIMEOUT, &ch->nttimeout, sizeof(ch->nttimeout));
- misdn_cfg_get(port, MISDN_CFG_NOAUTORESPOND_ON_SETUP, &ch->noautorespond_on_setup, sizeof(ch->noautorespond_on_setup));
- misdn_cfg_get(port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(ch->far_alerting));
- misdn_cfg_get(port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, sizeof(ch->allowed_bearers));
- misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));
- misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));
- if (hdlc) {
- switch (bc->capability) {
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- case INFO_CAPABILITY_DIGITAL_RESTRICTED:
- chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
- bc->hdlc = 1;
- break;
- }
-
- }
- /*Initialize new Jitterbuffer*/
- misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
- misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(ch->jb_upper_threshold));
- config_jitterbuffer(ch);
- misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));
- ast_copy_string(ast->context, ch->context, sizeof(ast->context));
- #ifdef MISDN_1_2
- update_pipeline_config(bc);
- #else
- update_ec_config(bc);
- #endif
- misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));
- misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
- misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
- chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
- ast->pickupgroup = pg;
- ast->callgroup = cg;
-
- if (orig == ORG_AST) {
- char callerid[BUFFERSIZE + 1];
- /* ORIGINATOR Asterisk (outgoing call) */
- misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(bc->te_choose_channel));
- if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
- if (strstr(faxdetect, "nojump"))
- ch->faxdetect = 2;
- else
- ch->faxdetect = 1;
- }
- misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
- if ( ! ast_strlen_zero(callerid) ) {
- chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid);
- ast_copy_string(bc->oad, callerid, sizeof(bc->oad));
- }
- misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(bc->dnumplan));
- misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(bc->onumplan));
- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
- debug_numplan(port, bc->dnumplan, "TON");
- debug_numplan(port, bc->onumplan, "LTON");
- debug_numplan(port, bc->cpnnumplan, "CTON");
- ch->overlap_dial = 0;
- } else {
- /* ORIGINATOR MISDN (incoming call) */
- char prefix[BUFFERSIZE + 1] = "";
- if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
- if (strstr(faxdetect, "nojump"))
- ch->faxdetect = 2;
- else
- ch->faxdetect = 1;
- }
- misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
- debug_numplan(port, bc->cpnnumplan, "CTON");
- switch (bc->onumplan) {
- case NUMPLAN_INTERNATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
- break;
- case NUMPLAN_NATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
- break;
- default:
- break;
- }
- ast_copy_string(buf, bc->oad, sizeof(buf));
- snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf);
- if (!ast_strlen_zero(bc->dad)) {
- ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad));
- }
- if ( ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) {
- ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad));
- }
- prefix[0] = 0;
- switch (bc->dnumplan) {
- case NUMPLAN_INTERNATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
- break;
- case NUMPLAN_NATIONAL:
- misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
- break;
- default:
- break;
- }
- ast_copy_string(buf, bc->dad, sizeof(buf));
- snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf);
- if (strcmp(bc->dad, ast->exten)) {
- ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten));
- }
- ast_set_callerid(ast, bc->oad, NULL, bc->oad);
- if ( !ast_strlen_zero(bc->rad) ) {
- if (ast->cid.cid_rdnis)
- ast_free(ast->cid.cid_rdnis);
- ast->cid.cid_rdnis = ast_strdup(bc->rad);
- }
-
- misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
- ast_mutex_init(&ch->overlap_tv_lock);
- } /* ORIG MISDN END */
- ch->overlap_dial_task = -1;
-
- if (ch->faxdetect || ch->ast_dsp) {
- misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
- if (!ch->dsp)
- ch->dsp = ast_dsp_new();
- if (ch->dsp) {
- if (ch->faxdetect)
- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
- else
- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT );
- }
- }
- /* AOCD initialization */
- bc->AOCDtype = Fac_None;
- return 0;
- }
- /*****************************/
- /*** AST Indications Start ***/
- /*****************************/
- static int misdn_call(struct ast_channel *ast, char *dest, int timeout)
- {
- int port = 0;
- int r;
- int exceed;
- int bridging;
- struct chan_list *ch;
- struct misdn_bchannel *newbc;
- char *opts, *ext;
- char *dest_cp;
- if (!ast) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
- return -1;
- }
- if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest ) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
- ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
- ch = MISDN_ASTERISK_TECH_PVT(ast);
- if (!ch) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
- ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- newbc = ch->bc;
- if (!newbc) {
- ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
- ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- /*
- * dest is ---v
- * Dial(mISDN/g:group_name[/extension[/options]])
- * Dial(mISDN/port[:preselected_channel][/extension[/options]])
- *
- * The dial extension could be empty if you are using MISDN_KEYPAD
- * to control ISDN provider features.
- */
- dest_cp = ast_strdupa(dest);
- strsep(&dest_cp, "/");/* Discard port/group token */
- ext = strsep(&dest_cp, "/");
- if (!ext) {
- ext = "";
- }
- opts = dest_cp;
-
- port = newbc->port;
- if ((exceed = add_out_calls(port))) {
- char tmp[16];
- snprintf(tmp, sizeof(tmp), "%d", exceed);
- pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
- return -1;
- }
-
- chan_misdn_log(1, port, "* CALL: %s\n", dest);
-
- chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context);
-
- chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten);
- if (ast->exten) {
- ast_copy_string(ast->exten, ext, sizeof(ast->exten));
- ast_copy_string(newbc->dad, ext, sizeof(newbc->dad));
- }
- ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));
- chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num);
- if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) {
- ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad));
- }
- newbc->capability = ast->transfercapability;
- pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
- if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
- chan_misdn_log(2, port, " --> * Call with flag Digital\n");
- }
- /* update screening and presentation */
- update_config(ch, ORG_AST);
-
- /* fill in some ies from channel vary*/
- import_ch(ast, newbc, ch);
- /* Finally The Options Override Everything */
- if (opts)
- misdn_set_opt_exec(ast, opts);
- else
- chan_misdn_log(2, port, "NO OPTS GIVEN\n");
- /*check for bridging*/
- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
- if (bridging && ch->other_ch) {
- #ifdef MISDN_1_2
- chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
- *ch->bc->pipeline = 0;
- *ch->other_ch->bc->pipeline = 0;
- #else
- chan_misdn_log(1, port, "Disabling EC on both Sides\n");
- ch->bc->ec_enable = 0;
- ch->other_ch->bc->ec_enable = 0;
- #endif
- }
- r = misdn_lib_send_event( newbc, EVENT_SETUP );
- /** we should have l3id after sending setup **/
- ch->l3id = newbc->l3_id;
- if ( r == -ENOCHAN ) {
- chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
- chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
- ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
- ast_setstate(ast, AST_STATE_DOWN);
- return -1;
- }
-
- chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1);
- ast_setstate(ast, AST_STATE_DIALING);
- ast->hangupcause = AST_CAUSE_NORMAL_CLEARING;
-
- if (newbc->nt)
- stop_bc_tones(ch);
- ch->state = MISDN_CALLING;
-
- return 0;
- }
- static int misdn_answer(struct ast_channel *ast)
- {
- struct chan_list *p;
- const char *tmp;
- if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) return -1;
-
- chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n");
-
- if (!p) {
- ast_log(LOG_WARNING, " --> Channel not connected ??\n");
- ast_queue_hangup_with_cause(ast, AST_CAUSE_NETWORK_OUT_OF_ORDER);
- }
- if (!p->bc) {
- chan_misdn_log(1, 0, " --> Got Answer, but there is no bc obj ??\n");
- ast_queue_hangup_with_cause(ast, AST_CAUSE_PROTOCOL_ERROR);
- }
- tmp = pbx_builtin_getvar_helper(p->ast, "CRYPT_KEY");
- if (!ast_strlen_zero(tmp)) {
- chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n");
- ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key));
- } else {
- chan_misdn_log(3, p->bc->port, " --> Connection is without BF encryption\n");
- }
- tmp = pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS");
- if (!ast_strlen_zero(tmp) && ast_true(tmp)) {
- chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n");
- p->bc->nodsp = 1;
- p->bc->hdlc = 0;
- p->bc->nojitter = 1;
- }
- p->state = MISDN_CONNECTED;
- stop_indicate(p);
- if ( ast_strlen_zero(p->bc->cad) ) {
- chan_misdn_log(2,p->bc->port," --> empty cad using dad\n");
- ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad));
- }
- misdn_lib_send_event( p->bc, EVENT_CONNECT);
- start_bc_tones(p);
- return 0;
- }
- static int misdn_digit_begin(struct ast_channel *chan, char digit)
- {
- /* XXX Modify this callback to support Asterisk controlling the length of DTMF */
- return 0;
- }
- static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
- {
- struct chan_list *p;
- struct misdn_bchannel *bc;
- char buf[2] = { digit, 0 };
-
- if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) return -1;
- bc = p->bc;
- chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
-
- if (!bc) {
- ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
- return -1;
- }
-
- switch (p->state ) {
- case MISDN_CALLING:
- if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1)
- strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1);
- break;
- case MISDN_CALLING_ACKNOWLEDGE:
- ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
- if (strlen(bc->dad) < sizeof(bc->dad) - 1)
- strncat(bc->dad, buf, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(p->ast->exten, bc->dad, sizeof(p->ast->exten));
- misdn_lib_send_event( bc, EVENT_INFORMATION);
- break;
- default:
- if ( bc->send_dtmf )
- send_digit_to_chan(p,digit);
- break;
- }
- return 0;
- }
- static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast)
- {
- struct chan_list *p;
- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast) )) return -1;
- chan_misdn_log(1, p->bc ? p->bc->port : 0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id);
- p->ast = ast;
- return 0;
- }
- static int misdn_indication(struct ast_channel *ast, int cond, const void *data, size_t datalen)
- {
- struct chan_list *p;
- if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) {
- ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
- return -1;
- }
-
- if (!p->bc) {
- if (p->hold.state == MISDN_HOLD_IDLE) {
- chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on %s\n", cond,
- ast->name);
- ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
- } else {
- chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on hold %s\n",
- cond, ast->name);
- }
- return -1;
- }
-
- chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] on %s\n\n", cond, ast->name);
-
- switch (cond) {
- case AST_CONTROL_BUSY:
- chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1);
- ast_setstate(ast, AST_STATE_BUSY);
- p->bc->out_cause = AST_CAUSE_USER_BUSY;
- if (p->state != MISDN_CONNECTED) {
- start_bc_tones(p);
- misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
- }
- return -1;
- case AST_CONTROL_RING:
- chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1);
- return -1;
- case AST_CONTROL_RINGING:
- chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
- switch (p->state) {
- case MISDN_ALERTING:
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1);
- break;
- case MISDN_CONNECTED:
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1);
- return -1;
- default:
- p->state = MISDN_ALERTING;
- chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
- misdn_lib_send_event( p->bc, EVENT_ALERTING);
- if (p->other_ch && p->other_ch->bc) {
- if (misdn_inband_avail(p->other_ch->bc)) {
- chan_misdn_log(2, p->bc->port, " --> other End is mISDN and has inband info available\n");
- break;
- }
- if (!p->other_ch->bc->nt) {
- chan_misdn_log(2, p->bc->port, " --> other End is mISDN TE so it has inband info for sure (?)\n");
- break;
- }
- }
- chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1);
- ast_setstate(ast, AST_STATE_RING);
- if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio)
- chan_misdn_log(2, p->bc->port, " --> incoming_early_audio off\n");
- else
- return -1;
- }
- break;
- case AST_CONTROL_ANSWER:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1);
- start_bc_tones(p);
- break;
- case AST_CONTROL_TAKEOFFHOOK:
- chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1);
- return -1;
- case AST_CONTROL_OFFHOOK:
- chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1);
- return -1;
- case AST_CONTROL_FLASH:
- chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1);
- break;
- case AST_CONTROL_PROGRESS:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1);
- misdn_lib_send_event( p->bc, EVENT_PROGRESS);
- break;
- case AST_CONTROL_PROCEEDING:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1);
- misdn_lib_send_event( p->bc, EVENT_PROCEEDING);
- break;
- case AST_CONTROL_CONGESTION:
- chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1);
- p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
- start_bc_tones(p);
- misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
- if (p->bc->nt) {
- hanguptone_indicate(p);
- }
- break;
- case -1 :
- chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1);
- stop_indicate(p);
- if (p->state == MISDN_CONNECTED)
- start_bc_tones(p);
- break;
- case AST_CONTROL_HOLD:
- ast_moh_start(ast, data, p->mohinterpret);
- chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
- break;
- case AST_CONTROL_UNHOLD:
- ast_moh_stop(ast);
- chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
- break;
- default:
- chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1);
- return -1;
- }
-
- return 0;
- }
- static int misdn_hangup(struct ast_channel *ast)
- {
- struct chan_list *p;
- struct misdn_bchannel *bc;
- const char *var;
- if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
- return -1;
- }
- MISDN_ASTERISK_TECH_PVT(ast) = NULL;
- ast_debug(1, "misdn_hangup(%s)\n", ast->name);
- if (p->hold.state == MISDN_HOLD_IDLE) {
- bc = p->bc;
- } else {
- p->hold.state = MISDN_HOLD_DISCONNECT;
- bc = misdn_lib_find_held_bc(p->hold.port, p->l3id);
- if (!bc) {
- chan_misdn_log(4, p->hold.port,
- "misdn_hangup: Could not find held bc for (%s)\n", ast->name);
- release_chan_early(p);
- return 0;
- }
- }
- if (ast->_state == AST_STATE_RESERVED || p->state == MISDN_NOTHING) {
- /* between request and call */
- ast_debug(1, "State Reserved (or nothing) => chanIsAvail\n");
- release_chan_early(p);
- if (bc) {
- misdn_lib_release(bc);
- }
- return 0;
- }
- if (!bc) {
- ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n",
- misdn_get_ch_state(p), p->l3id);
- release_chan_early(p);
- return 0;
- }
- p->ast = NULL;
- p->need_hangup = 0;
- p->need_queue_hangup = 0;
- p->need_busy = 0;
- if (!bc->nt) {
- stop_bc_tones(p);
- }
- bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;
- var = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE");
- if (!var) {
- var = pbx_builtin_getvar_helper(ast, "PRI_CAUSE");
- }
- if (var) {
- int tmpcause;
- tmpcause = atoi(var);
- bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
- }
- var = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
- if (var) {
- ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", var);
- ast_copy_string(bc->uu, var, sizeof(bc->uu));
- bc->uulen = strlen(bc->uu);
- }
- chan_misdn_log(1, bc->port,
- "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n",
- bc->pid,
- ast->context,
- ast->exten,
- ast->cid.cid_num,
- misdn_get_ch_state(p));
- chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
- chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
- chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);
- switch (p->state) {
- case MISDN_INCOMING_SETUP:
- /*
- * This is the only place in misdn_hangup, where we
- * can call release_chan, else it might create a lot of trouble.
- */
- ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
- release_chan(p, bc);
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
- return 0;
- case MISDN_DIALING:
- if (p->hold.state == MISDN_HOLD_IDLE) {
- start_bc_tones(p);
- hanguptone_indicate(p);
- }
- p->state = MISDN_CLEANING;
- if (bc->need_disconnect) {
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- break;
- case MISDN_CALLING_ACKNOWLEDGE:
- if (p->hold.state == MISDN_HOLD_IDLE) {
- start_bc_tones(p);
- hanguptone_indicate(p);
- }
- if (bc->need_disconnect) {
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- break;
- case MISDN_CALLING:
- case MISDN_ALERTING:
- case MISDN_PROGRESS:
- case MISDN_PROCEEDING:
- if (p->originator != ORG_AST && p->hold.state == MISDN_HOLD_IDLE) {
- hanguptone_indicate(p);
- }
- if (bc->need_disconnect) {
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- break;
- case MISDN_CONNECTED:
- /* Alerting or Disconnect */
- if (bc->nt && p->hold.state == MISDN_HOLD_IDLE) {
- start_bc_tones(p);
- hanguptone_indicate(p);
- bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
- }
- if (bc->need_disconnect) {
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- break;
- case MISDN_DISCONNECTED:
- if (bc->need_release) {
- misdn_lib_send_event(bc, EVENT_RELEASE);
- }
- break;
- case MISDN_CLEANING:
- return 0;
- case MISDN_BUSY:
- break;
- default:
- if (bc->nt) {
- bc->out_cause = -1;
- if (bc->need_release) {
- misdn_lib_send_event(bc, EVENT_RELEASE);
- }
- } else {
- if (bc->need_disconnect) {
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- }
- break;
- }
- p->state = MISDN_CLEANING;
- chan_misdn_log(3, bc->port, " --> Channel: %s hungup new state:%s\n", ast->name,
- misdn_get_ch_state(p));
- return 0;
- }
- static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame)
- {
- struct ast_frame *f;
-
- if (tmp->dsp) {
- f = ast_dsp_process(tmp->ast, tmp->dsp, frame);
- } else {
- chan_misdn_log(0, tmp->bc->port, "No DSP-Path found\n");
- return NULL;
- }
- if (!f || (f->frametype != AST_FRAME_DTMF)) {
- return f;
- }
-
- ast_debug(1, "Detected inband DTMF digit: %c\n", f->subclass);
-
- if (tmp->faxdetect && (f->subclass == 'f')) {
- /* Fax tone -- Handle and return NULL */
- if (!tmp->faxhandled) {
- struct ast_channel *ast = tmp->ast;
- tmp->faxhandled++;
- chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
- tmp->bc->rxgain = 0;
- isdn_lib_update_rxgain(tmp->bc);
- tmp->bc->txgain = 0;
- isdn_lib_update_txgain(tmp->bc);
- #ifdef MISDN_1_2
- *tmp->bc->pipeline = 0;
- #else
- tmp->bc->ec_enable = 0;
- #endif
- isdn_lib_update_ec(tmp->bc);
- isdn_lib_stop_dtmf(tmp->bc);
- switch (tmp->faxdetect) {
- case 1:
- if (strcmp(ast->exten, "fax")) {
- char *context;
- char context_tmp[BUFFERSIZE];
- misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
- context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
- if (ast_exists_extension(ast, context, "fax", 1, ast->cid.cid_num)) {
- ast_verb(3, "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
- /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
- pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
- if (ast_async_goto(ast, context, "fax", 1))
- ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
- } else
- ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten);
- } else {
- ast_debug(1, "Already in a fax extension, not redirecting\n");
- }
- break;
- case 2:
- ast_verb(3, "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
- break;
- }
- } else {
- ast_debug(1, "Fax already handled\n");
- }
- }
-
- if (tmp->ast_dsp && (f->subclass != 'f')) {
- chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass);
- }
- return f;
- }
- static struct ast_frame *misdn_read(struct ast_channel *ast)
- {
- struct chan_list *tmp;
- fd_set rrfs;
- struct timeval tv;
- int len, t;
- if (!ast) {
- chan_misdn_log(1, 0, "misdn_read called without ast\n");
- return NULL;
- }
- if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
- chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
- return NULL;
- }
- if (!tmp->bc && tmp->hold.state == MISDN_HOLD_IDLE) {
- chan_misdn_log(1, 0, "misdn_read called without bc\n");
- return NULL;
- }
- tv.tv_sec=0;
- tv.tv_usec=20000;
- FD_ZERO(&rrfs);
- FD_SET(tmp->pipe[0],&rrfs);
- t=select(FD_SETSIZE,&rrfs,NULL, NULL,&tv);
- if (!t) {
- chan_misdn_log(3, tmp->bc->port, "read Select Timed out\n");
- len=160;
- }
- if (t<0) {
- chan_misdn_log(-1, tmp->bc->port, "Select Error (err=%s)\n",strerror(errno));
- return NULL;
- }
- if (FD_ISSET(tmp->pipe[0],&rrfs)) {
- len=read(tmp->pipe[0],tmp->ast_rd_buf,sizeof(tmp->ast_rd_buf));
- if (len<=0) {
- /* we hangup here, since our pipe is closed */
- chan_misdn_log(2,tmp->bc->port,"misdn_read: Pipe closed, hanging up\n");
- return NULL;
- }
- } else {
- return NULL;
- }
- tmp->frame.frametype = AST_FRAME_VOICE;
- tmp->frame.subclass = AST_FORMAT_ALAW;
- tmp->frame.datalen = len;
- tmp->frame.samples = len;
- tmp->frame.mallocd = 0;
- tmp->frame.offset = 0;
- tmp->frame.delivery = ast_tv(0,0);
- tmp->frame.src = NULL;
- tmp->frame.data.ptr = tmp->ast_rd_buf;
- if (tmp->faxdetect && !tmp->faxhandled) {
- if (tmp->faxdetect_timeout) {
- if (ast_tvzero(tmp->faxdetect_tv)) {
- tmp->faxdetect_tv = ast_tvnow();
- chan_misdn_log(2, tmp->bc->port, "faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
- return process_ast_dsp(tmp, &tmp->frame);
- } else {
- struct timeval tv_now = ast_tvnow();
- int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
- if (diff <= (tmp->faxdetect_timeout * 1000)) {
- chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ...\n");
- return process_ast_dsp(tmp, &tmp->frame);
- } else {
- chan_misdn_log(2, tmp->bc->port, "faxdetect: stopping detection (time ran out) ...\n");
- tmp->faxdetect = 0;
- return &tmp->frame;
- }
- }
- } else {
- chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ... (no timeout)\n");
- return process_ast_dsp(tmp, &tmp->frame);
- }
- } else {
- if (tmp->ast_dsp)
- return process_ast_dsp(tmp, &tmp->frame);
- else
- return &tmp->frame;
- }
- }
- static int misdn_write(struct ast_channel *ast, struct ast_frame *frame)
- {
- struct chan_list *ch;
- int i = 0;
-
- if (!ast || ! (ch = MISDN_ASTERISK_TECH_PVT(ast)) ) return -1;
- if (ch->hold.state != MISDN_HOLD_IDLE) {
- chan_misdn_log(7, 0, "misdn_write: Returning because hold active\n");
- return 0;
- }
-
- if (!ch->bc ) {
- ast_log(LOG_WARNING, "private but no bc\n");
- return -1;
- }
-
- if (ch->notxtone) {
- chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
- return 0;
- }
- if (!frame->subclass) {
- chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
- return 0;
- }
-
- if (!(frame->subclass & prefformat)) {
-
- chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass);
- return 0;
- }
-
- if (!frame->samples ) {
- chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
-
- if (!strcmp(frame->src,"ast_prod")) {
- chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));
- if (ch->ts) {
- chan_misdn_log(4, ch->bc->port, "Starting Playtones\n");
- misdn_lib_tone_generator_start(ch->bc);
- }
- return 0;
- }
- return -1;
- }
- if ( ! ch->bc->addr ) {
- chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
- return 0;
- }
-
- #ifdef MISDN_DEBUG
- {
- int i, max = 5 > frame->samples ? frame->samples : 5;
- ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);
- for (i = 0; i < max ; i++)
- ast_debug(1, "%2.2x ", ((char*) frame->data.ptr)[i]);
- }
- #endif
- switch (ch->bc->bc_state) {
- case BCHAN_ACTIVATED:
- case BCHAN_BRIDGED:
- break;
- default:
- if (!ch->dropped_frame_cnt)
- chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n", frame->samples, ch->bc->addr, ast->exten, ast->cid.cid_num, misdn_get_ch_state( ch), ch->bc->bc_state, ch->bc->l3_id);
-
- ch->dropped_frame_cnt++;
- if (ch->dropped_frame_cnt > 100) {
- ch->dropped_frame_cnt = 0;
- chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x dropped > 100 frames!\n", frame->samples, ch->bc->addr);
- }
- return 0;
- }
- chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples);
- if ( !ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability) ) {
- /* Buffered Transmit (triggered by read from isdn side)*/
- if (misdn_jb_fill(ch->jb, frame->data.ptr, frame->samples) < 0) {
- if (ch->bc->active)
- cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
- }
-
- } else {
- /*transmit without jitterbuffer*/
- i = misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples);
- }
- return 0;
- }
- static enum ast_bridge_result misdn_bridge (struct ast_channel *c0,
- struct ast_channel *c1, int flags,
- struct ast_frame **fo,
- struct ast_channel **rc,
- int timeoutms)
- {
- struct chan_list *ch1, *ch2;
- struct ast_channel *carr[2], *who;
- int to = -1;
- struct ast_frame *f;
- int p1_b, p2_b;
- int bridging;
-
- ch1 = get_chan_by_ast(c0);
- ch2 = get_chan_by_ast(c1);
- carr[0] = c0;
- carr[1] = c1;
-
- if (!(ch1 && ch2))
- return -1;
- misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b));
- misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b));
- if (! p1_b || ! p2_b) {
- ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
- return AST_BRIDGE_FAILED;
- }
- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
- if (bridging) {
- /* trying to make a mISDN_dsp conference */
- chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
- misdn_lib_bridge(ch1->bc, ch2->bc);
- }
- ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
- chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad);
-
- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) )
- ch1->ignore_dtmf = 1;
- if (! (flags & AST_BRIDGE_DTMF_CHANNEL_1) )
- ch2->ignore_dtmf = 1;
- for (;/*ever*/;) {
- to = -1;
- who = ast_waitfor_n(carr, 2, &to);
- if (!who) {
- ast_log(LOG_NOTICE, "misdn_bridge: empty read, breaking out\n");
- break;
- }
- f = ast_read(who);
- if (!f || f->frametype == AST_FRAME_CONTROL) {
- /* got hangup .. */
- if (!f)
- chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
- else
- chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass);
- *fo = f;
- *rc = who;
- break;
- }
-
- if ( f->frametype == AST_FRAME_DTMF ) {
- chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass, who->exten);
- *fo = f;
- *rc = who;
- break;
- }
-
- #if 0
- if (f->frametype == AST_FRAME_VOICE) {
- chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
-
- continue;
- }
- #endif
- if (who == c0) {
- ast_write(c1, f);
- }
- else {
- ast_write(c0, f);
- }
- }
- chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);
- misdn_lib_split_bridge(ch1->bc, ch2->bc);
- return AST_BRIDGE_COMPLETE;
- }
- /** AST INDICATIONS END **/
- static int dialtone_indicate(struct chan_list *cl)
- {
- const struct tone_zone_sound *ts = NULL;
- struct ast_channel *ast = cl->ast;
- int nd = 0;
- if (!ast) {
- chan_misdn_log(0, cl->bc->port, "No Ast in dialtone_indicate\n");
- return -1;
- }
- misdn_cfg_get(cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd));
- if (nd) {
- chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
- return 0;
- }
-
- chan_misdn_log(3, cl->bc->port, " --> Dial\n");
- ts = ast_get_indication_tone(ast->zone, "dial");
- cl->ts = ts;
-
- if (ts) {
- cl->notxtone = 0;
- cl->norxtone = 0;
- /* This prods us in misdn_write */
- ast_playtones_start(ast, 0, ts->data, 0);
- }
- return 0;
- }
- static void hanguptone_indicate(struct chan_list *cl)
- {
- misdn_lib_send_tone(cl->bc, TONE_HANGUP);
- }
- static int stop_indicate(struct chan_list *cl)
- {
- struct ast_channel *ast = cl->ast;
- if (!ast) {
- chan_misdn_log(0, cl->bc->port, "No Ast in stop_indicate\n");
- return -1;
- }
- chan_misdn_log(3, cl->bc->port, " --> None\n");
- misdn_lib_tone_generator_stop(cl->bc);
- ast_playtones_stop(ast);
- cl->ts = NULL;
- /*ast_deactivate_generator(ast);*/
- return 0;
- }
- static int start_bc_tones(struct chan_list* cl)
- {
- misdn_lib_tone_generator_stop(cl->bc);
- cl->notxtone = 0;
- cl->norxtone = 0;
- return 0;
- }
- static int stop_bc_tones(struct chan_list *cl)
- {
- if (!cl) return -1;
- cl->notxtone = 1;
- cl->norxtone = 1;
-
- return 0;
- }
- static struct chan_list *init_chan_list(int orig)
- {
- struct chan_list *cl;
- cl = ast_calloc(1, sizeof(*cl));
- if (!cl) {
- chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
- return NULL;
- }
-
- cl->originator = orig;
- cl->need_queue_hangup = 1;
- cl->need_hangup = 1;
- cl->need_busy = 1;
- cl->overlap_dial_task = -1;
- return cl;
- }
- static struct ast_channel *misdn_request(const char *type, int format, void *data, int *cause)
- {
- struct ast_channel *tmp = NULL;
- char group[BUFFERSIZE + 1] = "";
- char dial_str[128];
- char *buf2 = ast_strdupa(data);
- char *ext;
- char *port_str;
- char *p = NULL;
- int channel = 0;
- int port = 0;
- struct misdn_bchannel *newbc = NULL;
- int dec = 0;
- struct chan_list *cl;
- snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);
- /*
- * data is ---v
- * Dial(mISDN/g:group_name[/extension[/options]])
- * Dial(mISDN/port[:preselected_channel][/extension[/options]])
- *
- * The dial extension could be empty if you are using MISDN_KEYPAD
- * to control ISDN provider features.
- */
- port_str = strsep(&buf2, "/");
- if (!ast_strlen_zero(port_str)) {
- if (port_str[0] == 'g' && port_str[1] == ':' ) {
- /* We make a group call lets checkout which ports are in my group */
- port_str += 2;
- ast_copy_string(group, port_str, sizeof(group));
- chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
- } else if ((p = strchr(port_str, ':'))) {
- /* we have a preselected channel */
- *p = 0;
- channel = atoi(++p);
- port = atoi(port_str);
- chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
- } else {
- port = atoi(port_str);
- }
- } else {
- ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
- return NULL;
- }
- ext = strsep(&buf2, "/");
- if (!ext) {
- ext = "";
- }
- if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
- chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
- dec = 1;
- }
- if (!ast_strlen_zero(group)) {
- char cfg_group[BUFFERSIZE + 1];
- struct robin_list *rr = NULL;
- /* Group dial */
- if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) {
- chan_misdn_log(4, port, " --> STARTING ROUND ROBIN...\n");
- rr = get_robin_position(group);
- }
- if (rr) {
- int robin_channel = rr->channel;
- int port_start;
- int next_chan = 1;
- do {
- port_start = 0;
- for (port = misdn_cfg_get_next_port_spin(rr->port); port > 0 && port != port_start;
- port = misdn_cfg_get_next_port_spin(port)) {
- if (!port_start)
- port_start = port;
- if (port >= port_start)
- next_chan = 1;
-
- if (port <= port_start && next_chan) {
- int maxbchans=misdn_lib_get_maxchans(port);
- if (++robin_channel >= maxbchans) {
- robin_channel = 1;
- }
- next_chan = 0;
- }
- misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
- if (!strcasecmp(cfg_group, group)) {
- int port_up;
- int check;
- misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
- port_up = misdn_lib_port_up(port, check);
- if (check && !port_up)
- chan_misdn_log(1, port, "L1 is not Up on this Port\n");
-
- if (check && port_up < 0) {
- ast_log(LOG_WARNING, "This port (%d) is blocked\n", port);
- }
- if (port_up > 0) {
- newbc = misdn_lib_get_free_bc(port, robin_channel, 0, 0);
- if (newbc) {
- chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
- if (port_up)
- chan_misdn_log(4, port, "portup:%d\n", port_up);
- rr->port = newbc->port;
- rr->channel = newbc->channel;
- break;
- }
- }
- }
- }
- } while (!newbc && robin_channel != rr->channel);
-
- } else {
- for (port = misdn_cfg_get_next_port(0); port > 0;
- port = misdn_cfg_get_next_port(port)) {
- misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
- chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
- if (!strcasecmp(cfg_group, group)) {
- int port_up;
- int check;
- misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
- port_up = misdn_lib_port_up(port, check);
- chan_misdn_log(4, port, "portup:%d\n", port_up);
- if (port_up > 0) {
- newbc = misdn_lib_get_free_bc(port, 0, 0, dec);
- if (newbc)
- break;
- }
- }
- }
- }
-
- /* Group dial failed ?*/
- if (!newbc) {
- ast_log(LOG_WARNING,
- "Could not Dial out on group '%s'.\n"
- "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
- "\tOr there was no free channel on none of the ports\n\n"
- , group);
- return NULL;
- }
- } else {
- /* 'Normal' Port dial * Port dial */
- if (channel)
- chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
- newbc = misdn_lib_get_free_bc(port, channel, 0, dec);
- if (!newbc) {
- ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext);
- return NULL;
- }
- }
-
- /* create ast_channel and link all the objects together */
- cl = init_chan_list(ORG_AST);
- if (!cl) {
- ast_log(LOG_ERROR, "Could not create call record for Dial(%s)\n", dial_str);
- return NULL;
- }
- cl->bc = newbc;
-
- tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel);
- if (!tmp) {
- ast_free(cl);
- ast_log(LOG_ERROR,"Could not create Asterisk object\n");
- return NULL;
- }
- cl->ast=tmp;
-
- /* register chan in local list */
- cl_queue_chan(&cl_te, cl) ;
-
- /* fill in the config into the objects */
- read_config(cl, ORG_AST);
- /* important */
- cl->need_hangup = 0;
-
- return tmp;
- }
- static int misdn_send_text(struct ast_channel *chan, const char *text)
- {
- struct chan_list *tmp = chan->tech_pvt;
-
- if (tmp && tmp->bc) {
- ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
- misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
- } else {
- ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
- return -1;
- }
-
- return 0;
- }
- static struct ast_channel_tech misdn_tech = {
- .type = "mISDN",
- .description = "Channel driver for mISDN Support (Bri/Pri)",
- .capabilities = AST_FORMAT_ALAW ,
- .requester = misdn_request,
- .send_digit_begin = misdn_digit_begin,
- .send_digit_end = misdn_digit_end,
- .call = misdn_call,
- .bridge = misdn_bridge,
- .hangup = misdn_hangup,
- .answer = misdn_answer,
- .read = misdn_read,
- .write = misdn_write,
- .indicate = misdn_indication,
- .fixup = misdn_fixup,
- .send_text = misdn_send_text,
- .properties = 0
- };
- static struct ast_channel_tech misdn_tech_wo_bridge = {
- .type = "mISDN",
- .description = "Channel driver for mISDN Support (Bri/Pri)",
- .capabilities = AST_FORMAT_ALAW ,
- .requester = misdn_request,
- .send_digit_begin = misdn_digit_begin,
- .send_digit_end = misdn_digit_end,
- .call = misdn_call,
- .hangup = misdn_hangup,
- .answer = misdn_answer,
- .read = misdn_read,
- .write = misdn_write,
- .indicate = misdn_indication,
- .fixup = misdn_fixup,
- .send_text = misdn_send_text,
- .properties = 0
- };
- static int glob_channel = 0;
- static void update_name(struct ast_channel *tmp, int port, int c)
- {
- int chan_offset = 0;
- int tmp_port = misdn_cfg_get_next_port(0);
- char newname[255];
- for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
- if (tmp_port == port)
- break;
- chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
- }
- if (c < 0)
- c = 0;
- snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c);
- if (strncmp(tmp->name, newname, strlen(newname))) {
- snprintf(newname, sizeof(newname), "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
- ast_change_name(tmp, newname);
- chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
- }
- }
- static struct ast_channel *misdn_new(struct chan_list *chlist, int state, char *exten, char *callerid, int format, int port, int c)
- {
- struct ast_channel *tmp;
- char *cid_name = 0, *cid_num = 0;
- int chan_offset = 0;
- int tmp_port = misdn_cfg_get_next_port(0);
- int bridging;
- for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
- if (tmp_port == port)
- break;
- chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
- }
- if (c < 0)
- c = 0;
- if (callerid) {
- ast_callerid_parse(callerid, &cid_name, &cid_num);
- }
- tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
- if (tmp) {
- chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid);
- tmp->nativeformats = prefformat;
- tmp->readformat = format;
- tmp->rawreadformat = format;
- tmp->writeformat = format;
- tmp->rawwriteformat = format;
-
- tmp->tech_pvt = chlist;
- misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
- if (bridging)
- tmp->tech = &misdn_tech;
- else
- tmp->tech = &misdn_tech_wo_bridge;
- tmp->writeformat = format;
- tmp->readformat = format;
- tmp->priority=1;
- if (exten)
- ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
- else
- chan_misdn_log(1, 0, "misdn_new: no exten given.\n");
- if (callerid)
- /* Don't use ast_set_callerid() here because it will
- * generate a needless NewCallerID event */
- tmp->cid.cid_ani = ast_strdup(cid_num);
- if (pipe(chlist->pipe) < 0)
- ast_log(LOG_ERROR, "Pipe failed\n");
- ast_channel_set_fd(tmp, 0, chlist->pipe[0]);
- if (state == AST_STATE_RING)
- tmp->rings = 1;
- else
- tmp->rings = 0;
-
- ast_jb_configure(tmp, misdn_get_global_jbconf());
- } else {
- chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
- }
-
- return tmp;
- }
- static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc)
- {
- struct chan_list *help = list;
- for (; help; help = help->next) {
- if (help->bc == bc) return help;
- }
- chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
- return NULL;
- }
- static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid)
- {
- struct chan_list *help = list;
- for (; help; help = help->next) {
- if ( help->bc && (help->bc->pid == pid) ) return help;
- }
- chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid);
- return NULL;
- }
- static struct chan_list *find_hold_call(struct chan_list *list, struct misdn_bchannel *bc)
- {
- struct chan_list *help = list;
- if (bc->pri) return NULL;
- chan_misdn_log(6, bc->port, "$$$ find_hold_call: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
- for (;help; help = help->next) {
- chan_misdn_log(4, bc->port, "$$$ find_hold_call: --> hold:%d channel:%d\n", help->hold.state, help->hold.channel);
- if (help->hold.state == MISDN_HOLD_ACTIVE && help->hold.port == bc->port)
- return help;
- }
- chan_misdn_log(6, bc->port, "$$$ find_hold_call: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);
- return NULL;
- }
- static struct chan_list *find_hold_call_l3(struct chan_list *list, unsigned long l3_id)
- {
- struct chan_list *help = list;
- for (; help; help = help->next) {
- if (help->hold.state != MISDN_HOLD_IDLE && help->l3id == l3_id)
- return help;
- }
- return NULL;
- }
- #define TRANSFER_ON_HELD_CALL_HANGUP 1
- #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
- /*!
- * \internal
- * \brief Find a suitable active call to go with a held call so we could try a transfer.
- *
- * \param list Channel list.
- * \param bc B channel record.
- *
- * \return Found call record or NULL.
- *
- * \note There could be a possibility where we find the wrong active call to transfer.
- * This concern is mitigated by the fact that there could be at most one other call
- * on a PTMP BRI link to another device. Maybe the l3_id could help in locating an
- * active call on the same TEI?
- */
- static struct chan_list *find_hold_active_call(struct chan_list *list, struct misdn_bchannel *bc)
- {
- for (; list; list = list->next) {
- if (list->hold.state == MISDN_HOLD_IDLE && list->bc && list->bc->port == bc->port
- && list->ast) {
- switch (list->state) {
- case MISDN_PROCEEDING:
- case MISDN_PROGRESS:
- case MISDN_ALERTING:
- case MISDN_CONNECTED:
- return list;
- default:
- break;
- }
- }
- }
- return NULL;
- }
- #endif /* defined(TRANSFER_ON_HELD_CALL_HANGUP) */
- static void cl_queue_chan(struct chan_list **list, struct chan_list *chan)
- {
- chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
-
- ast_mutex_lock(&cl_te_lock);
- if (!*list) {
- *list = chan;
- } else {
- struct chan_list *help = *list;
- for (; help->next; help = help->next);
- help->next = chan;
- }
- chan->next = NULL;
- ast_mutex_unlock(&cl_te_lock);
- }
- static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan)
- {
- struct chan_list *help;
- if (chan->dsp)
- ast_dsp_free(chan->dsp);
- ast_mutex_lock(&cl_te_lock);
- if (!*list) {
- ast_mutex_unlock(&cl_te_lock);
- return;
- }
-
- if (*list == chan) {
- *list = (*list)->next;
- ast_mutex_unlock(&cl_te_lock);
- return;
- }
-
- for (help = *list; help->next; help = help->next) {
- if (help->next == chan) {
- help->next = help->next->next;
- ast_mutex_unlock(&cl_te_lock);
- return;
- }
- }
-
- ast_mutex_unlock(&cl_te_lock);
- }
- /** Channel Queue End **/
- static int pbx_start_chan(struct chan_list *ch)
- {
- int ret = ast_pbx_start(ch->ast);
- if (ret >= 0)
- ch->need_hangup = 0;
- else
- ch->need_hangup = 1;
- return ret;
- }
- static void hangup_chan(struct chan_list *ch, struct misdn_bchannel *bc)
- {
- int port;
- if (!ch) {
- cb_log(1, 0, "Cannot hangup chan, no ch\n");
- return;
- }
- port = bc->port;
- cb_log(5, port, "hangup_chan called\n");
- if (ch->need_hangup) {
- cb_log(2, port, " --> hangup\n");
- ch->need_hangup = 0;
- ch->need_queue_hangup = 0;
- if (ch->ast) {
- send_cause2ast(ch->ast, bc, ch);
- ast_hangup(ch->ast);
- }
- return;
- }
- if (!ch->need_queue_hangup) {
- cb_log(2, port, " --> No need to queue hangup\n");
- }
- ch->need_queue_hangup = 0;
- if (ch->ast) {
- send_cause2ast(ch->ast, bc, ch);
- ast_queue_hangup_with_cause(ch->ast, bc->cause);
- cb_log(2, port, " --> queue_hangup\n");
- } else {
- cb_log(1, port, "Cannot hangup chan, no ast\n");
- }
- }
- /*!
- * \internal
- * \brief ISDN asked us to release channel, pendant to misdn_hangup.
- *
- * \param ch Call channel record to release.
- * \param bc Current B channel record associated with ch.
- *
- * \return Nothing
- *
- * \note ch must not be referenced after calling.
- */
- static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc)
- {
- struct ast_channel *ast;
- ch->state = MISDN_CLEANING;
- ast_mutex_lock(&release_lock);
- cl_dequeue_chan(&cl_te, ch);
- chan_misdn_log(5, bc->port, "release_chan: bc with pid:%d l3id: %x\n", bc->pid, bc->l3_id);
- /* releasing jitterbuffer */
- if (ch->jb) {
- misdn_jb_destroy(ch->jb);
- ch->jb = NULL;
- } else {
- if (!bc->nojitter) {
- chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n");
- }
- }
- if (ch->overlap_dial) {
- if (ch->overlap_dial_task != -1) {
- misdn_tasks_remove(ch->overlap_dial_task);
- ch->overlap_dial_task = -1;
- }
- ast_mutex_destroy(&ch->overlap_tv_lock);
- }
- if (ch->originator == ORG_AST) {
- --misdn_out_calls[bc->port];
- } else {
- --misdn_in_calls[bc->port];
- }
- close(ch->pipe[0]);
- close(ch->pipe[1]);
- ast = ch->ast;
- if (ast) {
- MISDN_ASTERISK_TECH_PVT(ast) = NULL;
- chan_misdn_log(1, bc->port,
- "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s\n",
- bc->pid,
- ast->context,
- ast->exten,
- ast->cid.cid_num);
- if (ast->_state != AST_STATE_RESERVED) {
- chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
- ast_setstate(ast, AST_STATE_DOWN);
- }
- }
- ast_free(ch);
- ast_mutex_unlock(&release_lock);
- }
- /*!
- * \internal
- * \brief Do everything in release_chan() that makes sense without a bc.
- *
- * \param ch Call channel record to release.
- *
- * \return Nothing
- *
- * \note ch must not be referenced after calling.
- */
- static void release_chan_early(struct chan_list *ch)
- {
- struct ast_channel *ast;
- ch->state = MISDN_CLEANING;
- ast_mutex_lock(&release_lock);
- cl_dequeue_chan(&cl_te, ch);
- /* releasing jitterbuffer */
- if (ch->jb) {
- misdn_jb_destroy(ch->jb);
- ch->jb = NULL;
- }
- if (ch->overlap_dial) {
- if (ch->overlap_dial_task != -1) {
- misdn_tasks_remove(ch->overlap_dial_task);
- ch->overlap_dial_task = -1;
- }
- ast_mutex_destroy(&ch->overlap_tv_lock);
- }
- if (ch->hold.state != MISDN_HOLD_IDLE) {
- if (ch->originator == ORG_AST) {
- --misdn_out_calls[ch->hold.port];
- } else {
- --misdn_in_calls[ch->hold.port];
- }
- }
- close(ch->pipe[0]);
- close(ch->pipe[1]);
- ast = ch->ast;
- if (ast) {
- MISDN_ASTERISK_TECH_PVT(ast) = NULL;
- if (ast->_state != AST_STATE_RESERVED) {
- ast_setstate(ast, AST_STATE_DOWN);
- }
- }
- ast_free(ch);
- ast_mutex_unlock(&release_lock);
- }
- /*!
- * \internal
- * \brief Attempt to transfer the active channel party to the held channel party.
- *
- * \param active_ch Channel currently connected.
- * \param held_ch Channel currently on hold.
- *
- * \retval 0 on success.
- * \retval -1 on error.
- */
- static int misdn_attempt_transfer(struct chan_list *active_ch, struct chan_list *held_ch)
- {
- int retval;
- struct ast_channel *bridged;
- switch (active_ch->state) {
- case MISDN_PROCEEDING:
- case MISDN_PROGRESS:
- case MISDN_ALERTING:
- case MISDN_CONNECTED:
- break;
- default:
- return -1;
- }
- bridged = ast_bridged_channel(held_ch->ast);
- if (bridged) {
- ast_queue_control(held_ch->ast, AST_CONTROL_UNHOLD);
- held_ch->hold.state = MISDN_HOLD_TRANSFER;
- chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
- held_ch->ast->name, active_ch->ast->name);
- retval = ast_channel_masquerade(active_ch->ast, bridged);
- } else {
- /*
- * Could not transfer. Held channel is not bridged anymore.
- * Held party probably got tired of waiting and hung up.
- */
- retval = -1;
- }
- return retval;
- }
- static void do_immediate_setup(struct misdn_bchannel *bc, struct chan_list *ch, struct ast_channel *ast)
- {
- char *predial;
- struct ast_frame fr;
- predial = ast_strdupa(ast->exten);
- ch->state = MISDN_DIALING;
- if (!ch->noautorespond_on_setup) {
- if (bc->nt) {
- int ret;
- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- } else {
- int ret;
- if ( misdn_lib_is_ptp(bc->port)) {
- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- } else {
- ret = misdn_lib_send_event(bc, EVENT_PROCEEDING );
- }
- }
- } else {
- ch->state = MISDN_INCOMING_SETUP;
- }
- chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num);
-
- strcpy(ast->exten, "s");
-
- if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->oad) || pbx_start_chan(ch) < 0) {
- ast = NULL;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- hangup_chan(ch, bc);
- hanguptone_indicate(ch);
- if (bc->nt)
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
- else
- misdn_lib_send_event(bc, EVENT_DISCONNECT );
- }
-
-
- while (!ast_strlen_zero(predial) ) {
- fr.frametype = AST_FRAME_DTMF;
- fr.subclass = *predial;
- fr.src = NULL;
- fr.data.ptr = NULL;
- fr.datalen = 0;
- fr.samples = 0;
- fr.mallocd = 0;
- fr.offset = 0;
- fr.delivery = ast_tv(0,0);
- if (ch->ast && MISDN_ASTERISK_PVT(ch->ast) && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
- ast_queue_frame(ch->ast, &fr);
- }
- predial++;
- }
- }
- static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch) {
- if (!ast) {
- chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
- return;
- }
- if (!bc) {
- chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
- return;
- }
- if (!ch) {
- chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
- return;
- }
- ast->hangupcause = bc->cause;
- switch (bc->cause) {
- case AST_CAUSE_UNALLOCATED:
- case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
- case AST_CAUSE_NO_ROUTE_DESTINATION:
- case 4: /* Send special information tone */
- case AST_CAUSE_NUMBER_CHANGED:
- case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
- /* Congestion Cases */
- /*
- * Not Queueing the Congestion anymore, since we want to hear
- * the inband message
- *
- chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Congestion pid:%d\n", bc ? bc->pid : -1);
- ch->state = MISDN_BUSY;
-
- ast_queue_control(ast, AST_CONTROL_CONGESTION);
- */
- break;
- case AST_CAUSE_CALL_REJECTED:
- case AST_CAUSE_USER_BUSY:
- ch->state = MISDN_BUSY;
- if (!ch->need_busy) {
- chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
- break;
- }
- chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
-
- ast_queue_control(ast, AST_CONTROL_BUSY);
-
- ch->need_busy = 0;
-
- break;
- }
- }
- /*! \brief Import parameters from the dialplan environment variables */
- void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
- {
- const char *tmp;
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_PID");
- if (tmp) {
- ch->other_pid = atoi(tmp);
- chan_misdn_log(3, bc->port, " --> IMPORT_PID: importing pid:%s\n", tmp);
- if (ch->other_pid > 0) {
- ch->other_ch = find_chan_by_pid(cl_te, ch->other_pid);
- if (ch->other_ch)
- ch->other_ch->other_ch = ch;
- }
- }
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_ADDRESS_COMPLETE");
- if (tmp && (atoi(tmp) == 1)) {
- bc->sending_complete = 1;
- }
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_USERUSER");
- if (tmp) {
- ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
- ast_copy_string(bc->uu, tmp, sizeof(bc->uu));
- bc->uulen = strlen(bc->uu);
- }
- tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD");
- if (tmp) {
- ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad));
- }
- }
- /*! \brief Export parameters to the dialplan environment variables */
- void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
- {
- char tmp[32];
- chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
- snprintf(tmp, sizeof(tmp), "%d", bc->pid);
- pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);
- if (bc->sending_complete) {
- snprintf(tmp, sizeof(tmp), "%d", bc->sending_complete);
- pbx_builtin_setvar_helper(chan, "MISDN_ADDRESS_COMPLETE", tmp);
- }
- if (bc->urate) {
- snprintf(tmp, sizeof(tmp), "%d", bc->urate);
- pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp);
- }
- if (bc->uulen)
- pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu);
- if (!ast_strlen_zero(bc->keypad))
- pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad);
- }
- int add_in_calls(int port)
- {
- int max_in_calls;
-
- misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
- misdn_in_calls[port]++;
- if (max_in_calls >= 0 && max_in_calls < misdn_in_calls[port]) {
- ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
- return misdn_in_calls[port] - max_in_calls;
- }
-
- return 0;
- }
- int add_out_calls(int port)
- {
- int max_out_calls;
-
- misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));
- if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
- ast_log(LOG_NOTICE, "Rejecting Outgoing Call on port[%d]\n", port);
- return (misdn_out_calls[port] + 1) - max_out_calls;
- }
- misdn_out_calls[port]++;
-
- return 0;
- }
- static void start_pbx(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
- if (pbx_start_chan(ch) < 0) {
- hangup_chan(ch, bc);
- chan_misdn_log(-1, bc->port, "ast_pbx_start returned <0 in SETUP\n");
- if (bc->nt) {
- hanguptone_indicate(ch);
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
- } else
- misdn_lib_send_event(bc, EVENT_RELEASE);
- }
- }
- static void wait_for_digits(struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan) {
- ch->state=MISDN_WAITING4DIGS;
- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- if (bc->nt && !bc->dad[0])
- dialtone_indicate(ch);
- }
- /************************************************************/
- /* Receive Events from isdn_lib here */
- /************************************************************/
- static enum event_response_e
- cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
- {
- int msn_valid;
- struct chan_list *held_ch;
- struct chan_list *ch = find_chan_by_bc(cl_te, bc);
-
- if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /* Debug Only Non-Bchan */
- int debuglevel = 1;
- if ( event == EVENT_CLEANUP && !user_data)
- debuglevel = 5;
- chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none");
- if (debuglevel == 1) {
- misdn_lib_log_ies(bc);
- chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
- }
- }
-
- if (!ch) {
- switch(event) {
- case EVENT_SETUP:
- case EVENT_DISCONNECT:
- case EVENT_RELEASE:
- case EVENT_RELEASE_COMPLETE:
- case EVENT_PORT_ALARM:
- case EVENT_RETRIEVE:
- case EVENT_NEW_BC:
- case EVENT_FACILITY:
- break;
- case EVENT_CLEANUP:
- case EVENT_TONE_GENERATE:
- case EVENT_BCHAN_DATA:
- return -1;
- default:
- chan_misdn_log(1, bc->port, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n", bc->l3_id, bc, manager_isdn_get_info(event), bc->port, bc->channel);
- return -1;
- }
- }
-
- if (ch) {
- switch (event) {
- case EVENT_TONE_GENERATE:
- break;
- case EVENT_DISCONNECT:
- case EVENT_RELEASE:
- case EVENT_RELEASE_COMPLETE:
- case EVENT_CLEANUP:
- case EVENT_TIMEOUT:
- if (!ch->ast)
- chan_misdn_log(3, bc->port, "ast_hangup already called, so we have no ast ptr anymore in event(%s)\n", manager_isdn_get_info(event));
- break;
- default:
- if (!ch->ast || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
- if (event != EVENT_BCHAN_DATA)
- ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
- return -1;
- }
- }
- }
-
-
- switch (event) {
- case EVENT_PORT_ALARM:
- {
- int boa = 0;
- misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(boa));
- if (boa) {
- cb_log(1, bc->port, " --> blocking\n");
- misdn_lib_port_block(bc->port);
- }
- }
- break;
- case EVENT_BCHAN_ACTIVATED:
- break;
-
- case EVENT_NEW_CHANNEL:
- update_name(ch->ast,bc->port,bc->channel);
- break;
-
- case EVENT_NEW_L3ID:
- ch->l3id=bc->l3_id;
- ch->addr=bc->addr;
- break;
- case EVENT_NEW_BC:
- if (!ch) {
- ch = find_hold_call(cl_te,bc);
- }
-
- if (!ch) {
- ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
- break;
- }
- if (bc)
- ch->bc = (struct misdn_bchannel *)user_data;
- break;
-
- case EVENT_DTMF_TONE:
- {
- /* sending INFOS as DTMF-Frames :) */
- struct ast_frame fr;
- memset(&fr, 0, sizeof(fr));
- fr.frametype = AST_FRAME_DTMF;
- fr.subclass = bc->dtmf ;
- fr.src = NULL;
- fr.data.ptr = NULL;
- fr.datalen = 0;
- fr.samples = 0;
- fr.mallocd = 0;
- fr.offset = 0;
- fr.delivery = ast_tv(0,0);
-
- if (!ch->ignore_dtmf) {
- chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
- ast_queue_frame(ch->ast, &fr);
- } else {
- chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
- }
- }
- break;
- case EVENT_STATUS:
- break;
-
- case EVENT_INFORMATION:
- {
- if ( ch->state != MISDN_CONNECTED )
- stop_indicate(ch);
-
- if (!ch->ast)
- break;
- if (ch->state == MISDN_WAITING4DIGS ) {
- /* Ok, incomplete Setup, waiting till extension exists */
- if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
- chan_misdn_log(1, bc->port, " --> using keypad as info\n");
- ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
- }
- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
- /* Check for Pickup Request first */
- if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
- if (ast_pickup_call(ch->ast)) {
- hangup_chan(ch, bc);
- } else {
- struct ast_channel *chan = ch->ast;
- ch->state = MISDN_CALLING_ACKNOWLEDGE;
- ast_setstate(chan, AST_STATE_DOWN);
- hangup_chan(ch, bc);
- ch->ast = NULL;
- break;
- }
- }
-
- if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
- ast_log(LOG_WARNING,
- "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
- bc->dad, ch->context, bc->port);
- strcpy(ch->ast->exten, "i");
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, ch->ast);
- break;
- }
- ast_log(LOG_WARNING,
- "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
- "\tMaybe you want to add an 'i' extension to catch this case.\n",
- bc->dad, ch->context, bc->port);
- if (bc->nt)
- hanguptone_indicate(ch);
- ch->state = MISDN_EXTCANTMATCH;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- break;
- }
- if (ch->overlap_dial) {
- ast_mutex_lock(&ch->overlap_tv_lock);
- ch->overlap_tv = ast_tvnow();
- ast_mutex_unlock(&ch->overlap_tv_lock);
- if (ch->overlap_dial_task == -1) {
- ch->overlap_dial_task =
- misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
- }
- break;
- }
- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
-
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, ch->ast);
- }
- } else {
- /* sending INFOS as DTMF-Frames :) */
- struct ast_frame fr;
- int digits;
- memset(&fr, 0, sizeof(fr));
- fr.frametype = AST_FRAME_DTMF;
- fr.subclass = bc->info_dad[0] ;
- fr.src = NULL;
- fr.data.ptr = NULL;
- fr.datalen = 0;
- fr.samples = 0;
- fr.mallocd = 0;
- fr.offset = 0;
- fr.delivery = ast_tv(0,0);
- misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
- if (ch->state != MISDN_CONNECTED ) {
- if (digits) {
- strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
- ast_cdr_update(ch->ast);
- }
-
- ast_queue_frame(ch->ast, &fr);
- }
- }
- }
- break;
- case EVENT_SETUP:
- {
- struct chan_list *ch = find_chan_by_bc(cl_te, bc);
- struct ast_channel *chan;
- int exceed;
- int pres, screen;
- int ai;
- int im;
- if (ch) {
- switch (ch->state) {
- case MISDN_NOTHING:
- ch = NULL;
- break;
- default:
- chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
- return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE; /* Ignore MSNs which are not in our List */
- }
- }
- msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad);
- if (!bc->nt && ! msn_valid) {
- chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
- return RESPONSE_IGNORE_SETUP; /* Ignore MSNs which are not in our List */
- }
- if (bc->cw) {
- int cause;
- chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n");
- misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause));
- bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING;
- return RESPONSE_RELEASE_SETUP;
- }
- print_bearer(bc);
- ch = init_chan_list(ORG_MISDN);
- if (!ch) {
- chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
- return 0;
- }
- ch->bc = bc;
- ch->l3id = bc->l3_id;
- ch->addr = bc->addr;
- ch->originator = ORG_MISDN;
- chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel);
- if (!chan) {
- ast_free(ch);
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
- ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n");
- return 0;
- }
- ch->ast = chan;
- if ((exceed = add_in_calls(bc->port))) {
- char tmp[16];
- snprintf(tmp, sizeof(tmp), "%d", exceed);
- pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
- }
- read_config(ch, ORG_MISDN);
- export_ch(chan, bc, ch);
- ch->ast->rings = 1;
- ast_setstate(ch->ast, AST_STATE_RINGING);
- switch (bc->pres) {
- case 1:
- pres = AST_PRES_RESTRICTED;
- chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n");
- break;
- case 2:
- pres = AST_PRES_UNAVAILABLE;
- chan_misdn_log(2, bc->port, " --> PRES: Unavailable (2)\n");
- break;
- default:
- pres = AST_PRES_ALLOWED;
- chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres);
- break;
- }
- switch (bc->screen) {
- default:
- case 0:
- screen = AST_PRES_USER_NUMBER_UNSCREENED;
- chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen);
- break;
- case 1:
- screen = AST_PRES_USER_NUMBER_PASSED_SCREEN;
- chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n");
- break;
- case 2:
- screen = AST_PRES_USER_NUMBER_FAILED_SCREEN;
- chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n");
- break;
- case 3:
- screen = AST_PRES_NETWORK_NUMBER;
- chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n");
- break;
- }
- chan->cid.cid_pres = pres | screen;
- pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
- chan->transfercapability = bc->capability;
- switch (bc->capability) {
- case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
- pbx_builtin_setvar_helper(chan, "CALLTYPE", "DIGITAL");
- break;
- default:
- pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
- }
- /** queue new chan **/
- cl_queue_chan(&cl_te, ch);
- if (!strstr(ch->allowed_bearers, "all")) {
- int i;
- for (i = 0; i < ARRAY_LEN(allowed_bearers_array); ++i) {
- if (allowed_bearers_array[i].cap == bc->capability) {
- if (strstr(ch->allowed_bearers, allowed_bearers_array[i].name)) {
- /* The bearer capability is allowed */
- if (allowed_bearers_array[i].deprecated) {
- chan_misdn_log(0, bc->port, "%s in allowed_bearers list is deprecated\n",
- allowed_bearers_array[i].name);
- }
- break;
- }
- }
- } /* end for */
- if (i == ARRAY_LEN(allowed_bearers_array)) {
- /* We did not find the bearer capability */
- chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
- bearer2str(bc->capability), bc->capability);
- bc->out_cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;
- ch->state = MISDN_EXTCANTMATCH;
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
- return RESPONSE_OK;
- }
- }
- /* Check for Pickup Request first */
- if (!strcmp(chan->exten, ast_pickup_ext())) {
- if (!ch->noautorespond_on_setup) {
- int ret;/** Sending SETUP_ACK**/
- ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- } else {
- ch->state = MISDN_INCOMING_SETUP;
- }
- if (ast_pickup_call(chan)) {
- hangup_chan(ch, bc);
- } else {
- ch->state = MISDN_CALLING_ACKNOWLEDGE;
- ast_setstate(chan, AST_STATE_DOWN);
- hangup_chan(ch, bc);
- ch->ast = NULL;
- break;
- }
- }
- /*
- * added support for s extension hope it will help those poor cretains
- * which haven't overlap dial.
- */
- misdn_cfg_get(bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
- if (ai) {
- do_immediate_setup(bc, ch, chan);
- break;
- }
- /* check if we should jump into s when we have no dad */
- misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
- if (im && ast_strlen_zero(bc->dad)) {
- do_immediate_setup(bc, ch, chan);
- break;
- }
- chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
- if(!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
- ast_log(LOG_WARNING,
- "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
- bc->dad, ch->context, bc->port);
- strcpy(ch->ast->exten, "i");
- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, chan);
- break;
- }
- ast_log(LOG_WARNING,
- "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
- "\tMaybe you want to add an 'i' extension to catch this case.\n",
- bc->dad, ch->context, bc->port);
- if (bc->nt)
- hanguptone_indicate(ch);
- ch->state = MISDN_EXTCANTMATCH;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- if (bc->nt)
- misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE );
- else
- misdn_lib_send_event(bc, EVENT_RELEASE );
- break;
- }
- /* Whatever happens, when sending_complete is set or we are PTMP TE, we will definitely
- * jump into the dialplan, when the dialed extension does not exist, the 's' extension
- * will be used by Asterisk automatically. */
- if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
- if (!ch->noautorespond_on_setup) {
- ch->state=MISDN_DIALING;
- misdn_lib_send_event(bc, EVENT_PROCEEDING );
- } else {
- ch->state = MISDN_INCOMING_SETUP;
- }
- start_pbx(ch, bc, chan);
- break;
- }
- /*
- * When we are NT and overlapdial is set and if
- * the number is empty, we wait for the ISDN timeout
- * instead of our own timer.
- */
- if (ch->overlap_dial && bc->nt && !bc->dad[0] ) {
- wait_for_digits(ch, bc, chan);
- break;
- }
- /*
- * If overlapdial we will definitely send a SETUP_ACKNOWLEDGE and wait for more
- * Infos with a Interdigit Timeout.
- * */
- if (ch->overlap_dial) {
- ast_mutex_lock(&ch->overlap_tv_lock);
- ch->overlap_tv = ast_tvnow();
- ast_mutex_unlock(&ch->overlap_tv_lock);
- wait_for_digits(ch, bc, chan);
- if (ch->overlap_dial_task == -1)
- ch->overlap_dial_task =
- misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
- break;
- }
- /* If the extension does not exist and we're not TE_PTMP we wait for more digits
- * without interdigit timeout.
- * */
- if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- wait_for_digits(ch, bc, chan);
- break;
- }
- /*
- * If the extension exists let's just jump into it.
- * */
- if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
- if (bc->need_more_infos)
- misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
- else
- misdn_lib_send_event(bc, EVENT_PROCEEDING);
- ch->state = MISDN_DIALING;
- start_pbx(ch, bc, chan);
- break;
- }
- }
- break;
- case EVENT_SETUP_ACKNOWLEDGE:
- {
- ch->state = MISDN_CALLING_ACKNOWLEDGE;
- if (bc->channel)
- update_name(ch->ast,bc->port,bc->channel);
-
- if (!ast_strlen_zero(bc->infos_pending)) {
- /* TX Pending Infos */
- strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1);
- if (!ch->ast)
- break;
- ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
- ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
- ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));
- misdn_lib_send_event(bc, EVENT_INFORMATION);
- }
- }
- break;
- case EVENT_PROCEEDING:
- {
- if (misdn_cap_is_speech(bc->capability) &&
- misdn_inband_avail(bc) ) {
- start_bc_tones(ch);
- }
- ch->state = MISDN_PROCEEDING;
-
- if (!ch->ast)
- break;
- ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
- }
- break;
- case EVENT_PROGRESS:
- if (bc->channel)
- update_name(ch->ast, bc->port, bc->channel);
- if (!bc->nt ) {
- if ( misdn_cap_is_speech(bc->capability) &&
- misdn_inband_avail(bc)
- ) {
- start_bc_tones(ch);
- }
-
- ch->state = MISDN_PROGRESS;
- if (!ch->ast)
- break;
- ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
- }
- break;
-
-
- case EVENT_ALERTING:
- {
- ch->state = MISDN_ALERTING;
-
- if (!ch->ast)
- break;
- ast_queue_control(ch->ast, AST_CONTROL_RINGING);
- ast_setstate(ch->ast, AST_STATE_RINGING);
-
- cb_log(7, bc->port, " --> Set State Ringing\n");
-
- if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
- cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
- start_bc_tones(ch);
- } else {
- cb_log(3, bc->port, " --> We have no inband Data, the other end must create ringing\n");
- if (ch->far_alerting) {
- cb_log(1, bc->port, " --> The other end can not do ringing eh ?.. we must do all ourself..");
- start_bc_tones(ch);
- /*tone_indicate(ch, TONE_FAR_ALERTING);*/
- }
- }
- }
- break;
- case EVENT_CONNECT:
- {
- struct ast_channel *bridged;
- /*we answer when we've got our very new L3 ID from the NT stack */
- misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);
- if (!ch->ast)
- break;
- bridged = ast_bridged_channel(ch->ast);
- stop_indicate(ch);
- if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) {
- struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged);
- chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad);
- if (bridged_ch) {
- bridged_ch->bc->cpnnumplan = bc->cpnnumplan;
- ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad));
- }
- }
- }
- ch->l3id=bc->l3_id;
- ch->addr=bc->addr;
- start_bc_tones(ch);
-
- ch->state = MISDN_CONNECTED;
-
- ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
- break;
- case EVENT_CONNECT_ACKNOWLEDGE:
- {
- ch->l3id = bc->l3_id;
- ch->addr = bc->addr;
- start_bc_tones(ch);
- ch->state = MISDN_CONNECTED;
- }
- break;
- case EVENT_DISCONNECT:
- /*we might not have an ch->ast ptr here anymore*/
- if (ch) {
- chan_misdn_log(3, bc->port, " --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->originator, bc->nt, misdn_inband_avail(bc), ch->state);
- if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
- /* If there's inband information available (e.g. a
- recorded message saying what was wrong with the
- dialled number, or perhaps even giving an
- alternative number, then play it instead of
- immediately releasing the call */
- chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
-
- ch->state = MISDN_DISCONNECTED;
- start_bc_tones(ch);
- if (ch->ast) {
- ch->ast->hangupcause = bc->cause;
- if (bc->cause == AST_CAUSE_USER_BUSY)
- ast_queue_control(ch->ast, AST_CONTROL_BUSY);
- }
- ch->need_busy = 0;
- break;
- }
- bc->need_disconnect = 0;
- stop_bc_tones(ch);
- /* Check for held channel, to implement transfer */
- held_ch = find_hold_call(cl_te, bc);
- if (!held_ch || !ch->ast || misdn_attempt_transfer(ch, held_ch)) {
- hangup_chan(ch, bc);
- }
- } else {
- held_ch = find_hold_call_l3(cl_te, bc->l3_id);
- if (held_ch && held_ch->hold.state == MISDN_HOLD_ACTIVE) {
- bc->need_disconnect = 0;
- #if defined(TRANSFER_ON_HELD_CALL_HANGUP)
- /*
- * Some phones disconnect the held call and the active call at the
- * same time to do the transfer. Unfortunately, either call could
- * be disconnected first.
- */
- ch = find_hold_active_call(cl_te, bc);
- if (!ch || misdn_attempt_transfer(ch, held_ch)) {
- held_ch->hold.state = MISDN_HOLD_DISCONNECT;
- hangup_chan(held_ch, bc);
- }
- #else
- hangup_chan(held_ch, bc);
- #endif /* defined(TRANSFER_ON_HELD_CALL_HANGUP) */
- }
- }
- bc->out_cause = -1;
- if (bc->need_release)
- misdn_lib_send_event(bc, EVENT_RELEASE);
- break;
-
- case EVENT_RELEASE:
- if (!ch) {
- ch = find_hold_call_l3(cl_te, bc->l3_id);
- if (!ch) {
- chan_misdn_log(1, bc->port,
- " --> no Ch, so we've already released. (%s)\n",
- manager_isdn_get_info(event));
- return -1;
- }
- }
- bc->need_disconnect = 0;
- bc->need_release = 0;
- hangup_chan(ch, bc);
- release_chan(ch, bc);
- break;
- case EVENT_RELEASE_COMPLETE:
- if (!ch) {
- ch = find_hold_call_l3(cl_te, bc->l3_id);
- if (!ch) {
- chan_misdn_log(1, bc->port,
- " --> no Ch, so we've already released. (%s)\n",
- manager_isdn_get_info(event));
- break;
- }
- }
- bc->need_disconnect = 0;
- bc->need_release = 0;
- bc->need_release_complete = 0;
- stop_bc_tones(ch);
- hangup_chan(ch, bc);
- release_chan(ch, bc);
- break;
- case EVENT_BCHAN_ERROR:
- case EVENT_CLEANUP:
- {
- stop_bc_tones(ch);
-
- switch (ch->state) {
- case MISDN_CALLING:
- bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
- break;
- default:
- break;
- }
-
- hangup_chan(ch, bc);
- release_chan(ch, bc);
- }
- break;
- case EVENT_TONE_GENERATE:
- {
- int tone_len = bc->tone_cnt;
- struct ast_channel *ast = ch->ast;
- void *tmp;
- int res;
- int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);
- chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len);
- if (!ast)
- break;
- if (!ast->generator)
- break;
- tmp = ast->generatordata;
- ast->generatordata = NULL;
- generate = ast->generator->generate;
- if (tone_len < 0 || tone_len > 512 ) {
- ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
- tone_len = 128;
- }
- res = generate(ast, tmp, tone_len, tone_len);
- ast->generatordata = tmp;
-
- if (res) {
- ast_log(LOG_WARNING, "Auto-deactivating generator\n");
- ast_deactivate_generator(ast);
- } else {
- bc->tone_cnt = 0;
- }
- }
- break;
- case EVENT_BCHAN_DATA:
- {
- if (ch->bc->AOCD_need_export)
- export_aoc_vars(ch->originator, ch->ast, ch->bc);
- if (!misdn_cap_is_speech(ch->bc->capability)) {
- struct ast_frame frame;
- /*In Data Modes we queue frames*/
- memset(&frame, 0, sizeof(frame));
- frame.frametype = AST_FRAME_VOICE; /*we have no data frames yet*/
- frame.subclass = AST_FORMAT_ALAW;
- frame.datalen = bc->bframe_len;
- frame.samples = bc->bframe_len;
- frame.mallocd = 0;
- frame.offset = 0;
- frame.delivery = ast_tv(0,0);
- frame.src = NULL;
- frame.data.ptr = bc->bframe;
- if (ch->ast)
- ast_queue_frame(ch->ast, &frame);
- } else {
- fd_set wrfs;
- struct timeval tv = { 0, 0 };
- int t;
- FD_ZERO(&wrfs);
- FD_SET(ch->pipe[1], &wrfs);
- t = select(FD_SETSIZE, NULL, &wrfs, NULL, &tv);
- if (!t) {
- chan_misdn_log(9, bc->port, "Select Timed out\n");
- break;
- }
-
- if (t < 0) {
- chan_misdn_log(-1, bc->port, "Select Error (err=%s)\n", strerror(errno));
- break;
- }
-
- if (FD_ISSET(ch->pipe[1], &wrfs)) {
- chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
- if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
- chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));
- stop_bc_tones(ch);
- hangup_chan(ch, bc);
- release_chan(ch, bc);
- }
- } else {
- chan_misdn_log(1, bc->port, "Write Pipe full!\n");
- }
- }
- }
- break;
- case EVENT_TIMEOUT:
- {
- if (ch && bc)
- chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch));
- switch (ch->state) {
- case MISDN_DIALING:
- case MISDN_PROGRESS:
- if (bc->nt && !ch->nttimeout)
- break;
-
- case MISDN_CALLING:
- case MISDN_ALERTING:
- case MISDN_PROCEEDING:
- case MISDN_CALLING_ACKNOWLEDGE:
- if (bc->nt) {
- bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
- hanguptone_indicate(ch);
- }
-
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- break;
- case MISDN_WAITING4DIGS:
- if (bc->nt) {
- bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
- bc->out_cause = AST_CAUSE_UNALLOCATED;
- hanguptone_indicate(ch);
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- } else {
- bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
- misdn_lib_send_event(bc, EVENT_RELEASE);
- }
-
- break;
- case MISDN_CLEANING:
- chan_misdn_log(1,bc->port," --> in state cleaning .. so ignoring, the stack should clean it for us\n");
- break;
- default:
- misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
- }
- }
- break;
-
- /****************************/
- /** Supplementary Services **/
- /****************************/
- case EVENT_RETRIEVE:
- if (!ch) {
- chan_misdn_log(4, bc->port, " --> no CH, searching for held call\n");
- ch = find_hold_call_l3(cl_te, bc->l3_id);
- if (!ch || ch->hold.state != MISDN_HOLD_ACTIVE) {
- ast_log(LOG_WARNING, "No held call found, cannot Retrieve\n");
- misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
- break;
- }
- }
- /* remember the channel again */
- ch->bc = bc;
- ch->hold.state = MISDN_HOLD_IDLE;
- ch->hold.port = 0;
- ch->hold.channel = 0;
- ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
-
- if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
- chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
- misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
- }
- break;
-
- case EVENT_HOLD:
- {
- int hold_allowed;
- struct ast_channel *bridged;
- misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
- if (!hold_allowed) {
- chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
- misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
- break;
- }
- bridged = ast_bridged_channel(ch->ast);
- if (bridged) {
- chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
- ch->l3id = bc->l3_id;
- /* forget the channel now */
- ch->bc = NULL;
- ch->hold.state = MISDN_HOLD_ACTIVE;
- ch->hold.port = bc->port;
- ch->hold.channel = bc->channel;
- ast_queue_control(ch->ast, AST_CONTROL_HOLD);
-
- misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
- } else {
- misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
- chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
- }
- }
- break;
-
- case EVENT_FACILITY:
- print_facility(&(bc->fac_in), bc);
-
- switch (bc->fac_in.Function) {
- #ifdef HAVE_MISDN_FAC_RESULT
- case Fac_RESULT:
- break;
- #endif
- case Fac_CD:
- if (ch) {
- struct ast_channel *bridged = ast_bridged_channel(ch->ast);
- struct chan_list *ch_br;
- if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
- ch_br = MISDN_ASTERISK_TECH_PVT(bridged);
- /*ch->state = MISDN_FACILITY_DEFLECTED;*/
- if (ch_br->bc) {
- if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) {
- ch_br->state = MISDN_DIALING;
- if (pbx_start_chan(ch_br) < 0) {
- chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
- }
- }
- }
- }
- misdn_lib_send_event(bc, EVENT_DISCONNECT);
- }
- break;
- case Fac_AOCDCurrency:
- if (ch) {
- bc->AOCDtype = Fac_AOCDCurrency;
- memcpy(&(bc->AOCD.currency), &(bc->fac_in.u.AOCDcur), sizeof(bc->AOCD.currency));
- bc->AOCD_need_export = 1;
- export_aoc_vars(ch->originator, ch->ast, bc);
- }
- break;
- case Fac_AOCDChargingUnit:
- if (ch) {
- bc->AOCDtype = Fac_AOCDChargingUnit;
- memcpy(&(bc->AOCD.chargingUnit), &(bc->fac_in.u.AOCDchu), sizeof(bc->AOCD.chargingUnit));
- bc->AOCD_need_export = 1;
- export_aoc_vars(ch->originator, ch->ast, bc);
- }
- break;
- case Fac_None:
- #ifdef HAVE_MISDN_FAC_ERROR
- case Fac_ERROR:
- #endif
- break;
- default:
- chan_misdn_log(0, bc->port," --> not yet handled: facility type:%d\n", bc->fac_in.Function);
- }
-
- break;
- case EVENT_RESTART:
- if (!bc->dummy) {
- stop_bc_tones(ch);
- release_chan(ch, bc);
- }
- break;
- default:
- chan_misdn_log(1, 0, "Got Unknown Event\n");
- break;
- }
-
- return RESPONSE_OK;
- }
- /** TE STUFF END **/
- /******************************************
- *
- * Asterisk Channel Endpoint END
- *
- *
- *******************************************/
- static int unload_module(void)
- {
- /* First, take us out of the channel loop */
- ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
- misdn_tasks_destroy();
-
- if (!g_config_initialized)
- return 0;
-
- ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
-
- /* ast_unregister_application("misdn_crypt"); */
- ast_unregister_application("misdn_set_opt");
- ast_unregister_application("misdn_facility");
- ast_unregister_application("misdn_check_l2l1");
-
- ast_channel_unregister(&misdn_tech);
- free_robin_list();
- misdn_cfg_destroy();
- misdn_lib_destroy();
-
- ast_free(misdn_out_calls);
- ast_free(misdn_in_calls);
- ast_free(misdn_debug_only);
- ast_free(misdn_ports);
- ast_free(misdn_debug);
-
- return 0;
- }
- static int load_module(void)
- {
- int i, port;
- int ntflags = 0, ntkc = 0;
- char ports[256] = "";
- char tempbuf[BUFFERSIZE + 1];
- char ntfile[BUFFERSIZE + 1];
- struct misdn_lib_iface iface = {
- .cb_event = cb_events,
- .cb_log = chan_misdn_log,
- .cb_jb_empty = chan_misdn_jb_empty,
- };
- max_ports = misdn_lib_maxports_get();
-
- if (max_ports <= 0) {
- ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
- return AST_MODULE_LOAD_DECLINE;
- }
-
- if (misdn_cfg_init(max_ports, 0)) {
- ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- g_config_initialized = 1;
-
- misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
- if (!misdn_debug) {
- ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- misdn_ports = ast_malloc(sizeof(int) * (max_ports + 1));
- if (!misdn_ports) {
- ast_free(misdn_debug);
- ast_log(LOG_ERROR, "Out of memory for misdn_ports\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- misdn_cfg_get(0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(misdn_debug[0]));
- for (i = 1; i <= max_ports; i++) {
- misdn_debug[i] = misdn_debug[0];
- misdn_ports[i] = i;
- }
- *misdn_ports = 0;
- misdn_debug_only = ast_calloc(max_ports + 1, sizeof(int));
- if (!misdn_debug_only) {
- ast_free(misdn_ports);
- ast_free(misdn_debug);
- ast_log(LOG_ERROR, "Out of memory for misdn_debug_only\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, sizeof(tempbuf));
- if (!ast_strlen_zero(tempbuf))
- tracing = 1;
- misdn_in_calls = ast_malloc(sizeof(int) * (max_ports + 1));
- if (!misdn_in_calls) {
- ast_free(misdn_debug_only);
- ast_free(misdn_ports);
- ast_free(misdn_debug);
- ast_log(LOG_ERROR, "Out of memory for misdn_in_calls\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- misdn_out_calls = ast_malloc(sizeof(int) * (max_ports + 1));
- if (!misdn_out_calls) {
- ast_free(misdn_in_calls);
- ast_free(misdn_debug_only);
- ast_free(misdn_ports);
- ast_free(misdn_debug);
- ast_log(LOG_ERROR, "Out of memory for misdn_out_calls\n");
- return AST_MODULE_LOAD_DECLINE;
- }
- for (i = 1; i <= max_ports; i++) {
- misdn_in_calls[i] = 0;
- misdn_out_calls[i] = 0;
- }
- ast_mutex_init(&cl_te_lock);
- ast_mutex_init(&release_lock);
- misdn_cfg_update_ptp();
- misdn_cfg_get_ports_string(ports);
- if (!ast_strlen_zero(ports))
- chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports);
- if (misdn_lib_init(ports, &iface, NULL))
- chan_misdn_log(0, 0, "No te ports initialized\n");
- misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags));
- misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile));
- misdn_cfg_get( 0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));
- misdn_lib_nt_keepcalls(ntkc);
- misdn_lib_nt_debug_init(ntflags, ntfile);
- if (ast_channel_register(&misdn_tech)) {
- ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
- unload_module();
- return AST_MODULE_LOAD_DECLINE;
- }
-
- ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));
- ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
- "misdn_set_opt(:<opt><optarg>:<opt><optarg>...):\n"
- "Sets mISDN opts. and optargs\n"
- "\n"
- "The available options are:\n"
- " a - Have Asterisk detect DTMF tones on called channel\n"
- " c - Make crypted outgoing call, optarg is keyindex\n"
- " d - Send display text to called phone, text is the optarg\n"
- " e - Perform echo cancelation on this channel,\n"
- " takes taps as optarg (32,64,128,256)\n"
- " e! - Disable echo cancelation on this channel\n"
- " f - Enable fax detection\n"
- " h - Make digital outgoing call\n"
- " h1 - Make HDLC mode digital outgoing call\n"
- " i - Ignore detected DTMF tones, don't signal them to Asterisk,\n"
- " they will be transported inband.\n"
- " jb - Set jitter buffer length, optarg is length\n"
- " jt - Set jitter buffer upper threshold, optarg is threshold\n"
- " jn - Disable jitter buffer\n"
- " n - Disable mISDN DSP on channel.\n"
- " Disables: echo cancel, DTMF detection, and volume control.\n"
- " p - Caller ID presentation,\n"
- " optarg is either 'allowed' or 'restricted'\n"
- " s - Send Non-inband DTMF as inband\n"
- " vr - Rx gain control, optarg is gain\n"
- " vt - Tx gain control, optarg is gain\n"
- );
-
- ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
- "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
- "Sends the Facility Message FACILITY_TYPE with \n"
- "the given Arguments to the current ISDN Channel\n"
- "Supported Facilities are:\n"
- "\n"
- "type=calldeflect args=Nr where to deflect\n"
- );
- ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
- "misdn_check_l2l1(<port>||g:<groupname>,timeout)"
- "Checks if the L2 and L1 are up on either the given <port> or\n"
- "on the ports in the group with <groupname>\n"
- "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
- "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
- "\n"
- "This application, ensures the L1/L2 state of the Ports in a group\n"
- "it is intended to make the pmp_l1_check option redundant and to\n"
- "fix a buggy switch config from your provider\n"
- "\n"
- "a sample dialplan would look like:\n\n"
- "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
- "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
- "\n"
- );
- misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
- /* start the l1 watchers */
-
- for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
- int l1timeout;
- misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
- if (l1timeout) {
- chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
- misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);
- }
- }
- chan_misdn_log(0, 0, "-- mISDN Channel Driver Registered --\n");
- return 0;
- }
- static int reload(void)
- {
- reload_config();
- return 0;
- }
- /*** SOME APPS ;)***/
- static int misdn_facility_exec(struct ast_channel *chan, void *data)
- {
- struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
- char *parse, *tok, *tokb;
- chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type);
-
- if (strcasecmp(chan->tech->type, "mISDN")) {
- ast_log(LOG_WARNING, "misdn_facility makes only sense with chan_misdn channels!\n");
- return -1;
- }
-
- if (ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "misdn_facility Requires arguments\n");
- return -1;
- }
- parse = ast_strdupa(data);
- tok = strtok_r(parse, "|", &tokb) ;
- if (!tok) {
- ast_log(LOG_WARNING, "misdn_facility Requires arguments\n");
- return -1;
- }
- if (!strcasecmp(tok, "calldeflect")) {
- tok = strtok_r(NULL, "|", &tokb) ;
-
- if (!tok) {
- ast_log(LOG_WARNING, "Facility: Call Defl Requires arguments\n");
- }
- if (strlen(tok) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) {
- ast_log(LOG_WARNING, "Facility: Number argument too long (up to 15 digits are allowed). Ignoring.\n");
- return 0;
- }
- ch->bc->fac_out.Function = Fac_CD;
- ast_copy_string((char *)ch->bc->fac_out.u.CDeflection.DeflectedToNumber, tok, sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
- misdn_lib_send_event(ch->bc, EVENT_FACILITY);
- } else {
- chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", tok);
- }
- return 0;
- }
- static int misdn_check_l2l1(struct ast_channel *chan, void *data)
- {
- char *parse;
- char group[BUFFERSIZE + 1];
- char *port_str;
- int port = 0;
- int timeout;
- int dowait = 0;
- int port_up;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(grouppar);
- AST_APP_ARG(timeout);
- );
- if (ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
- return -1;
- }
- parse = ast_strdupa(data);
- AST_STANDARD_APP_ARGS(args, parse);
- if (args.argc != 2) {
- ast_log(LOG_WARNING, "Wrong argument count\n");
- return 0;
- }
- /*ast_log(LOG_NOTICE, "Arguments: group/port '%s' timeout '%s'\n", args.grouppar, args.timeout);*/
- timeout = atoi(args.timeout);
- port_str = args.grouppar;
- if (port_str[0] == 'g' && port_str[1] == ':' ) {
- /* We make a group call lets checkout which ports are in my group */
- port_str += 2;
- ast_copy_string(group, port_str, sizeof(group));
- chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);
- for ( port = misdn_cfg_get_next_port(port);
- port > 0;
- port = misdn_cfg_get_next_port(port)) {
- char cfg_group[BUFFERSIZE + 1];
- chan_misdn_log(2, 0, "trying port %d\n", port);
- misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));
- if (!strcasecmp(cfg_group, group)) {
- port_up = misdn_lib_port_up(port, 1);
- if (!port_up) {
- chan_misdn_log(2, 0, " --> port '%d'\n", port);
- misdn_lib_get_port_up(port);
- dowait = 1;
- }
- }
- }
- } else {
- port = atoi(port_str);
- chan_misdn_log(2, 0, "Checking Port: %d\n",port);
- port_up = misdn_lib_port_up(port, 1);
- if (!port_up) {
- misdn_lib_get_port_up(port);
- dowait = 1;
- }
- }
- if (dowait) {
- chan_misdn_log(2, 0, "Waiting for '%d' seconds\n", timeout);
- ast_safe_sleep(chan, timeout * 1000);
- }
- return 0;
- }
- static int misdn_set_opt_exec(struct ast_channel *chan, void *data)
- {
- struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
- char *tok, *tokb, *parse;
- int keyidx = 0;
- int rxgain = 0;
- int txgain = 0;
- int change_jitter = 0;
- if (strcasecmp(chan->tech->type, "mISDN")) {
- ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n");
- return -1;
- }
-
- if (ast_strlen_zero((char *)data)) {
- ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
- return -1;
- }
- parse = ast_strdupa(data);
- for (tok = strtok_r(parse, ":", &tokb);
- tok;
- tok = strtok_r(NULL, ":", &tokb) ) {
- int neglect = 0;
- if (tok[0] == '!' ) {
- neglect = 1;
- tok++;
- }
-
- switch(tok[0]) {
-
- case 'd' :
- ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
- chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
- break;
-
- case 'n':
- chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
- ch->bc->nodsp = 1;
- break;
- case 'j':
- chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
- tok++;
- change_jitter = 1;
- switch ( tok[0] ) {
- case 'b':
- ch->jb_len = atoi(++tok);
- chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
- break;
- case 't' :
- ch->jb_upper_threshold = atoi(++tok);
- chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n", ch->jb_upper_threshold);
- break;
- case 'n':
- ch->bc->nojitter = 1;
- chan_misdn_log(1, ch->bc->port, " --> nojitter\n");
- break;
- default:
- ch->jb_len = 4000;
- ch->jb_upper_threshold = 0;
- chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
- chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
- }
- break;
- case 'v':
- tok++;
- switch (tok[0]) {
- case 'r' :
- rxgain = atoi(++tok);
- if (rxgain < -8)
- rxgain = -8;
- if (rxgain > 8)
- rxgain = 8;
- ch->bc->rxgain = rxgain;
- chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain);
- break;
- case 't':
- txgain = atoi(++tok);
- if (txgain < -8)
- txgain = -8;
- if (txgain > 8)
- txgain = 8;
- ch->bc->txgain = txgain;
- chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain);
- break;
- }
- break;
-
- case 'c':
- keyidx = atoi(++tok);
- {
- char keys[4096];
- char *key = NULL, *tmp = keys;
- int i;
- misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));
- for (i = 0; i < keyidx; i++) {
- key = strsep(&tmp, ",");
- }
- if (key) {
- ast_copy_string(ch->bc->crypt_key, key, sizeof(ch->bc->crypt_key));
- }
- chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n", ch->bc->crypt_key);
- break;
- }
- case 'e':
- chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
-
- if (neglect) {
- chan_misdn_log(1, ch->bc->port, " --> disabled\n");
- #ifdef MISDN_1_2
- *ch->bc->pipeline = 0;
- #else
- ch->bc->ec_enable = 0;
- #endif
- } else {
- #ifdef MISDN_1_2
- update_pipeline_config(ch->bc);
- #else
- ch->bc->ec_enable = 1;
- ch->bc->orig = ch->originator;
- tok++;
- if (*tok) {
- ch->bc->ec_deftaps = atoi(tok);
- }
- #endif
- }
-
- break;
- case 'h':
- chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
-
- if (strlen(tok) > 1 && tok[1] == '1') {
- chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
- if (!ch->bc->hdlc) {
- ch->bc->hdlc = 1;
- }
- }
- ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
- break;
-
- case 's':
- chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
- ch->bc->send_dtmf = 1;
- break;
-
- case 'f':
- chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
- ch->faxdetect = 1;
- misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
- break;
- case 'a':
- chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
- ch->ast_dsp = 1;
- break;
- case 'p':
- chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
- /* CRICH: callingpres!!! */
- if (strstr(tok,"allowed")) {
- ch->bc->pres = 0;
- } else if (strstr(tok, "restricted")) {
- ch->bc->pres = 1;
- } else if (strstr(tok, "not_screened")) {
- chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
- ch->bc->pres = 1;
- }
- break;
- case 'i' :
- chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
- ch->ignore_dtmf=1;
- break;
- default:
- break;
- }
- }
- if (change_jitter)
- config_jitterbuffer(ch);
- if (ch->faxdetect || ch->ast_dsp) {
- if (!ch->dsp)
- ch->dsp = ast_dsp_new();
- if (ch->dsp)
- ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
- }
- if (ch->ast_dsp) {
- chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
- ch->bc->nodsp = 1;
- }
-
- return 0;
- }
- int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len)
- {
- struct chan_list *ch = find_chan_by_bc(cl_te, bc);
-
- if (ch && ch->jb) {
- return misdn_jb_empty(ch->jb, buf, len);
- }
-
- return -1;
- }
- /*******************************************************/
- /***************** JITTERBUFFER ************************/
- /*******************************************************/
- /* allocates the jb-structure and initialize the elements*/
- struct misdn_jb *misdn_jb_init(int size, int upper_threshold)
- {
- int i;
- struct misdn_jb *jb;
- jb = ast_malloc(sizeof(*jb));
- if (!jb) {
- chan_misdn_log(-1, 0, "No free Mem for jb\n");
- return NULL;
- }
- jb->size = size;
- jb->upper_threshold = upper_threshold;
- jb->wp = 0;
- jb->rp = 0;
- jb->state_full = 0;
- jb->state_empty = 0;
- jb->bytes_wrote = 0;
- jb->samples = ast_malloc(size * sizeof(char));
- if (!jb->samples) {
- ast_free(jb);
- chan_misdn_log(-1, 0, "No free Mem for jb->samples\n");
- return NULL;
- }
- jb->ok = ast_malloc(size * sizeof(char));
- if (!jb->ok) {
- ast_free(jb->samples);
- ast_free(jb);
- chan_misdn_log(-1, 0, "No free Mem for jb->ok\n");
- return NULL;
- }
- for (i = 0; i < size; i++)
- jb->ok[i] = 0;
- ast_mutex_init(&jb->mutexjb);
- return jb;
- }
- /* frees the data and destroys the given jitterbuffer struct */
- void misdn_jb_destroy(struct misdn_jb *jb)
- {
- ast_mutex_destroy(&jb->mutexjb);
-
- ast_free(jb->ok);
- ast_free(jb->samples);
- ast_free(jb);
- }
- /* fills the jitterbuffer with len data returns < 0 if there was an
- error (buffer overflow). */
- int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len)
- {
- int i, j, rp, wp;
- if (!jb || ! data)
- return 0;
- ast_mutex_lock(&jb->mutexjb);
-
- wp = jb->wp;
- rp = jb->rp;
-
- for (i = 0; i < len; i++) {
- jb->samples[wp] = data[i];
- jb->ok[wp] = 1;
- wp = (wp != jb->size - 1) ? wp + 1 : 0;
- if (wp == jb->rp)
- jb->state_full = 1;
- }
- if (wp >= rp)
- jb->state_buffer = wp - rp;
- else
- jb->state_buffer = jb->size - rp + wp;
- chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
- if (jb->state_full) {
- jb->wp = wp;
- rp = wp;
- for (j = 0; j < jb->upper_threshold; j++)
- rp = (rp != 0) ? rp - 1 : jb->size - 1;
- jb->rp = rp;
- jb->state_full = 0;
- jb->state_empty = 1;
- ast_mutex_unlock(&jb->mutexjb);
- return -1;
- }
- if (!jb->state_empty) {
- jb->bytes_wrote += len;
- if (jb->bytes_wrote >= jb->upper_threshold) {
- jb->state_empty = 1;
- jb->bytes_wrote = 0;
- }
- }
- jb->wp = wp;
- ast_mutex_unlock(&jb->mutexjb);
-
- return 0;
- }
- /* gets len bytes out of the jitterbuffer if available, else only the
- available data is returned and the return value indicates the number
- of data. */
- int misdn_jb_empty(struct misdn_jb *jb, char *data, int len)
- {
- int i, wp, rp, read = 0;
- ast_mutex_lock(&jb->mutexjb);
- rp = jb->rp;
- wp = jb->wp;
- if (jb->state_empty) {
- for (i = 0; i < len; i++) {
- if (wp == rp) {
- jb->rp = rp;
- jb->state_empty = 0;
- ast_mutex_unlock(&jb->mutexjb);
- return read;
- } else {
- if (jb->ok[rp] == 1) {
- data[i] = jb->samples[rp];
- jb->ok[rp] = 0;
- rp = (rp != jb->size - 1) ? rp + 1 : 0;
- read += 1;
- }
- }
- }
- if (wp >= rp)
- jb->state_buffer = wp - rp;
- else
- jb->state_buffer = jb->size - rp + wp;
- chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);
- jb->rp = rp;
- } else
- chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb);
- ast_mutex_unlock(&jb->mutexjb);
- return read;
- }
- /*******************************************************/
- /*************** JITTERBUFFER END *********************/
- /*******************************************************/
- static void chan_misdn_log(int level, int port, char *tmpl, ...)
- {
- va_list ap;
- char buf[1024];
- char port_buf[8];
- if (! ((0 <= port) && (port <= max_ports))) {
- ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port);
- port = 0;
- level = -1;
- }
- snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);
- va_start(ap, tmpl);
- vsnprintf(buf, sizeof(buf), tmpl, ap);
- va_end(ap);
- if (level == -1)
- ast_log(LOG_WARNING, "%s", buf);
- else if (misdn_debug_only[port] ?
- (level == 1 && misdn_debug[port]) || (level == misdn_debug[port])
- : level <= misdn_debug[port]) {
-
- ast_console_puts(port_buf);
- ast_console_puts(buf);
- }
-
- if ((level <= misdn_debug[0]) && !ast_strlen_zero(global_tracefile) ) {
- char ctimebuf[30];
- time_t tm = time(NULL);
- char *tmp = ctime_r(&tm, ctimebuf), *p;
- FILE *fp = fopen(global_tracefile, "a+");
- p = strchr(tmp, '\n');
- if (p)
- *p = ':';
-
- if (!fp) {
- ast_console_puts("Error opening Tracefile: [ ");
- ast_console_puts(global_tracefile);
- ast_console_puts(" ] ");
-
- ast_console_puts(strerror(errno));
- ast_console_puts("\n");
- return ;
- }
-
- fputs(tmp, fp);
- fputs(" ", fp);
- fputs(port_buf, fp);
- fputs(" ", fp);
- fputs(buf, fp);
- fclose(fp);
- }
- }
- AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Channel driver for mISDN Support (BRI/PRI)",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
|