chan_skinny.c 223 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * chan_skinny was developed by Jeremy McNamara & Florian Overkamp
  7. * chan_skinny was heavily modified/fixed by North Antara
  8. *
  9. * See http://www.asterisk.org for more information about
  10. * the Asterisk project. Please do not directly contact
  11. * any of the maintainers of this project for assistance;
  12. * the project provides a web site, mailing lists and IRC
  13. * channels for your use.
  14. *
  15. * This program is free software, distributed under the terms of
  16. * the GNU General Public License Version 2. See the LICENSE file
  17. * at the top of the source tree.
  18. */
  19. /*! \file
  20. *
  21. * \brief Implementation of the Skinny protocol
  22. *
  23. * \author Jeremy McNamara & Florian Overkamp & North Antara
  24. * \ingroup channel_drivers
  25. */
  26. /*** MODULEINFO
  27. <support_level>extended</support_level>
  28. <defaultenabled>no</defaultenabled>
  29. ***/
  30. #include "asterisk.h"
  31. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  32. #include <sys/socket.h>
  33. #include <netinet/in.h>
  34. #include <netinet/tcp.h>
  35. #include <sys/ioctl.h>
  36. #include <net/if.h>
  37. #include <fcntl.h>
  38. #include <netdb.h>
  39. #include <arpa/inet.h>
  40. #include <sys/signal.h>
  41. #include <signal.h>
  42. #include <ctype.h>
  43. #include "asterisk/lock.h"
  44. #include "asterisk/channel.h"
  45. #include "asterisk/config.h"
  46. #include "asterisk/module.h"
  47. #include "asterisk/pbx.h"
  48. #include "asterisk/sched.h"
  49. #include "asterisk/io.h"
  50. #include "asterisk/rtp_engine.h"
  51. #include "asterisk/netsock.h"
  52. #include "asterisk/acl.h"
  53. #include "asterisk/callerid.h"
  54. #include "asterisk/cli.h"
  55. #include "asterisk/manager.h"
  56. #include "asterisk/say.h"
  57. #include "asterisk/cdr.h"
  58. #include "asterisk/astdb.h"
  59. #include "asterisk/features.h"
  60. #include "asterisk/app.h"
  61. #include "asterisk/musiconhold.h"
  62. #include "asterisk/utils.h"
  63. #include "asterisk/dsp.h"
  64. #include "asterisk/stringfields.h"
  65. #include "asterisk/abstract_jb.h"
  66. #include "asterisk/threadstorage.h"
  67. #include "asterisk/devicestate.h"
  68. #include "asterisk/event.h"
  69. #include "asterisk/indications.h"
  70. #include "asterisk/linkedlists.h"
  71. /*** DOCUMENTATION
  72. <manager name="SKINNYdevices" language="en_US">
  73. <synopsis>
  74. List SKINNY devices (text format).
  75. </synopsis>
  76. <syntax>
  77. <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
  78. </syntax>
  79. <description>
  80. <para>Lists Skinny devices in text format with details on current status.
  81. Devicelist will follow as separate events, followed by a final event called
  82. DevicelistComplete.</para>
  83. </description>
  84. </manager>
  85. <manager name="SKINNYshowdevice" language="en_US">
  86. <synopsis>
  87. Show SKINNY device (text format).
  88. </synopsis>
  89. <syntax>
  90. <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
  91. <parameter name="Device" required="true">
  92. <para>The device name you want to check.</para>
  93. </parameter>
  94. </syntax>
  95. <description>
  96. <para>Show one SKINNY device with details on current status.</para>
  97. </description>
  98. </manager>
  99. <manager name="SKINNYlines" language="en_US">
  100. <synopsis>
  101. List SKINNY lines (text format).
  102. </synopsis>
  103. <syntax>
  104. <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
  105. </syntax>
  106. <description>
  107. <para>Lists Skinny lines in text format with details on current status.
  108. Linelist will follow as separate events, followed by a final event called
  109. LinelistComplete.</para>
  110. </description>
  111. </manager>
  112. <manager name="SKINNYshowline" language="en_US">
  113. <synopsis>
  114. Show SKINNY line (text format).
  115. </synopsis>
  116. <syntax>
  117. <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
  118. <parameter name="Line" required="true">
  119. <para>The line name you want to check.</para>
  120. </parameter>
  121. </syntax>
  122. <description>
  123. <para>Show one SKINNY line with details on current status.</para>
  124. </description>
  125. </manager>
  126. ***/
  127. #ifdef SKINNY_DEVMODE
  128. #define SKINNY_DEVONLY(code) \
  129. code
  130. #else
  131. #define SKINNY_DEVONLY(code)
  132. #endif
  133. /*************************************
  134. * Skinny/Asterisk Protocol Settings *
  135. *************************************/
  136. static const char tdesc[] = "Skinny Client Control Protocol (Skinny)";
  137. static const char config[] = "skinny.conf";
  138. static format_t default_capability = AST_FORMAT_ULAW | AST_FORMAT_ALAW;
  139. static struct ast_codec_pref default_prefs;
  140. enum skinny_codecs {
  141. SKINNY_CODEC_ALAW = 2,
  142. SKINNY_CODEC_ULAW = 4,
  143. SKINNY_CODEC_G723_1 = 9,
  144. SKINNY_CODEC_G729A = 12,
  145. SKINNY_CODEC_G726_32 = 82, /* XXX Which packing order does this translate to? */
  146. SKINNY_CODEC_H261 = 100,
  147. SKINNY_CODEC_H263 = 101
  148. };
  149. #define DEFAULT_SKINNY_PORT 2000
  150. #define DEFAULT_SKINNY_BACKLOG 2
  151. #define SKINNY_MAX_PACKET 1000
  152. #define DEFAULT_AUTH_TIMEOUT 30
  153. #define DEFAULT_AUTH_LIMIT 50
  154. static struct {
  155. unsigned int tos;
  156. unsigned int tos_audio;
  157. unsigned int tos_video;
  158. unsigned int cos;
  159. unsigned int cos_audio;
  160. unsigned int cos_video;
  161. } qos = { 0, 0, 0, 0, 0, 0 };
  162. static int keep_alive = 120;
  163. static int auth_timeout = DEFAULT_AUTH_TIMEOUT;
  164. static int auth_limit = DEFAULT_AUTH_LIMIT;
  165. static int unauth_sessions = 0;
  166. static char global_vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */
  167. static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */
  168. static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */
  169. static char date_format[6] = "D-M-Y";
  170. static char version_id[16] = "P002F202";
  171. #if __BYTE_ORDER == __LITTLE_ENDIAN
  172. #define letohl(x) (x)
  173. #define letohs(x) (x)
  174. #define htolel(x) (x)
  175. #define htoles(x) (x)
  176. #else
  177. #if defined(HAVE_BYTESWAP_H)
  178. #include <byteswap.h>
  179. #define letohl(x) bswap_32(x)
  180. #define letohs(x) bswap_16(x)
  181. #define htolel(x) bswap_32(x)
  182. #define htoles(x) bswap_16(x)
  183. #elif defined(HAVE_SYS_ENDIAN_SWAP16)
  184. #include <sys/endian.h>
  185. #define letohl(x) __swap32(x)
  186. #define letohs(x) __swap16(x)
  187. #define htolel(x) __swap32(x)
  188. #define htoles(x) __swap16(x)
  189. #elif defined(HAVE_SYS_ENDIAN_BSWAP16)
  190. #include <sys/endian.h>
  191. #define letohl(x) bswap32(x)
  192. #define letohs(x) bswap16(x)
  193. #define htolel(x) bswap32(x)
  194. #define htoles(x) bswap16(x)
  195. #else
  196. #define __bswap_16(x) \
  197. ((((x) & 0xff00) >> 8) | \
  198. (((x) & 0x00ff) << 8))
  199. #define __bswap_32(x) \
  200. ((((x) & 0xff000000) >> 24) | \
  201. (((x) & 0x00ff0000) >> 8) | \
  202. (((x) & 0x0000ff00) << 8) | \
  203. (((x) & 0x000000ff) << 24))
  204. #define letohl(x) __bswap_32(x)
  205. #define letohs(x) __bswap_16(x)
  206. #define htolel(x) __bswap_32(x)
  207. #define htoles(x) __bswap_16(x)
  208. #endif
  209. #endif
  210. /*! Global jitterbuffer configuration - by default, jb is disabled
  211. * \note Values shown here match the defaults shown in skinny.conf.sample */
  212. static struct ast_jb_conf default_jbconf =
  213. {
  214. .flags = 0,
  215. .max_size = 200,
  216. .resync_threshold = 1000,
  217. .impl = "fixed",
  218. .target_extra = 40,
  219. };
  220. static struct ast_jb_conf global_jbconf;
  221. #ifdef SKINNY_DEVMODE
  222. AST_THREADSTORAGE(message2str_threadbuf);
  223. #define MESSAGE2STR_BUFSIZE 35
  224. #endif
  225. AST_THREADSTORAGE(device2str_threadbuf);
  226. #define DEVICE2STR_BUFSIZE 15
  227. AST_THREADSTORAGE(control2str_threadbuf);
  228. #define CONTROL2STR_BUFSIZE 100
  229. /*********************
  230. * Protocol Messages *
  231. *********************/
  232. /* message types */
  233. #define KEEP_ALIVE_MESSAGE 0x0000
  234. /* no additional struct */
  235. #define REGISTER_MESSAGE 0x0001
  236. struct register_message {
  237. char name[16];
  238. uint32_t userId;
  239. uint32_t instance;
  240. uint32_t ip;
  241. uint32_t type;
  242. uint32_t maxStreams;
  243. };
  244. #define IP_PORT_MESSAGE 0x0002
  245. #define KEYPAD_BUTTON_MESSAGE 0x0003
  246. struct keypad_button_message {
  247. uint32_t button;
  248. uint32_t lineInstance;
  249. uint32_t callReference;
  250. };
  251. #define ENBLOC_CALL_MESSAGE 0x0004
  252. struct enbloc_call_message {
  253. char calledParty[24];
  254. };
  255. #define STIMULUS_MESSAGE 0x0005
  256. struct stimulus_message {
  257. uint32_t stimulus;
  258. uint32_t stimulusInstance;
  259. uint32_t callreference;
  260. };
  261. #define OFFHOOK_MESSAGE 0x0006
  262. struct offhook_message {
  263. uint32_t instance;
  264. uint32_t reference;
  265. };
  266. #define ONHOOK_MESSAGE 0x0007
  267. struct onhook_message {
  268. uint32_t instance;
  269. uint32_t reference;
  270. };
  271. #define CAPABILITIES_RES_MESSAGE 0x0010
  272. struct station_capabilities {
  273. uint32_t codec;
  274. uint32_t frames;
  275. union {
  276. char res[8];
  277. uint32_t rate;
  278. } payloads;
  279. };
  280. #define SKINNY_MAX_CAPABILITIES 18
  281. struct capabilities_res_message {
  282. uint32_t count;
  283. struct station_capabilities caps[SKINNY_MAX_CAPABILITIES];
  284. };
  285. #define SPEED_DIAL_STAT_REQ_MESSAGE 0x000A
  286. struct speed_dial_stat_req_message {
  287. uint32_t speedDialNumber;
  288. };
  289. #define LINE_STATE_REQ_MESSAGE 0x000B
  290. struct line_state_req_message {
  291. uint32_t lineNumber;
  292. };
  293. #define TIME_DATE_REQ_MESSAGE 0x000D
  294. #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
  295. #define VERSION_REQ_MESSAGE 0x000F
  296. #define SERVER_REQUEST_MESSAGE 0x0012
  297. #define ALARM_MESSAGE 0x0020
  298. struct alarm_message {
  299. uint32_t alarmSeverity;
  300. char displayMessage[80];
  301. uint32_t alarmParam1;
  302. uint32_t alarmParam2;
  303. };
  304. #define OPEN_RECEIVE_CHANNEL_ACK_MESSAGE 0x0022
  305. struct open_receive_channel_ack_message {
  306. uint32_t status;
  307. uint32_t ipAddr;
  308. uint32_t port;
  309. uint32_t passThruId;
  310. };
  311. #define SOFT_KEY_SET_REQ_MESSAGE 0x0025
  312. #define SOFT_KEY_EVENT_MESSAGE 0x0026
  313. struct soft_key_event_message {
  314. uint32_t softKeyEvent;
  315. uint32_t instance;
  316. uint32_t callreference;
  317. };
  318. #define UNREGISTER_MESSAGE 0x0027
  319. #define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
  320. #define HEADSET_STATUS_MESSAGE 0x002B
  321. #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
  322. #define REGISTER_ACK_MESSAGE 0x0081
  323. struct register_ack_message {
  324. uint32_t keepAlive;
  325. char dateTemplate[6];
  326. char res[2];
  327. uint32_t secondaryKeepAlive;
  328. char res2[4];
  329. };
  330. #define START_TONE_MESSAGE 0x0082
  331. struct start_tone_message {
  332. uint32_t tone;
  333. uint32_t space;
  334. uint32_t instance;
  335. uint32_t reference;
  336. };
  337. #define STOP_TONE_MESSAGE 0x0083
  338. struct stop_tone_message {
  339. uint32_t instance;
  340. uint32_t reference;
  341. };
  342. #define SET_RINGER_MESSAGE 0x0085
  343. struct set_ringer_message {
  344. uint32_t ringerMode;
  345. uint32_t unknown1; /* See notes in transmit_ringer_mode */
  346. uint32_t unknown2;
  347. uint32_t space[2];
  348. };
  349. #define SET_LAMP_MESSAGE 0x0086
  350. struct set_lamp_message {
  351. uint32_t stimulus;
  352. uint32_t stimulusInstance;
  353. uint32_t deviceStimulus;
  354. };
  355. #define SET_SPEAKER_MESSAGE 0x0088
  356. struct set_speaker_message {
  357. uint32_t mode;
  358. };
  359. /* XXX When do we need to use this? */
  360. #define SET_MICROPHONE_MESSAGE 0x0089
  361. struct set_microphone_message {
  362. uint32_t mode;
  363. };
  364. #define START_MEDIA_TRANSMISSION_MESSAGE 0x008A
  365. struct media_qualifier {
  366. uint32_t precedence;
  367. uint32_t vad;
  368. uint16_t packets;
  369. uint32_t bitRate;
  370. };
  371. struct start_media_transmission_message {
  372. uint32_t conferenceId;
  373. uint32_t passThruPartyId;
  374. uint32_t remoteIp;
  375. uint32_t remotePort;
  376. uint32_t packetSize;
  377. uint32_t payloadType;
  378. struct media_qualifier qualifier;
  379. uint32_t space[16];
  380. };
  381. #define STOP_MEDIA_TRANSMISSION_MESSAGE 0x008B
  382. struct stop_media_transmission_message {
  383. uint32_t conferenceId;
  384. uint32_t passThruPartyId;
  385. uint32_t space[3];
  386. };
  387. #define CALL_INFO_MESSAGE 0x008F
  388. struct call_info_message {
  389. char callingPartyName[40];
  390. char callingParty[24];
  391. char calledPartyName[40];
  392. char calledParty[24];
  393. uint32_t instance;
  394. uint32_t reference;
  395. uint32_t type;
  396. char originalCalledPartyName[40];
  397. char originalCalledParty[24];
  398. char lastRedirectingPartyName[40];
  399. char lastRedirectingParty[24];
  400. uint32_t originalCalledPartyRedirectReason;
  401. uint32_t lastRedirectingReason;
  402. char callingPartyVoiceMailbox[24];
  403. char calledPartyVoiceMailbox[24];
  404. char originalCalledPartyVoiceMailbox[24];
  405. char lastRedirectingVoiceMailbox[24];
  406. uint32_t space[3];
  407. };
  408. #define FORWARD_STAT_MESSAGE 0x0090
  409. struct forward_stat_message {
  410. uint32_t activeforward;
  411. uint32_t lineNumber;
  412. uint32_t fwdall;
  413. char fwdallnum[24];
  414. uint32_t fwdbusy;
  415. char fwdbusynum[24];
  416. uint32_t fwdnoanswer;
  417. char fwdnoanswernum[24];
  418. };
  419. #define SPEED_DIAL_STAT_RES_MESSAGE 0x0091
  420. struct speed_dial_stat_res_message {
  421. uint32_t speedDialNumber;
  422. char speedDialDirNumber[24];
  423. char speedDialDisplayName[40];
  424. };
  425. #define LINE_STAT_RES_MESSAGE 0x0092
  426. struct line_stat_res_message {
  427. uint32_t lineNumber;
  428. char lineDirNumber[24];
  429. char lineDisplayName[24];
  430. uint32_t space[15];
  431. };
  432. #define DEFINETIMEDATE_MESSAGE 0x0094
  433. struct definetimedate_message {
  434. uint32_t year; /* since 1900 */
  435. uint32_t month;
  436. uint32_t dayofweek; /* monday = 1 */
  437. uint32_t day;
  438. uint32_t hour;
  439. uint32_t minute;
  440. uint32_t seconds;
  441. uint32_t milliseconds;
  442. uint32_t timestamp;
  443. };
  444. #define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
  445. struct button_definition {
  446. uint8_t instanceNumber;
  447. uint8_t buttonDefinition;
  448. };
  449. struct button_definition_template {
  450. uint8_t buttonDefinition;
  451. /* for now, anything between 0xB0 and 0xCF is custom */
  452. /*int custom;*/
  453. };
  454. #define STIMULUS_REDIAL 0x01
  455. #define STIMULUS_SPEEDDIAL 0x02
  456. #define STIMULUS_HOLD 0x03
  457. #define STIMULUS_TRANSFER 0x04
  458. #define STIMULUS_FORWARDALL 0x05
  459. #define STIMULUS_FORWARDBUSY 0x06
  460. #define STIMULUS_FORWARDNOANSWER 0x07
  461. #define STIMULUS_DISPLAY 0x08
  462. #define STIMULUS_LINE 0x09
  463. #define STIMULUS_VOICEMAIL 0x0F
  464. #define STIMULUS_AUTOANSWER 0x11
  465. #define STIMULUS_DND 0x3F
  466. #define STIMULUS_CONFERENCE 0x7D
  467. #define STIMULUS_CALLPARK 0x7E
  468. #define STIMULUS_CALLPICKUP 0x7F
  469. #define STIMULUS_NONE 0xFF
  470. /* Button types */
  471. #define BT_REDIAL STIMULUS_REDIAL
  472. #define BT_SPEEDDIAL STIMULUS_SPEEDDIAL
  473. #define BT_HOLD STIMULUS_HOLD
  474. #define BT_TRANSFER STIMULUS_TRANSFER
  475. #define BT_FORWARDALL STIMULUS_FORWARDALL
  476. #define BT_FORWARDBUSY STIMULUS_FORWARDBUSY
  477. #define BT_FORWARDNOANSWER STIMULUS_FORWARDNOANSWER
  478. #define BT_DISPLAY STIMULUS_DISPLAY
  479. #define BT_LINE STIMULUS_LINE
  480. #define BT_VOICEMAIL STIMULUS_VOICEMAIL
  481. #define BT_AUTOANSWER STIMULUS_AUTOANSWER
  482. #define BT_DND STIMULUS_DND
  483. #define BT_CONFERENCE STIMULUS_CONFERENCE
  484. #define BT_CALLPARK STIMULUS_CALLPARK
  485. #define BT_CALLPICKUP STIMULUS_CALLPICKUP
  486. #define BT_NONE 0x00
  487. /* Custom button types - add our own between 0xB0 and 0xCF.
  488. This may need to be revised in the future,
  489. if stimuluses are ever added in this range. */
  490. #define BT_CUST_LINESPEEDDIAL 0xB0 /* line or speeddial with/without hint */
  491. #define BT_CUST_LINE 0xB1 /* line or speeddial with hint only */
  492. struct button_template_res_message {
  493. uint32_t buttonOffset;
  494. uint32_t buttonCount;
  495. uint32_t totalButtonCount;
  496. struct button_definition definition[42];
  497. };
  498. #define VERSION_RES_MESSAGE 0x0098
  499. struct version_res_message {
  500. char version[16];
  501. };
  502. #define DISPLAYTEXT_MESSAGE 0x0099
  503. struct displaytext_message {
  504. char text[40];
  505. };
  506. #define CLEAR_NOTIFY_MESSAGE 0x0115
  507. #define CLEAR_DISPLAY_MESSAGE 0x009A
  508. #define CAPABILITIES_REQ_MESSAGE 0x009B
  509. #define REGISTER_REJ_MESSAGE 0x009D
  510. struct register_rej_message {
  511. char errMsg[33];
  512. };
  513. #define SERVER_RES_MESSAGE 0x009E
  514. struct server_identifier {
  515. char serverName[48];
  516. };
  517. struct server_res_message {
  518. struct server_identifier server[5];
  519. uint32_t serverListenPort[5];
  520. uint32_t serverIpAddr[5];
  521. };
  522. #define RESET_MESSAGE 0x009F
  523. struct reset_message {
  524. uint32_t resetType;
  525. };
  526. #define KEEP_ALIVE_ACK_MESSAGE 0x0100
  527. #define OPEN_RECEIVE_CHANNEL_MESSAGE 0x0105
  528. struct open_receive_channel_message {
  529. uint32_t conferenceId;
  530. uint32_t partyId;
  531. uint32_t packets;
  532. uint32_t capability;
  533. uint32_t echo;
  534. uint32_t bitrate;
  535. uint32_t space[16];
  536. };
  537. #define CLOSE_RECEIVE_CHANNEL_MESSAGE 0x0106
  538. struct close_receive_channel_message {
  539. uint32_t conferenceId;
  540. uint32_t partyId;
  541. uint32_t space[2];
  542. };
  543. #define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
  544. struct soft_key_template_definition {
  545. char softKeyLabel[16];
  546. uint32_t softKeyEvent;
  547. };
  548. #define KEYDEF_ONHOOK 0
  549. #define KEYDEF_CONNECTED 1
  550. #define KEYDEF_ONHOLD 2
  551. #define KEYDEF_RINGIN 3
  552. #define KEYDEF_OFFHOOK 4
  553. #define KEYDEF_CONNWITHTRANS 5
  554. #define KEYDEF_DADFD 6 /* Digits After Dialing First Digit */
  555. #define KEYDEF_CONNWITHCONF 7
  556. #define KEYDEF_RINGOUT 8
  557. #define KEYDEF_OFFHOOKWITHFEAT 9
  558. #define KEYDEF_UNKNOWN 10
  559. #define SOFTKEY_NONE 0x00
  560. #define SOFTKEY_REDIAL 0x01
  561. #define SOFTKEY_NEWCALL 0x02
  562. #define SOFTKEY_HOLD 0x03
  563. #define SOFTKEY_TRNSFER 0x04
  564. #define SOFTKEY_CFWDALL 0x05
  565. #define SOFTKEY_CFWDBUSY 0x06
  566. #define SOFTKEY_CFWDNOANSWER 0x07
  567. #define SOFTKEY_BKSPC 0x08
  568. #define SOFTKEY_ENDCALL 0x09
  569. #define SOFTKEY_RESUME 0x0A
  570. #define SOFTKEY_ANSWER 0x0B
  571. #define SOFTKEY_INFO 0x0C
  572. #define SOFTKEY_CONFRN 0x0D
  573. #define SOFTKEY_PARK 0x0E
  574. #define SOFTKEY_JOIN 0x0F
  575. #define SOFTKEY_MEETME 0x10
  576. #define SOFTKEY_PICKUP 0x11
  577. #define SOFTKEY_GPICKUP 0x12
  578. #define SOFTKEY_DND 0x13
  579. #define SOFTKEY_IDIVERT 0x14
  580. static struct soft_key_template_definition soft_key_template_default[] = {
  581. { "\200\001", SOFTKEY_REDIAL },
  582. { "\200\002", SOFTKEY_NEWCALL },
  583. { "\200\003", SOFTKEY_HOLD },
  584. { "\200\004", SOFTKEY_TRNSFER },
  585. { "\200\005", SOFTKEY_CFWDALL },
  586. { "\200\006", SOFTKEY_CFWDBUSY },
  587. { "\200\007", SOFTKEY_CFWDNOANSWER },
  588. { "\200\010", SOFTKEY_BKSPC },
  589. { "\200\011", SOFTKEY_ENDCALL },
  590. { "\200\012", SOFTKEY_RESUME },
  591. { "\200\013", SOFTKEY_ANSWER },
  592. { "\200\014", SOFTKEY_INFO },
  593. { "\200\015", SOFTKEY_CONFRN },
  594. { "\200\016", SOFTKEY_PARK },
  595. { "\200\017", SOFTKEY_JOIN },
  596. { "\200\020", SOFTKEY_MEETME },
  597. { "\200\021", SOFTKEY_PICKUP },
  598. { "\200\022", SOFTKEY_GPICKUP },
  599. { "\200\077", SOFTKEY_DND },
  600. { "\200\120", SOFTKEY_IDIVERT },
  601. };
  602. /* Localized message "codes" (in octal)
  603. Below is en_US (taken from a 7970)
  604. \200\xxx
  605. \000: ???
  606. \001: Redial
  607. \002: New Call
  608. \003: Hold
  609. \004: Transfer
  610. \005: CFwdALL
  611. \006: CFwdBusy
  612. \007: CFwdNoAnswer
  613. \010: <<
  614. \011: EndCall
  615. \012: Resume
  616. \013: Answer
  617. \014: Info
  618. \015: Confrn
  619. \016: Park
  620. \017: Join
  621. \020: MeetMe
  622. \021: PickUp
  623. \022: GPickUp
  624. \023: Your current options
  625. \024: Off Hook
  626. \025: On Hook
  627. \026: Ring out
  628. \027: From
  629. \030: Connected
  630. \031: Busy
  631. \032: Line In Use
  632. \033: Call Waiting
  633. \034: Call Transfer
  634. \035: Call Park
  635. \036: Call Proceed
  636. \037: In Use Remote
  637. \040: Enter number
  638. \041: Call park At
  639. \042: Primary Only
  640. \043: Temp Fail
  641. \044: You Have VoiceMail
  642. \045: Forwarded to
  643. \046: Can Not Complete Conference
  644. \047: No Conference Bridge
  645. \050: Can Not Hold Primary Control
  646. \051: Invalid Conference Participant
  647. \052: In Conference Already
  648. \053: No Participant Info
  649. \054: Exceed Maximum Parties
  650. \055: Key Is Not Active
  651. \056: Error No License
  652. \057: Error DBConfig
  653. \060: Error Database
  654. \061: Error Pass Limit
  655. \062: Error Unknown
  656. \063: Error Mismatch
  657. \064: Conference
  658. \065: Park Number
  659. \066: Private
  660. \067: Not Enough Bandwidth
  661. \070: Unknown Number
  662. \071: RmLstC
  663. \072: Voicemail
  664. \073: ImmDiv
  665. \074: Intrcpt
  666. \075: SetWtch
  667. \076: TrnsfVM
  668. \077: DND
  669. \100: DivAll
  670. \101: CallBack
  671. \102: Network congestion,rerouting
  672. \103: Barge
  673. \104: Failed to setup Barge
  674. \105: Another Barge exists
  675. \106: Incompatible device type
  676. \107: No Park Number Available
  677. \110: CallPark Reversion
  678. \111: Service is not Active
  679. \112: High Traffic Try Again Later
  680. \113: QRT
  681. \114: MCID
  682. \115: DirTrfr
  683. \116: Select
  684. \117: ConfList
  685. \120: iDivert
  686. \121: cBarge
  687. \122: Can Not Complete Transfer
  688. \123: Can Not Join Calls
  689. \124: Mcid Successful
  690. \125: Number Not Configured
  691. \126: Security Error
  692. \127: Video Bandwidth Unavailable
  693. \130: VidMode
  694. \131: Max Call Duration Timeout
  695. \132: Max Hold Duration Timeout
  696. \133: OPickUp
  697. \134: ???
  698. \135: ???
  699. \136: ???
  700. \137: ???
  701. \140: ???
  702. \141: External Transfer Restricted
  703. \142: ???
  704. \143: ???
  705. \144: ???
  706. \145: Mac Address
  707. \146: Host Name
  708. \147: Domain Name
  709. \150: IP Address
  710. \151: Subnet Mask
  711. \152: TFTP Server 1
  712. \153: Default Router 1
  713. \154: Default Router 2
  714. \155: Default Router 3
  715. \156: Default Router 4
  716. \157: Default Router 5
  717. \160: DNS Server 1
  718. \161: DNS Server 2
  719. \162: DNS Server 3
  720. \163: DNS Server 4
  721. \164: DNS Server 5
  722. \165: Operational VLAN Id
  723. \166: Admin. VLAN Id
  724. \167: CallManager 1
  725. \170: CallManager 2
  726. \171: CallManager 3
  727. \172: CallManager 4
  728. \173: CallManager 5
  729. \174: Information URL
  730. \175: Directories URL
  731. \176: Messages URL
  732. \177: Services URL
  733. */
  734. struct soft_key_definitions {
  735. const uint8_t mode;
  736. const uint8_t *defaults;
  737. const int count;
  738. };
  739. static const uint8_t soft_key_default_onhook[] = {
  740. SOFTKEY_REDIAL,
  741. SOFTKEY_NEWCALL,
  742. SOFTKEY_CFWDALL,
  743. SOFTKEY_CFWDBUSY,
  744. SOFTKEY_DND,
  745. /*SOFTKEY_GPICKUP,
  746. SOFTKEY_CONFRN,*/
  747. };
  748. static const uint8_t soft_key_default_connected[] = {
  749. SOFTKEY_HOLD,
  750. SOFTKEY_ENDCALL,
  751. SOFTKEY_TRNSFER,
  752. SOFTKEY_PARK,
  753. SOFTKEY_CFWDALL,
  754. SOFTKEY_CFWDBUSY,
  755. };
  756. static const uint8_t soft_key_default_onhold[] = {
  757. SOFTKEY_RESUME,
  758. SOFTKEY_NEWCALL,
  759. SOFTKEY_ENDCALL,
  760. SOFTKEY_TRNSFER,
  761. };
  762. static const uint8_t soft_key_default_ringin[] = {
  763. SOFTKEY_ANSWER,
  764. SOFTKEY_ENDCALL,
  765. SOFTKEY_TRNSFER,
  766. };
  767. static const uint8_t soft_key_default_offhook[] = {
  768. SOFTKEY_REDIAL,
  769. SOFTKEY_ENDCALL,
  770. SOFTKEY_CFWDALL,
  771. SOFTKEY_CFWDBUSY,
  772. /*SOFTKEY_GPICKUP,*/
  773. };
  774. static const uint8_t soft_key_default_connwithtrans[] = {
  775. SOFTKEY_HOLD,
  776. SOFTKEY_ENDCALL,
  777. SOFTKEY_TRNSFER,
  778. SOFTKEY_PARK,
  779. SOFTKEY_CFWDALL,
  780. SOFTKEY_CFWDBUSY,
  781. };
  782. static const uint8_t soft_key_default_dadfd[] = {
  783. SOFTKEY_BKSPC,
  784. SOFTKEY_ENDCALL,
  785. };
  786. static const uint8_t soft_key_default_connwithconf[] = {
  787. SOFTKEY_NONE,
  788. };
  789. static const uint8_t soft_key_default_ringout[] = {
  790. SOFTKEY_NONE,
  791. SOFTKEY_ENDCALL,
  792. };
  793. static const uint8_t soft_key_default_offhookwithfeat[] = {
  794. SOFTKEY_REDIAL,
  795. SOFTKEY_ENDCALL,
  796. SOFTKEY_TRNSFER,
  797. };
  798. static const uint8_t soft_key_default_unknown[] = {
  799. SOFTKEY_NONE,
  800. };
  801. static const struct soft_key_definitions soft_key_default_definitions[] = {
  802. {KEYDEF_ONHOOK, soft_key_default_onhook, sizeof(soft_key_default_onhook) / sizeof(uint8_t)},
  803. {KEYDEF_CONNECTED, soft_key_default_connected, sizeof(soft_key_default_connected) / sizeof(uint8_t)},
  804. {KEYDEF_ONHOLD, soft_key_default_onhold, sizeof(soft_key_default_onhold) / sizeof(uint8_t)},
  805. {KEYDEF_RINGIN, soft_key_default_ringin, sizeof(soft_key_default_ringin) / sizeof(uint8_t)},
  806. {KEYDEF_OFFHOOK, soft_key_default_offhook, sizeof(soft_key_default_offhook) / sizeof(uint8_t)},
  807. {KEYDEF_CONNWITHTRANS, soft_key_default_connwithtrans, sizeof(soft_key_default_connwithtrans) / sizeof(uint8_t)},
  808. {KEYDEF_DADFD, soft_key_default_dadfd, sizeof(soft_key_default_dadfd) / sizeof(uint8_t)},
  809. {KEYDEF_CONNWITHCONF, soft_key_default_connwithconf, sizeof(soft_key_default_connwithconf) / sizeof(uint8_t)},
  810. {KEYDEF_RINGOUT, soft_key_default_ringout, sizeof(soft_key_default_ringout) / sizeof(uint8_t)},
  811. {KEYDEF_OFFHOOKWITHFEAT, soft_key_default_offhookwithfeat, sizeof(soft_key_default_offhookwithfeat) / sizeof(uint8_t)},
  812. {KEYDEF_UNKNOWN, soft_key_default_unknown, sizeof(soft_key_default_unknown) / sizeof(uint8_t)}
  813. };
  814. struct soft_key_template_res_message {
  815. uint32_t softKeyOffset;
  816. uint32_t softKeyCount;
  817. uint32_t totalSoftKeyCount;
  818. struct soft_key_template_definition softKeyTemplateDefinition[32];
  819. };
  820. #define SOFT_KEY_SET_RES_MESSAGE 0x0109
  821. struct soft_key_set_definition {
  822. uint8_t softKeyTemplateIndex[16];
  823. uint16_t softKeyInfoIndex[16];
  824. };
  825. struct soft_key_set_res_message {
  826. uint32_t softKeySetOffset;
  827. uint32_t softKeySetCount;
  828. uint32_t totalSoftKeySetCount;
  829. struct soft_key_set_definition softKeySetDefinition[16];
  830. uint32_t res;
  831. };
  832. #define SELECT_SOFT_KEYS_MESSAGE 0x0110
  833. struct select_soft_keys_message {
  834. uint32_t instance;
  835. uint32_t reference;
  836. uint32_t softKeySetIndex;
  837. uint32_t validKeyMask;
  838. };
  839. #define CALL_STATE_MESSAGE 0x0111
  840. struct call_state_message {
  841. uint32_t callState;
  842. uint32_t lineInstance;
  843. uint32_t callReference;
  844. uint32_t space[3];
  845. };
  846. #define DISPLAY_PROMPT_STATUS_MESSAGE 0x0112
  847. struct display_prompt_status_message {
  848. uint32_t messageTimeout;
  849. char promptMessage[32];
  850. uint32_t lineInstance;
  851. uint32_t callReference;
  852. uint32_t space[3];
  853. };
  854. #define CLEAR_PROMPT_MESSAGE 0x0113
  855. struct clear_prompt_message {
  856. uint32_t lineInstance;
  857. uint32_t callReference;
  858. };
  859. #define DISPLAY_NOTIFY_MESSAGE 0x0114
  860. struct display_notify_message {
  861. uint32_t displayTimeout;
  862. char displayMessage[100];
  863. };
  864. #define ACTIVATE_CALL_PLANE_MESSAGE 0x0116
  865. struct activate_call_plane_message {
  866. uint32_t lineInstance;
  867. };
  868. #define DIALED_NUMBER_MESSAGE 0x011D
  869. struct dialed_number_message {
  870. char dialedNumber[24];
  871. uint32_t lineInstance;
  872. uint32_t callReference;
  873. };
  874. union skinny_data {
  875. struct alarm_message alarm;
  876. struct speed_dial_stat_req_message speeddialreq;
  877. struct register_message reg;
  878. struct register_ack_message regack;
  879. struct register_rej_message regrej;
  880. struct capabilities_res_message caps;
  881. struct version_res_message version;
  882. struct button_template_res_message buttontemplate;
  883. struct displaytext_message displaytext;
  884. struct display_prompt_status_message displaypromptstatus;
  885. struct clear_prompt_message clearpromptstatus;
  886. struct definetimedate_message definetimedate;
  887. struct start_tone_message starttone;
  888. struct stop_tone_message stoptone;
  889. struct speed_dial_stat_res_message speeddial;
  890. struct line_state_req_message line;
  891. struct line_stat_res_message linestat;
  892. struct soft_key_set_res_message softkeysets;
  893. struct soft_key_template_res_message softkeytemplate;
  894. struct server_res_message serverres;
  895. struct reset_message reset;
  896. struct set_lamp_message setlamp;
  897. struct set_ringer_message setringer;
  898. struct call_state_message callstate;
  899. struct keypad_button_message keypad;
  900. struct select_soft_keys_message selectsoftkey;
  901. struct activate_call_plane_message activatecallplane;
  902. struct stimulus_message stimulus;
  903. struct offhook_message offhook;
  904. struct onhook_message onhook;
  905. struct set_speaker_message setspeaker;
  906. struct set_microphone_message setmicrophone;
  907. struct call_info_message callinfo;
  908. struct start_media_transmission_message startmedia;
  909. struct stop_media_transmission_message stopmedia;
  910. struct open_receive_channel_message openreceivechannel;
  911. struct open_receive_channel_ack_message openreceivechannelack;
  912. struct close_receive_channel_message closereceivechannel;
  913. struct display_notify_message displaynotify;
  914. struct dialed_number_message dialednumber;
  915. struct soft_key_event_message softkeyeventmessage;
  916. struct enbloc_call_message enbloccallmessage;
  917. struct forward_stat_message forwardstat;
  918. };
  919. /* packet composition */
  920. struct skinny_req {
  921. int len;
  922. int res;
  923. int e;
  924. union skinny_data data;
  925. };
  926. /* XXX This is the combined size of the variables above. (len, res, e)
  927. If more are added, this MUST change.
  928. (sizeof(skinny_req) - sizeof(skinny_data)) DOES NOT WORK on all systems (amd64?). */
  929. static int skinny_header_size = 12;
  930. /*****************************
  931. * Asterisk specific globals *
  932. *****************************/
  933. static int skinnydebug = 0;
  934. static int skinnyreload = 0;
  935. /* a hostname, portnumber, socket and such is usefull for VoIP protocols */
  936. static struct sockaddr_in bindaddr;
  937. static char ourhost[256];
  938. static int ourport;
  939. static struct in_addr __ourip;
  940. static struct ast_hostent ahp;
  941. static struct hostent *hp;
  942. static int skinnysock = -1;
  943. static pthread_t accept_t;
  944. static int callnums = 1;
  945. #define SKINNY_DEVICE_UNKNOWN -1
  946. #define SKINNY_DEVICE_NONE 0
  947. #define SKINNY_DEVICE_30SPPLUS 1
  948. #define SKINNY_DEVICE_12SPPLUS 2
  949. #define SKINNY_DEVICE_12SP 3
  950. #define SKINNY_DEVICE_12 4
  951. #define SKINNY_DEVICE_30VIP 5
  952. #define SKINNY_DEVICE_7910 6
  953. #define SKINNY_DEVICE_7960 7
  954. #define SKINNY_DEVICE_7940 8
  955. #define SKINNY_DEVICE_7935 9
  956. #define SKINNY_DEVICE_ATA186 12 /* Cisco ATA-186 */
  957. #define SKINNY_DEVICE_7941 115
  958. #define SKINNY_DEVICE_7971 119
  959. #define SKINNY_DEVICE_7914 124 /* Expansion module */
  960. #define SKINNY_DEVICE_7985 302
  961. #define SKINNY_DEVICE_7911 307
  962. #define SKINNY_DEVICE_7961GE 308
  963. #define SKINNY_DEVICE_7941GE 309
  964. #define SKINNY_DEVICE_7931 348
  965. #define SKINNY_DEVICE_7921 365
  966. #define SKINNY_DEVICE_7906 369
  967. #define SKINNY_DEVICE_7962 404 /* Not found */
  968. #define SKINNY_DEVICE_7937 431
  969. #define SKINNY_DEVICE_7942 434
  970. #define SKINNY_DEVICE_7945 435
  971. #define SKINNY_DEVICE_7965 436
  972. #define SKINNY_DEVICE_7975 437
  973. #define SKINNY_DEVICE_7905 20000
  974. #define SKINNY_DEVICE_7920 30002
  975. #define SKINNY_DEVICE_7970 30006
  976. #define SKINNY_DEVICE_7912 30007
  977. #define SKINNY_DEVICE_7902 30008
  978. #define SKINNY_DEVICE_CIPC 30016 /* Cisco IP Communicator */
  979. #define SKINNY_DEVICE_7961 30018
  980. #define SKINNY_DEVICE_7936 30019
  981. #define SKINNY_DEVICE_SCCPGATEWAY_AN 30027 /* Analog gateway */
  982. #define SKINNY_DEVICE_SCCPGATEWAY_BRI 30028 /* BRI gateway */
  983. #define SKINNY_SPEAKERON 1
  984. #define SKINNY_SPEAKEROFF 2
  985. #define SKINNY_MICON 1
  986. #define SKINNY_MICOFF 2
  987. #define SKINNY_OFFHOOK 1
  988. #define SKINNY_ONHOOK 2
  989. #define SKINNY_RINGOUT 3
  990. #define SKINNY_RINGIN 4
  991. #define SKINNY_CONNECTED 5
  992. #define SKINNY_BUSY 6
  993. #define SKINNY_CONGESTION 7
  994. #define SKINNY_HOLD 8
  995. #define SKINNY_CALLWAIT 9
  996. #define SKINNY_TRANSFER 10
  997. #define SKINNY_PARK 11
  998. #define SKINNY_PROGRESS 12
  999. #define SKINNY_CALLREMOTEMULTILINE 13
  1000. #define SKINNY_INVALID 14
  1001. #define SKINNY_SILENCE 0x00 /* Note sure this is part of the protocol, remove? */
  1002. #define SKINNY_DIALTONE 0x21
  1003. #define SKINNY_BUSYTONE 0x23
  1004. #define SKINNY_ALERT 0x24
  1005. #define SKINNY_REORDER 0x25
  1006. #define SKINNY_CALLWAITTONE 0x2D
  1007. #define SKINNY_NOTONE 0x7F
  1008. #define SKINNY_LAMP_OFF 1
  1009. #define SKINNY_LAMP_ON 2
  1010. #define SKINNY_LAMP_WINK 3
  1011. #define SKINNY_LAMP_FLASH 4
  1012. #define SKINNY_LAMP_BLINK 5
  1013. #define SKINNY_RING_OFF 1
  1014. #define SKINNY_RING_INSIDE 2
  1015. #define SKINNY_RING_OUTSIDE 3
  1016. #define SKINNY_RING_FEATURE 4
  1017. #define SKINNY_CFWD_ALL (1 << 0)
  1018. #define SKINNY_CFWD_BUSY (1 << 1)
  1019. #define SKINNY_CFWD_NOANSWER (1 << 2)
  1020. /* Skinny rtp stream modes. Do we really need this? */
  1021. #define SKINNY_CX_SENDONLY 0
  1022. #define SKINNY_CX_RECVONLY 1
  1023. #define SKINNY_CX_SENDRECV 2
  1024. #define SKINNY_CX_CONF 3
  1025. #define SKINNY_CX_CONFERENCE 3
  1026. #define SKINNY_CX_MUTE 4
  1027. #define SKINNY_CX_INACTIVE 4
  1028. #if 0
  1029. static const char * const skinny_cxmodes[] = {
  1030. "sendonly",
  1031. "recvonly",
  1032. "sendrecv",
  1033. "confrnce",
  1034. "inactive"
  1035. };
  1036. #endif
  1037. /* driver scheduler */
  1038. static struct sched_context *sched = NULL;
  1039. static struct io_context *io;
  1040. /* Protect the monitoring thread, so only one process can kill or start it, and not
  1041. when it's doing something critical. */
  1042. AST_MUTEX_DEFINE_STATIC(monlock);
  1043. /* Protect the network socket */
  1044. AST_MUTEX_DEFINE_STATIC(netlock);
  1045. /* This is the thread for the monitor which checks for input on the channels
  1046. which are not currently in use. */
  1047. static pthread_t monitor_thread = AST_PTHREADT_NULL;
  1048. /* Wait up to 16 seconds for first digit */
  1049. static int firstdigittimeout = 16000;
  1050. /* How long to wait for following digits */
  1051. static int gendigittimeout = 8000;
  1052. /* How long to wait for an extra digit, if there is an ambiguous match */
  1053. static int matchdigittimeout = 3000;
  1054. struct skinny_subchannel {
  1055. ast_mutex_t lock;
  1056. struct ast_channel *owner;
  1057. struct ast_rtp_instance *rtp;
  1058. struct ast_rtp_instance *vrtp;
  1059. unsigned int callid;
  1060. /* time_t lastouttime; */ /* Unused */
  1061. int progress;
  1062. int ringing;
  1063. int onhold;
  1064. /* int lastout; */ /* Unused */
  1065. int cxmode;
  1066. int nat;
  1067. int outgoing;
  1068. int alreadygone;
  1069. int blindxfer;
  1070. int xferor;
  1071. AST_LIST_ENTRY(skinny_subchannel) list;
  1072. struct skinny_subchannel *related;
  1073. struct skinny_line *parent;
  1074. };
  1075. #define SKINNY_LINE_OPTIONS \
  1076. char name[80]; \
  1077. char label[24]; \
  1078. char accountcode[AST_MAX_ACCOUNT_CODE]; \
  1079. char exten[AST_MAX_EXTENSION]; \
  1080. char context[AST_MAX_CONTEXT]; \
  1081. char language[MAX_LANGUAGE]; \
  1082. char cid_num[AST_MAX_EXTENSION]; \
  1083. char cid_name[AST_MAX_EXTENSION]; \
  1084. char lastcallerid[AST_MAX_EXTENSION]; \
  1085. int cfwdtype; \
  1086. char call_forward_all[AST_MAX_EXTENSION]; \
  1087. char call_forward_busy[AST_MAX_EXTENSION]; \
  1088. char call_forward_noanswer[AST_MAX_EXTENSION]; \
  1089. char mailbox[AST_MAX_EXTENSION]; \
  1090. char vmexten[AST_MAX_EXTENSION]; \
  1091. char regexten[AST_MAX_EXTENSION]; \
  1092. char regcontext[AST_MAX_CONTEXT]; \
  1093. char parkinglot[AST_MAX_CONTEXT]; \
  1094. char mohinterpret[MAX_MUSICCLASS]; \
  1095. char mohsuggest[MAX_MUSICCLASS]; \
  1096. char lastnumberdialed[AST_MAX_EXTENSION]; \
  1097. int curtone; \
  1098. ast_group_t callgroup; \
  1099. ast_group_t pickupgroup; \
  1100. int callwaiting; \
  1101. int transfer; \
  1102. int threewaycalling; \
  1103. int mwiblink; \
  1104. int cancallforward; \
  1105. int getforward; \
  1106. int callreturn; \
  1107. int dnd; \
  1108. int hascallerid; \
  1109. int hidecallerid; \
  1110. int amaflags; \
  1111. int type; \
  1112. int instance; \
  1113. int group; \
  1114. int needdestroy; \
  1115. format_t confcapability; \
  1116. struct ast_codec_pref confprefs; \
  1117. format_t capability; \
  1118. struct ast_codec_pref prefs; \
  1119. int nonCodecCapability; \
  1120. int onhooktime; \
  1121. int msgstate; \
  1122. int immediate; \
  1123. int hookstate; \
  1124. int nat; \
  1125. int directmedia; \
  1126. int prune;
  1127. struct skinny_line {
  1128. SKINNY_LINE_OPTIONS
  1129. ast_mutex_t lock;
  1130. struct ast_event_sub *mwi_event_sub; /* Event based MWI */
  1131. struct skinny_subchannel *activesub;
  1132. AST_LIST_HEAD(, skinny_subchannel) sub;
  1133. AST_LIST_ENTRY(skinny_line) list;
  1134. AST_LIST_ENTRY(skinny_line) all;
  1135. struct skinny_device *device;
  1136. struct ast_variable *chanvars; /*!< Channel variables to set for inbound call */
  1137. int newmsgs;
  1138. };
  1139. static struct skinny_line_options{
  1140. SKINNY_LINE_OPTIONS
  1141. } default_line_struct = {
  1142. .callwaiting = 1,
  1143. .transfer = 1,
  1144. .mwiblink = 0,
  1145. .dnd = 0,
  1146. .hidecallerid = 0,
  1147. .amaflags = 0,
  1148. .instance = 0,
  1149. .directmedia = 0,
  1150. .nat = 0,
  1151. .confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW,
  1152. .capability = 0,
  1153. .getforward = 0,
  1154. .needdestroy = 0,
  1155. .prune = 0,
  1156. .hookstate = SKINNY_ONHOOK,
  1157. };
  1158. static struct skinny_line_options *default_line = &default_line_struct;
  1159. static AST_LIST_HEAD_STATIC(lines, skinny_line);
  1160. struct skinny_speeddial {
  1161. ast_mutex_t lock;
  1162. char label[42];
  1163. char context[AST_MAX_CONTEXT];
  1164. char exten[AST_MAX_EXTENSION];
  1165. int instance;
  1166. int stateid;
  1167. int laststate;
  1168. int isHint;
  1169. AST_LIST_ENTRY(skinny_speeddial) list;
  1170. struct skinny_device *parent;
  1171. };
  1172. struct skinny_addon {
  1173. ast_mutex_t lock;
  1174. char type[10];
  1175. AST_LIST_ENTRY(skinny_addon) list;
  1176. struct skinny_device *parent;
  1177. };
  1178. #define SKINNY_DEVICE_OPTIONS \
  1179. char name[80]; \
  1180. char id[16]; \
  1181. char version_id[16]; \
  1182. char exten[AST_MAX_EXTENSION]; \
  1183. char vmexten[AST_MAX_EXTENSION]; \
  1184. int type; \
  1185. int registered; \
  1186. int lastlineinstance; \
  1187. int lastcallreference; \
  1188. format_t confcapability; \
  1189. struct ast_codec_pref confprefs; \
  1190. format_t capability; \
  1191. int earlyrtp; \
  1192. int transfer; \
  1193. int callwaiting; \
  1194. int mwiblink; \
  1195. int dnd; \
  1196. int prune;
  1197. struct skinny_device {
  1198. SKINNY_DEVICE_OPTIONS
  1199. struct type *first;
  1200. struct type *last;
  1201. ast_mutex_t lock;
  1202. struct sockaddr_in addr;
  1203. struct in_addr ourip;
  1204. struct ast_ha *ha;
  1205. struct skinnysession *session;
  1206. struct skinny_line *activeline;
  1207. AST_LIST_HEAD(, skinny_line) lines;
  1208. AST_LIST_HEAD(, skinny_speeddial) speeddials;
  1209. AST_LIST_HEAD(, skinny_addon) addons;
  1210. AST_LIST_ENTRY(skinny_device) list;
  1211. };
  1212. static struct skinny_device_options {
  1213. SKINNY_DEVICE_OPTIONS
  1214. } default_device_struct = {
  1215. .transfer = 1,
  1216. .earlyrtp = 1,
  1217. .callwaiting = 1,
  1218. .mwiblink = 0,
  1219. .dnd = 0,
  1220. .confcapability = AST_FORMAT_ULAW | AST_FORMAT_ALAW,
  1221. .capability = 0,
  1222. .prune = 0,
  1223. };
  1224. static struct skinny_device_options *default_device = &default_device_struct;
  1225. static AST_LIST_HEAD_STATIC(devices, skinny_device);
  1226. struct skinnysession {
  1227. pthread_t t;
  1228. ast_mutex_t lock;
  1229. time_t start;
  1230. struct sockaddr_in sin;
  1231. int fd;
  1232. char inbuf[SKINNY_MAX_PACKET];
  1233. char outbuf[SKINNY_MAX_PACKET];
  1234. struct skinny_device *device;
  1235. AST_LIST_ENTRY(skinnysession) list;
  1236. };
  1237. static struct ast_channel *skinny_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
  1238. static AST_LIST_HEAD_STATIC(sessions, skinnysession);
  1239. static int skinny_devicestate(void *data);
  1240. static int skinny_call(struct ast_channel *ast, char *dest, int timeout);
  1241. static int skinny_hangup(struct ast_channel *ast);
  1242. static int skinny_answer(struct ast_channel *ast);
  1243. static struct ast_frame *skinny_read(struct ast_channel *ast);
  1244. static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);
  1245. static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
  1246. static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
  1247. static int skinny_senddigit_begin(struct ast_channel *ast, char digit);
  1248. static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
  1249. static void mwi_event_cb(const struct ast_event *event, void *userdata);
  1250. static int skinny_reload(void);
  1251. static const struct ast_channel_tech skinny_tech = {
  1252. .type = "Skinny",
  1253. .description = tdesc,
  1254. .capabilities = AST_FORMAT_AUDIO_MASK,
  1255. .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER,
  1256. .requester = skinny_request,
  1257. .devicestate = skinny_devicestate,
  1258. .call = skinny_call,
  1259. .hangup = skinny_hangup,
  1260. .answer = skinny_answer,
  1261. .read = skinny_read,
  1262. .write = skinny_write,
  1263. .indicate = skinny_indicate,
  1264. .fixup = skinny_fixup,
  1265. .send_digit_begin = skinny_senddigit_begin,
  1266. .send_digit_end = skinny_senddigit_end,
  1267. .bridge = ast_rtp_instance_bridge,
  1268. };
  1269. static int skinny_extensionstate_cb(char *context, char* id, struct ast_state_cb_info *info, void *data);
  1270. static int skinny_transfer(struct skinny_subchannel *sub);
  1271. static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn)
  1272. {
  1273. struct skinny_device *d = s->device;
  1274. struct skinny_addon *a;
  1275. int i;
  1276. switch (d->type) {
  1277. case SKINNY_DEVICE_30SPPLUS:
  1278. case SKINNY_DEVICE_30VIP:
  1279. /* 13 rows, 2 columns */
  1280. for (i = 0; i < 4; i++)
  1281. (btn++)->buttonDefinition = BT_CUST_LINE;
  1282. (btn++)->buttonDefinition = BT_REDIAL;
  1283. (btn++)->buttonDefinition = BT_VOICEMAIL;
  1284. (btn++)->buttonDefinition = BT_CALLPARK;
  1285. (btn++)->buttonDefinition = BT_FORWARDALL;
  1286. (btn++)->buttonDefinition = BT_CONFERENCE;
  1287. for (i = 0; i < 4; i++)
  1288. (btn++)->buttonDefinition = BT_NONE;
  1289. for (i = 0; i < 13; i++)
  1290. (btn++)->buttonDefinition = BT_SPEEDDIAL;
  1291. break;
  1292. case SKINNY_DEVICE_12SPPLUS:
  1293. case SKINNY_DEVICE_12SP:
  1294. case SKINNY_DEVICE_12:
  1295. /* 6 rows, 2 columns */
  1296. for (i = 0; i < 2; i++)
  1297. (btn++)->buttonDefinition = BT_CUST_LINE;
  1298. for (i = 0; i < 4; i++)
  1299. (btn++)->buttonDefinition = BT_SPEEDDIAL;
  1300. (btn++)->buttonDefinition = BT_HOLD;
  1301. (btn++)->buttonDefinition = BT_REDIAL;
  1302. (btn++)->buttonDefinition = BT_TRANSFER;
  1303. (btn++)->buttonDefinition = BT_FORWARDALL;
  1304. (btn++)->buttonDefinition = BT_CALLPARK;
  1305. (btn++)->buttonDefinition = BT_VOICEMAIL;
  1306. break;
  1307. case SKINNY_DEVICE_7910:
  1308. (btn++)->buttonDefinition = BT_LINE;
  1309. (btn++)->buttonDefinition = BT_HOLD;
  1310. (btn++)->buttonDefinition = BT_TRANSFER;
  1311. (btn++)->buttonDefinition = BT_DISPLAY;
  1312. (btn++)->buttonDefinition = BT_VOICEMAIL;
  1313. (btn++)->buttonDefinition = BT_CONFERENCE;
  1314. (btn++)->buttonDefinition = BT_FORWARDALL;
  1315. for (i = 0; i < 2; i++)
  1316. (btn++)->buttonDefinition = BT_SPEEDDIAL;
  1317. (btn++)->buttonDefinition = BT_REDIAL;
  1318. break;
  1319. case SKINNY_DEVICE_7960:
  1320. case SKINNY_DEVICE_7961:
  1321. case SKINNY_DEVICE_7961GE:
  1322. case SKINNY_DEVICE_7962:
  1323. case SKINNY_DEVICE_7965:
  1324. for (i = 0; i < 6; i++)
  1325. (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
  1326. break;
  1327. case SKINNY_DEVICE_7940:
  1328. case SKINNY_DEVICE_7941:
  1329. case SKINNY_DEVICE_7941GE:
  1330. case SKINNY_DEVICE_7942:
  1331. case SKINNY_DEVICE_7945:
  1332. for (i = 0; i < 2; i++)
  1333. (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
  1334. break;
  1335. case SKINNY_DEVICE_7935:
  1336. case SKINNY_DEVICE_7936:
  1337. for (i = 0; i < 2; i++)
  1338. (btn++)->buttonDefinition = BT_LINE;
  1339. break;
  1340. case SKINNY_DEVICE_ATA186:
  1341. (btn++)->buttonDefinition = BT_LINE;
  1342. break;
  1343. case SKINNY_DEVICE_7970:
  1344. case SKINNY_DEVICE_7971:
  1345. case SKINNY_DEVICE_7975:
  1346. case SKINNY_DEVICE_CIPC:
  1347. for (i = 0; i < 8; i++)
  1348. (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
  1349. break;
  1350. case SKINNY_DEVICE_7985:
  1351. /* XXX I have no idea what the buttons look like on these. */
  1352. ast_log(LOG_WARNING, "Unsupported device type '%d (7985)' found.\n", d->type);
  1353. break;
  1354. case SKINNY_DEVICE_7912:
  1355. case SKINNY_DEVICE_7911:
  1356. case SKINNY_DEVICE_7905:
  1357. (btn++)->buttonDefinition = BT_LINE;
  1358. (btn++)->buttonDefinition = BT_HOLD;
  1359. break;
  1360. case SKINNY_DEVICE_7920:
  1361. /* XXX I don't know if this is right. */
  1362. for (i = 0; i < 4; i++)
  1363. (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
  1364. break;
  1365. case SKINNY_DEVICE_7921:
  1366. for (i = 0; i < 6; i++)
  1367. (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
  1368. break;
  1369. case SKINNY_DEVICE_7902:
  1370. ast_log(LOG_WARNING, "Unsupported device type '%d (7902)' found.\n", d->type);
  1371. break;
  1372. case SKINNY_DEVICE_7906:
  1373. ast_log(LOG_WARNING, "Unsupported device type '%d (7906)' found.\n", d->type);
  1374. break;
  1375. case SKINNY_DEVICE_7931:
  1376. ast_log(LOG_WARNING, "Unsupported device type '%d (7931)' found.\n", d->type);
  1377. break;
  1378. case SKINNY_DEVICE_7937:
  1379. ast_log(LOG_WARNING, "Unsupported device type '%d (7937)' found.\n", d->type);
  1380. break;
  1381. case SKINNY_DEVICE_7914:
  1382. ast_log(LOG_WARNING, "Unsupported device type '%d (7914)' found. Expansion module registered by itself?\n", d->type);
  1383. break;
  1384. case SKINNY_DEVICE_SCCPGATEWAY_AN:
  1385. case SKINNY_DEVICE_SCCPGATEWAY_BRI:
  1386. ast_log(LOG_WARNING, "Unsupported device type '%d (SCCP gateway)' found.\n", d->type);
  1387. break;
  1388. default:
  1389. ast_log(LOG_WARNING, "Unknown device type '%d' found.\n", d->type);
  1390. break;
  1391. }
  1392. AST_LIST_LOCK(&d->addons);
  1393. AST_LIST_TRAVERSE(&d->addons, a, list) {
  1394. if (!strcasecmp(a->type, "7914")) {
  1395. for (i = 0; i < 14; i++)
  1396. (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL;
  1397. } else {
  1398. ast_log(LOG_WARNING, "Unknown addon type '%s' found. Skipping.\n", a->type);
  1399. }
  1400. }
  1401. AST_LIST_UNLOCK(&d->addons);
  1402. return btn;
  1403. }
  1404. static struct skinny_req *req_alloc(size_t size, int response_message)
  1405. {
  1406. struct skinny_req *req;
  1407. if (!(req = ast_calloc(1, skinny_header_size + size + 4)))
  1408. return NULL;
  1409. req->len = htolel(size+4);
  1410. req->e = htolel(response_message);
  1411. return req;
  1412. }
  1413. static struct skinny_line *find_line_by_instance(struct skinny_device *d, int instance)
  1414. {
  1415. struct skinny_line *l;
  1416. /*Dialing from on hook or on a 7920 uses instance 0 in requests
  1417. but we need to start looking at instance 1 */
  1418. if (!instance)
  1419. instance = 1;
  1420. AST_LIST_TRAVERSE(&d->lines, l, list){
  1421. if (l->instance == instance)
  1422. break;
  1423. }
  1424. if (!l) {
  1425. ast_log(LOG_WARNING, "Could not find line with instance '%d' on device '%s'\n", instance, d->name);
  1426. }
  1427. return l;
  1428. }
  1429. static struct skinny_line *find_line_by_name(const char *dest)
  1430. {
  1431. struct skinny_line *l;
  1432. struct skinny_line *tmpl = NULL;
  1433. struct skinny_device *d;
  1434. char line[256];
  1435. char *at;
  1436. char *device;
  1437. int checkdevice = 0;
  1438. ast_copy_string(line, dest, sizeof(line));
  1439. at = strchr(line, '@');
  1440. if (at)
  1441. *at++ = '\0';
  1442. device = at;
  1443. if (!ast_strlen_zero(device))
  1444. checkdevice = 1;
  1445. AST_LIST_LOCK(&devices);
  1446. AST_LIST_TRAVERSE(&devices, d, list){
  1447. if (checkdevice && tmpl)
  1448. break;
  1449. else if (!checkdevice) {
  1450. /* This is a match, since we're checking for line on every device. */
  1451. } else if (!strcasecmp(d->name, device)) {
  1452. if (skinnydebug)
  1453. ast_verb(2, "Found device: %s\n", d->name);
  1454. } else
  1455. continue;
  1456. /* Found the device (or we don't care which device) */
  1457. AST_LIST_TRAVERSE(&d->lines, l, list){
  1458. /* Search for the right line */
  1459. if (!strcasecmp(l->name, line)) {
  1460. if (tmpl) {
  1461. ast_verb(2, "Ambiguous line name: %s\n", line);
  1462. AST_LIST_UNLOCK(&devices);
  1463. return NULL;
  1464. } else
  1465. tmpl = l;
  1466. }
  1467. }
  1468. }
  1469. AST_LIST_UNLOCK(&devices);
  1470. return tmpl;
  1471. }
  1472. /*!
  1473. * implement the setvar config line
  1474. */
  1475. static struct ast_variable *add_var(const char *buf, struct ast_variable *list)
  1476. {
  1477. struct ast_variable *tmpvar = NULL;
  1478. char *varname = ast_strdupa(buf), *varval = NULL;
  1479. if ((varval = strchr(varname,'='))) {
  1480. *varval++ = '\0';
  1481. if ((tmpvar = ast_variable_new(varname, varval, ""))) {
  1482. tmpvar->next = list;
  1483. list = tmpvar;
  1484. }
  1485. }
  1486. return list;
  1487. }
  1488. /* It's quicker/easier to find the subchannel when we know the instance number too */
  1489. static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference)
  1490. {
  1491. struct skinny_line *l = find_line_by_instance(d, instance);
  1492. struct skinny_subchannel *sub;
  1493. if (!l) {
  1494. return NULL;
  1495. }
  1496. /* 7920 phones set call reference to 0, so use the first
  1497. sub-channel on the list.
  1498. This MIGHT need more love to be right */
  1499. if (!reference)
  1500. sub = AST_LIST_FIRST(&l->sub);
  1501. else {
  1502. AST_LIST_TRAVERSE(&l->sub, sub, list) {
  1503. if (sub->callid == reference)
  1504. break;
  1505. }
  1506. }
  1507. if (!sub) {
  1508. ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name);
  1509. }
  1510. return sub;
  1511. }
  1512. /* Find the subchannel when we only have the callid - this shouldn't happen often */
  1513. static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_device *d, int reference)
  1514. {
  1515. struct skinny_line *l;
  1516. struct skinny_subchannel *sub = NULL;
  1517. AST_LIST_TRAVERSE(&d->lines, l, list){
  1518. AST_LIST_TRAVERSE(&l->sub, sub, list){
  1519. if (sub->callid == reference)
  1520. break;
  1521. }
  1522. if (sub)
  1523. break;
  1524. }
  1525. if (!l) {
  1526. ast_log(LOG_WARNING, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference, d->name);
  1527. } else {
  1528. if (!sub) {
  1529. ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference, l->name, d->name);
  1530. }
  1531. }
  1532. return sub;
  1533. }
  1534. static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance, int isHint)
  1535. {
  1536. struct skinny_speeddial *sd;
  1537. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  1538. if (sd->isHint == isHint && sd->instance == instance)
  1539. break;
  1540. }
  1541. if (!sd) {
  1542. ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name);
  1543. }
  1544. return sd;
  1545. }
  1546. static format_t codec_skinny2ast(enum skinny_codecs skinnycodec)
  1547. {
  1548. switch (skinnycodec) {
  1549. case SKINNY_CODEC_ALAW:
  1550. return AST_FORMAT_ALAW;
  1551. case SKINNY_CODEC_ULAW:
  1552. return AST_FORMAT_ULAW;
  1553. case SKINNY_CODEC_G723_1:
  1554. return AST_FORMAT_G723_1;
  1555. case SKINNY_CODEC_G729A:
  1556. return AST_FORMAT_G729A;
  1557. case SKINNY_CODEC_G726_32:
  1558. return AST_FORMAT_G726_AAL2; /* XXX Is this right? */
  1559. case SKINNY_CODEC_H261:
  1560. return AST_FORMAT_H261;
  1561. case SKINNY_CODEC_H263:
  1562. return AST_FORMAT_H263;
  1563. default:
  1564. return 0;
  1565. }
  1566. }
  1567. static int codec_ast2skinny(format_t astcodec)
  1568. {
  1569. switch (astcodec) {
  1570. case AST_FORMAT_ALAW:
  1571. return SKINNY_CODEC_ALAW;
  1572. case AST_FORMAT_ULAW:
  1573. return SKINNY_CODEC_ULAW;
  1574. case AST_FORMAT_G723_1:
  1575. return SKINNY_CODEC_G723_1;
  1576. case AST_FORMAT_G729A:
  1577. return SKINNY_CODEC_G729A;
  1578. case AST_FORMAT_G726_AAL2: /* XXX Is this right? */
  1579. return SKINNY_CODEC_G726_32;
  1580. case AST_FORMAT_H261:
  1581. return SKINNY_CODEC_H261;
  1582. case AST_FORMAT_H263:
  1583. return SKINNY_CODEC_H263;
  1584. default:
  1585. return 0;
  1586. }
  1587. }
  1588. static int set_callforwards(struct skinny_line *l, const char *cfwd, int cfwdtype)
  1589. {
  1590. if (!l)
  1591. return 0;
  1592. if (!ast_strlen_zero(cfwd)) {
  1593. if (cfwdtype & SKINNY_CFWD_ALL) {
  1594. l->cfwdtype |= SKINNY_CFWD_ALL;
  1595. ast_copy_string(l->call_forward_all, cfwd, sizeof(l->call_forward_all));
  1596. }
  1597. if (cfwdtype & SKINNY_CFWD_BUSY) {
  1598. l->cfwdtype |= SKINNY_CFWD_BUSY;
  1599. ast_copy_string(l->call_forward_busy, cfwd, sizeof(l->call_forward_busy));
  1600. }
  1601. if (cfwdtype & SKINNY_CFWD_NOANSWER) {
  1602. l->cfwdtype |= SKINNY_CFWD_NOANSWER;
  1603. ast_copy_string(l->call_forward_noanswer, cfwd, sizeof(l->call_forward_noanswer));
  1604. }
  1605. } else {
  1606. if (cfwdtype & SKINNY_CFWD_ALL) {
  1607. l->cfwdtype &= ~SKINNY_CFWD_ALL;
  1608. memset(l->call_forward_all, 0, sizeof(l->call_forward_all));
  1609. }
  1610. if (cfwdtype & SKINNY_CFWD_BUSY) {
  1611. l->cfwdtype &= ~SKINNY_CFWD_BUSY;
  1612. memset(l->call_forward_busy, 0, sizeof(l->call_forward_busy));
  1613. }
  1614. if (cfwdtype & SKINNY_CFWD_NOANSWER) {
  1615. l->cfwdtype &= ~SKINNY_CFWD_NOANSWER;
  1616. memset(l->call_forward_noanswer, 0, sizeof(l->call_forward_noanswer));
  1617. }
  1618. }
  1619. return l->cfwdtype;
  1620. }
  1621. static void cleanup_stale_contexts(char *new, char *old)
  1622. {
  1623. char *oldcontext, *newcontext, *stalecontext, *stringp, newlist[AST_MAX_CONTEXT];
  1624. while ((oldcontext = strsep(&old, "&"))) {
  1625. stalecontext = '\0';
  1626. ast_copy_string(newlist, new, sizeof(newlist));
  1627. stringp = newlist;
  1628. while ((newcontext = strsep(&stringp, "&"))) {
  1629. if (strcmp(newcontext, oldcontext) == 0) {
  1630. /* This is not the context you're looking for */
  1631. stalecontext = '\0';
  1632. break;
  1633. } else if (strcmp(newcontext, oldcontext)) {
  1634. stalecontext = oldcontext;
  1635. }
  1636. }
  1637. if (stalecontext)
  1638. ast_context_destroy(ast_context_find(stalecontext), "Skinny");
  1639. }
  1640. }
  1641. static void register_exten(struct skinny_line *l)
  1642. {
  1643. char multi[256];
  1644. char *stringp, *ext, *context;
  1645. if (ast_strlen_zero(regcontext))
  1646. return;
  1647. ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
  1648. stringp = multi;
  1649. while ((ext = strsep(&stringp, "&"))) {
  1650. if ((context = strchr(ext, '@'))) {
  1651. *context++ = '\0'; /* split ext@context */
  1652. if (!ast_context_find(context)) {
  1653. ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
  1654. continue;
  1655. }
  1656. } else {
  1657. context = regcontext;
  1658. }
  1659. ast_add_extension(context, 1, ext, 1, NULL, NULL, "Noop",
  1660. ast_strdup(l->name), ast_free_ptr, "Skinny");
  1661. }
  1662. }
  1663. static void unregister_exten(struct skinny_line *l)
  1664. {
  1665. char multi[256];
  1666. char *stringp, *ext, *context;
  1667. if (ast_strlen_zero(regcontext))
  1668. return;
  1669. ast_copy_string(multi, S_OR(l->regexten, l->name), sizeof(multi));
  1670. stringp = multi;
  1671. while ((ext = strsep(&stringp, "&"))) {
  1672. if ((context = strchr(ext, '@'))) {
  1673. *context++ = '\0'; /* split ext@context */
  1674. if (!ast_context_find(context)) {
  1675. ast_log(LOG_WARNING, "Context %s must exist in regcontext= in skinny.conf!\n", context);
  1676. continue;
  1677. }
  1678. } else {
  1679. context = regcontext;
  1680. }
  1681. ast_context_remove_extension(context, ext, 1, NULL);
  1682. }
  1683. }
  1684. static int skinny_register(struct skinny_req *req, struct skinnysession *s)
  1685. {
  1686. struct skinny_device *d;
  1687. struct skinny_line *l;
  1688. struct skinny_speeddial *sd;
  1689. struct sockaddr_in sin;
  1690. socklen_t slen;
  1691. int instance;
  1692. AST_LIST_LOCK(&devices);
  1693. AST_LIST_TRAVERSE(&devices, d, list){
  1694. struct ast_sockaddr addr;
  1695. ast_sockaddr_from_sin(&addr, &s->sin);
  1696. if (!strcasecmp(req->data.reg.name, d->id)
  1697. && ast_apply_ha(d->ha, &addr)) {
  1698. s->device = d;
  1699. d->type = letohl(req->data.reg.type);
  1700. if (ast_strlen_zero(d->version_id)) {
  1701. ast_copy_string(d->version_id, version_id, sizeof(d->version_id));
  1702. }
  1703. d->registered = 1;
  1704. d->session = s;
  1705. slen = sizeof(sin);
  1706. if (getsockname(s->fd, (struct sockaddr *)&sin, &slen)) {
  1707. ast_log(LOG_WARNING, "Cannot get socket name\n");
  1708. sin.sin_addr = __ourip;
  1709. }
  1710. d->ourip = sin.sin_addr;
  1711. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  1712. sd->stateid = ast_extension_state_add(sd->context, sd->exten, skinny_extensionstate_cb, sd);
  1713. }
  1714. instance = 0;
  1715. AST_LIST_TRAVERSE(&d->lines, l, list) {
  1716. instance++;
  1717. }
  1718. AST_LIST_TRAVERSE(&d->lines, l, list) {
  1719. /* FIXME: All sorts of issues will occur if this line is already connected to a device */
  1720. if (l->device) {
  1721. manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Rejected\r\nCause: LINE_ALREADY_CONNECTED\r\n", l->name, l->device->name);
  1722. ast_verb(1, "Line %s already connected to %s. Not connecting to %s.\n", l->name, l->device->name, d->name);
  1723. } else {
  1724. l->device = d;
  1725. l->capability = l->confcapability & d->capability;
  1726. l->prefs = l->confprefs;
  1727. if (!l->prefs.order[0]) {
  1728. l->prefs = d->confprefs;
  1729. }
  1730. /* l->capability = d->capability;
  1731. l->prefs = d->prefs; */
  1732. l->instance = instance;
  1733. l->newmsgs = ast_app_has_voicemail(l->mailbox, NULL);
  1734. set_callforwards(l, NULL, 0);
  1735. manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Registered\r\n", l->name, d->name);
  1736. register_exten(l);
  1737. /* initialize MWI on line and device */
  1738. mwi_event_cb(0, l);
  1739. ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
  1740. }
  1741. --instance;
  1742. }
  1743. break;
  1744. }
  1745. }
  1746. AST_LIST_UNLOCK(&devices);
  1747. if (!d) {
  1748. return 0;
  1749. }
  1750. return 1;
  1751. }
  1752. static int skinny_unregister(struct skinny_req *req, struct skinnysession *s)
  1753. {
  1754. struct skinny_device *d;
  1755. struct skinny_line *l;
  1756. struct skinny_speeddial *sd;
  1757. d = s->device;
  1758. if (d) {
  1759. d->session = NULL;
  1760. d->registered = 0;
  1761. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  1762. if (sd->stateid > -1)
  1763. ast_extension_state_del(sd->stateid, NULL);
  1764. }
  1765. AST_LIST_TRAVERSE(&d->lines, l, list) {
  1766. if (l->device == d) {
  1767. l->device = NULL;
  1768. l->capability = 0;
  1769. ast_parse_allow_disallow(&l->prefs, &l->capability, "all", 0);
  1770. l->instance = 0;
  1771. manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
  1772. unregister_exten(l);
  1773. ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Skinny/%s@%s", l->name, d->name);
  1774. }
  1775. }
  1776. }
  1777. return -1; /* main loop will destroy the session */
  1778. }
  1779. #ifdef SKINNY_DEVMODE
  1780. static char *message2str(int type)
  1781. {
  1782. char *tmp;
  1783. switch (letohl(type)) {
  1784. case KEEP_ALIVE_MESSAGE:
  1785. return "KEEP_ALIVE_MESSAGE";
  1786. case REGISTER_MESSAGE:
  1787. return "REGISTER_MESSAGE";
  1788. case IP_PORT_MESSAGE:
  1789. return "IP_PORT_MESSAGE";
  1790. case KEYPAD_BUTTON_MESSAGE:
  1791. return "KEYPAD_BUTTON_MESSAGE";
  1792. case ENBLOC_CALL_MESSAGE:
  1793. return "ENBLOC_CALL_MESSAGE";
  1794. case STIMULUS_MESSAGE:
  1795. return "STIMULUS_MESSAGE";
  1796. case OFFHOOK_MESSAGE:
  1797. return "OFFHOOK_MESSAGE";
  1798. case ONHOOK_MESSAGE:
  1799. return "ONHOOK_MESSAGE";
  1800. case CAPABILITIES_RES_MESSAGE:
  1801. return "CAPABILITIES_RES_MESSAGE";
  1802. case SPEED_DIAL_STAT_REQ_MESSAGE:
  1803. return "SPEED_DIAL_STAT_REQ_MESSAGE";
  1804. case LINE_STATE_REQ_MESSAGE:
  1805. return "LINE_STATE_REQ_MESSAGE";
  1806. case TIME_DATE_REQ_MESSAGE:
  1807. return "TIME_DATE_REQ_MESSAGE";
  1808. case BUTTON_TEMPLATE_REQ_MESSAGE:
  1809. return "BUTTON_TEMPLATE_REQ_MESSAGE";
  1810. case VERSION_REQ_MESSAGE:
  1811. return "VERSION_REQ_MESSAGE";
  1812. case SERVER_REQUEST_MESSAGE:
  1813. return "SERVER_REQUEST_MESSAGE";
  1814. case ALARM_MESSAGE:
  1815. return "ALARM_MESSAGE";
  1816. case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
  1817. return "OPEN_RECEIVE_CHANNEL_ACK_MESSAGE";
  1818. case SOFT_KEY_SET_REQ_MESSAGE:
  1819. return "SOFT_KEY_SET_REQ_MESSAGE";
  1820. case SOFT_KEY_EVENT_MESSAGE:
  1821. return "SOFT_KEY_EVENT_MESSAGE";
  1822. case UNREGISTER_MESSAGE:
  1823. return "UNREGISTER_MESSAGE";
  1824. case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
  1825. return "SOFT_KEY_TEMPLATE_REQ_MESSAGE";
  1826. case HEADSET_STATUS_MESSAGE:
  1827. return "HEADSET_STATUS_MESSAGE";
  1828. case REGISTER_AVAILABLE_LINES_MESSAGE:
  1829. return "REGISTER_AVAILABLE_LINES_MESSAGE";
  1830. case REGISTER_ACK_MESSAGE:
  1831. return "REGISTER_ACK_MESSAGE";
  1832. case START_TONE_MESSAGE:
  1833. return "START_TONE_MESSAGE";
  1834. case STOP_TONE_MESSAGE:
  1835. return "STOP_TONE_MESSAGE";
  1836. case SET_RINGER_MESSAGE:
  1837. return "SET_RINGER_MESSAGE";
  1838. case SET_LAMP_MESSAGE:
  1839. return "SET_LAMP_MESSAGE";
  1840. case SET_SPEAKER_MESSAGE:
  1841. return "SET_SPEAKER_MESSAGE";
  1842. case SET_MICROPHONE_MESSAGE:
  1843. return "SET_MICROPHONE_MESSAGE";
  1844. case START_MEDIA_TRANSMISSION_MESSAGE:
  1845. return "START_MEDIA_TRANSMISSION_MESSAGE";
  1846. case STOP_MEDIA_TRANSMISSION_MESSAGE:
  1847. return "STOP_MEDIA_TRANSMISSION_MESSAGE";
  1848. case CALL_INFO_MESSAGE:
  1849. return "CALL_INFO_MESSAGE";
  1850. case FORWARD_STAT_MESSAGE:
  1851. return "FORWARD_STAT_MESSAGE";
  1852. case SPEED_DIAL_STAT_RES_MESSAGE:
  1853. return "SPEED_DIAL_STAT_RES_MESSAGE";
  1854. case LINE_STAT_RES_MESSAGE:
  1855. return "LINE_STAT_RES_MESSAGE";
  1856. case DEFINETIMEDATE_MESSAGE:
  1857. return "DEFINETIMEDATE_MESSAGE";
  1858. case BUTTON_TEMPLATE_RES_MESSAGE:
  1859. return "BUTTON_TEMPLATE_RES_MESSAGE";
  1860. case VERSION_RES_MESSAGE:
  1861. return "VERSION_RES_MESSAGE";
  1862. case DISPLAYTEXT_MESSAGE:
  1863. return "DISPLAYTEXT_MESSAGE";
  1864. case CLEAR_NOTIFY_MESSAGE:
  1865. return "CLEAR_NOTIFY_MESSAGE";
  1866. case CLEAR_DISPLAY_MESSAGE:
  1867. return "CLEAR_DISPLAY_MESSAGE";
  1868. case CAPABILITIES_REQ_MESSAGE:
  1869. return "CAPABILITIES_REQ_MESSAGE";
  1870. case REGISTER_REJ_MESSAGE:
  1871. return "REGISTER_REJ_MESSAGE";
  1872. case SERVER_RES_MESSAGE:
  1873. return "SERVER_RES_MESSAGE";
  1874. case RESET_MESSAGE:
  1875. return "RESET_MESSAGE";
  1876. case KEEP_ALIVE_ACK_MESSAGE:
  1877. return "KEEP_ALIVE_ACK_MESSAGE";
  1878. case OPEN_RECEIVE_CHANNEL_MESSAGE:
  1879. return "OPEN_RECEIVE_CHANNEL_MESSAGE";
  1880. case CLOSE_RECEIVE_CHANNEL_MESSAGE:
  1881. return "CLOSE_RECEIVE_CHANNEL_MESSAGE";
  1882. case SOFT_KEY_TEMPLATE_RES_MESSAGE:
  1883. return "SOFT_KEY_TEMPLATE_RES_MESSAGE";
  1884. case SOFT_KEY_SET_RES_MESSAGE:
  1885. return "SOFT_KEY_SET_RES_MESSAGE";
  1886. case SELECT_SOFT_KEYS_MESSAGE:
  1887. return "SELECT_SOFT_KEYS_MESSAGE";
  1888. case CALL_STATE_MESSAGE:
  1889. return "CALL_STATE_MESSAGE";
  1890. case DISPLAY_PROMPT_STATUS_MESSAGE:
  1891. return "DISPLAY_PROMPT_STATUS_MESSAGE";
  1892. case CLEAR_PROMPT_MESSAGE:
  1893. return "CLEAR_PROMPT_MESSAGE";
  1894. case DISPLAY_NOTIFY_MESSAGE:
  1895. return "DISPLAY_NOTIFY_MESSAGE";
  1896. case ACTIVATE_CALL_PLANE_MESSAGE:
  1897. return "ACTIVATE_CALL_PLANE_MESSAGE";
  1898. case DIALED_NUMBER_MESSAGE:
  1899. return "DIALED_NUMBER_MESSAGE";
  1900. default:
  1901. if (!(tmp = ast_threadstorage_get(&message2str_threadbuf, MESSAGE2STR_BUFSIZE)))
  1902. return "Unknown";
  1903. snprintf(tmp, MESSAGE2STR_BUFSIZE, "UNKNOWN_MESSAGE-%d", type);
  1904. return tmp;
  1905. }
  1906. }
  1907. #endif
  1908. static int transmit_response(struct skinny_device *d, struct skinny_req *req)
  1909. {
  1910. struct skinnysession *s = d->session;
  1911. int res = 0;
  1912. if (!s) {
  1913. ast_log(LOG_WARNING, "Asked to transmit to a non-existent session!\n");
  1914. return -1;
  1915. }
  1916. ast_mutex_lock(&s->lock);
  1917. SKINNY_DEVONLY(if (skinnydebug>1) ast_verb(4, "Transmitting %s to %s\n", message2str(req->e), d->name);)
  1918. if ((letohl(req->len) > SKINNY_MAX_PACKET) || (letohl(req->len) < 0)) {
  1919. ast_log(LOG_WARNING, "transmit_response: the length of the request (%d) is out of bounds (%d)\n", letohl(req->len), SKINNY_MAX_PACKET);
  1920. ast_mutex_unlock(&s->lock);
  1921. return -1;
  1922. }
  1923. memset(s->outbuf, 0, sizeof(s->outbuf));
  1924. memcpy(s->outbuf, req, skinny_header_size);
  1925. memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
  1926. res = write(s->fd, s->outbuf, letohl(req->len)+8);
  1927. if (res != letohl(req->len)+8) {
  1928. ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
  1929. if (res == -1) {
  1930. if (skinnydebug)
  1931. ast_log(LOG_WARNING, "Transmit: Skinny Client was lost, unregistering\n");
  1932. skinny_unregister(NULL, s);
  1933. }
  1934. }
  1935. ast_free(req);
  1936. ast_mutex_unlock(&s->lock);
  1937. return 1;
  1938. }
  1939. static void transmit_speaker_mode(struct skinny_device *d, int mode)
  1940. {
  1941. struct skinny_req *req;
  1942. if (!(req = req_alloc(sizeof(struct set_speaker_message), SET_SPEAKER_MESSAGE)))
  1943. return;
  1944. req->data.setspeaker.mode = htolel(mode);
  1945. transmit_response(d, req);
  1946. }
  1947. /*
  1948. static void transmit_microphone_mode(struct skinny_device *d, int mode)
  1949. {
  1950. struct skinny_req *req;
  1951. if (!(req = req_alloc(sizeof(struct set_microphone_message), SET_MICROPHONE_MESSAGE)))
  1952. return;
  1953. req->data.setmicrophone.mode = htolel(mode);
  1954. transmit_response(d, req);
  1955. }
  1956. */
  1957. static void transmit_callinfo(struct skinny_device *d, const char *fromname, const char *fromnum, const char *toname, const char *tonum, int instance, int callid, int calltype)
  1958. {
  1959. struct skinny_req *req;
  1960. /* We should not be able to get here without a device */
  1961. if (!d)
  1962. return;
  1963. if (!(req = req_alloc(sizeof(struct call_info_message), CALL_INFO_MESSAGE)))
  1964. return;
  1965. if (skinnydebug)
  1966. ast_verb(1, "Setting Callinfo to %s(%s) from %s(%s) on %s(%d)\n", fromname, fromnum, toname, tonum, d->name, instance);
  1967. if (fromname) {
  1968. ast_copy_string(req->data.callinfo.callingPartyName, fromname, sizeof(req->data.callinfo.callingPartyName));
  1969. }
  1970. if (fromnum) {
  1971. ast_copy_string(req->data.callinfo.callingParty, fromnum, sizeof(req->data.callinfo.callingParty));
  1972. }
  1973. if (toname) {
  1974. ast_copy_string(req->data.callinfo.calledPartyName, toname, sizeof(req->data.callinfo.calledPartyName));
  1975. }
  1976. if (tonum) {
  1977. ast_copy_string(req->data.callinfo.calledParty, tonum, sizeof(req->data.callinfo.calledParty));
  1978. }
  1979. req->data.callinfo.instance = htolel(instance);
  1980. req->data.callinfo.reference = htolel(callid);
  1981. req->data.callinfo.type = htolel(calltype);
  1982. transmit_response(d, req);
  1983. }
  1984. static void transmit_connect(struct skinny_device *d, struct skinny_subchannel *sub)
  1985. {
  1986. struct skinny_req *req;
  1987. struct skinny_line *l = sub->parent;
  1988. struct ast_format_list fmt;
  1989. if (!(req = req_alloc(sizeof(struct open_receive_channel_message), OPEN_RECEIVE_CHANNEL_MESSAGE)))
  1990. return;
  1991. fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
  1992. req->data.openreceivechannel.conferenceId = htolel(sub->callid);
  1993. req->data.openreceivechannel.partyId = htolel(sub->callid);
  1994. req->data.openreceivechannel.packets = htolel(fmt.cur_ms);
  1995. req->data.openreceivechannel.capability = htolel(codec_ast2skinny(fmt.bits));
  1996. req->data.openreceivechannel.echo = htolel(0);
  1997. req->data.openreceivechannel.bitrate = htolel(0);
  1998. transmit_response(d, req);
  1999. }
  2000. static void transmit_start_tone(struct skinny_device *d, int tone, int instance, int reference)
  2001. {
  2002. struct skinny_req *req;
  2003. if (!(req = req_alloc(sizeof(struct start_tone_message), START_TONE_MESSAGE)))
  2004. return;
  2005. req->data.starttone.tone = htolel(tone);
  2006. req->data.starttone.instance = htolel(instance);
  2007. req->data.starttone.reference = htolel(reference);
  2008. transmit_response(d, req);
  2009. }
  2010. static void transmit_stop_tone(struct skinny_device *d, int instance, int reference)
  2011. {
  2012. struct skinny_req *req;
  2013. if (!(req = req_alloc(sizeof(struct stop_tone_message), STOP_TONE_MESSAGE)))
  2014. return;
  2015. req->data.stoptone.instance = htolel(instance);
  2016. req->data.stoptone.reference = htolel(reference);
  2017. transmit_response(d, req);
  2018. }
  2019. static void transmit_selectsoftkeys(struct skinny_device *d, int instance, int callid, int softkey)
  2020. {
  2021. struct skinny_req *req;
  2022. if (!(req = req_alloc(sizeof(struct select_soft_keys_message), SELECT_SOFT_KEYS_MESSAGE)))
  2023. return;
  2024. req->data.selectsoftkey.instance = htolel(instance);
  2025. req->data.selectsoftkey.reference = htolel(callid);
  2026. req->data.selectsoftkey.softKeySetIndex = htolel(softkey);
  2027. req->data.selectsoftkey.validKeyMask = htolel(0xFFFFFFFF);
  2028. transmit_response(d, req);
  2029. }
  2030. static void transmit_lamp_indication(struct skinny_device *d, int stimulus, int instance, int indication)
  2031. {
  2032. struct skinny_req *req;
  2033. if (!(req = req_alloc(sizeof(struct set_lamp_message), SET_LAMP_MESSAGE)))
  2034. return;
  2035. req->data.setlamp.stimulus = htolel(stimulus);
  2036. req->data.setlamp.stimulusInstance = htolel(instance);
  2037. req->data.setlamp.deviceStimulus = htolel(indication);
  2038. transmit_response(d, req);
  2039. }
  2040. static void transmit_ringer_mode(struct skinny_device *d, int mode)
  2041. {
  2042. struct skinny_req *req;
  2043. if (skinnydebug)
  2044. ast_verb(1, "Setting ringer mode to '%d'.\n", mode);
  2045. if (!(req = req_alloc(sizeof(struct set_ringer_message), SET_RINGER_MESSAGE)))
  2046. return;
  2047. req->data.setringer.ringerMode = htolel(mode);
  2048. /* XXX okay, I don't quite know what this is, but here's what happens (on a 7960).
  2049. Note: The phone will always show as ringing on the display.
  2050. 1: phone will audibly ring over and over
  2051. 2: phone will audibly ring only once
  2052. any other value, will NOT cause the phone to audibly ring
  2053. */
  2054. req->data.setringer.unknown1 = htolel(1);
  2055. /* XXX the value here doesn't seem to change anything. Must be higher than 0.
  2056. Perhaps a packet capture can shed some light on this. */
  2057. req->data.setringer.unknown2 = htolel(1);
  2058. transmit_response(d, req);
  2059. }
  2060. static void transmit_clear_display_message(struct skinny_device *d, int instance, int reference)
  2061. {
  2062. struct skinny_req *req;
  2063. if (!(req = req_alloc(0, CLEAR_DISPLAY_MESSAGE)))
  2064. return;
  2065. //what do we want hear CLEAR_DISPLAY_MESSAGE or CLEAR_PROMPT_STATUS???
  2066. //if we are clearing the display, it appears there is no instance and refernece info (size 0)
  2067. //req->data.clearpromptstatus.lineInstance = instance;
  2068. //req->data.clearpromptstatus.callReference = reference;
  2069. if (skinnydebug)
  2070. ast_verb(1, "Clearing Display\n");
  2071. transmit_response(d, req);
  2072. }
  2073. /* This function is not currently used, but will be (wedhorn)*/
  2074. /* static void transmit_display_message(struct skinny_device *d, const char *text, int instance, int reference)
  2075. {
  2076. struct skinny_req *req;
  2077. if (text == 0) {
  2078. ast_verb(1, "Bug, Asked to display empty message\n");
  2079. return;
  2080. }
  2081. if (!(req = req_alloc(sizeof(struct displaytext_message), DISPLAYTEXT_MESSAGE)))
  2082. return;
  2083. ast_copy_string(req->data.displaytext.text, text, sizeof(req->data.displaytext.text));
  2084. if (skinnydebug)
  2085. ast_verb(1, "Displaying message '%s'\n", req->data.displaytext.text);
  2086. transmit_response(d, req);
  2087. } */
  2088. static void transmit_displaynotify(struct skinny_device *d, const char *text, int t)
  2089. {
  2090. struct skinny_req *req;
  2091. if (!(req = req_alloc(sizeof(struct display_notify_message), DISPLAY_NOTIFY_MESSAGE)))
  2092. return;
  2093. ast_copy_string(req->data.displaynotify.displayMessage, text, sizeof(req->data.displaynotify.displayMessage));
  2094. req->data.displaynotify.displayTimeout = htolel(t);
  2095. if (skinnydebug)
  2096. ast_verb(1, "Displaying notify '%s'\n", text);
  2097. transmit_response(d, req);
  2098. }
  2099. static void transmit_displaypromptstatus(struct skinny_device *d, const char *text, int t, int instance, int callid)
  2100. {
  2101. struct skinny_req *req;
  2102. if (!(req = req_alloc(sizeof(struct display_prompt_status_message), DISPLAY_PROMPT_STATUS_MESSAGE)))
  2103. return;
  2104. ast_copy_string(req->data.displaypromptstatus.promptMessage, text, sizeof(req->data.displaypromptstatus.promptMessage));
  2105. req->data.displaypromptstatus.messageTimeout = htolel(t);
  2106. req->data.displaypromptstatus.lineInstance = htolel(instance);
  2107. req->data.displaypromptstatus.callReference = htolel(callid);
  2108. if (skinnydebug)
  2109. ast_verb(1, "Displaying Prompt Status '%s'\n", text);
  2110. transmit_response(d, req);
  2111. }
  2112. static void transmit_clearpromptmessage(struct skinny_device *d, int instance, int callid)
  2113. {
  2114. struct skinny_req *req;
  2115. if (!(req = req_alloc(sizeof(struct clear_prompt_message), CLEAR_PROMPT_MESSAGE)))
  2116. return;
  2117. req->data.clearpromptstatus.lineInstance = htolel(instance);
  2118. req->data.clearpromptstatus.callReference = htolel(callid);
  2119. if (skinnydebug)
  2120. ast_verb(1, "Clearing Prompt\n");
  2121. transmit_response(d, req);
  2122. }
  2123. static void transmit_dialednumber(struct skinny_device *d, const char *text, int instance, int callid)
  2124. {
  2125. struct skinny_req *req;
  2126. if (!(req = req_alloc(sizeof(struct dialed_number_message), DIALED_NUMBER_MESSAGE)))
  2127. return;
  2128. ast_copy_string(req->data.dialednumber.dialedNumber, text, sizeof(req->data.dialednumber.dialedNumber));
  2129. req->data.dialednumber.lineInstance = htolel(instance);
  2130. req->data.dialednumber.callReference = htolel(callid);
  2131. transmit_response(d, req);
  2132. }
  2133. static void transmit_closereceivechannel(struct skinny_device *d, struct skinny_subchannel *sub)
  2134. {
  2135. struct skinny_req *req;
  2136. if (!(req = req_alloc(sizeof(struct close_receive_channel_message), CLOSE_RECEIVE_CHANNEL_MESSAGE)))
  2137. return;
  2138. req->data.closereceivechannel.conferenceId = htolel(0);
  2139. req->data.closereceivechannel.partyId = htolel(sub->callid);
  2140. transmit_response(d, req);
  2141. }
  2142. static void transmit_stopmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub)
  2143. {
  2144. struct skinny_req *req;
  2145. if (!(req = req_alloc(sizeof(struct stop_media_transmission_message), STOP_MEDIA_TRANSMISSION_MESSAGE)))
  2146. return;
  2147. req->data.stopmedia.conferenceId = htolel(0);
  2148. req->data.stopmedia.passThruPartyId = htolel(sub->callid);
  2149. transmit_response(d, req);
  2150. }
  2151. static void transmit_startmediatransmission(struct skinny_device *d, struct skinny_subchannel *sub, struct sockaddr_in dest, struct ast_format_list fmt)
  2152. {
  2153. struct skinny_req *req;
  2154. if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE)))
  2155. return;
  2156. req->data.startmedia.conferenceId = htolel(sub->callid);
  2157. req->data.startmedia.passThruPartyId = htolel(sub->callid);
  2158. req->data.startmedia.remoteIp = dest.sin_addr.s_addr;
  2159. req->data.startmedia.remotePort = htolel(ntohs(dest.sin_port));
  2160. req->data.startmedia.packetSize = htolel(fmt.cur_ms);
  2161. req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits));
  2162. req->data.startmedia.qualifier.precedence = htolel(127);
  2163. req->data.startmedia.qualifier.vad = htolel(0);
  2164. req->data.startmedia.qualifier.packets = htolel(0);
  2165. req->data.startmedia.qualifier.bitRate = htolel(0);
  2166. transmit_response(d, req);
  2167. }
  2168. static void transmit_activatecallplane(struct skinny_device *d, struct skinny_line *l)
  2169. {
  2170. struct skinny_req *req;
  2171. if (!(req = req_alloc(sizeof(struct activate_call_plane_message), ACTIVATE_CALL_PLANE_MESSAGE)))
  2172. return;
  2173. req->data.activatecallplane.lineInstance = htolel(l->instance);
  2174. transmit_response(d, req);
  2175. }
  2176. static void transmit_callstate(struct skinny_device *d, int buttonInstance, unsigned callid, int state)
  2177. {
  2178. struct skinny_req *req;
  2179. if (!(req = req_alloc(sizeof(struct call_state_message), CALL_STATE_MESSAGE)))
  2180. return;
  2181. req->data.callstate.callState = htolel(state);
  2182. req->data.callstate.lineInstance = htolel(buttonInstance);
  2183. req->data.callstate.callReference = htolel(callid);
  2184. transmit_response(d, req);
  2185. }
  2186. static void transmit_cfwdstate(struct skinny_device *d, struct skinny_line *l)
  2187. {
  2188. struct skinny_req *req;
  2189. int anyon = 0;
  2190. if (!(req = req_alloc(sizeof(struct forward_stat_message), FORWARD_STAT_MESSAGE)))
  2191. return;
  2192. if (l->cfwdtype & SKINNY_CFWD_ALL) {
  2193. if (!ast_strlen_zero(l->call_forward_all)) {
  2194. ast_copy_string(req->data.forwardstat.fwdallnum, l->call_forward_all, sizeof(req->data.forwardstat.fwdallnum));
  2195. req->data.forwardstat.fwdall = htolel(1);
  2196. anyon++;
  2197. } else {
  2198. req->data.forwardstat.fwdall = htolel(0);
  2199. }
  2200. }
  2201. if (l->cfwdtype & SKINNY_CFWD_BUSY) {
  2202. if (!ast_strlen_zero(l->call_forward_busy)) {
  2203. ast_copy_string(req->data.forwardstat.fwdbusynum, l->call_forward_busy, sizeof(req->data.forwardstat.fwdbusynum));
  2204. req->data.forwardstat.fwdbusy = htolel(1);
  2205. anyon++;
  2206. } else {
  2207. req->data.forwardstat.fwdbusy = htolel(0);
  2208. }
  2209. }
  2210. if (l->cfwdtype & SKINNY_CFWD_NOANSWER) {
  2211. if (!ast_strlen_zero(l->call_forward_noanswer)) {
  2212. ast_copy_string(req->data.forwardstat.fwdnoanswernum, l->call_forward_noanswer, sizeof(req->data.forwardstat.fwdnoanswernum));
  2213. req->data.forwardstat.fwdnoanswer = htolel(1);
  2214. anyon++;
  2215. } else {
  2216. req->data.forwardstat.fwdnoanswer = htolel(0);
  2217. }
  2218. }
  2219. req->data.forwardstat.lineNumber = htolel(l->instance);
  2220. if (anyon)
  2221. req->data.forwardstat.activeforward = htolel(7);
  2222. else
  2223. req->data.forwardstat.activeforward = htolel(0);
  2224. transmit_response(d, req);
  2225. }
  2226. static void transmit_speeddialstatres(struct skinny_device *d, struct skinny_speeddial *sd)
  2227. {
  2228. struct skinny_req *req;
  2229. if (!(req = req_alloc(sizeof(struct speed_dial_stat_res_message), SPEED_DIAL_STAT_RES_MESSAGE)))
  2230. return;
  2231. req->data.speeddialreq.speedDialNumber = htolel(sd->instance);
  2232. ast_copy_string(req->data.speeddial.speedDialDirNumber, sd->exten, sizeof(req->data.speeddial.speedDialDirNumber));
  2233. ast_copy_string(req->data.speeddial.speedDialDisplayName, sd->label, sizeof(req->data.speeddial.speedDialDisplayName));
  2234. transmit_response(d, req);
  2235. }
  2236. static void transmit_linestatres(struct skinny_device *d, struct skinny_line *l)
  2237. {
  2238. struct skinny_req *req;
  2239. if (!(req = req_alloc(sizeof(struct line_stat_res_message), LINE_STAT_RES_MESSAGE)))
  2240. return;
  2241. req->data.linestat.lineNumber = letohl(l->instance);
  2242. memcpy(req->data.linestat.lineDirNumber, l->name, sizeof(req->data.linestat.lineDirNumber));
  2243. memcpy(req->data.linestat.lineDisplayName, l->label, sizeof(req->data.linestat.lineDisplayName));
  2244. transmit_response(d, req);
  2245. }
  2246. static void transmit_definetimedate(struct skinny_device *d)
  2247. {
  2248. struct skinny_req *req;
  2249. struct timeval now = ast_tvnow();
  2250. struct ast_tm cmtime;
  2251. if (!(req = req_alloc(sizeof(struct definetimedate_message), DEFINETIMEDATE_MESSAGE)))
  2252. return;
  2253. ast_localtime(&now, &cmtime, NULL);
  2254. req->data.definetimedate.year = htolel(cmtime.tm_year+1900);
  2255. req->data.definetimedate.month = htolel(cmtime.tm_mon+1);
  2256. req->data.definetimedate.dayofweek = htolel(cmtime.tm_wday);
  2257. req->data.definetimedate.day = htolel(cmtime.tm_mday);
  2258. req->data.definetimedate.hour = htolel(cmtime.tm_hour);
  2259. req->data.definetimedate.minute = htolel(cmtime.tm_min);
  2260. req->data.definetimedate.seconds = htolel(cmtime.tm_sec);
  2261. req->data.definetimedate.milliseconds = htolel(cmtime.tm_usec / 1000);
  2262. req->data.definetimedate.timestamp = htolel(now.tv_sec);
  2263. transmit_response(d, req);
  2264. }
  2265. static void transmit_versionres(struct skinny_device *d)
  2266. {
  2267. struct skinny_req *req;
  2268. if (!(req = req_alloc(sizeof(struct version_res_message), VERSION_RES_MESSAGE)))
  2269. return;
  2270. ast_copy_string(req->data.version.version, d->version_id, sizeof(req->data.version.version));
  2271. transmit_response(d, req);
  2272. }
  2273. static void transmit_serverres(struct skinny_device *d)
  2274. {
  2275. struct skinny_req *req;
  2276. if (!(req = req_alloc(sizeof(struct server_res_message), SERVER_RES_MESSAGE)))
  2277. return;
  2278. memcpy(req->data.serverres.server[0].serverName, ourhost,
  2279. sizeof(req->data.serverres.server[0].serverName));
  2280. req->data.serverres.serverListenPort[0] = htolel(ourport);
  2281. req->data.serverres.serverIpAddr[0] = htolel(d->ourip.s_addr);
  2282. transmit_response(d, req);
  2283. }
  2284. static void transmit_softkeysetres(struct skinny_device *d)
  2285. {
  2286. struct skinny_req *req;
  2287. int i;
  2288. int x;
  2289. int y;
  2290. const struct soft_key_definitions *softkeymode = soft_key_default_definitions;
  2291. if (!(req = req_alloc(sizeof(struct soft_key_set_res_message), SOFT_KEY_SET_RES_MESSAGE)))
  2292. return;
  2293. req->data.softkeysets.softKeySetOffset = htolel(0);
  2294. req->data.softkeysets.softKeySetCount = htolel(11);
  2295. req->data.softkeysets.totalSoftKeySetCount = htolel(11);
  2296. for (x = 0; x < sizeof(soft_key_default_definitions) / sizeof(struct soft_key_definitions); x++) {
  2297. const uint8_t *defaults = softkeymode->defaults;
  2298. /* XXX I wanted to get the size of the array dynamically, but that wasn't wanting to work.
  2299. This will have to do for now. */
  2300. for (y = 0; y < softkeymode->count; y++) {
  2301. for (i = 0; i < (sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition)); i++) {
  2302. if (defaults[y] == i+1) {
  2303. req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyTemplateIndex[y] = (i+1);
  2304. req->data.softkeysets.softKeySetDefinition[softkeymode->mode].softKeyInfoIndex[y] = htoles(i+301);
  2305. if (skinnydebug)
  2306. ast_verbose("softKeySetDefinition : softKeyTemplateIndex: %d softKeyInfoIndex: %d\n", i+1, i+301);
  2307. }
  2308. }
  2309. }
  2310. softkeymode++;
  2311. }
  2312. transmit_response(d, req);
  2313. }
  2314. static void transmit_softkeytemplateres(struct skinny_device *d)
  2315. {
  2316. struct skinny_req *req;
  2317. if (!(req = req_alloc(sizeof(struct soft_key_template_res_message), SOFT_KEY_TEMPLATE_RES_MESSAGE)))
  2318. return;
  2319. req->data.softkeytemplate.softKeyOffset = htolel(0);
  2320. req->data.softkeytemplate.softKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
  2321. req->data.softkeytemplate.totalSoftKeyCount = htolel(sizeof(soft_key_template_default) / sizeof(struct soft_key_template_definition));
  2322. memcpy(req->data.softkeytemplate.softKeyTemplateDefinition,
  2323. soft_key_template_default,
  2324. sizeof(soft_key_template_default));
  2325. transmit_response(d, req);
  2326. }
  2327. static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
  2328. {
  2329. struct skinny_speeddial *sd = data;
  2330. struct skinny_device *d = sd->parent;
  2331. char hint[AST_MAX_EXTENSION];
  2332. int state = info->exten_state;
  2333. /* only interested in device state here */
  2334. if (info->reason != AST_HINT_UPDATE_DEVICE) {
  2335. return 0;
  2336. }
  2337. if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, sd->context, sd->exten)) {
  2338. /* If they are not registered, we will override notification and show no availability */
  2339. if (ast_device_state(hint) == AST_DEVICE_UNAVAILABLE) {
  2340. transmit_lamp_indication(d, STIMULUS_LINE, sd->instance, SKINNY_LAMP_FLASH);
  2341. transmit_callstate(d, sd->instance, SKINNY_ONHOOK, 0);
  2342. }
  2343. } else {
  2344. switch (state) {
  2345. case AST_EXTENSION_DEACTIVATED: /* Retry after a while */
  2346. case AST_EXTENSION_REMOVED: /* Extension is gone */
  2347. ast_verb(2, "Extension state: Watcher for hint %s %s. Notify Device %s\n", exten, state == AST_EXTENSION_DEACTIVATED ? "deactivated" : "removed", d->name);
  2348. sd->stateid = -1;
  2349. transmit_lamp_indication(d, STIMULUS_LINE, sd->instance, SKINNY_LAMP_OFF);
  2350. transmit_callstate(d, sd->instance, SKINNY_ONHOOK, 0);
  2351. break;
  2352. case AST_EXTENSION_RINGING:
  2353. case AST_EXTENSION_UNAVAILABLE:
  2354. transmit_lamp_indication(d, STIMULUS_LINE, sd->instance, SKINNY_LAMP_BLINK);
  2355. transmit_callstate(d, sd->instance, SKINNY_RINGIN, 0);
  2356. break;
  2357. case AST_EXTENSION_BUSY: /* callstate = SKINNY_BUSY wasn't wanting to work - I'll settle for this */
  2358. case AST_EXTENSION_INUSE:
  2359. transmit_lamp_indication(d, STIMULUS_LINE, sd->instance, SKINNY_LAMP_ON);
  2360. transmit_callstate(d, sd->instance, SKINNY_CALLREMOTEMULTILINE, 0);
  2361. break;
  2362. case AST_EXTENSION_ONHOLD:
  2363. transmit_lamp_indication(d, STIMULUS_LINE, sd->instance, SKINNY_LAMP_WINK);
  2364. transmit_callstate(d, sd->instance, SKINNY_HOLD, 0);
  2365. break;
  2366. case AST_EXTENSION_NOT_INUSE:
  2367. default:
  2368. transmit_lamp_indication(d, STIMULUS_LINE, sd->instance, SKINNY_LAMP_OFF);
  2369. transmit_callstate(d, sd->instance, SKINNY_ONHOOK, 0);
  2370. break;
  2371. }
  2372. }
  2373. sd->laststate = state;
  2374. return 0;
  2375. }
  2376. static void update_connectedline(struct skinny_subchannel *sub, const void *data, size_t datalen)
  2377. {
  2378. struct ast_channel *c = sub->owner;
  2379. struct skinny_line *l = sub->parent;
  2380. struct skinny_device *d = l->device;
  2381. if (!c->caller.id.number.valid
  2382. || ast_strlen_zero(c->caller.id.number.str)
  2383. || !c->connected.id.number.valid
  2384. || ast_strlen_zero(c->connected.id.number.str))
  2385. return;
  2386. if (sub->owner->_state == AST_STATE_UP) {
  2387. transmit_callstate(d, l->instance, sub->callid, SKINNY_CONNECTED);
  2388. transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
  2389. if (sub->outgoing)
  2390. transmit_callinfo(d,
  2391. S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
  2392. c->connected.id.number.str,
  2393. l->cid_name, l->cid_num, l->instance, sub->callid, 1);
  2394. else
  2395. transmit_callinfo(d, l->cid_name, l->cid_num,
  2396. S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
  2397. c->connected.id.number.str,
  2398. l->instance, sub->callid, 2);
  2399. } else {
  2400. if (sub->outgoing) {
  2401. transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGIN);
  2402. transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
  2403. transmit_callinfo(d,
  2404. S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
  2405. c->connected.id.number.str,
  2406. l->cid_name, l->cid_num, l->instance, sub->callid, 1);
  2407. } else {
  2408. if (!sub->ringing) {
  2409. transmit_callstate(d, l->instance, sub->callid, SKINNY_RINGOUT);
  2410. transmit_displaypromptstatus(d, "Ring-Out", 0, l->instance, sub->callid);
  2411. sub->ringing = 1;
  2412. } else {
  2413. transmit_callstate(d, l->instance, sub->callid, SKINNY_PROGRESS);
  2414. transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
  2415. sub->progress = 1;
  2416. }
  2417. transmit_callinfo(d, l->cid_name, l->cid_num,
  2418. S_COR(c->connected.id.name.valid, c->connected.id.name.str, ""),
  2419. c->connected.id.number.str,
  2420. l->instance, sub->callid, 2);
  2421. }
  2422. }
  2423. }
  2424. static void mwi_event_cb(const struct ast_event *event, void *userdata)
  2425. {
  2426. struct skinny_line *l = userdata;
  2427. struct skinny_device *d = l->device;
  2428. if (d) {
  2429. struct skinnysession *s = d->session;
  2430. struct skinny_line *l2;
  2431. int new_msgs = 0;
  2432. int dev_msgs = 0;
  2433. if (s) {
  2434. if (event) {
  2435. l->newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
  2436. }
  2437. if (l->newmsgs) {
  2438. transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, l->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
  2439. } else {
  2440. transmit_lamp_indication(d, STIMULUS_VOICEMAIL, l->instance, SKINNY_LAMP_OFF);
  2441. }
  2442. /* find out wether the device lamp should be on or off */
  2443. AST_LIST_TRAVERSE(&d->lines, l2, list) {
  2444. if (l2->newmsgs) {
  2445. dev_msgs++;
  2446. }
  2447. }
  2448. if (dev_msgs) {
  2449. transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, d->mwiblink?SKINNY_LAMP_BLINK:SKINNY_LAMP_ON);
  2450. } else {
  2451. transmit_lamp_indication(d, STIMULUS_VOICEMAIL, 0, SKINNY_LAMP_OFF);
  2452. }
  2453. ast_verb(3, "Skinny mwi_event_cb found %d new messages\n", new_msgs);
  2454. }
  2455. }
  2456. }
  2457. /* I do not believe skinny can deal with video.
  2458. Anyone know differently? */
  2459. /* Yes, it can. Currently 7985 and Cisco VT Advantage do video. */
  2460. static enum ast_rtp_glue_result skinny_get_vrtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
  2461. {
  2462. struct skinny_subchannel *sub = NULL;
  2463. if (!(sub = c->tech_pvt) || !(sub->vrtp))
  2464. return AST_RTP_GLUE_RESULT_FORBID;
  2465. ao2_ref(sub->vrtp, +1);
  2466. *instance = sub->vrtp;
  2467. return AST_RTP_GLUE_RESULT_REMOTE;
  2468. }
  2469. static enum ast_rtp_glue_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp_instance **instance)
  2470. {
  2471. struct skinny_subchannel *sub = NULL;
  2472. struct skinny_line *l;
  2473. enum ast_rtp_glue_result res = AST_RTP_GLUE_RESULT_REMOTE;
  2474. if (skinnydebug)
  2475. ast_verb(1, "skinny_get_rtp_peer() Channel = %s\n", c->name);
  2476. if (!(sub = c->tech_pvt))
  2477. return AST_RTP_GLUE_RESULT_FORBID;
  2478. ast_mutex_lock(&sub->lock);
  2479. if (!(sub->rtp)){
  2480. ast_mutex_unlock(&sub->lock);
  2481. return AST_RTP_GLUE_RESULT_FORBID;
  2482. }
  2483. ao2_ref(sub->rtp, +1);
  2484. *instance = sub->rtp;
  2485. l = sub->parent;
  2486. if (!l->directmedia || l->nat){
  2487. res = AST_RTP_GLUE_RESULT_LOCAL;
  2488. if (skinnydebug)
  2489. ast_verb(1, "skinny_get_rtp_peer() Using AST_RTP_GLUE_RESULT_LOCAL \n");
  2490. }
  2491. ast_mutex_unlock(&sub->lock);
  2492. return res;
  2493. }
  2494. static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp_instance *rtp, struct ast_rtp_instance *vrtp, struct ast_rtp_instance *trtp, format_t codecs, int nat_active)
  2495. {
  2496. struct skinny_subchannel *sub;
  2497. struct skinny_line *l;
  2498. struct skinny_device *d;
  2499. struct ast_format_list fmt;
  2500. struct sockaddr_in us = { 0, };
  2501. struct sockaddr_in them = { 0, };
  2502. struct ast_sockaddr them_tmp;
  2503. struct ast_sockaddr us_tmp;
  2504. sub = c->tech_pvt;
  2505. if (c->_state != AST_STATE_UP)
  2506. return 0;
  2507. if (!sub) {
  2508. return -1;
  2509. }
  2510. l = sub->parent;
  2511. d = l->device;
  2512. if (rtp){
  2513. ast_rtp_instance_get_remote_address(rtp, &them_tmp);
  2514. ast_sockaddr_to_sin(&them_tmp, &them);
  2515. /* Shutdown any early-media or previous media on re-invite */
  2516. transmit_stopmediatransmission(d, sub);
  2517. if (skinnydebug)
  2518. ast_verb(1, "Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port));
  2519. fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
  2520. if (skinnydebug)
  2521. ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(fmt.bits), fmt.cur_ms);
  2522. if (!(l->directmedia) || (l->nat)){
  2523. ast_rtp_instance_get_local_address(rtp, &us_tmp);
  2524. ast_sockaddr_to_sin(&us_tmp, &us);
  2525. us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
  2526. transmit_startmediatransmission(d, sub, us, fmt);
  2527. } else {
  2528. transmit_startmediatransmission(d, sub, them, fmt);
  2529. }
  2530. return 0;
  2531. }
  2532. /* Need a return here to break the bridge */
  2533. return 0;
  2534. }
  2535. static struct ast_rtp_glue skinny_rtp_glue = {
  2536. .type = "Skinny",
  2537. .get_rtp_info = skinny_get_rtp_peer,
  2538. .get_vrtp_info = skinny_get_vrtp_peer,
  2539. .update_peer = skinny_set_rtp_peer,
  2540. };
  2541. static char *handle_skinny_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  2542. {
  2543. switch (cmd) {
  2544. case CLI_INIT:
  2545. #ifdef SKINNY_DEVMODE
  2546. e->command = "skinny set debug {off|on|packet}";
  2547. e->usage =
  2548. "Usage: skinny set debug {off|on|packet}\n"
  2549. " Enables/Disables dumping of Skinny packets for debugging purposes\n";
  2550. #else
  2551. e->command = "skinny set debug {off|on}";
  2552. e->usage =
  2553. "Usage: skinny set debug {off|on}\n"
  2554. " Enables/Disables dumping of Skinny packets for debugging purposes\n";
  2555. #endif
  2556. return NULL;
  2557. case CLI_GENERATE:
  2558. return NULL;
  2559. }
  2560. if (a->argc != e->args)
  2561. return CLI_SHOWUSAGE;
  2562. if (!strncasecmp(a->argv[e->args - 1], "on", 2)) {
  2563. skinnydebug = 1;
  2564. ast_cli(a->fd, "Skinny Debugging Enabled\n");
  2565. return CLI_SUCCESS;
  2566. } else if (!strncasecmp(a->argv[e->args - 1], "off", 3)) {
  2567. skinnydebug = 0;
  2568. ast_cli(a->fd, "Skinny Debugging Disabled\n");
  2569. return CLI_SUCCESS;
  2570. #ifdef SKINNY_DEVMODE
  2571. } else if (!strncasecmp(a->argv[e->args - 1], "packet", 6)) {
  2572. skinnydebug = 2;
  2573. ast_cli(a->fd, "Skinny Debugging Enabled including Packets\n");
  2574. return CLI_SUCCESS;
  2575. #endif
  2576. } else {
  2577. return CLI_SHOWUSAGE;
  2578. }
  2579. }
  2580. static char *handle_skinny_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  2581. {
  2582. switch (cmd) {
  2583. case CLI_INIT:
  2584. e->command = "skinny reload";
  2585. e->usage =
  2586. "Usage: skinny reload\n"
  2587. " Reloads the chan_skinny configuration\n";
  2588. return NULL;
  2589. case CLI_GENERATE:
  2590. return NULL;
  2591. }
  2592. if (a->argc != e->args)
  2593. return CLI_SHOWUSAGE;
  2594. skinny_reload();
  2595. return CLI_SUCCESS;
  2596. }
  2597. static char *complete_skinny_devices(const char *word, int state)
  2598. {
  2599. struct skinny_device *d;
  2600. char *result = NULL;
  2601. int wordlen = strlen(word), which = 0;
  2602. AST_LIST_TRAVERSE(&devices, d, list) {
  2603. if (!strncasecmp(word, d->id, wordlen) && ++which > state)
  2604. result = ast_strdup(d->id);
  2605. }
  2606. return result;
  2607. }
  2608. static char *complete_skinny_show_device(const char *line, const char *word, int pos, int state)
  2609. {
  2610. return (pos == 3 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
  2611. }
  2612. static char *complete_skinny_reset(const char *line, const char *word, int pos, int state)
  2613. {
  2614. return (pos == 2 ? ast_strdup(complete_skinny_devices(word, state)) : NULL);
  2615. }
  2616. static char *complete_skinny_show_line(const char *line, const char *word, int pos, int state)
  2617. {
  2618. struct skinny_device *d;
  2619. struct skinny_line *l;
  2620. char *result = NULL;
  2621. int wordlen = strlen(word), which = 0;
  2622. if (pos != 3)
  2623. return NULL;
  2624. AST_LIST_TRAVERSE(&devices, d, list) {
  2625. AST_LIST_TRAVERSE(&d->lines, l, list) {
  2626. if (!strncasecmp(word, l->name, wordlen) && ++which > state)
  2627. result = ast_strdup(l->name);
  2628. }
  2629. }
  2630. return result;
  2631. }
  2632. static char *handle_skinny_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  2633. {
  2634. struct skinny_device *d;
  2635. struct skinny_req *req;
  2636. switch (cmd) {
  2637. case CLI_INIT:
  2638. e->command = "skinny reset";
  2639. e->usage =
  2640. "Usage: skinny reset <DeviceId|DeviceName|all> [restart]\n"
  2641. " Causes a Skinny device to reset itself, optionally with a full restart\n";
  2642. return NULL;
  2643. case CLI_GENERATE:
  2644. return complete_skinny_reset(a->line, a->word, a->pos, a->n);
  2645. }
  2646. if (a->argc < 3 || a->argc > 4)
  2647. return CLI_SHOWUSAGE;
  2648. AST_LIST_LOCK(&devices);
  2649. AST_LIST_TRAVERSE(&devices, d, list) {
  2650. int fullrestart = 0;
  2651. if (!strcasecmp(a->argv[2], d->id) || !strcasecmp(a->argv[2], d->name) || !strcasecmp(a->argv[2], "all")) {
  2652. if (!(d->session))
  2653. continue;
  2654. if (!(req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE)))
  2655. continue;
  2656. if (a->argc == 4 && !strcasecmp(a->argv[3], "restart"))
  2657. fullrestart = 1;
  2658. if (fullrestart)
  2659. req->data.reset.resetType = 2;
  2660. else
  2661. req->data.reset.resetType = 1;
  2662. ast_verb(3, "%s device %s.\n", (fullrestart) ? "Restarting" : "Resetting", d->id);
  2663. transmit_response(d, req);
  2664. }
  2665. }
  2666. AST_LIST_UNLOCK(&devices);
  2667. return CLI_SUCCESS;
  2668. }
  2669. static char *device2str(int type)
  2670. {
  2671. char *tmp;
  2672. switch (type) {
  2673. case SKINNY_DEVICE_NONE:
  2674. return "No Device";
  2675. case SKINNY_DEVICE_30SPPLUS:
  2676. return "30SP Plus";
  2677. case SKINNY_DEVICE_12SPPLUS:
  2678. return "12SP Plus";
  2679. case SKINNY_DEVICE_12SP:
  2680. return "12SP";
  2681. case SKINNY_DEVICE_12:
  2682. return "12";
  2683. case SKINNY_DEVICE_30VIP:
  2684. return "30VIP";
  2685. case SKINNY_DEVICE_7910:
  2686. return "7910";
  2687. case SKINNY_DEVICE_7960:
  2688. return "7960";
  2689. case SKINNY_DEVICE_7940:
  2690. return "7940";
  2691. case SKINNY_DEVICE_7935:
  2692. return "7935";
  2693. case SKINNY_DEVICE_ATA186:
  2694. return "ATA186";
  2695. case SKINNY_DEVICE_7941:
  2696. return "7941";
  2697. case SKINNY_DEVICE_7971:
  2698. return "7971";
  2699. case SKINNY_DEVICE_7914:
  2700. return "7914";
  2701. case SKINNY_DEVICE_7985:
  2702. return "7985";
  2703. case SKINNY_DEVICE_7911:
  2704. return "7911";
  2705. case SKINNY_DEVICE_7961GE:
  2706. return "7961GE";
  2707. case SKINNY_DEVICE_7941GE:
  2708. return "7941GE";
  2709. case SKINNY_DEVICE_7931:
  2710. return "7931";
  2711. case SKINNY_DEVICE_7921:
  2712. return "7921";
  2713. case SKINNY_DEVICE_7906:
  2714. return "7906";
  2715. case SKINNY_DEVICE_7962:
  2716. return "7962";
  2717. case SKINNY_DEVICE_7937:
  2718. return "7937";
  2719. case SKINNY_DEVICE_7942:
  2720. return "7942";
  2721. case SKINNY_DEVICE_7945:
  2722. return "7945";
  2723. case SKINNY_DEVICE_7965:
  2724. return "7965";
  2725. case SKINNY_DEVICE_7975:
  2726. return "7975";
  2727. case SKINNY_DEVICE_7905:
  2728. return "7905";
  2729. case SKINNY_DEVICE_7920:
  2730. return "7920";
  2731. case SKINNY_DEVICE_7970:
  2732. return "7970";
  2733. case SKINNY_DEVICE_7912:
  2734. return "7912";
  2735. case SKINNY_DEVICE_7902:
  2736. return "7902";
  2737. case SKINNY_DEVICE_CIPC:
  2738. return "IP Communicator";
  2739. case SKINNY_DEVICE_7961:
  2740. return "7961";
  2741. case SKINNY_DEVICE_7936:
  2742. return "7936";
  2743. case SKINNY_DEVICE_SCCPGATEWAY_AN:
  2744. return "SCCPGATEWAY_AN";
  2745. case SKINNY_DEVICE_SCCPGATEWAY_BRI:
  2746. return "SCCPGATEWAY_BRI";
  2747. case SKINNY_DEVICE_UNKNOWN:
  2748. return "Unknown";
  2749. default:
  2750. if (!(tmp = ast_threadstorage_get(&device2str_threadbuf, DEVICE2STR_BUFSIZE)))
  2751. return "Unknown";
  2752. snprintf(tmp, DEVICE2STR_BUFSIZE, "UNKNOWN-%d", type);
  2753. return tmp;
  2754. }
  2755. }
  2756. /*! \brief Print codec list from preference to CLI/manager */
  2757. static void print_codec_to_cli(int fd, struct ast_codec_pref *pref)
  2758. {
  2759. int x, codec;
  2760. for(x = 0; x < 32 ; x++) {
  2761. codec = ast_codec_pref_index(pref, x);
  2762. if (!codec)
  2763. break;
  2764. ast_cli(fd, "%s", ast_getformatname(codec));
  2765. ast_cli(fd, ":%d", pref->framing[x]);
  2766. if (x < 31 && ast_codec_pref_index(pref, x + 1))
  2767. ast_cli(fd, ",");
  2768. }
  2769. if (!x)
  2770. ast_cli(fd, "none");
  2771. }
  2772. static char *_skinny_show_devices(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
  2773. {
  2774. struct skinny_device *d;
  2775. struct skinny_line *l;
  2776. const char *id;
  2777. char idtext[256] = "";
  2778. int total_devices = 0;
  2779. if (s) { /* Manager - get ActionID */
  2780. id = astman_get_header(m, "ActionID");
  2781. if (!ast_strlen_zero(id))
  2782. snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
  2783. }
  2784. switch (argc) {
  2785. case 3:
  2786. break;
  2787. default:
  2788. return CLI_SHOWUSAGE;
  2789. }
  2790. if (!s) {
  2791. ast_cli(fd, "Name DeviceId IP Type R NL\n");
  2792. ast_cli(fd, "-------------------- ---------------- --------------- --------------- - --\n");
  2793. }
  2794. AST_LIST_LOCK(&devices);
  2795. AST_LIST_TRAVERSE(&devices, d, list) {
  2796. int numlines = 0;
  2797. total_devices++;
  2798. AST_LIST_TRAVERSE(&d->lines, l, list) {
  2799. numlines++;
  2800. }
  2801. if (!s) {
  2802. ast_cli(fd, "%-20s %-16s %-15s %-15s %c %2d\n",
  2803. d->name,
  2804. d->id,
  2805. d->session?ast_inet_ntoa(d->session->sin.sin_addr):"",
  2806. device2str(d->type),
  2807. d->registered?'Y':'N',
  2808. numlines);
  2809. } else {
  2810. astman_append(s,
  2811. "Event: DeviceEntry\r\n%s"
  2812. "Channeltype: SKINNY\r\n"
  2813. "ObjectName: %s\r\n"
  2814. "ChannelObjectType: device\r\n"
  2815. "DeviceId: %s\r\n"
  2816. "IPaddress: %s\r\n"
  2817. "Type: %s\r\n"
  2818. "Devicestatus: %s\r\n"
  2819. "NumberOfLines: %d\r\n",
  2820. idtext,
  2821. d->name,
  2822. d->id,
  2823. d->session?ast_inet_ntoa(d->session->sin.sin_addr):"-none-",
  2824. device2str(d->type),
  2825. d->registered?"registered":"unregistered",
  2826. numlines);
  2827. }
  2828. }
  2829. AST_LIST_UNLOCK(&devices);
  2830. if (total)
  2831. *total = total_devices;
  2832. return CLI_SUCCESS;
  2833. }
  2834. /*! \brief Show SKINNY devices in the manager API */
  2835. /* Inspired from chan_sip */
  2836. static int manager_skinny_show_devices(struct mansession *s, const struct message *m)
  2837. {
  2838. const char *id = astman_get_header(m, "ActionID");
  2839. const char *a[] = {"skinny", "show", "devices"};
  2840. char idtext[256] = "";
  2841. int total = 0;
  2842. if (!ast_strlen_zero(id))
  2843. snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
  2844. astman_send_listack(s, m, "Device status list will follow", "start");
  2845. /* List the devices in separate manager events */
  2846. _skinny_show_devices(-1, &total, s, m, 3, a);
  2847. /* Send final confirmation */
  2848. astman_append(s,
  2849. "Event: DevicelistComplete\r\n"
  2850. "EventList: Complete\r\n"
  2851. "ListItems: %d\r\n"
  2852. "%s"
  2853. "\r\n", total, idtext);
  2854. return 0;
  2855. }
  2856. static char *handle_skinny_show_devices(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  2857. {
  2858. switch (cmd) {
  2859. case CLI_INIT:
  2860. e->command = "skinny show devices";
  2861. e->usage =
  2862. "Usage: skinny show devices\n"
  2863. " Lists all devices known to the Skinny subsystem.\n";
  2864. return NULL;
  2865. case CLI_GENERATE:
  2866. return NULL;
  2867. }
  2868. return _skinny_show_devices(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
  2869. }
  2870. static char *_skinny_show_device(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
  2871. {
  2872. struct skinny_device *d;
  2873. struct skinny_line *l;
  2874. struct skinny_speeddial *sd;
  2875. struct skinny_addon *sa;
  2876. char codec_buf[512];
  2877. if (argc < 4) {
  2878. return CLI_SHOWUSAGE;
  2879. }
  2880. AST_LIST_LOCK(&devices);
  2881. AST_LIST_TRAVERSE(&devices, d, list) {
  2882. if (!strcasecmp(argv[3], d->id) || !strcasecmp(argv[3], d->name)) {
  2883. int numlines = 0, numaddons = 0, numspeeddials = 0;
  2884. AST_LIST_TRAVERSE(&d->lines, l, list){
  2885. numlines++;
  2886. }
  2887. AST_LIST_TRAVERSE(&d->addons, sa, list) {
  2888. numaddons++;
  2889. }
  2890. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  2891. numspeeddials++;
  2892. }
  2893. if (type == 0) { /* CLI */
  2894. ast_cli(fd, "Name: %s\n", d->name);
  2895. ast_cli(fd, "Id: %s\n", d->id);
  2896. ast_cli(fd, "version: %s\n", S_OR(d->version_id, "Unknown"));
  2897. ast_cli(fd, "Ip address: %s\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
  2898. ast_cli(fd, "Port: %d\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
  2899. ast_cli(fd, "Device Type: %s\n", device2str(d->type));
  2900. ast_cli(fd, "Conf Codecs:");
  2901. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->confcapability);
  2902. ast_cli(fd, "%s\n", codec_buf);
  2903. ast_cli(fd, "Neg Codecs: ");
  2904. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, d->capability);
  2905. ast_cli(fd, "%s\n", codec_buf);
  2906. ast_cli(fd, "Registered: %s\n", (d->registered ? "Yes" : "No"));
  2907. ast_cli(fd, "Lines: %d\n", numlines);
  2908. AST_LIST_TRAVERSE(&d->lines, l, list) {
  2909. ast_cli(fd, " %s (%s)\n", l->name, l->label);
  2910. }
  2911. AST_LIST_TRAVERSE(&d->addons, sa, list) {
  2912. numaddons++;
  2913. }
  2914. ast_cli(fd, "Addons: %d\n", numaddons);
  2915. AST_LIST_TRAVERSE(&d->addons, sa, list) {
  2916. ast_cli(fd, " %s\n", sa->type);
  2917. }
  2918. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  2919. numspeeddials++;
  2920. }
  2921. ast_cli(fd, "Speeddials: %d\n", numspeeddials);
  2922. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  2923. ast_cli(fd, " %s (%s) ishint: %d\n", sd->exten, sd->label, sd->isHint);
  2924. }
  2925. } else { /* manager */
  2926. astman_append(s, "Channeltype: SKINNY\r\n");
  2927. astman_append(s, "ObjectName: %s\r\n", d->name);
  2928. astman_append(s, "ChannelObjectType: device\r\n");
  2929. astman_append(s, "Id: %s\r\n", d->id);
  2930. astman_append(s, "version: %s\r\n", S_OR(d->version_id, "Unknown"));
  2931. astman_append(s, "Ipaddress: %s\r\n", (d->session ? ast_inet_ntoa(d->session->sin.sin_addr) : "Unknown"));
  2932. astman_append(s, "Port: %d\r\n", (d->session ? ntohs(d->session->sin.sin_port) : 0));
  2933. astman_append(s, "DeviceType: %s\r\n", device2str(d->type));
  2934. astman_append(s, "Codecs: ");
  2935. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->confcapability);
  2936. astman_append(s, "%s\r\n", codec_buf);
  2937. astman_append(s, "CodecOrder: ");
  2938. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, d->capability);
  2939. astman_append(s, "%s\r\n", codec_buf);
  2940. astman_append(s, "Devicestatus: %s\r\n", (d->registered?"registered":"unregistered"));
  2941. astman_append(s, "NumberOfLines: %d\r\n", numlines);
  2942. AST_LIST_TRAVERSE(&d->lines, l, list) {
  2943. astman_append(s, "Line: %s (%s)\r\n", l->name, l->label);
  2944. }
  2945. astman_append(s, "NumberOfAddons: %d\r\n", numaddons);
  2946. AST_LIST_TRAVERSE(&d->addons, sa, list) {
  2947. astman_append(s, "Addon: %s\r\n", sa->type);
  2948. }
  2949. astman_append(s, "NumberOfSpeeddials: %d\r\n", numspeeddials);
  2950. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  2951. astman_append(s, "Speeddial: %s (%s) ishint: %d\r\n", sd->exten, sd->label, sd->isHint);
  2952. }
  2953. }
  2954. }
  2955. }
  2956. AST_LIST_UNLOCK(&devices);
  2957. return CLI_SUCCESS;
  2958. }
  2959. static int manager_skinny_show_device(struct mansession *s, const struct message *m)
  2960. {
  2961. const char *a[4];
  2962. const char *device;
  2963. device = astman_get_header(m, "Device");
  2964. if (ast_strlen_zero(device)) {
  2965. astman_send_error(s, m, "Device: <name> missing.");
  2966. return 0;
  2967. }
  2968. a[0] = "skinny";
  2969. a[1] = "show";
  2970. a[2] = "device";
  2971. a[3] = device;
  2972. _skinny_show_device(1, -1, s, m, 4, a);
  2973. astman_append(s, "\r\n\r\n" );
  2974. return 0;
  2975. }
  2976. /*! \brief Show device information */
  2977. static char *handle_skinny_show_device(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  2978. {
  2979. switch (cmd) {
  2980. case CLI_INIT:
  2981. e->command = "skinny show device";
  2982. e->usage =
  2983. "Usage: skinny show device <DeviceId|DeviceName>\n"
  2984. " Lists all deviceinformation of a specific device known to the Skinny subsystem.\n";
  2985. return NULL;
  2986. case CLI_GENERATE:
  2987. return complete_skinny_show_device(a->line, a->word, a->pos, a->n);
  2988. }
  2989. return _skinny_show_device(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
  2990. }
  2991. static char *_skinny_show_lines(int fd, int *total, struct mansession *s, const struct message *m, int argc, const char *argv[])
  2992. {
  2993. struct skinny_line *l;
  2994. struct skinny_subchannel *sub;
  2995. int total_lines = 0;
  2996. int verbose = 0;
  2997. const char *id;
  2998. char idtext[256] = "";
  2999. if (s) { /* Manager - get ActionID */
  3000. id = astman_get_header(m, "ActionID");
  3001. if (!ast_strlen_zero(id))
  3002. snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
  3003. }
  3004. switch (argc) {
  3005. case 4:
  3006. verbose = 1;
  3007. break;
  3008. case 3:
  3009. verbose = 0;
  3010. break;
  3011. default:
  3012. return CLI_SHOWUSAGE;
  3013. }
  3014. if (!s) {
  3015. ast_cli(fd, "Name Device Name Instance Label \n");
  3016. ast_cli(fd, "-------------------- -------------------- -------- --------------------\n");
  3017. }
  3018. AST_LIST_LOCK(&lines);
  3019. AST_LIST_TRAVERSE(&lines, l, all) {
  3020. total_lines++;
  3021. if (!s) {
  3022. ast_cli(fd, "%-20s %-20s %8d %-20s\n",
  3023. l->name,
  3024. (l->device ? l->device->name : "Not connected"),
  3025. l->instance,
  3026. l->label);
  3027. if (verbose) {
  3028. AST_LIST_TRAVERSE(&l->sub, sub, list) {
  3029. ast_cli(fd, " %s> %s to %s\n",
  3030. (sub == l->activesub?"Active ":"Inactive"),
  3031. sub->owner->name,
  3032. (ast_bridged_channel(sub->owner)?ast_bridged_channel(sub->owner)->name:"")
  3033. );
  3034. }
  3035. }
  3036. } else {
  3037. astman_append(s,
  3038. "Event: LineEntry\r\n%s"
  3039. "Channeltype: SKINNY\r\n"
  3040. "ObjectName: %s\r\n"
  3041. "ChannelObjectType: line\r\n"
  3042. "Device: %s\r\n"
  3043. "Instance: %d\r\n"
  3044. "Label: %s\r\n",
  3045. idtext,
  3046. l->name,
  3047. (l->device?l->device->name:"None"),
  3048. l->instance,
  3049. l->label);
  3050. }
  3051. }
  3052. AST_LIST_UNLOCK(&lines);
  3053. if (total) {
  3054. *total = total_lines;
  3055. }
  3056. return CLI_SUCCESS;
  3057. }
  3058. /*! \brief Show Skinny lines in the manager API */
  3059. /* Inspired from chan_sip */
  3060. static int manager_skinny_show_lines(struct mansession *s, const struct message *m)
  3061. {
  3062. const char *id = astman_get_header(m, "ActionID");
  3063. const char *a[] = {"skinny", "show", "lines"};
  3064. char idtext[256] = "";
  3065. int total = 0;
  3066. if (!ast_strlen_zero(id))
  3067. snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
  3068. astman_send_listack(s, m, "Line status list will follow", "start");
  3069. /* List the lines in separate manager events */
  3070. _skinny_show_lines(-1, &total, s, m, 3, a);
  3071. /* Send final confirmation */
  3072. astman_append(s,
  3073. "Event: LinelistComplete\r\n"
  3074. "EventList: Complete\r\n"
  3075. "ListItems: %d\r\n"
  3076. "%s"
  3077. "\r\n", total, idtext);
  3078. return 0;
  3079. }
  3080. static char *handle_skinny_show_lines(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  3081. {
  3082. switch (cmd) {
  3083. case CLI_INIT:
  3084. e->command = "skinny show lines [verbose]";
  3085. e->usage =
  3086. "Usage: skinny show lines\n"
  3087. " Lists all lines known to the Skinny subsystem.\n"
  3088. " If 'verbose' is specified, the output includes\n"
  3089. " information about subs for each line.\n";
  3090. return NULL;
  3091. case CLI_GENERATE:
  3092. return NULL;
  3093. }
  3094. if (a->argc == e->args) {
  3095. if (strcasecmp(a->argv[e->args-1], "verbose")) {
  3096. return CLI_SHOWUSAGE;
  3097. }
  3098. } else if (a->argc != e->args - 1) {
  3099. return CLI_SHOWUSAGE;
  3100. }
  3101. return _skinny_show_lines(a->fd, NULL, NULL, NULL, a->argc, (const char **) a->argv);
  3102. }
  3103. static char *_skinny_show_line(int type, int fd, struct mansession *s, const struct message *m, int argc, const char *argv[])
  3104. {
  3105. struct skinny_device *d;
  3106. struct skinny_line *l;
  3107. struct ast_codec_pref *pref;
  3108. int x = 0, codec = 0;
  3109. char codec_buf[512];
  3110. char group_buf[256];
  3111. char cbuf[256];
  3112. switch (argc) {
  3113. case 4:
  3114. break;
  3115. case 6:
  3116. break;
  3117. default:
  3118. return CLI_SHOWUSAGE;
  3119. }
  3120. AST_LIST_LOCK(&devices);
  3121. /* Show all lines matching the one supplied */
  3122. AST_LIST_TRAVERSE(&devices, d, list) {
  3123. if (argc == 6 && (strcasecmp(argv[5], d->id) && strcasecmp(argv[5], d->name))) {
  3124. continue;
  3125. }
  3126. AST_LIST_TRAVERSE(&d->lines, l, list) {
  3127. if (strcasecmp(argv[3], l->name)) {
  3128. continue;
  3129. }
  3130. if (type == 0) { /* CLI */
  3131. ast_cli(fd, "Line: %s\n", l->name);
  3132. ast_cli(fd, "On Device: %s\n", d->name);
  3133. ast_cli(fd, "Line Label: %s\n", l->label);
  3134. ast_cli(fd, "Extension: %s\n", S_OR(l->exten, "<not set>"));
  3135. ast_cli(fd, "Context: %s\n", l->context);
  3136. ast_cli(fd, "CallGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
  3137. ast_cli(fd, "PickupGroup: %s\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
  3138. ast_cli(fd, "Language: %s\n", S_OR(l->language, "<not set>"));
  3139. ast_cli(fd, "Accountcode: %s\n", S_OR(l->accountcode, "<not set>"));
  3140. ast_cli(fd, "AmaFlag: %s\n", ast_cdr_flags2str(l->amaflags));
  3141. ast_cli(fd, "CallerId Number: %s\n", S_OR(l->cid_num, "<not set>"));
  3142. ast_cli(fd, "CallerId Name: %s\n", S_OR(l->cid_name, "<not set>"));
  3143. ast_cli(fd, "Hide CallerId: %s\n", (l->hidecallerid ? "Yes" : "No"));
  3144. ast_cli(fd, "CFwdAll: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
  3145. ast_cli(fd, "CFwdBusy: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
  3146. ast_cli(fd, "CFwdNoAnswer: %s\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
  3147. ast_cli(fd, "VoicemailBox: %s\n", S_OR(l->mailbox, "<not set>"));
  3148. ast_cli(fd, "VoicemailNumber: %s\n", S_OR(l->vmexten, "<not set>"));
  3149. ast_cli(fd, "MWIblink: %d\n", l->mwiblink);
  3150. ast_cli(fd, "Regextension: %s\n", S_OR(l->regexten, "<not set>"));
  3151. ast_cli(fd, "Regcontext: %s\n", S_OR(l->regcontext, "<not set>"));
  3152. ast_cli(fd, "MoHInterpret: %s\n", S_OR(l->mohinterpret, "<not set>"));
  3153. ast_cli(fd, "MoHSuggest: %s\n", S_OR(l->mohsuggest, "<not set>"));
  3154. ast_cli(fd, "Last dialed nr: %s\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
  3155. ast_cli(fd, "Last CallerID: %s\n", S_OR(l->lastcallerid, "<not set>"));
  3156. ast_cli(fd, "Transfer enabled: %s\n", (l->transfer ? "Yes" : "No"));
  3157. ast_cli(fd, "Callwaiting: %s\n", (l->callwaiting ? "Yes" : "No"));
  3158. ast_cli(fd, "3Way Calling: %s\n", (l->threewaycalling ? "Yes" : "No"));
  3159. ast_cli(fd, "Can forward: %s\n", (l->cancallforward ? "Yes" : "No"));
  3160. ast_cli(fd, "Do Not Disturb: %s\n", (l->dnd ? "Yes" : "No"));
  3161. ast_cli(fd, "NAT: %s\n", (l->nat ? "Yes" : "No"));
  3162. ast_cli(fd, "immediate: %s\n", (l->immediate ? "Yes" : "No"));
  3163. ast_cli(fd, "Group: %d\n", l->group);
  3164. ast_cli(fd, "Parkinglot: %s\n", S_OR(l->parkinglot, "<not set>"));
  3165. ast_cli(fd, "Conf Codecs: ");
  3166. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability);
  3167. ast_cli(fd, "%s\n", codec_buf);
  3168. ast_cli(fd, "Neg Codecs: ");
  3169. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->capability);
  3170. ast_cli(fd, "%s\n", codec_buf);
  3171. ast_cli(fd, "Codec Order: (");
  3172. print_codec_to_cli(fd, &l->prefs);
  3173. ast_cli(fd, ")\n");
  3174. ast_cli(fd, "\n");
  3175. } else { /* manager */
  3176. astman_append(s, "Channeltype: SKINNY\r\n");
  3177. astman_append(s, "ObjectName: %s\r\n", l->name);
  3178. astman_append(s, "ChannelObjectType: line\r\n");
  3179. astman_append(s, "Device: %s\r\n", d->name);
  3180. astman_append(s, "LineLabel: %s\r\n", l->label);
  3181. astman_append(s, "Extension: %s\r\n", S_OR(l->exten, "<not set>"));
  3182. astman_append(s, "Context: %s\r\n", l->context);
  3183. astman_append(s, "CallGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->callgroup));
  3184. astman_append(s, "PickupGroup: %s\r\n", ast_print_group(group_buf, sizeof(group_buf), l->pickupgroup));
  3185. astman_append(s, "Language: %s\r\n", S_OR(l->language, "<not set>"));
  3186. astman_append(s, "Accountcode: %s\r\n", S_OR(l->accountcode, "<not set>"));
  3187. astman_append(s, "AMAflags: %s\r\n", ast_cdr_flags2str(l->amaflags));
  3188. astman_append(s, "Callerid: %s\r\n", ast_callerid_merge(cbuf, sizeof(cbuf), l->cid_name, l->cid_num, ""));
  3189. astman_append(s, "HideCallerId: %s\r\n", (l->hidecallerid ? "Yes" : "No"));
  3190. astman_append(s, "CFwdAll: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_ALL), l->call_forward_all, "<not set>"));
  3191. astman_append(s, "CFwdBusy: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_BUSY), l->call_forward_busy, "<not set>"));
  3192. astman_append(s, "CFwdNoAnswer: %s\r\n", S_COR((l->cfwdtype & SKINNY_CFWD_NOANSWER), l->call_forward_noanswer, "<not set>"));
  3193. astman_append(s, "VoicemailBox: %s\r\n", S_OR(l->mailbox, "<not set>"));
  3194. astman_append(s, "VoicemailNumber: %s\r\n", S_OR(l->vmexten, "<not set>"));
  3195. astman_append(s, "MWIblink: %d\r\n", l->mwiblink);
  3196. astman_append(s, "RegExtension: %s\r\n", S_OR(l->regexten, "<not set>"));
  3197. astman_append(s, "Regcontext: %s\r\n", S_OR(l->regcontext, "<not set>"));
  3198. astman_append(s, "MoHInterpret: %s\r\n", S_OR(l->mohinterpret, "<not set>"));
  3199. astman_append(s, "MoHSuggest: %s\r\n", S_OR(l->mohsuggest, "<not set>"));
  3200. astman_append(s, "LastDialedNr: %s\r\n", S_OR(l->lastnumberdialed, "<no calls made yet>"));
  3201. astman_append(s, "LastCallerID: %s\r\n", S_OR(l->lastcallerid, "<not set>"));
  3202. astman_append(s, "Transfer: %s\r\n", (l->transfer ? "Yes" : "No"));
  3203. astman_append(s, "Callwaiting: %s\r\n", (l->callwaiting ? "Yes" : "No"));
  3204. astman_append(s, "3WayCalling: %s\r\n", (l->threewaycalling ? "Yes" : "No"));
  3205. astman_append(s, "CanForward: %s\r\n", (l->cancallforward ? "Yes" : "No"));
  3206. astman_append(s, "DoNotDisturb: %s\r\n", (l->dnd ? "Yes" : "No"));
  3207. astman_append(s, "NAT: %s\r\n", (l->nat ? "Yes" : "No"));
  3208. astman_append(s, "immediate: %s\r\n", (l->immediate ? "Yes" : "No"));
  3209. astman_append(s, "Group: %d\r\n", l->group);
  3210. astman_append(s, "Parkinglot: %s\r\n", S_OR(l->parkinglot, "<not set>"));
  3211. ast_getformatname_multiple(codec_buf, sizeof(codec_buf) - 1, l->confcapability);
  3212. astman_append(s, "Codecs: %s\r\n", codec_buf);
  3213. astman_append(s, "CodecOrder: ");
  3214. pref = &l->prefs;
  3215. for(x = 0; x < 32 ; x++) {
  3216. codec = ast_codec_pref_index(pref, x);
  3217. if (!codec)
  3218. break;
  3219. astman_append(s, "%s", ast_getformatname(codec));
  3220. if (x < 31 && ast_codec_pref_index(pref, x+1))
  3221. astman_append(s, ",");
  3222. }
  3223. astman_append(s, "\r\n");
  3224. }
  3225. }
  3226. }
  3227. AST_LIST_UNLOCK(&devices);
  3228. return CLI_SUCCESS;
  3229. }
  3230. static int manager_skinny_show_line(struct mansession *s, const struct message *m)
  3231. {
  3232. const char *a[4];
  3233. const char *line;
  3234. line = astman_get_header(m, "Line");
  3235. if (ast_strlen_zero(line)) {
  3236. astman_send_error(s, m, "Line: <name> missing.");
  3237. return 0;
  3238. }
  3239. a[0] = "skinny";
  3240. a[1] = "show";
  3241. a[2] = "line";
  3242. a[3] = line;
  3243. _skinny_show_line(1, -1, s, m, 4, a);
  3244. astman_append(s, "\r\n\r\n" );
  3245. return 0;
  3246. }
  3247. /*! \brief List line information. */
  3248. static char *handle_skinny_show_line(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  3249. {
  3250. switch (cmd) {
  3251. case CLI_INIT:
  3252. e->command = "skinny show line";
  3253. e->usage =
  3254. "Usage: skinny show line <Line> [ on <DeviceID|DeviceName> ]\n"
  3255. " List all lineinformation of a specific line known to the Skinny subsystem.\n";
  3256. return NULL;
  3257. case CLI_GENERATE:
  3258. return complete_skinny_show_line(a->line, a->word, a->pos, a->n);
  3259. }
  3260. return _skinny_show_line(0, a->fd, NULL, NULL, a->argc, (const char **) a->argv);
  3261. }
  3262. /*! \brief List global settings for the Skinny subsystem. */
  3263. static char *handle_skinny_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  3264. {
  3265. switch (cmd) {
  3266. case CLI_INIT:
  3267. e->command = "skinny show settings";
  3268. e->usage =
  3269. "Usage: skinny show settings\n"
  3270. " Lists all global configuration settings of the Skinny subsystem.\n";
  3271. return NULL;
  3272. case CLI_GENERATE:
  3273. return NULL;
  3274. }
  3275. if (a->argc != 3)
  3276. return CLI_SHOWUSAGE;
  3277. ast_cli(a->fd, "\nGlobal Settings:\n");
  3278. ast_cli(a->fd, " Skinny Port: %d\n", ntohs(bindaddr.sin_port));
  3279. ast_cli(a->fd, " Bindaddress: %s\n", ast_inet_ntoa(bindaddr.sin_addr));
  3280. ast_cli(a->fd, " KeepAlive: %d\n", keep_alive);
  3281. ast_cli(a->fd, " Date Format: %s\n", date_format);
  3282. ast_cli(a->fd, " Voice Mail Extension: %s\n", S_OR(global_vmexten, "(not set)"));
  3283. ast_cli(a->fd, " Reg. context: %s\n", S_OR(regcontext, "(not set)"));
  3284. ast_cli(a->fd, " Jitterbuffer enabled: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_ENABLED)));
  3285. if (ast_test_flag(&global_jbconf, AST_JB_ENABLED)) {
  3286. ast_cli(a->fd, " Jitterbuffer forced: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_FORCED)));
  3287. ast_cli(a->fd, " Jitterbuffer max size: %ld\n", global_jbconf.max_size);
  3288. ast_cli(a->fd, " Jitterbuffer resync: %ld\n", global_jbconf.resync_threshold);
  3289. ast_cli(a->fd, " Jitterbuffer impl: %s\n", global_jbconf.impl);
  3290. if (!strcasecmp(global_jbconf.impl, "adaptive")) {
  3291. ast_cli(a->fd, " Jitterbuffer tgt extra: %ld\n", global_jbconf.target_extra);
  3292. }
  3293. ast_cli(a->fd, " Jitterbuffer log: %s\n", AST_CLI_YESNO(ast_test_flag(&global_jbconf, AST_JB_LOG)));
  3294. }
  3295. return CLI_SUCCESS;
  3296. }
  3297. static struct ast_cli_entry cli_skinny[] = {
  3298. AST_CLI_DEFINE(handle_skinny_show_devices, "List defined Skinny devices"),
  3299. AST_CLI_DEFINE(handle_skinny_show_device, "List Skinny device information"),
  3300. AST_CLI_DEFINE(handle_skinny_show_lines, "List defined Skinny lines per device"),
  3301. AST_CLI_DEFINE(handle_skinny_show_line, "List Skinny line information"),
  3302. AST_CLI_DEFINE(handle_skinny_show_settings, "List global Skinny settings"),
  3303. AST_CLI_DEFINE(handle_skinny_set_debug, "Enable/Disable Skinny debugging"),
  3304. AST_CLI_DEFINE(handle_skinny_reset, "Reset Skinny device(s)"),
  3305. AST_CLI_DEFINE(handle_skinny_reload, "Reload Skinny config"),
  3306. };
  3307. static void start_rtp(struct skinny_subchannel *sub)
  3308. {
  3309. struct skinny_line *l = sub->parent;
  3310. struct skinny_device *d = l->device;
  3311. int hasvideo = 0;
  3312. struct ast_sockaddr bindaddr_tmp;
  3313. ast_mutex_lock(&sub->lock);
  3314. /* Allocate the RTP */
  3315. ast_sockaddr_from_sin(&bindaddr_tmp, &bindaddr);
  3316. sub->rtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
  3317. if (hasvideo)
  3318. sub->vrtp = ast_rtp_instance_new("asterisk", sched, &bindaddr_tmp, NULL);
  3319. if (sub->rtp) {
  3320. ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_RTCP, 1);
  3321. }
  3322. if (sub->vrtp) {
  3323. ast_rtp_instance_set_prop(sub->vrtp, AST_RTP_PROPERTY_RTCP, 1);
  3324. }
  3325. if (sub->rtp && sub->owner) {
  3326. ast_channel_set_fd(sub->owner, 0, ast_rtp_instance_fd(sub->rtp, 0));
  3327. ast_channel_set_fd(sub->owner, 1, ast_rtp_instance_fd(sub->rtp, 1));
  3328. }
  3329. if (hasvideo && sub->vrtp && sub->owner) {
  3330. ast_channel_set_fd(sub->owner, 2, ast_rtp_instance_fd(sub->vrtp, 0));
  3331. ast_channel_set_fd(sub->owner, 3, ast_rtp_instance_fd(sub->vrtp, 1));
  3332. }
  3333. if (sub->rtp) {
  3334. ast_rtp_instance_set_qos(sub->rtp, qos.tos_audio, qos.cos_audio, "Skinny RTP");
  3335. ast_rtp_instance_set_prop(sub->rtp, AST_RTP_PROPERTY_NAT, l->nat);
  3336. }
  3337. if (sub->vrtp) {
  3338. ast_rtp_instance_set_qos(sub->vrtp, qos.tos_video, qos.cos_video, "Skinny VRTP");
  3339. ast_rtp_instance_set_prop(sub->vrtp, AST_RTP_PROPERTY_NAT, l->nat);
  3340. }
  3341. /* Set Frame packetization */
  3342. if (sub->rtp)
  3343. ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(sub->rtp), sub->rtp, &l->prefs);
  3344. /* Create the RTP connection */
  3345. transmit_connect(d, sub);
  3346. ast_mutex_unlock(&sub->lock);
  3347. }
  3348. static void *skinny_newcall(void *data)
  3349. {
  3350. struct ast_channel *c = data;
  3351. struct skinny_subchannel *sub = c->tech_pvt;
  3352. struct skinny_line *l = sub->parent;
  3353. struct skinny_device *d = l->device;
  3354. int res = 0;
  3355. ast_copy_string(l->lastnumberdialed, c->exten, sizeof(l->lastnumberdialed));
  3356. ast_set_callerid(c,
  3357. l->hidecallerid ? "" : l->cid_num,
  3358. l->hidecallerid ? "" : l->cid_name,
  3359. c->caller.ani.number.valid ? NULL : l->cid_num);
  3360. #if 1 /* XXX This code is probably not necessary */
  3361. ast_party_number_free(&c->connected.id.number);
  3362. ast_party_number_init(&c->connected.id.number);
  3363. c->connected.id.number.valid = 1;
  3364. c->connected.id.number.str = ast_strdup(c->exten);
  3365. ast_party_name_free(&c->connected.id.name);
  3366. ast_party_name_init(&c->connected.id.name);
  3367. #endif
  3368. ast_setstate(c, AST_STATE_RING);
  3369. if (!sub->rtp) {
  3370. start_rtp(sub);
  3371. }
  3372. res = ast_pbx_run(c);
  3373. if (res) {
  3374. ast_log(LOG_WARNING, "PBX exited non-zero\n");
  3375. transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
  3376. }
  3377. return NULL;
  3378. }
  3379. static void *skinny_ss(void *data)
  3380. {
  3381. struct ast_channel *c = data;
  3382. struct skinny_subchannel *sub = c->tech_pvt;
  3383. struct skinny_line *l = sub->parent;
  3384. struct skinny_device *d = l->device;
  3385. int len = 0;
  3386. int timeout = firstdigittimeout;
  3387. int res = 0;
  3388. int loop_pause = 100;
  3389. ast_verb(3, "Starting simple switch on '%s@%s'\n", l->name, d->name);
  3390. len = strlen(d->exten);
  3391. while (len < AST_MAX_EXTENSION-1) {
  3392. res = 1; /* Assume that we will get a digit */
  3393. while (strlen(d->exten) == len){
  3394. ast_safe_sleep(c, loop_pause);
  3395. timeout -= loop_pause;
  3396. if ( (timeout -= loop_pause) <= 0){
  3397. res = 0;
  3398. break;
  3399. }
  3400. res = 1;
  3401. }
  3402. timeout = 0;
  3403. len = strlen(d->exten);
  3404. if (!ast_ignore_pattern(c->context, d->exten)) {
  3405. transmit_stop_tone(d, l->instance, sub->callid);
  3406. }
  3407. if (ast_exists_extension(c, c->context, d->exten, 1, l->cid_num)) {
  3408. if (!res || !ast_matchmore_extension(c, c->context, d->exten, 1, l->cid_num)) {
  3409. if (l->getforward) {
  3410. /* Record this as the forwarding extension */
  3411. set_callforwards(l, d->exten, l->getforward);
  3412. ast_verb(3, "Setting call forward (%d) to '%s' on channel %s\n",
  3413. l->cfwdtype, d->exten, c->name);
  3414. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  3415. transmit_lamp_indication(d, STIMULUS_FORWARDALL, 1, SKINNY_LAMP_ON);
  3416. transmit_displaynotify(d, "CFwd enabled", 10);
  3417. transmit_cfwdstate(d, l);
  3418. ast_safe_sleep(c, 500);
  3419. ast_indicate(c, -1);
  3420. ast_safe_sleep(c, 1000);
  3421. memset(d->exten, 0, sizeof(d->exten));
  3422. len = 0;
  3423. l->getforward = 0;
  3424. if (sub->owner && sub->owner->_state != AST_STATE_UP) {
  3425. ast_indicate(c, -1);
  3426. ast_hangup(c);
  3427. }
  3428. return NULL;
  3429. } else {
  3430. ast_copy_string(c->exten, d->exten, sizeof(c->exten));
  3431. ast_copy_string(l->lastnumberdialed, d->exten, sizeof(l->lastnumberdialed));
  3432. memset(d->exten, 0, sizeof(d->exten));
  3433. skinny_newcall(c);
  3434. return NULL;
  3435. }
  3436. } else {
  3437. /* It's a match, but they just typed a digit, and there is an ambiguous match,
  3438. so just set the timeout to matchdigittimeout and wait some more */
  3439. timeout = matchdigittimeout;
  3440. }
  3441. } else if (res == 0) {
  3442. ast_debug(1, "Not enough digits (%s) (and no ambiguous match)...\n", d->exten);
  3443. memset(d->exten, 0, sizeof(d->exten));
  3444. if (l->hookstate == SKINNY_OFFHOOK) {
  3445. transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
  3446. }
  3447. if (sub->owner && sub->owner->_state != AST_STATE_UP) {
  3448. ast_indicate(c, -1);
  3449. ast_hangup(c);
  3450. }
  3451. return NULL;
  3452. } else if (!ast_canmatch_extension(c, c->context, d->exten, 1,
  3453. S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))
  3454. && ((d->exten[0] != '*') || (!ast_strlen_zero(d->exten) > 2))) {
  3455. ast_log(LOG_WARNING, "Can't match [%s] from '%s' in context %s\n", d->exten,
  3456. S_COR(c->caller.id.number.valid, c->caller.id.number.str, "<Unknown Caller>"),
  3457. c->context);
  3458. memset(d->exten, 0, sizeof(d->exten));
  3459. if (l->hookstate == SKINNY_OFFHOOK) {
  3460. transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
  3461. /* hang out for 3 seconds to let congestion play */
  3462. ast_safe_sleep(c, 3000);
  3463. }
  3464. break;
  3465. }
  3466. if (!timeout) {
  3467. timeout = gendigittimeout;
  3468. }
  3469. if (len && !ast_ignore_pattern(c->context, d->exten)) {
  3470. ast_indicate(c, -1);
  3471. }
  3472. }
  3473. if (c)
  3474. ast_hangup(c);
  3475. memset(d->exten, 0, sizeof(d->exten));
  3476. return NULL;
  3477. }
  3478. static int skinny_call(struct ast_channel *ast, char *dest, int timeout)
  3479. {
  3480. int res = 0;
  3481. struct skinny_subchannel *sub = ast->tech_pvt;
  3482. struct skinny_line *l = sub->parent;
  3483. struct skinny_device *d = l->device;
  3484. if (!d->registered) {
  3485. ast_log(LOG_ERROR, "Device not registered, cannot call %s\n", dest);
  3486. return -1;
  3487. }
  3488. if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
  3489. ast_log(LOG_WARNING, "skinny_call called on %s, neither down nor reserved\n", ast->name);
  3490. return -1;
  3491. }
  3492. if (skinnydebug)
  3493. ast_verb(3, "skinny_call(%s)\n", ast->name);
  3494. if (l->dnd) {
  3495. ast_queue_control(ast, AST_CONTROL_BUSY);
  3496. return -1;
  3497. }
  3498. if (AST_LIST_NEXT(sub,list) && !l->callwaiting) {
  3499. ast_queue_control(ast, AST_CONTROL_BUSY);
  3500. return -1;
  3501. }
  3502. switch (l->hookstate) {
  3503. case SKINNY_OFFHOOK:
  3504. break;
  3505. case SKINNY_ONHOOK:
  3506. l->activesub = sub;
  3507. break;
  3508. default:
  3509. ast_log(LOG_ERROR, "Don't know how to deal with hookstate %d\n", l->hookstate);
  3510. break;
  3511. }
  3512. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_RINGIN);
  3513. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGIN);
  3514. transmit_displaypromptstatus(d, "Ring-In", 0, l->instance, sub->callid);
  3515. transmit_callinfo(d,
  3516. S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
  3517. S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, ""),
  3518. l->cid_name, l->cid_num, l->instance, sub->callid, 1);
  3519. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
  3520. transmit_ringer_mode(d, SKINNY_RING_INSIDE);
  3521. ast_setstate(ast, AST_STATE_RINGING);
  3522. ast_queue_control(ast, AST_CONTROL_RINGING);
  3523. sub->outgoing = 1;
  3524. return res;
  3525. }
  3526. static int skinny_hangup(struct ast_channel *ast)
  3527. {
  3528. struct skinny_subchannel *sub = ast->tech_pvt;
  3529. struct skinny_line *l;
  3530. struct skinny_device *d;
  3531. if (!sub) {
  3532. ast_debug(1, "Asked to hangup channel not connected\n");
  3533. return 0;
  3534. }
  3535. l = sub->parent;
  3536. d = l->device;
  3537. if (skinnydebug)
  3538. ast_verb(3,"Hanging up %s/%d\n",d->name,sub->callid);
  3539. AST_LIST_REMOVE(&l->sub, sub, list);
  3540. if (d->registered) {
  3541. /* Ignoring l->type, doesn't seem relevant and previous code
  3542. assigned rather than tested, ie always true */
  3543. if (!AST_LIST_EMPTY(&l->sub)) {
  3544. if (sub->related) {
  3545. sub->related->related = NULL;
  3546. }
  3547. if (sub == l->activesub) { /* we are killing the active sub, but there are other subs on the line*/
  3548. ast_verb(4,"Killing active sub %d\n", sub->callid);
  3549. if (sub->related) {
  3550. l->activesub = sub->related;
  3551. } else {
  3552. if (AST_LIST_NEXT(sub, list)) {
  3553. l->activesub = AST_LIST_NEXT(sub, list);
  3554. } else {
  3555. l->activesub = AST_LIST_FIRST(&l->sub);
  3556. }
  3557. }
  3558. //transmit_callstate(d, l->instance, SKINNY_ONHOOK, sub->callid);
  3559. transmit_activatecallplane(d, l);
  3560. transmit_closereceivechannel(d, sub);
  3561. transmit_stopmediatransmission(d, sub);
  3562. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
  3563. transmit_stop_tone(d, l->instance, sub->callid);
  3564. } else { /* we are killing a background sub on the line with other subs*/
  3565. ast_verb(4,"Killing inactive sub %d\n", sub->callid);
  3566. if (AST_LIST_NEXT(sub, list)) {
  3567. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_BLINK);
  3568. } else {
  3569. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
  3570. }
  3571. }
  3572. } else { /* no more subs on line so make idle */
  3573. ast_verb(4,"Killing only sub %d\n", sub->callid);
  3574. l->hookstate = SKINNY_ONHOOK;
  3575. transmit_closereceivechannel(d, sub);
  3576. transmit_stopmediatransmission(d, sub);
  3577. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  3578. transmit_clearpromptmessage(d, l->instance, sub->callid);
  3579. transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
  3580. transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
  3581. transmit_activatecallplane(d, l);
  3582. l->activesub = NULL;
  3583. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_OFF);
  3584. if (sub->parent == d->activeline) {
  3585. transmit_activatecallplane(d, l);
  3586. transmit_closereceivechannel(d, sub);
  3587. transmit_stopmediatransmission(d, sub);
  3588. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  3589. transmit_ringer_mode(d, SKINNY_RING_OFF);
  3590. transmit_clear_display_message(d, l->instance, sub->callid);
  3591. transmit_stop_tone(d, l->instance, sub->callid);
  3592. /* we should check to see if we can start the ringer if another line is ringing */
  3593. }
  3594. }
  3595. }
  3596. ast_mutex_lock(&sub->lock);
  3597. sub->owner = NULL;
  3598. ast->tech_pvt = NULL;
  3599. sub->alreadygone = 0;
  3600. sub->outgoing = 0;
  3601. if (sub->rtp) {
  3602. ast_rtp_instance_destroy(sub->rtp);
  3603. sub->rtp = NULL;
  3604. }
  3605. ast_mutex_unlock(&sub->lock);
  3606. ast_free(sub);
  3607. ast_module_unref(ast_module_info->self);
  3608. return 0;
  3609. }
  3610. static int skinny_answer(struct ast_channel *ast)
  3611. {
  3612. int res = 0;
  3613. struct skinny_subchannel *sub = ast->tech_pvt;
  3614. struct skinny_line *l = sub->parent;
  3615. struct skinny_device *d = l->device;
  3616. if (sub->blindxfer) {
  3617. if (skinnydebug)
  3618. ast_debug(1, "skinny_answer(%s) on %s@%s-%d with BlindXFER, transferring\n",
  3619. ast->name, l->name, d->name, sub->callid);
  3620. ast_setstate(ast, AST_STATE_UP);
  3621. skinny_transfer(sub);
  3622. return 0;
  3623. }
  3624. sub->cxmode = SKINNY_CX_SENDRECV;
  3625. if (!sub->rtp) {
  3626. start_rtp(sub);
  3627. }
  3628. if (skinnydebug)
  3629. ast_verb(1, "skinny_answer(%s) on %s@%s-%d\n", ast->name, l->name, d->name, sub->callid);
  3630. if (ast->_state != AST_STATE_UP) {
  3631. ast_setstate(ast, AST_STATE_UP);
  3632. }
  3633. transmit_stop_tone(d, l->instance, sub->callid);
  3634. /* order matters here...
  3635. for some reason, transmit_callinfo must be before transmit_callstate,
  3636. or you won't get keypad messages in some situations. */
  3637. transmit_callinfo(d,
  3638. S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, ""),
  3639. S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, ""),
  3640. l->lastnumberdialed, l->lastnumberdialed, l->instance, sub->callid, 2);
  3641. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
  3642. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
  3643. transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
  3644. transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
  3645. l->activesub = sub;
  3646. return res;
  3647. }
  3648. /* Retrieve audio/etc from channel. Assumes sub->lock is already held. */
  3649. static struct ast_frame *skinny_rtp_read(struct skinny_subchannel *sub)
  3650. {
  3651. struct ast_channel *ast = sub->owner;
  3652. struct ast_frame *f;
  3653. if (!sub->rtp) {
  3654. /* We have no RTP allocated for this channel */
  3655. return &ast_null_frame;
  3656. }
  3657. switch(ast->fdno) {
  3658. case 0:
  3659. f = ast_rtp_instance_read(sub->rtp, 0); /* RTP Audio */
  3660. break;
  3661. case 1:
  3662. f = ast_rtp_instance_read(sub->rtp, 1); /* RTCP Control Channel */
  3663. break;
  3664. case 2:
  3665. f = ast_rtp_instance_read(sub->vrtp, 0); /* RTP Video */
  3666. break;
  3667. case 3:
  3668. f = ast_rtp_instance_read(sub->vrtp, 1); /* RTCP Control Channel for video */
  3669. break;
  3670. #if 0
  3671. case 5:
  3672. /* Not yet supported */
  3673. f = ast_udptl_read(sub->udptl); /* UDPTL for T.38 */
  3674. break;
  3675. #endif
  3676. default:
  3677. f = &ast_null_frame;
  3678. }
  3679. if (ast) {
  3680. /* We already hold the channel lock */
  3681. if (f->frametype == AST_FRAME_VOICE) {
  3682. if (f->subclass.codec != ast->nativeformats) {
  3683. ast_debug(1, "Oooh, format changed to %s\n", ast_getformatname(f->subclass.codec));
  3684. ast->nativeformats = f->subclass.codec;
  3685. ast_set_read_format(ast, ast->readformat);
  3686. ast_set_write_format(ast, ast->writeformat);
  3687. }
  3688. }
  3689. }
  3690. return f;
  3691. }
  3692. static struct ast_frame *skinny_read(struct ast_channel *ast)
  3693. {
  3694. struct ast_frame *fr;
  3695. struct skinny_subchannel *sub = ast->tech_pvt;
  3696. ast_mutex_lock(&sub->lock);
  3697. fr = skinny_rtp_read(sub);
  3698. ast_mutex_unlock(&sub->lock);
  3699. return fr;
  3700. }
  3701. static int skinny_write(struct ast_channel *ast, struct ast_frame *frame)
  3702. {
  3703. struct skinny_subchannel *sub = ast->tech_pvt;
  3704. int res = 0;
  3705. if (frame->frametype != AST_FRAME_VOICE) {
  3706. if (frame->frametype == AST_FRAME_IMAGE) {
  3707. return 0;
  3708. } else {
  3709. ast_log(LOG_WARNING, "Can't send %d type frames with skinny_write\n", frame->frametype);
  3710. return 0;
  3711. }
  3712. } else {
  3713. if (!(frame->subclass.codec & ast->nativeformats)) {
  3714. char buf[256];
  3715. ast_log(LOG_WARNING, "Asked to transmit frame type %s, while native formats is %s (read/write = %s/%s)\n",
  3716. ast_getformatname(frame->subclass.codec),
  3717. ast_getformatname_multiple(buf, sizeof(buf), ast->nativeformats),
  3718. ast_getformatname(ast->readformat),
  3719. ast_getformatname(ast->writeformat));
  3720. return -1;
  3721. }
  3722. }
  3723. if (sub) {
  3724. ast_mutex_lock(&sub->lock);
  3725. if (sub->rtp) {
  3726. res = ast_rtp_instance_write(sub->rtp, frame);
  3727. }
  3728. ast_mutex_unlock(&sub->lock);
  3729. }
  3730. return res;
  3731. }
  3732. static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
  3733. {
  3734. struct skinny_subchannel *sub = newchan->tech_pvt;
  3735. ast_log(LOG_NOTICE, "skinny_fixup(%s, %s)\n", oldchan->name, newchan->name);
  3736. if (sub->owner != oldchan) {
  3737. ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, sub->owner);
  3738. return -1;
  3739. }
  3740. sub->owner = newchan;
  3741. return 0;
  3742. }
  3743. static int skinny_senddigit_begin(struct ast_channel *ast, char digit)
  3744. {
  3745. return -1; /* Start inband indications */
  3746. }
  3747. static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
  3748. {
  3749. #if 0
  3750. struct skinny_subchannel *sub = ast->tech_pvt;
  3751. struct skinny_line *l = sub->parent;
  3752. struct skinny_device *d = l->device;
  3753. int tmp;
  3754. /* not right */
  3755. sprintf(tmp, "%d", digit);
  3756. //transmit_tone(d, digit, l->instance, sub->callid);
  3757. #endif
  3758. return -1; /* Stop inband indications */
  3759. }
  3760. static int get_devicestate(struct skinny_line *l)
  3761. {
  3762. struct skinny_subchannel *sub;
  3763. int res = AST_DEVICE_UNKNOWN;
  3764. if (!l)
  3765. res = AST_DEVICE_INVALID;
  3766. else if (!l->device)
  3767. res = AST_DEVICE_UNAVAILABLE;
  3768. else if (l->dnd)
  3769. res = AST_DEVICE_BUSY;
  3770. else {
  3771. if (l->hookstate == SKINNY_ONHOOK) {
  3772. res = AST_DEVICE_NOT_INUSE;
  3773. } else {
  3774. res = AST_DEVICE_INUSE;
  3775. }
  3776. AST_LIST_TRAVERSE(&l->sub, sub, list) {
  3777. if (sub->onhold) {
  3778. res = AST_DEVICE_ONHOLD;
  3779. break;
  3780. }
  3781. }
  3782. }
  3783. return res;
  3784. }
  3785. static char *control2str(int ind) {
  3786. char *tmp;
  3787. switch (ind) {
  3788. case AST_CONTROL_HANGUP:
  3789. return "Other end has hungup";
  3790. case AST_CONTROL_RING:
  3791. return "Local ring";
  3792. case AST_CONTROL_RINGING:
  3793. return "Remote end is ringing";
  3794. case AST_CONTROL_ANSWER:
  3795. return "Remote end has answered";
  3796. case AST_CONTROL_BUSY:
  3797. return "Remote end is busy";
  3798. case AST_CONTROL_TAKEOFFHOOK:
  3799. return "Make it go off hook";
  3800. case AST_CONTROL_OFFHOOK:
  3801. return "Line is off hook";
  3802. case AST_CONTROL_CONGESTION:
  3803. return "Congestion (circuits busy)";
  3804. case AST_CONTROL_FLASH:
  3805. return "Flash hook";
  3806. case AST_CONTROL_WINK:
  3807. return "Wink";
  3808. case AST_CONTROL_OPTION:
  3809. return "Set a low-level option";
  3810. case AST_CONTROL_RADIO_KEY:
  3811. return "Key Radio";
  3812. case AST_CONTROL_RADIO_UNKEY:
  3813. return "Un-Key Radio";
  3814. case AST_CONTROL_PROGRESS:
  3815. return "Remote end is making Progress";
  3816. case AST_CONTROL_PROCEEDING:
  3817. return "Remote end is proceeding";
  3818. case AST_CONTROL_HOLD:
  3819. return "Hold";
  3820. case AST_CONTROL_UNHOLD:
  3821. return "Unhold";
  3822. case AST_CONTROL_SRCUPDATE:
  3823. return "Media Source Update";
  3824. case AST_CONTROL_CONNECTED_LINE:
  3825. return "Connected Line";
  3826. case AST_CONTROL_REDIRECTING:
  3827. return "Redirecting";
  3828. case AST_CONTROL_INCOMPLETE:
  3829. return "Incomplete";
  3830. case -1:
  3831. return "Stop tone";
  3832. default:
  3833. if (!(tmp = ast_threadstorage_get(&control2str_threadbuf, CONTROL2STR_BUFSIZE)))
  3834. return "Unknown";
  3835. snprintf(tmp, CONTROL2STR_BUFSIZE, "UNKNOWN-%d", ind);
  3836. return tmp;
  3837. }
  3838. }
  3839. static int skinny_transfer(struct skinny_subchannel *sub)
  3840. {
  3841. struct skinny_subchannel *xferor; /* the sub doing the transferring */
  3842. struct skinny_subchannel *xferee; /* the sub being transferred */
  3843. struct ast_tone_zone_sound *ts = NULL;
  3844. if (ast_bridged_channel(sub->owner) || ast_bridged_channel(sub->related->owner)) {
  3845. if (sub->xferor) {
  3846. xferor = sub;
  3847. xferee = sub->related;
  3848. } else {
  3849. xferor = sub;
  3850. xferee = sub->related;
  3851. }
  3852. if (skinnydebug) {
  3853. ast_debug(1, "Transferee channels (local/remote): %s and %s\n",
  3854. xferee->owner->name, ast_bridged_channel(xferee->owner)?ast_bridged_channel(xferee->owner)->name:"");
  3855. ast_debug(1, "Transferor channels (local/remote): %s and %s\n",
  3856. xferor->owner->name, ast_bridged_channel(xferor->owner)?ast_bridged_channel(xferor->owner)->name:"");
  3857. }
  3858. if (ast_bridged_channel(xferor->owner)) {
  3859. if (ast_bridged_channel(xferee->owner)) {
  3860. ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
  3861. }
  3862. if (xferor->owner->_state == AST_STATE_RING) {
  3863. /* play ringing inband */
  3864. if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) {
  3865. ast_playtones_start(xferor->owner, 0, ts->data, 1);
  3866. ts = ast_tone_zone_sound_unref(ts);
  3867. }
  3868. }
  3869. if (skinnydebug)
  3870. ast_debug(1, "Transfer Masquerading %s to %s\n",
  3871. xferee->owner->name, ast_bridged_channel(xferor->owner)?ast_bridged_channel(xferor->owner)->name:"");
  3872. if (ast_channel_masquerade(xferee->owner, ast_bridged_channel(xferor->owner))) {
  3873. ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
  3874. ast_bridged_channel(xferor->owner)->name, xferee->owner->name);
  3875. return -1;
  3876. }
  3877. } else if (ast_bridged_channel(xferee->owner)) {
  3878. ast_queue_control(xferee->owner, AST_CONTROL_UNHOLD);
  3879. if (xferor->owner->_state == AST_STATE_RING) {
  3880. /* play ringing inband */
  3881. if ((ts = ast_get_indication_tone(xferor->owner->zone, "ring"))) {
  3882. ast_playtones_start(xferor->owner, 0, ts->data, 1);
  3883. ts = ast_tone_zone_sound_unref(ts);
  3884. }
  3885. }
  3886. if (skinnydebug)
  3887. ast_debug(1, "Transfer Masquerading %s to %s\n",
  3888. xferor->owner->name, ast_bridged_channel(xferee->owner)?ast_bridged_channel(xferee->owner)->name:"");
  3889. if (ast_channel_masquerade(xferor->owner, ast_bridged_channel(xferee->owner))) {
  3890. ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
  3891. ast_bridged_channel(xferee->owner)->name, xferor->owner->name);
  3892. return -1;
  3893. }
  3894. return 0;
  3895. } else {
  3896. if (option_debug)
  3897. ast_log(LOG_DEBUG, "Neither %s nor %s are in a bridge, nothing to transfer\n",
  3898. xferor->owner->name, xferee->owner->name);
  3899. }
  3900. }
  3901. return 0;
  3902. }
  3903. static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen)
  3904. {
  3905. struct skinny_subchannel *sub = ast->tech_pvt;
  3906. struct skinny_line *l = sub->parent;
  3907. struct skinny_device *d = l->device;
  3908. struct skinnysession *s = d->session;
  3909. if (!s) {
  3910. ast_log(LOG_NOTICE, "Asked to indicate '%s' condition on channel %s, but session does not exist.\n", control2str(ind), ast->name);
  3911. return -1;
  3912. }
  3913. if (skinnydebug)
  3914. ast_verb(3, "Asked to indicate '%s' condition on channel %s\n", control2str(ind), ast->name);
  3915. switch(ind) {
  3916. case AST_CONTROL_RINGING:
  3917. if (sub->blindxfer) {
  3918. if (skinnydebug)
  3919. ast_debug(1, "Channel %s set up for Blind Xfer, so Xfer rather than ring device\n", ast->name);
  3920. skinny_transfer(sub);
  3921. break;
  3922. }
  3923. if (ast->_state != AST_STATE_UP) {
  3924. if (!sub->progress) {
  3925. if (!d->earlyrtp) {
  3926. transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
  3927. }
  3928. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_RINGOUT);
  3929. transmit_dialednumber(d, l->lastnumberdialed, l->instance, sub->callid);
  3930. transmit_displaypromptstatus(d, "Ring Out", 0, l->instance, sub->callid);
  3931. transmit_callinfo(d,
  3932. S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
  3933. S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
  3934. S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, l->lastnumberdialed),
  3935. S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, l->lastnumberdialed),
  3936. l->instance, sub->callid, 2); /* 2 = outgoing from phone */
  3937. sub->ringing = 1;
  3938. if (!d->earlyrtp) {
  3939. break;
  3940. }
  3941. }
  3942. }
  3943. return -1; /* Tell asterisk to provide inband signalling */
  3944. case AST_CONTROL_BUSY:
  3945. if (ast->_state != AST_STATE_UP) {
  3946. if (!d->earlyrtp) {
  3947. transmit_start_tone(d, SKINNY_BUSYTONE, l->instance, sub->callid);
  3948. }
  3949. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_BUSY);
  3950. sub->alreadygone = 1;
  3951. ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
  3952. if (!d->earlyrtp) {
  3953. break;
  3954. }
  3955. }
  3956. return -1; /* Tell asterisk to provide inband signalling */
  3957. case AST_CONTROL_INCOMPLETE:
  3958. /* Support for incomplete not supported for chan_skinny; treat as congestion */
  3959. case AST_CONTROL_CONGESTION:
  3960. if (ast->_state != AST_STATE_UP) {
  3961. if (!d->earlyrtp) {
  3962. transmit_start_tone(d, SKINNY_REORDER, l->instance, sub->callid);
  3963. }
  3964. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONGESTION);
  3965. sub->alreadygone = 1;
  3966. ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
  3967. if (!d->earlyrtp) {
  3968. break;
  3969. }
  3970. }
  3971. return -1; /* Tell asterisk to provide inband signalling */
  3972. case AST_CONTROL_PROGRESS:
  3973. if ((ast->_state != AST_STATE_UP) && !sub->progress && !sub->outgoing) {
  3974. if (!d->earlyrtp) {
  3975. transmit_start_tone(d, SKINNY_ALERT, l->instance, sub->callid);
  3976. }
  3977. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_PROGRESS);
  3978. transmit_displaypromptstatus(d, "Call Progress", 0, l->instance, sub->callid);
  3979. transmit_callinfo(d,
  3980. S_COR(ast->caller.id.name.valid, ast->caller.id.name.str, ""),
  3981. S_COR(ast->caller.id.number.valid, ast->caller.id.number.str, ""),
  3982. S_COR(ast->connected.id.name.valid, ast->connected.id.name.str, l->lastnumberdialed),
  3983. S_COR(ast->connected.id.number.valid, ast->connected.id.number.str, l->lastnumberdialed),
  3984. l->instance, sub->callid, 2); /* 2 = outgoing from phone */
  3985. sub->progress = 1;
  3986. if (!d->earlyrtp) {
  3987. break;
  3988. }
  3989. }
  3990. return -1; /* Tell asterisk to provide inband signalling */
  3991. case -1: /* STOP_TONE */
  3992. transmit_stop_tone(d, l->instance, sub->callid);
  3993. break;
  3994. case AST_CONTROL_HOLD:
  3995. ast_moh_start(ast, data, l->mohinterpret);
  3996. break;
  3997. case AST_CONTROL_UNHOLD:
  3998. ast_moh_stop(ast);
  3999. break;
  4000. case AST_CONTROL_PROCEEDING:
  4001. break;
  4002. case AST_CONTROL_SRCUPDATE:
  4003. ast_rtp_instance_update_source(sub->rtp);
  4004. break;
  4005. case AST_CONTROL_SRCCHANGE:
  4006. ast_rtp_instance_change_source(sub->rtp);
  4007. break;
  4008. case AST_CONTROL_CONNECTED_LINE:
  4009. update_connectedline(sub, data, datalen);
  4010. break;
  4011. default:
  4012. ast_log(LOG_WARNING, "Don't know how to indicate condition %d\n", ind);
  4013. return -1; /* Tell asterisk to provide inband signalling */
  4014. }
  4015. return 0;
  4016. }
  4017. static struct ast_channel *skinny_new(struct skinny_line *l, int state, const char *linkedid)
  4018. {
  4019. struct ast_channel *tmp;
  4020. struct skinny_subchannel *sub;
  4021. struct skinny_device *d = l->device;
  4022. struct ast_variable *v = NULL;
  4023. int fmt;
  4024. if (!l->device) {
  4025. ast_log(LOG_WARNING, "Device for line %s is not registered.\n", l->name);
  4026. return NULL;
  4027. }
  4028. tmp = ast_channel_alloc(1, state, l->cid_num, l->cid_name, l->accountcode, l->exten, l->context, linkedid, l->amaflags, "Skinny/%s@%s-%d", l->name, d->name, callnums);
  4029. if (!tmp) {
  4030. ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
  4031. return NULL;
  4032. } else {
  4033. sub = ast_calloc(1, sizeof(*sub));
  4034. if (!sub) {
  4035. ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
  4036. return NULL;
  4037. } else {
  4038. ast_mutex_init(&sub->lock);
  4039. sub->owner = tmp;
  4040. sub->callid = callnums++;
  4041. d->lastlineinstance = l->instance;
  4042. d->lastcallreference = sub->callid;
  4043. sub->cxmode = SKINNY_CX_INACTIVE;
  4044. sub->nat = l->nat;
  4045. sub->parent = l;
  4046. sub->onhold = 0;
  4047. sub->blindxfer = 0;
  4048. sub->xferor = 0;
  4049. sub->related = NULL;
  4050. AST_LIST_INSERT_HEAD(&l->sub, sub, list);
  4051. //l->activesub = sub;
  4052. }
  4053. tmp->tech = &skinny_tech;
  4054. tmp->tech_pvt = sub;
  4055. tmp->nativeformats = l->capability;
  4056. if (!tmp->nativeformats)
  4057. // Should throw an error
  4058. tmp->nativeformats = default_capability;
  4059. fmt = ast_best_codec(tmp->nativeformats);
  4060. if (skinnydebug) {
  4061. char buf[256];
  4062. ast_verb(1, "skinny_new: tmp->nativeformats=%s fmt=%s\n",
  4063. ast_getformatname_multiple(buf, sizeof(buf), tmp->nativeformats),
  4064. ast_getformatname(fmt));
  4065. }
  4066. if (sub->rtp) {
  4067. ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
  4068. }
  4069. if (state == AST_STATE_RING) {
  4070. tmp->rings = 1;
  4071. }
  4072. tmp->writeformat = fmt;
  4073. tmp->rawwriteformat = fmt;
  4074. tmp->readformat = fmt;
  4075. tmp->rawreadformat = fmt;
  4076. if (!ast_strlen_zero(l->language))
  4077. ast_string_field_set(tmp, language, l->language);
  4078. if (!ast_strlen_zero(l->accountcode))
  4079. ast_string_field_set(tmp, accountcode, l->accountcode);
  4080. if (!ast_strlen_zero(l->parkinglot))
  4081. ast_string_field_set(tmp, parkinglot, l->parkinglot);
  4082. if (l->amaflags)
  4083. tmp->amaflags = l->amaflags;
  4084. ast_module_ref(ast_module_info->self);
  4085. tmp->callgroup = l->callgroup;
  4086. tmp->pickupgroup = l->pickupgroup;
  4087. /* XXX Need to figure out how to handle CFwdNoAnswer */
  4088. if (l->cfwdtype & SKINNY_CFWD_ALL) {
  4089. ast_string_field_set(tmp, call_forward, l->call_forward_all);
  4090. } else if (l->cfwdtype & SKINNY_CFWD_BUSY) {
  4091. if (get_devicestate(l) != AST_DEVICE_NOT_INUSE) {
  4092. ast_string_field_set(tmp, call_forward, l->call_forward_busy);
  4093. }
  4094. }
  4095. ast_copy_string(tmp->context, l->context, sizeof(tmp->context));
  4096. ast_copy_string(tmp->exten, l->exten, sizeof(tmp->exten));
  4097. /* Don't use ast_set_callerid() here because it will
  4098. * generate a needless NewCallerID event */
  4099. if (!ast_strlen_zero(l->cid_num)) {
  4100. tmp->caller.ani.number.valid = 1;
  4101. tmp->caller.ani.number.str = ast_strdup(l->cid_num);
  4102. }
  4103. tmp->priority = 1;
  4104. tmp->adsicpe = AST_ADSI_UNAVAILABLE;
  4105. if (sub->rtp)
  4106. ast_jb_configure(tmp, &global_jbconf);
  4107. /* Set channel variables for this call from configuration */
  4108. for (v = l->chanvars ; v ; v = v->next)
  4109. pbx_builtin_setvar_helper(tmp, v->name, v->value);
  4110. if (state != AST_STATE_DOWN) {
  4111. if (ast_pbx_start(tmp)) {
  4112. ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
  4113. ast_hangup(tmp);
  4114. tmp = NULL;
  4115. }
  4116. }
  4117. }
  4118. return tmp;
  4119. }
  4120. static int skinny_hold(struct skinny_subchannel *sub)
  4121. {
  4122. struct skinny_line *l = sub->parent;
  4123. struct skinny_device *d = l->device;
  4124. /* Don't try to hold a channel that doesn't exist */
  4125. if (!sub || !sub->owner)
  4126. return 0;
  4127. /* Channel needs to be put on hold */
  4128. if (skinnydebug)
  4129. ast_verb(1, "Putting on Hold(%d)\n", l->instance);
  4130. ast_queue_control_data(sub->owner, AST_CONTROL_HOLD,
  4131. S_OR(l->mohsuggest, NULL),
  4132. !ast_strlen_zero(l->mohsuggest) ? strlen(l->mohsuggest) + 1 : 0);
  4133. transmit_activatecallplane(d, l);
  4134. transmit_closereceivechannel(d, sub);
  4135. transmit_stopmediatransmission(d, sub);
  4136. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_HOLD);
  4137. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_WINK);
  4138. sub->onhold = 1;
  4139. return 1;
  4140. }
  4141. static int skinny_unhold(struct skinny_subchannel *sub)
  4142. {
  4143. struct skinny_line *l = sub->parent;
  4144. struct skinny_device *d = l->device;
  4145. /* Don't try to unhold a channel that doesn't exist */
  4146. if (!sub || !sub->owner)
  4147. return 0;
  4148. /* Channel is on hold, so we will unhold */
  4149. if (skinnydebug)
  4150. ast_verb(1, "Taking off Hold(%d)\n", l->instance);
  4151. ast_queue_control(sub->owner, AST_CONTROL_UNHOLD);
  4152. transmit_activatecallplane(d, l);
  4153. transmit_connect(d, sub);
  4154. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
  4155. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
  4156. l->hookstate = SKINNY_OFFHOOK;
  4157. sub->onhold = 0;
  4158. return 1;
  4159. }
  4160. static int handle_hold_button(struct skinny_subchannel *sub)
  4161. {
  4162. if (!sub)
  4163. return -1;
  4164. if (sub->related) {
  4165. skinny_hold(sub);
  4166. skinny_unhold(sub->related);
  4167. sub->parent->activesub = sub->related;
  4168. } else {
  4169. if (sub->onhold) {
  4170. skinny_unhold(sub);
  4171. transmit_selectsoftkeys(sub->parent->device, sub->parent->instance, sub->callid, KEYDEF_CONNECTED);
  4172. } else {
  4173. skinny_hold(sub);
  4174. transmit_selectsoftkeys(sub->parent->device, sub->parent->instance, sub->callid, KEYDEF_ONHOLD);
  4175. }
  4176. }
  4177. return 1;
  4178. }
  4179. static int handle_transfer_button(struct skinny_subchannel *sub)
  4180. {
  4181. struct skinny_line *l;
  4182. struct skinny_device *d;
  4183. struct skinny_subchannel *newsub;
  4184. struct ast_channel *c;
  4185. pthread_t t;
  4186. if (!sub) {
  4187. ast_verbose("Transfer: No subchannel to transfer\n");
  4188. return -1;
  4189. }
  4190. l = sub->parent;
  4191. d = l->device;
  4192. if (!sub->related) {
  4193. /* Another sub has not been created so this must be first XFER press */
  4194. if (!sub->onhold) {
  4195. skinny_hold(sub);
  4196. }
  4197. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4198. if (c) {
  4199. newsub = c->tech_pvt;
  4200. /* point the sub and newsub at each other so we know they are related */
  4201. newsub->related = sub;
  4202. sub->related = newsub;
  4203. newsub->xferor = 1;
  4204. l->activesub = newsub;
  4205. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4206. transmit_activatecallplane(d, l);
  4207. transmit_clear_display_message(d, l->instance, newsub->callid);
  4208. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, newsub->callid);
  4209. transmit_selectsoftkeys(d, l->instance, newsub->callid, KEYDEF_OFFHOOKWITHFEAT);
  4210. /* start the switch thread */
  4211. if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
  4212. ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
  4213. ast_hangup(c);
  4214. }
  4215. } else {
  4216. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4217. }
  4218. } else {
  4219. /* We already have a related sub so we can either complete XFER or go into BLINDXFER (or cancel BLINDXFER */
  4220. if (sub->blindxfer) {
  4221. /* toggle blindxfer off */
  4222. sub->blindxfer = 0;
  4223. sub->related->blindxfer = 0;
  4224. /* we really need some indications */
  4225. } else {
  4226. /* We were doing attended transfer */
  4227. if (sub->owner->_state == AST_STATE_DOWN || sub->related->owner->_state == AST_STATE_DOWN) {
  4228. /* one of the subs so we cant transfer yet, toggle blindxfer on */
  4229. sub->blindxfer = 1;
  4230. sub->related->blindxfer = 1;
  4231. } else {
  4232. /* big assumption we have two channels, lets transfer */
  4233. skinny_transfer(sub);
  4234. }
  4235. }
  4236. }
  4237. return 0;
  4238. }
  4239. static int handle_keep_alive_message(struct skinny_req *req, struct skinnysession *s)
  4240. {
  4241. if (!(req = req_alloc(0, KEEP_ALIVE_ACK_MESSAGE)))
  4242. return -1;
  4243. transmit_response(s->device, req);
  4244. return 1;
  4245. }
  4246. static int handle_register_message(struct skinny_req *req, struct skinnysession *s)
  4247. {
  4248. struct skinny_device *d = NULL;
  4249. char name[16];
  4250. int res;
  4251. memcpy(&name, req->data.reg.name, sizeof(name));
  4252. res = skinny_register(req, s);
  4253. if (!res) {
  4254. ast_log(LOG_ERROR, "Rejecting Device %s: Device not found\n", name);
  4255. if (!(req = req_alloc(sizeof(struct register_rej_message), REGISTER_REJ_MESSAGE)))
  4256. return -1;
  4257. snprintf(req->data.regrej.errMsg, sizeof(req->data.regrej.errMsg), "No Authority: %s", name);
  4258. /* transmit_respons in line as we don't have a valid d */
  4259. ast_mutex_lock(&s->lock);
  4260. if (letohl(req->len) > SKINNY_MAX_PACKET || letohl(req->len) < 0) {
  4261. ast_log(LOG_WARNING, "transmit_response: the length (%d) of the request is out of bounds (%d) \n", letohl(req->len), SKINNY_MAX_PACKET);
  4262. ast_mutex_unlock(&s->lock);
  4263. return -1;
  4264. }
  4265. memset(s->outbuf, 0, sizeof(s->outbuf));
  4266. memcpy(s->outbuf, req, skinny_header_size);
  4267. memcpy(s->outbuf+skinny_header_size, &req->data, letohl(req->len));
  4268. res = write(s->fd, s->outbuf, letohl(req->len)+8);
  4269. if (res != letohl(req->len)+8) {
  4270. ast_log(LOG_WARNING, "Transmit: write only sent %d out of %d bytes: %s\n", res, letohl(req->len)+8, strerror(errno));
  4271. }
  4272. ast_mutex_unlock(&s->lock);
  4273. return 0;
  4274. }
  4275. ast_atomic_fetchadd_int(&unauth_sessions, -1);
  4276. ast_verb(3, "Device '%s' successfully registered\n", name);
  4277. d = s->device;
  4278. if (!(req = req_alloc(sizeof(struct register_ack_message), REGISTER_ACK_MESSAGE)))
  4279. return -1;
  4280. req->data.regack.res[0] = '0';
  4281. req->data.regack.res[1] = '\0';
  4282. req->data.regack.keepAlive = htolel(keep_alive);
  4283. memcpy(req->data.regack.dateTemplate, date_format, sizeof(req->data.regack.dateTemplate));
  4284. req->data.regack.res2[0] = '0';
  4285. req->data.regack.res2[1] = '\0';
  4286. req->data.regack.secondaryKeepAlive = htolel(keep_alive);
  4287. transmit_response(d, req);
  4288. if (skinnydebug)
  4289. ast_verb(1, "Requesting capabilities\n");
  4290. if (!(req = req_alloc(0, CAPABILITIES_REQ_MESSAGE)))
  4291. return -1;
  4292. transmit_response(d, req);
  4293. return res;
  4294. }
  4295. static int handle_callforward_button(struct skinny_subchannel *sub, int cfwdtype)
  4296. {
  4297. struct skinny_line *l = sub->parent;
  4298. struct skinny_device *d = l->device;
  4299. struct ast_channel *c = sub->owner;
  4300. pthread_t t;
  4301. if (l->hookstate == SKINNY_ONHOOK) {
  4302. l->hookstate = SKINNY_OFFHOOK;
  4303. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  4304. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4305. transmit_activatecallplane(d, l);
  4306. }
  4307. transmit_clear_display_message(d, l->instance, sub->callid);
  4308. if (l->cfwdtype & cfwdtype) {
  4309. set_callforwards(l, NULL, cfwdtype);
  4310. ast_safe_sleep(c, 500);
  4311. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  4312. transmit_closereceivechannel(d, sub);
  4313. transmit_stopmediatransmission(d, sub);
  4314. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  4315. transmit_clearpromptmessage(d, l->instance, sub->callid);
  4316. transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
  4317. transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
  4318. transmit_activatecallplane(d, l);
  4319. transmit_displaynotify(d, "CFwd disabled", 10);
  4320. if (sub->owner && sub->owner->_state != AST_STATE_UP) {
  4321. ast_indicate(c, -1);
  4322. ast_hangup(c);
  4323. }
  4324. transmit_cfwdstate(d, l);
  4325. } else {
  4326. l->getforward = cfwdtype;
  4327. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  4328. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
  4329. if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
  4330. ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
  4331. ast_hangup(c);
  4332. }
  4333. }
  4334. return 0;
  4335. }
  4336. static int handle_ip_port_message(struct skinny_req *req, struct skinnysession *s)
  4337. {
  4338. /* no response necessary */
  4339. return 1;
  4340. }
  4341. static int handle_keypad_button_message(struct skinny_req *req, struct skinnysession *s)
  4342. {
  4343. struct skinny_subchannel *sub = NULL;
  4344. struct skinny_line *l;
  4345. struct skinny_device *d = s->device;
  4346. struct ast_frame f = { 0, };
  4347. char dgt;
  4348. int digit;
  4349. int lineInstance;
  4350. int callReference;
  4351. digit = letohl(req->data.keypad.button);
  4352. lineInstance = letohl(req->data.keypad.lineInstance);
  4353. callReference = letohl(req->data.keypad.callReference);
  4354. if (digit == 14) {
  4355. dgt = '*';
  4356. } else if (digit == 15) {
  4357. dgt = '#';
  4358. } else if (digit >= 0 && digit <= 9) {
  4359. dgt = '0' + digit;
  4360. } else {
  4361. /* digit=10-13 (A,B,C,D ?), or
  4362. * digit is bad value
  4363. *
  4364. * probably should not end up here, but set
  4365. * value for backward compatibility, and log
  4366. * a warning.
  4367. */
  4368. dgt = '0' + digit;
  4369. ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
  4370. }
  4371. f.subclass.integer = dgt;
  4372. f.src = "skinny";
  4373. if (lineInstance && callReference)
  4374. sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
  4375. else
  4376. sub = d->activeline->activesub;
  4377. //sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
  4378. if (!sub)
  4379. return 0;
  4380. l = sub->parent;
  4381. if (sub->owner) {
  4382. if (sub->owner->_state == 0) {
  4383. f.frametype = AST_FRAME_DTMF_BEGIN;
  4384. ast_queue_frame(sub->owner, &f);
  4385. }
  4386. /* XXX MUST queue this frame to all lines in threeway call if threeway call is active */
  4387. f.frametype = AST_FRAME_DTMF_END;
  4388. ast_queue_frame(sub->owner, &f);
  4389. /* XXX This seriously needs to be fixed */
  4390. if (AST_LIST_NEXT(sub, list) && AST_LIST_NEXT(sub, list)->owner) {
  4391. if (sub->owner->_state == 0) {
  4392. f.frametype = AST_FRAME_DTMF_BEGIN;
  4393. ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
  4394. }
  4395. f.frametype = AST_FRAME_DTMF_END;
  4396. ast_queue_frame(AST_LIST_NEXT(sub, list)->owner, &f);
  4397. }
  4398. } else {
  4399. if (skinnydebug)
  4400. ast_verb(1, "No owner: %s\n", l->name);
  4401. }
  4402. return 1;
  4403. }
  4404. static int handle_stimulus_message(struct skinny_req *req, struct skinnysession *s)
  4405. {
  4406. struct skinny_device *d = s->device;
  4407. struct skinny_line *l;
  4408. struct skinny_subchannel *sub;
  4409. /*struct skinny_speeddial *sd;*/
  4410. struct ast_channel *c;
  4411. pthread_t t;
  4412. int event;
  4413. int instance;
  4414. int callreference;
  4415. /*int res = 0;*/
  4416. event = letohl(req->data.stimulus.stimulus);
  4417. instance = letohl(req->data.stimulus.stimulusInstance);
  4418. callreference = letohl(req->data.stimulus.callreference);
  4419. if (skinnydebug)
  4420. ast_verb(1, "callreference in handle_stimulus_message is '%d'\n", callreference);
  4421. /* Note that this call should be using the passed in instance and callreference */
  4422. sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
  4423. if (!sub) {
  4424. l = find_line_by_instance(d, d->lastlineinstance);
  4425. if (!l) {
  4426. return 0;
  4427. }
  4428. sub = l->activesub;
  4429. } else {
  4430. l = sub->parent;
  4431. }
  4432. switch(event) {
  4433. case STIMULUS_REDIAL:
  4434. if (skinnydebug)
  4435. ast_verb(1, "Received Stimulus: Redial(%d/%d)\n", instance, callreference);
  4436. if (ast_strlen_zero(l->lastnumberdialed)) {
  4437. ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found.\n");
  4438. l->hookstate = SKINNY_ONHOOK;
  4439. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  4440. transmit_closereceivechannel(d, sub);
  4441. transmit_stopmediatransmission(d, sub);
  4442. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  4443. transmit_clearpromptmessage(d, l->instance, sub->callid);
  4444. transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
  4445. transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
  4446. transmit_activatecallplane(d, l);
  4447. break;
  4448. }
  4449. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4450. if (!c) {
  4451. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4452. } else {
  4453. sub = c->tech_pvt;
  4454. l = sub->parent;
  4455. l->activesub = sub;
  4456. if (l->hookstate == SKINNY_ONHOOK) {
  4457. l->hookstate = SKINNY_OFFHOOK;
  4458. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4459. transmit_activatecallplane(d, l);
  4460. }
  4461. transmit_clear_display_message(d, l->instance, sub->callid);
  4462. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  4463. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
  4464. if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
  4465. transmit_stop_tone(d, l->instance, sub->callid);
  4466. }
  4467. ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
  4468. if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
  4469. ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
  4470. ast_hangup(c);
  4471. }
  4472. }
  4473. break;
  4474. case STIMULUS_SPEEDDIAL:
  4475. {
  4476. struct skinny_speeddial *sd;
  4477. if (skinnydebug)
  4478. ast_verb(1, "Received Stimulus: SpeedDial(%d/%d)\n", instance, callreference);
  4479. if (!(sd = find_speeddial_by_instance(d, instance, 0))) {
  4480. return 0;
  4481. }
  4482. if (!sub || !sub->owner)
  4483. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4484. else
  4485. c = sub->owner;
  4486. if (!c) {
  4487. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4488. } else {
  4489. sub = c->tech_pvt;
  4490. l = sub->parent;
  4491. l->activesub = sub;
  4492. if (l->hookstate == SKINNY_ONHOOK) {
  4493. l->hookstate = SKINNY_OFFHOOK;
  4494. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  4495. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4496. transmit_activatecallplane(d, l);
  4497. }
  4498. transmit_clear_display_message(d, l->instance, sub->callid);
  4499. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  4500. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
  4501. if (!ast_ignore_pattern(c->context, sd->exten)) {
  4502. transmit_stop_tone(d, l->instance, sub->callid);
  4503. }
  4504. if (ast_exists_extension(c, c->context, sd->exten, 1, l->cid_num)) {
  4505. ast_copy_string(c->exten, sd->exten, sizeof(c->exten));
  4506. ast_copy_string(l->lastnumberdialed, sd->exten, sizeof(l->lastnumberdialed));
  4507. if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
  4508. ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
  4509. ast_hangup(c);
  4510. }
  4511. break;
  4512. }
  4513. }
  4514. }
  4515. break;
  4516. case STIMULUS_HOLD:
  4517. if (skinnydebug)
  4518. ast_verb(1, "Received Stimulus: Hold(%d/%d)\n", instance, callreference);
  4519. handle_hold_button(sub);
  4520. break;
  4521. case STIMULUS_TRANSFER:
  4522. if (skinnydebug)
  4523. ast_verb(1, "Received Stimulus: Transfer(%d/%d)\n", instance, callreference);
  4524. if (l->transfer)
  4525. handle_transfer_button(sub);
  4526. else
  4527. transmit_displaynotify(d, "Transfer disabled", 10);
  4528. break;
  4529. case STIMULUS_CONFERENCE:
  4530. if (skinnydebug)
  4531. ast_verb(1, "Received Stimulus: Conference(%d/%d)\n", instance, callreference);
  4532. /* XXX determine the best way to pull off a conference. Meetme? */
  4533. break;
  4534. case STIMULUS_VOICEMAIL:
  4535. if (skinnydebug)
  4536. ast_verb(1, "Received Stimulus: Voicemail(%d/%d)\n", instance, callreference);
  4537. if (!sub || !sub->owner) {
  4538. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4539. } else {
  4540. c = sub->owner;
  4541. }
  4542. if (!c) {
  4543. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4544. } else {
  4545. sub = c->tech_pvt;
  4546. l = sub->parent;
  4547. l->activesub = sub;
  4548. if (ast_strlen_zero(l->vmexten)) /* Exit the call if no VM pilot */
  4549. break;
  4550. if (l->hookstate == SKINNY_ONHOOK){
  4551. l->hookstate = SKINNY_OFFHOOK;
  4552. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  4553. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4554. transmit_activatecallplane(d, l);
  4555. }
  4556. transmit_clear_display_message(d, l->instance, sub->callid);
  4557. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  4558. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
  4559. if (!ast_ignore_pattern(c->context, l->vmexten)) {
  4560. transmit_stop_tone(d, l->instance, sub->callid);
  4561. }
  4562. if (ast_exists_extension(c, c->context, l->vmexten, 1, l->cid_num)) {
  4563. ast_copy_string(c->exten, l->vmexten, sizeof(c->exten));
  4564. ast_copy_string(l->lastnumberdialed, l->vmexten, sizeof(l->lastnumberdialed));
  4565. if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
  4566. ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
  4567. ast_hangup(c);
  4568. }
  4569. break;
  4570. }
  4571. }
  4572. break;
  4573. case STIMULUS_CALLPARK:
  4574. {
  4575. int extout;
  4576. char message[32];
  4577. if (skinnydebug)
  4578. ast_verb(1, "Received Stimulus: Park Call(%d/%d)\n", instance, callreference);
  4579. if ((sub && sub->owner) && (sub->owner->_state == AST_STATE_UP)){
  4580. c = sub->owner;
  4581. if (ast_bridged_channel(c)) {
  4582. if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
  4583. snprintf(message, sizeof(message), "Call Parked at: %d", extout);
  4584. transmit_displaynotify(d, message, 10);
  4585. } else {
  4586. transmit_displaynotify(d, "Call Park failed", 10);
  4587. }
  4588. } else {
  4589. transmit_displaynotify(d, "Call Park not available", 10);
  4590. }
  4591. } else {
  4592. transmit_displaynotify(d, "Call Park not available", 10);
  4593. }
  4594. break;
  4595. }
  4596. case STIMULUS_DND:
  4597. if (skinnydebug)
  4598. ast_verb(1, "Received Stimulus: DND (%d/%d)\n", instance, callreference);
  4599. /* Do not disturb */
  4600. if (l->dnd != 0){
  4601. ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
  4602. l->dnd = 0;
  4603. transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_ON);
  4604. transmit_displaynotify(d, "DnD disabled", 10);
  4605. } else {
  4606. ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
  4607. l->dnd = 1;
  4608. transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_OFF);
  4609. transmit_displaynotify(d, "DnD enabled", 10);
  4610. }
  4611. break;
  4612. case STIMULUS_FORWARDALL:
  4613. if (skinnydebug)
  4614. ast_verb(1, "Received Stimulus: Forward All(%d/%d)\n", instance, callreference);
  4615. if (!sub || !sub->owner) {
  4616. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4617. } else {
  4618. c = sub->owner;
  4619. }
  4620. if (!c) {
  4621. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4622. } else {
  4623. sub = c->tech_pvt;
  4624. handle_callforward_button(sub, SKINNY_CFWD_ALL);
  4625. }
  4626. break;
  4627. case STIMULUS_FORWARDBUSY:
  4628. if (skinnydebug)
  4629. ast_verb(1, "Received Stimulus: Forward Busy (%d/%d)\n", instance, callreference);
  4630. if (!sub || !sub->owner) {
  4631. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4632. } else {
  4633. c = sub->owner;
  4634. }
  4635. if (!c) {
  4636. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4637. } else {
  4638. sub = c->tech_pvt;
  4639. handle_callforward_button(sub, SKINNY_CFWD_BUSY);
  4640. }
  4641. break;
  4642. case STIMULUS_FORWARDNOANSWER:
  4643. if (skinnydebug)
  4644. ast_verb(1, "Received Stimulus: Forward No Answer (%d/%d)\n", instance, callreference);
  4645. #if 0 /* Not sure how to handle this yet */
  4646. if (!sub || !sub->owner) {
  4647. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4648. } else {
  4649. c = sub->owner;
  4650. }
  4651. if (!c) {
  4652. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4653. } else {
  4654. sub = c->tech_pvt;
  4655. handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
  4656. }
  4657. #endif
  4658. break;
  4659. case STIMULUS_DISPLAY:
  4660. /* Not sure what this is */
  4661. if (skinnydebug)
  4662. ast_verb(1, "Received Stimulus: Display(%d/%d)\n", instance, callreference);
  4663. break;
  4664. case STIMULUS_LINE:
  4665. if (skinnydebug)
  4666. ast_verb(1, "Received Stimulus: Line(%d/%d)\n", instance, callreference);
  4667. l = find_line_by_instance(d, instance);
  4668. if (!l) {
  4669. return 0;
  4670. }
  4671. d->activeline = l;
  4672. /* turn the speaker on */
  4673. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  4674. transmit_ringer_mode(d, SKINNY_RING_OFF);
  4675. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
  4676. l->hookstate = SKINNY_OFFHOOK;
  4677. if (sub && sub->outgoing) {
  4678. /* We're answering a ringing call */
  4679. ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
  4680. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4681. transmit_activatecallplane(d, l);
  4682. transmit_stop_tone(d, l->instance, sub->callid);
  4683. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
  4684. transmit_displaypromptstatus(d, "Connected", 0, l->instance, sub->callid);
  4685. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
  4686. start_rtp(sub);
  4687. ast_setstate(sub->owner, AST_STATE_UP);
  4688. } else {
  4689. if (sub && sub->owner) {
  4690. ast_debug(1, "Current subchannel [%s] already has owner\n", sub->owner->name);
  4691. } else {
  4692. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4693. if (c) {
  4694. sub = c->tech_pvt;
  4695. l->activesub = sub;
  4696. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4697. transmit_activatecallplane(d, l);
  4698. transmit_clear_display_message(d, l->instance, sub->callid);
  4699. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  4700. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
  4701. /* start the switch thread */
  4702. if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
  4703. ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
  4704. ast_hangup(c);
  4705. }
  4706. } else {
  4707. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4708. }
  4709. }
  4710. }
  4711. break;
  4712. default:
  4713. if (skinnydebug)
  4714. ast_verb(1, "RECEIVED UNKNOWN STIMULUS: %d(%d/%d)\n", event, instance, callreference);
  4715. break;
  4716. }
  4717. ast_devstate_changed(AST_DEVICE_UNKNOWN, "Skinny/%s@%s", l->name, d->name);
  4718. return 1;
  4719. }
  4720. static int handle_offhook_message(struct skinny_req *req, struct skinnysession *s)
  4721. {
  4722. struct skinny_device *d = s->device;
  4723. struct skinny_line *l;
  4724. struct skinny_subchannel *sub;
  4725. struct ast_channel *c;
  4726. struct skinny_line *tmp;
  4727. pthread_t t;
  4728. int instance;
  4729. /* if any line on a device is offhook, than the device must be offhook,
  4730. unless we have shared lines CCM seems that it would never get here,
  4731. but asterisk does, so we may need to do more work. Ugly, we should
  4732. probably move hookstate from line to device, afterall, it's actually
  4733. a device that changes hookstates */
  4734. AST_LIST_TRAVERSE(&d->lines, tmp, list) {
  4735. if (tmp->hookstate == SKINNY_OFFHOOK) {
  4736. ast_verbose(VERBOSE_PREFIX_3 "Got offhook message when device (%s@%s) already offhook\n", tmp->name, d->name);
  4737. return 0;
  4738. }
  4739. }
  4740. instance = letohl(req->data.offhook.instance);
  4741. if (instance) {
  4742. sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
  4743. if (!sub) {
  4744. l = find_line_by_instance(d, d->lastlineinstance);
  4745. if (!l) {
  4746. return 0;
  4747. }
  4748. } else {
  4749. l = sub->parent;
  4750. }
  4751. } else {
  4752. l = d->activeline;
  4753. sub = l->activesub;
  4754. }
  4755. /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
  4756. transmit_definetimedate(d);
  4757. transmit_ringer_mode(d, SKINNY_RING_OFF);
  4758. l->hookstate = SKINNY_OFFHOOK;
  4759. ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);
  4760. if (sub && sub->onhold) {
  4761. return 1;
  4762. }
  4763. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
  4764. if (sub && sub->outgoing) {
  4765. /* We're answering a ringing call */
  4766. ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
  4767. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4768. transmit_activatecallplane(d, l);
  4769. transmit_stop_tone(d, l->instance, sub->callid);
  4770. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
  4771. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
  4772. start_rtp(sub);
  4773. ast_setstate(sub->owner, AST_STATE_UP);
  4774. } else {
  4775. if (sub && sub->owner) {
  4776. ast_debug(1, "Current sub [%s] already has owner\n", sub->owner->name);
  4777. } else {
  4778. c = skinny_new(l, AST_STATE_DOWN, NULL);
  4779. if (c) {
  4780. sub = c->tech_pvt;
  4781. l->activesub = sub;
  4782. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4783. transmit_activatecallplane(d, l);
  4784. transmit_clear_display_message(d, l->instance, sub->callid);
  4785. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  4786. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
  4787. /* start the switch thread */
  4788. if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
  4789. ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
  4790. ast_hangup(c);
  4791. }
  4792. } else {
  4793. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  4794. }
  4795. }
  4796. }
  4797. return 1;
  4798. }
  4799. static int handle_onhook_message(struct skinny_req *req, struct skinnysession *s)
  4800. {
  4801. struct skinny_device *d = s->device;
  4802. struct skinny_line *l;
  4803. struct skinny_subchannel *sub;
  4804. int instance;
  4805. int reference;
  4806. int onlysub = 0;
  4807. instance = letohl(req->data.onhook.instance);
  4808. reference = letohl(req->data.onhook.reference);
  4809. if (instance && reference) {
  4810. sub = find_subchannel_by_instance_reference(d, instance, reference);
  4811. if (!sub) {
  4812. return 0;
  4813. }
  4814. l = sub->parent;
  4815. } else {
  4816. l = d->activeline;
  4817. sub = l->activesub;
  4818. if (!sub) {
  4819. return 0;
  4820. }
  4821. }
  4822. if (l->hookstate == SKINNY_ONHOOK) {
  4823. /* Something else already put us back on hook */
  4824. return 0;
  4825. }
  4826. ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
  4827. if (sub->onhold) {
  4828. return 0;
  4829. }
  4830. if (!AST_LIST_NEXT(sub, list)) {
  4831. onlysub = 1;
  4832. } else {
  4833. AST_LIST_REMOVE(&l->sub, sub, list);
  4834. }
  4835. sub->cxmode = SKINNY_CX_RECVONLY;
  4836. if (onlysub || sub->xferor){ /* is this the only call to this device? */
  4837. l->hookstate = SKINNY_ONHOOK;
  4838. if (skinnydebug)
  4839. ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name, reference);
  4840. }
  4841. if (l->hookstate == SKINNY_ONHOOK) {
  4842. transmit_closereceivechannel(d, sub);
  4843. transmit_stopmediatransmission(d, sub);
  4844. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  4845. transmit_clearpromptmessage(d, instance, sub->callid);
  4846. transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
  4847. transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
  4848. transmit_activatecallplane(d, l);
  4849. } else if (l->hookstate == SKINNY_OFFHOOK) {
  4850. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  4851. transmit_activatecallplane(d, l);
  4852. } else {
  4853. transmit_callstate(d, l->instance, sub->callid, l->hookstate);
  4854. }
  4855. if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
  4856. /* We're allowed to transfer, we have two active calls and
  4857. we made at least one of the calls. Let's try and transfer */
  4858. handle_transfer_button(sub);
  4859. } else {
  4860. /* Hangup the current call */
  4861. /* If there is another active call, skinny_hangup will ring the phone with the other call */
  4862. if (sub->xferor && sub->related){
  4863. sub->related->related = NULL;
  4864. sub->related->blindxfer = 0;
  4865. }
  4866. if (sub->owner) {
  4867. sub->alreadygone = 1;
  4868. ast_queue_hangup(sub->owner);
  4869. } else {
  4870. ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
  4871. l->name, d->name, sub->callid);
  4872. }
  4873. /* Not ideal, but let's send updated time at onhook and offhook, as it clears the display */
  4874. transmit_definetimedate(d);
  4875. }
  4876. return 1;
  4877. }
  4878. static int handle_capabilities_res_message(struct skinny_req *req, struct skinnysession *s)
  4879. {
  4880. struct skinny_device *d = s->device;
  4881. struct skinny_line *l;
  4882. uint32_t count = 0;
  4883. format_t codecs = 0;
  4884. int i;
  4885. char buf[256];
  4886. count = letohl(req->data.caps.count);
  4887. if (count > SKINNY_MAX_CAPABILITIES) {
  4888. count = SKINNY_MAX_CAPABILITIES;
  4889. ast_log(LOG_WARNING, "Received more capabilities than we can handle (%d). Ignoring the rest.\n", SKINNY_MAX_CAPABILITIES);
  4890. }
  4891. for (i = 0; i < count; i++) {
  4892. format_t acodec = 0;
  4893. int scodec = 0;
  4894. scodec = letohl(req->data.caps.caps[i].codec);
  4895. acodec = codec_skinny2ast(scodec);
  4896. if (skinnydebug)
  4897. ast_verb(1, "Adding codec capability '%" PRId64 " (%d)'\n", acodec, scodec);
  4898. codecs |= acodec;
  4899. }
  4900. d->capability = d->confcapability & codecs;
  4901. ast_verb(0, "Device capability set to '%s'\n", ast_getformatname_multiple(buf, sizeof(buf), d->capability));
  4902. AST_LIST_TRAVERSE(&d->lines, l, list) {
  4903. ast_mutex_lock(&l->lock);
  4904. l->capability = l->confcapability & d->capability;
  4905. ast_mutex_unlock(&l->lock);
  4906. }
  4907. return 1;
  4908. }
  4909. static int handle_button_template_req_message(struct skinny_req *req, struct skinnysession *s)
  4910. {
  4911. struct skinny_device *d = s->device;
  4912. struct skinny_line *l;
  4913. int i;
  4914. struct skinny_speeddial *sd;
  4915. struct button_definition_template btn[42];
  4916. int lineInstance = 1;
  4917. int speeddialInstance = 1;
  4918. int buttonCount = 0;
  4919. if (!(req = req_alloc(sizeof(struct button_template_res_message), BUTTON_TEMPLATE_RES_MESSAGE)))
  4920. return -1;
  4921. memset(&btn, 0, sizeof(btn));
  4922. get_button_template(s, btn);
  4923. for (i=0; i<42; i++) {
  4924. int btnSet = 0;
  4925. switch (btn[i].buttonDefinition) {
  4926. case BT_CUST_LINE:
  4927. /* assume failure */
  4928. req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
  4929. req->data.buttontemplate.definition[i].instanceNumber = 0;
  4930. AST_LIST_TRAVERSE(&d->lines, l, list) {
  4931. if (l->instance == lineInstance) {
  4932. ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
  4933. req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
  4934. req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
  4935. lineInstance++;
  4936. buttonCount++;
  4937. btnSet = 1;
  4938. break;
  4939. }
  4940. }
  4941. if (!btnSet) {
  4942. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  4943. if (sd->isHint && sd->instance == lineInstance) {
  4944. ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
  4945. req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
  4946. req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
  4947. lineInstance++;
  4948. buttonCount++;
  4949. btnSet = 1;
  4950. break;
  4951. }
  4952. }
  4953. }
  4954. break;
  4955. case BT_CUST_LINESPEEDDIAL:
  4956. /* assume failure */
  4957. req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
  4958. req->data.buttontemplate.definition[i].instanceNumber = 0;
  4959. AST_LIST_TRAVERSE(&d->lines, l, list) {
  4960. if (l->instance == lineInstance) {
  4961. ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
  4962. req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
  4963. req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
  4964. lineInstance++;
  4965. buttonCount++;
  4966. btnSet = 1;
  4967. break;
  4968. }
  4969. }
  4970. if (!btnSet) {
  4971. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  4972. if (sd->isHint && sd->instance == lineInstance) {
  4973. ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
  4974. req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
  4975. req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
  4976. lineInstance++;
  4977. buttonCount++;
  4978. btnSet = 1;
  4979. break;
  4980. } else if (!sd->isHint && sd->instance == speeddialInstance) {
  4981. ast_verb(0, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
  4982. req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
  4983. req->data.buttontemplate.definition[i].instanceNumber = speeddialInstance;
  4984. speeddialInstance++;
  4985. buttonCount++;
  4986. btnSet = 1;
  4987. break;
  4988. }
  4989. }
  4990. }
  4991. break;
  4992. case BT_LINE:
  4993. req->data.buttontemplate.definition[i].buttonDefinition = htolel(BT_NONE);
  4994. req->data.buttontemplate.definition[i].instanceNumber = htolel(0);
  4995. AST_LIST_TRAVERSE(&d->lines, l, list) {
  4996. if (l->instance == lineInstance) {
  4997. ast_verb(0, "Adding button: %d, %d\n", BT_LINE, lineInstance);
  4998. req->data.buttontemplate.definition[i].buttonDefinition = BT_LINE;
  4999. req->data.buttontemplate.definition[i].instanceNumber = lineInstance;
  5000. lineInstance++;
  5001. buttonCount++;
  5002. btnSet = 1;
  5003. break;
  5004. }
  5005. }
  5006. break;
  5007. case BT_SPEEDDIAL:
  5008. req->data.buttontemplate.definition[i].buttonDefinition = BT_NONE;
  5009. req->data.buttontemplate.definition[i].instanceNumber = 0;
  5010. AST_LIST_TRAVERSE(&d->speeddials, sd, list) {
  5011. if (!sd->isHint && sd->instance == speeddialInstance) {
  5012. ast_verb(0, "Adding button: %d, %d\n", BT_SPEEDDIAL, speeddialInstance);
  5013. req->data.buttontemplate.definition[i].buttonDefinition = BT_SPEEDDIAL;
  5014. req->data.buttontemplate.definition[i].instanceNumber = speeddialInstance - 1;
  5015. speeddialInstance++;
  5016. buttonCount++;
  5017. btnSet = 1;
  5018. break;
  5019. }
  5020. }
  5021. break;
  5022. case BT_NONE:
  5023. break;
  5024. default:
  5025. ast_verb(0, "Adding button: %d, %d\n", btn[i].buttonDefinition, 0);
  5026. req->data.buttontemplate.definition[i].buttonDefinition = htolel(btn[i].buttonDefinition);
  5027. req->data.buttontemplate.definition[i].instanceNumber = 0;
  5028. buttonCount++;
  5029. btnSet = 1;
  5030. break;
  5031. }
  5032. }
  5033. req->data.buttontemplate.buttonOffset = 0;
  5034. req->data.buttontemplate.buttonCount = htolel(buttonCount);
  5035. req->data.buttontemplate.totalButtonCount = htolel(buttonCount);
  5036. if (skinnydebug)
  5037. ast_verb(1, "Sending %d template to %s\n",
  5038. d->type,
  5039. d->name);
  5040. transmit_response(d, req);
  5041. return 1;
  5042. }
  5043. static int handle_open_receive_channel_ack_message(struct skinny_req *req, struct skinnysession *s)
  5044. {
  5045. struct skinny_device *d = s->device;
  5046. struct skinny_line *l;
  5047. struct skinny_subchannel *sub;
  5048. struct ast_format_list fmt;
  5049. struct sockaddr_in sin = { 0, };
  5050. struct sockaddr_in us = { 0, };
  5051. struct ast_sockaddr sin_tmp;
  5052. struct ast_sockaddr us_tmp;
  5053. uint32_t addr;
  5054. int port;
  5055. int status;
  5056. int passthruid;
  5057. status = letohl(req->data.openreceivechannelack.status);
  5058. if (status) {
  5059. ast_log(LOG_ERROR, "Open Receive Channel Failure\n");
  5060. return 0;
  5061. }
  5062. addr = req->data.openreceivechannelack.ipAddr;
  5063. port = letohl(req->data.openreceivechannelack.port);
  5064. passthruid = letohl(req->data.openreceivechannelack.passThruId);
  5065. sin.sin_family = AF_INET;
  5066. sin.sin_addr.s_addr = addr;
  5067. sin.sin_port = htons(port);
  5068. sub = find_subchannel_by_reference(d, passthruid);
  5069. if (!sub)
  5070. return 0;
  5071. l = sub->parent;
  5072. if (sub->rtp) {
  5073. ast_sockaddr_from_sin(&sin_tmp, &sin);
  5074. ast_rtp_instance_set_remote_address(sub->rtp, &sin_tmp);
  5075. ast_rtp_instance_get_local_address(sub->rtp, &us_tmp);
  5076. ast_sockaddr_to_sin(&us_tmp, &us);
  5077. us.sin_addr.s_addr = us.sin_addr.s_addr ? us.sin_addr.s_addr : d->ourip.s_addr;
  5078. } else {
  5079. ast_log(LOG_ERROR, "No RTP structure, this is very bad\n");
  5080. return 0;
  5081. }
  5082. if (skinnydebug) {
  5083. ast_verb(1, "device ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
  5084. ast_verb(1, "asterisk ipaddr = %s:%d\n", ast_inet_ntoa(us.sin_addr), ntohs(us.sin_port));
  5085. }
  5086. fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability));
  5087. if (skinnydebug)
  5088. ast_verb(1, "Setting payloadType to '%s' (%d ms)\n", ast_getformatname(fmt.bits), fmt.cur_ms);
  5089. transmit_startmediatransmission(d, sub, us, fmt);
  5090. return 1;
  5091. }
  5092. static int handle_enbloc_call_message(struct skinny_req *req, struct skinnysession *s)
  5093. {
  5094. struct skinny_device *d = s->device;
  5095. struct skinny_line *l;
  5096. struct skinny_subchannel *sub = NULL;
  5097. struct ast_channel *c;
  5098. pthread_t t;
  5099. if (skinnydebug)
  5100. ast_verb(1, "Received Enbloc Call: %s\n", req->data.enbloccallmessage.calledParty);
  5101. sub = find_subchannel_by_instance_reference(d, d->lastlineinstance, d->lastcallreference);
  5102. if (!sub) {
  5103. l = find_line_by_instance(d, d->lastlineinstance);
  5104. if (!l) {
  5105. return 0;
  5106. }
  5107. } else {
  5108. l = sub->parent;
  5109. }
  5110. c = skinny_new(l, AST_STATE_DOWN, NULL);
  5111. if(!c) {
  5112. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  5113. } else {
  5114. l->hookstate = SKINNY_OFFHOOK;
  5115. sub = c->tech_pvt;
  5116. l->activesub = sub;
  5117. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  5118. transmit_activatecallplane(d, l);
  5119. transmit_clear_display_message(d, l->instance, sub->callid);
  5120. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  5121. if (!ast_ignore_pattern(c->context, req->data.enbloccallmessage.calledParty)) {
  5122. transmit_stop_tone(d, l->instance, sub->callid);
  5123. }
  5124. ast_copy_string(c->exten, req->data.enbloccallmessage.calledParty, sizeof(c->exten));
  5125. if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
  5126. ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
  5127. ast_hangup(c);
  5128. }
  5129. }
  5130. return 1;
  5131. }
  5132. static int handle_soft_key_event_message(struct skinny_req *req, struct skinnysession *s)
  5133. {
  5134. struct skinny_device *d = s->device;
  5135. struct skinny_line *l;
  5136. struct skinny_subchannel *sub = NULL;
  5137. struct ast_channel *c;
  5138. pthread_t t;
  5139. int event;
  5140. int instance;
  5141. int callreference;
  5142. event = letohl(req->data.softkeyeventmessage.softKeyEvent);
  5143. instance = letohl(req->data.softkeyeventmessage.instance);
  5144. callreference = letohl(req->data.softkeyeventmessage.callreference);
  5145. if (instance) {
  5146. l = find_line_by_instance(d, instance);
  5147. if (callreference) {
  5148. sub = find_subchannel_by_instance_reference(d, instance, callreference);
  5149. } else {
  5150. sub = find_subchannel_by_instance_reference(d, instance, d->lastcallreference);
  5151. }
  5152. } else {
  5153. l = find_line_by_instance(d, d->lastlineinstance);
  5154. }
  5155. if (!l) {
  5156. if (skinnydebug)
  5157. ast_verb(1, "Received Softkey Event: %d(%d/%d)\n", event, instance, callreference);
  5158. return 0;
  5159. }
  5160. ast_devstate_changed(AST_DEVICE_INUSE, "Skinny/%s@%s", l->name, d->name);
  5161. switch(event) {
  5162. case SOFTKEY_NONE:
  5163. if (skinnydebug)
  5164. ast_verb(1, "Received Softkey Event: None(%d/%d)\n", instance, callreference);
  5165. break;
  5166. case SOFTKEY_REDIAL:
  5167. if (skinnydebug)
  5168. ast_verb(1, "Received Softkey Event: Redial(%d/%d)\n", instance, callreference);
  5169. if (ast_strlen_zero(l->lastnumberdialed)) {
  5170. ast_log(LOG_WARNING, "Attempted redial, but no previously dialed number found. Ignoring button.\n");
  5171. break;
  5172. }
  5173. if (!sub || !sub->owner) {
  5174. c = skinny_new(l, AST_STATE_DOWN, NULL);
  5175. } else {
  5176. c = sub->owner;
  5177. }
  5178. if (!c) {
  5179. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  5180. } else {
  5181. sub = c->tech_pvt;
  5182. l->activesub = sub;
  5183. if (l->hookstate == SKINNY_ONHOOK) {
  5184. l->hookstate = SKINNY_OFFHOOK;
  5185. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  5186. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  5187. transmit_activatecallplane(d, l);
  5188. }
  5189. transmit_clear_display_message(d, l->instance, sub->callid);
  5190. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  5191. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_RINGOUT);
  5192. if (!ast_ignore_pattern(c->context, l->lastnumberdialed)) {
  5193. transmit_stop_tone(d, l->instance, sub->callid);
  5194. }
  5195. ast_copy_string(c->exten, l->lastnumberdialed, sizeof(c->exten));
  5196. if (ast_pthread_create(&t, NULL, skinny_newcall, c)) {
  5197. ast_log(LOG_WARNING, "Unable to create new call thread: %s\n", strerror(errno));
  5198. ast_hangup(c);
  5199. }
  5200. }
  5201. break;
  5202. case SOFTKEY_NEWCALL: /* Actually the DIAL softkey */
  5203. if (skinnydebug)
  5204. ast_verb(1, "Received Softkey Event: New Call(%d/%d)\n", instance, callreference);
  5205. /* New Call ALWAYS gets a new sub-channel */
  5206. c = skinny_new(l, AST_STATE_DOWN, NULL);
  5207. sub = c->tech_pvt;
  5208. /* transmit_ringer_mode(d, SKINNY_RING_OFF);
  5209. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON); */
  5210. /* l->hookstate = SKINNY_OFFHOOK; */
  5211. if (!c) {
  5212. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  5213. } else {
  5214. sub = c->tech_pvt;
  5215. l->activesub = sub;
  5216. if (l->hookstate == SKINNY_ONHOOK) {
  5217. l->hookstate = SKINNY_OFFHOOK;
  5218. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  5219. }
  5220. ast_verb(1, "Call-id: %d\n", sub->callid);
  5221. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  5222. transmit_activatecallplane(d, l);
  5223. transmit_clear_display_message(d, l->instance, sub->callid);
  5224. transmit_start_tone(d, SKINNY_DIALTONE, l->instance, sub->callid);
  5225. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_OFFHOOK);
  5226. /* start the switch thread */
  5227. if (ast_pthread_create(&t, NULL, skinny_ss, c)) {
  5228. ast_log(LOG_WARNING, "Unable to create switch thread: %s\n", strerror(errno));
  5229. ast_hangup(c);
  5230. }
  5231. }
  5232. break;
  5233. case SOFTKEY_HOLD:
  5234. if (skinnydebug)
  5235. ast_verb(1, "Received Softkey Event: Hold(%d/%d)\n", instance, callreference);
  5236. handle_hold_button(sub);
  5237. break;
  5238. case SOFTKEY_TRNSFER:
  5239. if (skinnydebug)
  5240. ast_verb(1, "Received Softkey Event: Transfer(%d/%d)\n", instance, callreference);
  5241. if (l->transfer)
  5242. handle_transfer_button(sub);
  5243. else
  5244. transmit_displaynotify(d, "Transfer disabled", 10);
  5245. break;
  5246. case SOFTKEY_DND:
  5247. if (skinnydebug)
  5248. ast_verb(1, "Received Softkey Event: DND(%d/%d)\n", instance, callreference);
  5249. /* Do not disturb */
  5250. if (l->dnd != 0){
  5251. ast_verb(3, "Disabling DND on %s@%s\n", l->name, d->name);
  5252. l->dnd = 0;
  5253. transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_ON);
  5254. transmit_displaynotify(d, "DnD disabled", 10);
  5255. } else {
  5256. ast_verb(3, "Enabling DND on %s@%s\n", l->name, d->name);
  5257. l->dnd = 1;
  5258. transmit_lamp_indication(d, STIMULUS_DND, 1, SKINNY_LAMP_OFF);
  5259. transmit_displaynotify(d, "DnD enabled", 10);
  5260. }
  5261. break;
  5262. case SOFTKEY_CFWDALL:
  5263. if (skinnydebug)
  5264. ast_verb(1, "Received Softkey Event: Forward All(%d/%d)\n", instance, callreference);
  5265. if (!sub || !sub->owner) {
  5266. c = skinny_new(l, AST_STATE_DOWN, NULL);
  5267. } else {
  5268. c = sub->owner;
  5269. }
  5270. if (!c) {
  5271. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  5272. } else {
  5273. sub = c->tech_pvt;
  5274. l->activesub = sub;
  5275. handle_callforward_button(sub, SKINNY_CFWD_ALL);
  5276. }
  5277. break;
  5278. case SOFTKEY_CFWDBUSY:
  5279. if (skinnydebug)
  5280. ast_verb(1, "Received Softkey Event: Forward Busy (%d/%d)\n", instance, callreference);
  5281. if (!sub || !sub->owner) {
  5282. c = skinny_new(l, AST_STATE_DOWN, NULL);
  5283. } else {
  5284. c = sub->owner;
  5285. }
  5286. if (!c) {
  5287. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  5288. } else {
  5289. sub = c->tech_pvt;
  5290. l->activesub = sub;
  5291. handle_callforward_button(sub, SKINNY_CFWD_BUSY);
  5292. }
  5293. break;
  5294. case SOFTKEY_CFWDNOANSWER:
  5295. if (skinnydebug)
  5296. ast_verb(1, "Received Softkey Event: Forward No Answer (%d/%d)\n", instance, callreference);
  5297. #if 0 /* Not sure how to handle this yet */
  5298. if (!sub || !sub->owner) {
  5299. c = skinny_new(l, AST_STATE_DOWN, NULL);
  5300. } else {
  5301. c = sub->owner;
  5302. }
  5303. if (!c) {
  5304. ast_log(LOG_WARNING, "Unable to create channel for %s@%s\n", l->name, d->name);
  5305. } else {
  5306. sub = c->tech_pvt;
  5307. l->activesub = sub;
  5308. handle_callforward_button(sub, SKINNY_CFWD_NOANSWER);
  5309. }
  5310. #endif
  5311. break;
  5312. case SOFTKEY_BKSPC:
  5313. if (skinnydebug)
  5314. ast_verb(1, "Received Softkey Event: Backspace(%d/%d)\n", instance, callreference);
  5315. break;
  5316. case SOFTKEY_ENDCALL:
  5317. if (skinnydebug)
  5318. ast_verb(1, "Received Softkey Event: End Call(%d/%d)\n", instance, callreference);
  5319. if (l->hookstate == SKINNY_ONHOOK) {
  5320. /* Something else already put us back on hook */
  5321. break;
  5322. }
  5323. if (sub) {
  5324. int onlysub = 0;
  5325. if (!AST_LIST_NEXT(sub, list)) {
  5326. onlysub = 1;
  5327. } else {
  5328. AST_LIST_REMOVE(&l->sub, sub, list);
  5329. }
  5330. sub->cxmode = SKINNY_CX_RECVONLY;
  5331. if (onlysub || sub->xferor){ /*Are there other calls to this device */
  5332. l->hookstate = SKINNY_ONHOOK;
  5333. if (skinnydebug)
  5334. ast_debug(1, "Skinny %s@%s-%d went on hook\n", l->name, d->name, callreference);
  5335. }
  5336. if (l->hookstate == SKINNY_ONHOOK) {
  5337. transmit_closereceivechannel(d, sub);
  5338. transmit_stopmediatransmission(d, sub);
  5339. transmit_speaker_mode(d, SKINNY_SPEAKEROFF);
  5340. transmit_clearpromptmessage(d, instance, sub->callid);
  5341. transmit_callstate(d, l->instance, sub->callid, SKINNY_ONHOOK);
  5342. transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
  5343. transmit_activatecallplane(d, l);
  5344. } else if (l->hookstate == SKINNY_OFFHOOK) {
  5345. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  5346. transmit_activatecallplane(d, l);
  5347. } else {
  5348. transmit_callstate(d, l->instance, sub->callid, l->hookstate);
  5349. }
  5350. ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
  5351. if (skinnydebug)
  5352. ast_verb(1, "Skinny %s@%s went on hook\n", l->name, d->name);
  5353. if (l->transfer && sub->xferor && sub->owner->_state >= AST_STATE_RING) {
  5354. /* We're allowed to transfer, we have two active calls and
  5355. we made at least one of the calls. Let's try and transfer */
  5356. handle_transfer_button(sub);
  5357. } else {
  5358. /* Hangup the current call */
  5359. /* If there is another active call, skinny_hangup will ring the phone with the other call */
  5360. if (sub->xferor && sub->related){
  5361. sub->related->related = NULL;
  5362. sub->related->blindxfer = 0;
  5363. }
  5364. if (sub->owner) {
  5365. sub->alreadygone = 1;
  5366. ast_queue_hangup(sub->owner);
  5367. } else {
  5368. ast_log(LOG_WARNING, "Skinny(%s@%s-%d) channel already destroyed\n",
  5369. l->name, d->name, sub->callid);
  5370. }
  5371. }
  5372. if ((l->hookstate == SKINNY_ONHOOK) && (AST_LIST_NEXT(sub, list) && !AST_LIST_NEXT(sub, list)->rtp)) {
  5373. ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Skinny/%s@%s", l->name, d->name);
  5374. }
  5375. }
  5376. break;
  5377. case SOFTKEY_RESUME:
  5378. if (skinnydebug)
  5379. ast_verb(1, "Received Softkey Event: Resume(%d/%d)\n", instance, callreference);
  5380. if (sub) {
  5381. if (sub->onhold) {
  5382. skinny_unhold(sub);
  5383. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
  5384. } else {
  5385. skinny_hold(sub);
  5386. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_ONHOLD);
  5387. }
  5388. }
  5389. break;
  5390. case SOFTKEY_ANSWER:
  5391. if (skinnydebug)
  5392. ast_verb(1, "Received Softkey Event: Answer(%d/%d)\n", instance, callreference);
  5393. transmit_ringer_mode(d, SKINNY_RING_OFF);
  5394. transmit_lamp_indication(d, STIMULUS_LINE, l->instance, SKINNY_LAMP_ON);
  5395. if (l->hookstate == SKINNY_ONHOOK) {
  5396. transmit_speaker_mode(d, SKINNY_SPEAKERON);
  5397. l->hookstate = SKINNY_OFFHOOK;
  5398. }
  5399. if (sub && sub->outgoing) {
  5400. /* We're answering a ringing call */
  5401. ast_queue_control(sub->owner, AST_CONTROL_ANSWER);
  5402. transmit_callstate(d, l->instance, sub->callid, SKINNY_OFFHOOK);
  5403. transmit_activatecallplane(d, l);
  5404. transmit_stop_tone(d, l->instance, sub->callid);
  5405. transmit_callstate(d, sub->parent->instance, sub->callid, SKINNY_CONNECTED);
  5406. transmit_selectsoftkeys(d, l->instance, sub->callid, KEYDEF_CONNECTED);
  5407. start_rtp(sub);
  5408. ast_setstate(sub->owner, AST_STATE_UP);
  5409. }
  5410. break;
  5411. case SOFTKEY_INFO:
  5412. if (skinnydebug)
  5413. ast_verb(1, "Received Softkey Event: Info(%d/%d)\n", instance, callreference);
  5414. break;
  5415. case SOFTKEY_CONFRN:
  5416. if (skinnydebug)
  5417. ast_verb(1, "Received Softkey Event: Conference(%d/%d)\n", instance, callreference);
  5418. /* XXX determine the best way to pull off a conference. Meetme? */
  5419. break;
  5420. case SOFTKEY_PARK:
  5421. {
  5422. int extout;
  5423. char message[32];
  5424. if (skinnydebug)
  5425. ast_verb(1, "Received Softkey Event: Park Call(%d/%d)\n", instance, callreference);
  5426. if ((sub && sub->owner) && (sub->owner->_state == AST_STATE_UP)){
  5427. c = sub->owner;
  5428. if (ast_bridged_channel(c)) {
  5429. if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
  5430. snprintf(message, sizeof(message), "Call Parked at: %d", extout);
  5431. transmit_displaynotify(d, message, 10);
  5432. } else {
  5433. transmit_displaynotify(d, "Call Park failed", 10);
  5434. }
  5435. } else {
  5436. transmit_displaynotify(d, "Call Park not available", 10);
  5437. }
  5438. } else {
  5439. transmit_displaynotify(d, "Call Park not available", 10);
  5440. }
  5441. break;
  5442. }
  5443. case SOFTKEY_JOIN:
  5444. if (skinnydebug)
  5445. ast_verb(1, "Received Softkey Event: Join(%d/%d)\n", instance, callreference);
  5446. break;
  5447. case SOFTKEY_MEETME:
  5448. /* XXX How is this different from CONFRN? */
  5449. if (skinnydebug)
  5450. ast_verb(1, "Received Softkey Event: Meetme(%d/%d)\n", instance, callreference);
  5451. break;
  5452. case SOFTKEY_PICKUP:
  5453. if (skinnydebug)
  5454. ast_verb(1, "Received Softkey Event: Pickup(%d/%d)\n", instance, callreference);
  5455. break;
  5456. case SOFTKEY_GPICKUP:
  5457. if (skinnydebug)
  5458. ast_verb(1, "Received Softkey Event: Group Pickup(%d/%d)\n", instance, callreference);
  5459. break;
  5460. default:
  5461. if (skinnydebug)
  5462. ast_verb(1, "Received unknown Softkey Event: %d(%d/%d)\n", event, instance, callreference);
  5463. break;
  5464. }
  5465. return 1;
  5466. }
  5467. static int handle_message(struct skinny_req *req, struct skinnysession *s)
  5468. {
  5469. int res = 0;
  5470. struct skinny_speeddial *sd;
  5471. struct skinny_line *l;
  5472. struct skinny_device *d = s->device;
  5473. size_t len;
  5474. if ((!s->device) && (letohl(req->e) != REGISTER_MESSAGE && letohl(req->e) != ALARM_MESSAGE)) {
  5475. ast_log(LOG_WARNING, "Client sent message #%d without first registering.\n", req->e);
  5476. ast_free(req);
  5477. return 0;
  5478. }
  5479. SKINNY_DEVONLY(if (skinnydebug > 1) {
  5480. ast_verb(4, "Received %s from %s\n", message2str(req->e), s->device->name);
  5481. })
  5482. switch(letohl(req->e)) {
  5483. case KEEP_ALIVE_MESSAGE:
  5484. res = handle_keep_alive_message(req, s);
  5485. break;
  5486. case REGISTER_MESSAGE:
  5487. if (skinnydebug)
  5488. ast_verb(1, "Device %s is attempting to register\n", req->data.reg.name);
  5489. res = handle_register_message(req, s);
  5490. break;
  5491. case IP_PORT_MESSAGE:
  5492. res = handle_ip_port_message(req, s);
  5493. break;
  5494. case KEYPAD_BUTTON_MESSAGE:
  5495. {
  5496. struct skinny_device *d = s->device;
  5497. struct skinny_subchannel *sub;
  5498. int lineInstance;
  5499. int callReference;
  5500. if (skinnydebug)
  5501. ast_verb(1, "Collected digit: [%d]\n", letohl(req->data.keypad.button));
  5502. lineInstance = letohl(req->data.keypad.lineInstance);
  5503. callReference = letohl(req->data.keypad.callReference);
  5504. if (lineInstance) {
  5505. sub = find_subchannel_by_instance_reference(d, lineInstance, callReference);
  5506. } else {
  5507. sub = d->activeline->activesub;
  5508. }
  5509. if (sub && ((sub->owner && sub->owner->_state < AST_STATE_UP) || sub->onhold)) {
  5510. char dgt;
  5511. int digit = letohl(req->data.keypad.button);
  5512. if (digit == 14) {
  5513. dgt = '*';
  5514. } else if (digit == 15) {
  5515. dgt = '#';
  5516. } else if (digit >= 0 && digit <= 9) {
  5517. dgt = '0' + digit;
  5518. } else {
  5519. /* digit=10-13 (A,B,C,D ?), or
  5520. * digit is bad value
  5521. *
  5522. * probably should not end up here, but set
  5523. * value for backward compatibility, and log
  5524. * a warning.
  5525. */
  5526. dgt = '0' + digit;
  5527. ast_log(LOG_WARNING, "Unsupported digit %d\n", digit);
  5528. }
  5529. len = strlen(d->exten);
  5530. if (len < sizeof(d->exten) - 1) {
  5531. d->exten[len] = dgt;
  5532. d->exten[len + 1] = '\0';
  5533. } else {
  5534. ast_log(AST_LOG_WARNING, "Dropping digit with value %d because digit queue is full\n", dgt);
  5535. }
  5536. } else
  5537. res = handle_keypad_button_message(req, s);
  5538. }
  5539. break;
  5540. case ENBLOC_CALL_MESSAGE:
  5541. res = handle_enbloc_call_message(req, s);
  5542. break;
  5543. case STIMULUS_MESSAGE:
  5544. res = handle_stimulus_message(req, s);
  5545. break;
  5546. case OFFHOOK_MESSAGE:
  5547. res = handle_offhook_message(req, s);
  5548. break;
  5549. case ONHOOK_MESSAGE:
  5550. res = handle_onhook_message(req, s);
  5551. break;
  5552. case CAPABILITIES_RES_MESSAGE:
  5553. if (skinnydebug)
  5554. ast_verb(1, "Received CapabilitiesRes\n");
  5555. res = handle_capabilities_res_message(req, s);
  5556. break;
  5557. case SPEED_DIAL_STAT_REQ_MESSAGE:
  5558. if (skinnydebug)
  5559. ast_verb(1, "Received SpeedDialStatRequest\n");
  5560. if ( (sd = find_speeddial_by_instance(s->device, letohl(req->data.speeddialreq.speedDialNumber), 0)) ) {
  5561. transmit_speeddialstatres(d, sd);
  5562. }
  5563. break;
  5564. case LINE_STATE_REQ_MESSAGE:
  5565. if (skinnydebug)
  5566. ast_verb(1, "Received LineStatRequest\n");
  5567. if ((l = find_line_by_instance(d, letohl(req->data.line.lineNumber)))) {
  5568. transmit_linestatres(d, l);
  5569. }
  5570. break;
  5571. case TIME_DATE_REQ_MESSAGE:
  5572. if (skinnydebug)
  5573. ast_verb(1, "Received Time/Date Request\n");
  5574. transmit_definetimedate(d);
  5575. break;
  5576. case BUTTON_TEMPLATE_REQ_MESSAGE:
  5577. if (skinnydebug)
  5578. ast_verb(1, "Buttontemplate requested\n");
  5579. res = handle_button_template_req_message(req, s);
  5580. break;
  5581. case VERSION_REQ_MESSAGE:
  5582. if (skinnydebug)
  5583. ast_verb(1, "Version Request\n");
  5584. transmit_versionres(d);
  5585. break;
  5586. case SERVER_REQUEST_MESSAGE:
  5587. if (skinnydebug)
  5588. ast_verb(1, "Received Server Request\n");
  5589. transmit_serverres(d);
  5590. break;
  5591. case ALARM_MESSAGE:
  5592. /* no response necessary */
  5593. if (skinnydebug)
  5594. ast_verb(1, "Received Alarm Message: %s\n", req->data.alarm.displayMessage);
  5595. break;
  5596. case OPEN_RECEIVE_CHANNEL_ACK_MESSAGE:
  5597. if (skinnydebug)
  5598. ast_verb(1, "Received Open Receive Channel Ack\n");
  5599. res = handle_open_receive_channel_ack_message(req, s);
  5600. break;
  5601. case SOFT_KEY_SET_REQ_MESSAGE:
  5602. if (skinnydebug)
  5603. ast_verb(1, "Received SoftKeySetReq\n");
  5604. transmit_softkeysetres(d);
  5605. transmit_selectsoftkeys(d, 0, 0, KEYDEF_ONHOOK);
  5606. break;
  5607. case SOFT_KEY_EVENT_MESSAGE:
  5608. res = handle_soft_key_event_message(req, s);
  5609. break;
  5610. case UNREGISTER_MESSAGE:
  5611. if (skinnydebug)
  5612. ast_verb(1, "Received Unregister Request\n");
  5613. res = skinny_unregister(req, s);
  5614. break;
  5615. case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
  5616. if (skinnydebug)
  5617. ast_verb(1, "Received SoftKey Template Request\n");
  5618. transmit_softkeytemplateres(d);
  5619. break;
  5620. case HEADSET_STATUS_MESSAGE:
  5621. /* XXX umm...okay? Why do I care? */
  5622. break;
  5623. case REGISTER_AVAILABLE_LINES_MESSAGE:
  5624. /* XXX I have no clue what this is for, but my phone was sending it, so... */
  5625. break;
  5626. default:
  5627. if (skinnydebug)
  5628. ast_verb(1, "RECEIVED UNKNOWN MESSAGE TYPE: %x\n", letohl(req->e));
  5629. break;
  5630. }
  5631. if (res >= 0 && req)
  5632. ast_free(req);
  5633. return res;
  5634. }
  5635. static void destroy_session(struct skinnysession *s)
  5636. {
  5637. struct skinnysession *cur;
  5638. AST_LIST_LOCK(&sessions);
  5639. AST_LIST_TRAVERSE_SAFE_BEGIN(&sessions, cur, list) {
  5640. if (cur == s) {
  5641. AST_LIST_REMOVE_CURRENT(list);
  5642. if (s->fd > -1)
  5643. close(s->fd);
  5644. if (!s->device)
  5645. ast_atomic_fetchadd_int(&unauth_sessions, -1);
  5646. ast_mutex_destroy(&s->lock);
  5647. ast_free(s);
  5648. } else {
  5649. ast_log(LOG_WARNING, "Trying to delete nonexistent session %p?\n", s);
  5650. }
  5651. }
  5652. AST_LIST_TRAVERSE_SAFE_END
  5653. AST_LIST_UNLOCK(&sessions);
  5654. }
  5655. static int get_input(struct skinnysession *s)
  5656. {
  5657. int res;
  5658. int dlen = 0;
  5659. int timeout = keep_alive * 1100;
  5660. time_t now;
  5661. int *bufaddr;
  5662. struct pollfd fds[1];
  5663. if (!s->device) {
  5664. if(time(&now) == -1) {
  5665. ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
  5666. return -1;
  5667. }
  5668. timeout = (auth_timeout - (now - s->start)) * 1000;
  5669. if (timeout < 0) {
  5670. /* we have timed out */
  5671. if (skinnydebug)
  5672. ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
  5673. return -1;
  5674. }
  5675. }
  5676. fds[0].fd = s->fd;
  5677. fds[0].events = POLLIN;
  5678. fds[0].revents = 0;
  5679. res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
  5680. /* we add 10% to the keep_alive to deal */
  5681. /* with network delays, etc */
  5682. if (res < 0) {
  5683. if (errno != EINTR) {
  5684. ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno));
  5685. return res;
  5686. }
  5687. } else if (res == 0) {
  5688. if (skinnydebug) {
  5689. if (s->device) {
  5690. ast_verb(1, "Skinny Client was lost, unregistering\n");
  5691. } else {
  5692. ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
  5693. }
  5694. }
  5695. skinny_unregister(NULL, s);
  5696. return -1;
  5697. }
  5698. if (fds[0].revents) {
  5699. ast_mutex_lock(&s->lock);
  5700. memset(s->inbuf, 0, sizeof(s->inbuf));
  5701. res = read(s->fd, s->inbuf, 4);
  5702. if (res < 0) {
  5703. ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
  5704. if (skinnydebug)
  5705. ast_verb(1, "Skinny Client was lost, unregistering\n");
  5706. skinny_unregister(NULL, s);
  5707. ast_mutex_unlock(&s->lock);
  5708. return res;
  5709. } else if (res != 4) {
  5710. ast_log(LOG_WARNING, "Skinny Client sent less data than expected. Expected 4 but got %d.\n", res);
  5711. ast_mutex_unlock(&s->lock);
  5712. if (res == 0) {
  5713. if (skinnydebug)
  5714. ast_verb(1, "Skinny Client was lost, unregistering\n");
  5715. skinny_unregister(NULL, s);
  5716. }
  5717. return -1;
  5718. }
  5719. bufaddr = (int *)s->inbuf;
  5720. dlen = letohl(*bufaddr);
  5721. if (dlen < 4) {
  5722. ast_debug(1, "Skinny Client sent invalid data.\n");
  5723. ast_mutex_unlock(&s->lock);
  5724. return -1;
  5725. }
  5726. if (dlen+8 > sizeof(s->inbuf)) {
  5727. dlen = sizeof(s->inbuf) - 8;
  5728. }
  5729. *bufaddr = htolel(dlen);
  5730. res = read(s->fd, s->inbuf+4, dlen+4);
  5731. ast_mutex_unlock(&s->lock);
  5732. if (res < 0) {
  5733. ast_log(LOG_WARNING, "read() returned error: %s\n", strerror(errno));
  5734. return res;
  5735. } else if (res != (dlen+4)) {
  5736. ast_log(LOG_WARNING, "Skinny Client sent less data than expected.\n");
  5737. return -1;
  5738. }
  5739. return res;
  5740. }
  5741. return 0;
  5742. }
  5743. static struct skinny_req *skinny_req_parse(struct skinnysession *s)
  5744. {
  5745. struct skinny_req *req;
  5746. int *bufaddr;
  5747. if (!(req = ast_calloc(1, SKINNY_MAX_PACKET)))
  5748. return NULL;
  5749. ast_mutex_lock(&s->lock);
  5750. memcpy(req, s->inbuf, skinny_header_size);
  5751. bufaddr = (int *)(s->inbuf);
  5752. memcpy(&req->data, s->inbuf+skinny_header_size, letohl(*bufaddr)-4);
  5753. ast_mutex_unlock(&s->lock);
  5754. if (letohl(req->e) < 0) {
  5755. ast_log(LOG_ERROR, "Event Message is NULL from socket %d, This is bad\n", s->fd);
  5756. ast_free(req);
  5757. return NULL;
  5758. }
  5759. return req;
  5760. }
  5761. static void *skinny_session(void *data)
  5762. {
  5763. int res;
  5764. struct skinny_req *req;
  5765. struct skinnysession *s = data;
  5766. ast_verb(3, "Starting Skinny session from %s\n", ast_inet_ntoa(s->sin.sin_addr));
  5767. for (;;) {
  5768. res = get_input(s);
  5769. if (res < 0) {
  5770. break;
  5771. }
  5772. if (res > 0)
  5773. {
  5774. if (!(req = skinny_req_parse(s))) {
  5775. destroy_session(s);
  5776. return NULL;
  5777. }
  5778. res = handle_message(req, s);
  5779. if (res < 0) {
  5780. destroy_session(s);
  5781. return NULL;
  5782. }
  5783. }
  5784. }
  5785. ast_debug(3, "Skinny Session returned: %s\n", strerror(errno));
  5786. if (s)
  5787. destroy_session(s);
  5788. return 0;
  5789. }
  5790. static void *accept_thread(void *ignore)
  5791. {
  5792. int as;
  5793. struct sockaddr_in sin;
  5794. socklen_t sinlen;
  5795. struct skinnysession *s;
  5796. struct protoent *p;
  5797. int arg = 1;
  5798. for (;;) {
  5799. sinlen = sizeof(sin);
  5800. as = accept(skinnysock, (struct sockaddr *)&sin, &sinlen);
  5801. if (as < 0) {
  5802. ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
  5803. continue;
  5804. }
  5805. if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= auth_limit) {
  5806. close(as);
  5807. ast_atomic_fetchadd_int(&unauth_sessions, -1);
  5808. continue;
  5809. }
  5810. p = getprotobyname("tcp");
  5811. if(p) {
  5812. if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
  5813. ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
  5814. }
  5815. }
  5816. if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
  5817. close(as);
  5818. ast_atomic_fetchadd_int(&unauth_sessions, -1);
  5819. continue;
  5820. }
  5821. memcpy(&s->sin, &sin, sizeof(sin));
  5822. ast_mutex_init(&s->lock);
  5823. s->fd = as;
  5824. if(time(&s->start) == -1) {
  5825. ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
  5826. destroy_session(s);
  5827. continue;
  5828. }
  5829. AST_LIST_LOCK(&sessions);
  5830. AST_LIST_INSERT_HEAD(&sessions, s, list);
  5831. AST_LIST_UNLOCK(&sessions);
  5832. if (ast_pthread_create(&s->t, NULL, skinny_session, s)) {
  5833. destroy_session(s);
  5834. }
  5835. }
  5836. if (skinnydebug)
  5837. ast_verb(1, "killing accept thread\n");
  5838. close(as);
  5839. return 0;
  5840. }
  5841. static void *do_monitor(void *data)
  5842. {
  5843. int res;
  5844. /* This thread monitors all the interfaces which are not yet in use
  5845. (and thus do not have a separate thread) indefinitely */
  5846. /* From here on out, we die whenever asked */
  5847. for(;;) {
  5848. pthread_testcancel();
  5849. /* Wait for sched or io */
  5850. res = ast_sched_wait(sched);
  5851. if ((res < 0) || (res > 1000)) {
  5852. res = 1000;
  5853. }
  5854. res = ast_io_wait(io, res);
  5855. ast_mutex_lock(&monlock);
  5856. if (res >= 0) {
  5857. ast_sched_runq(sched);
  5858. }
  5859. ast_mutex_unlock(&monlock);
  5860. }
  5861. /* Never reached */
  5862. return NULL;
  5863. }
  5864. static int restart_monitor(void)
  5865. {
  5866. /* If we're supposed to be stopped -- stay stopped */
  5867. if (monitor_thread == AST_PTHREADT_STOP)
  5868. return 0;
  5869. ast_mutex_lock(&monlock);
  5870. if (monitor_thread == pthread_self()) {
  5871. ast_mutex_unlock(&monlock);
  5872. ast_log(LOG_WARNING, "Cannot kill myself\n");
  5873. return -1;
  5874. }
  5875. if (monitor_thread != AST_PTHREADT_NULL) {
  5876. /* Wake up the thread */
  5877. pthread_kill(monitor_thread, SIGURG);
  5878. } else {
  5879. /* Start a new monitor */
  5880. if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
  5881. ast_mutex_unlock(&monlock);
  5882. ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
  5883. return -1;
  5884. }
  5885. }
  5886. ast_mutex_unlock(&monlock);
  5887. return 0;
  5888. }
  5889. static int skinny_devicestate(void *data)
  5890. {
  5891. struct skinny_line *l;
  5892. char *tmp;
  5893. tmp = ast_strdupa(data);
  5894. l = find_line_by_name(tmp);
  5895. return get_devicestate(l);
  5896. }
  5897. static struct ast_channel *skinny_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
  5898. {
  5899. struct skinny_line *l;
  5900. struct ast_channel *tmpc = NULL;
  5901. char tmp[256];
  5902. char *dest = data;
  5903. if (!(format &= AST_FORMAT_AUDIO_MASK)) {
  5904. ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n", ast_getformatname_multiple(tmp, sizeof(tmp), format));
  5905. return NULL;
  5906. }
  5907. ast_copy_string(tmp, dest, sizeof(tmp));
  5908. if (ast_strlen_zero(tmp)) {
  5909. ast_log(LOG_NOTICE, "Skinny channels require a device\n");
  5910. return NULL;
  5911. }
  5912. l = find_line_by_name(tmp);
  5913. if (!l) {
  5914. ast_log(LOG_NOTICE, "No available lines on: %s\n", dest);
  5915. return NULL;
  5916. }
  5917. ast_verb(3, "skinny_request(%s)\n", tmp);
  5918. tmpc = skinny_new(l, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
  5919. if (!tmpc) {
  5920. ast_log(LOG_WARNING, "Unable to make channel for '%s'\n", tmp);
  5921. }
  5922. restart_monitor();
  5923. return tmpc;
  5924. }
  5925. #define TYPE_GENERAL 1
  5926. #define TYPE_DEF_DEVICE 2
  5927. #define TYPE_DEF_LINE 4
  5928. #define TYPE_DEVICE 8
  5929. #define TYPE_LINE 16
  5930. #define CLINE_OPTS ((struct skinny_line_options *)item)
  5931. #define CLINE ((struct skinny_line *)item)
  5932. #define CDEV_OPTS ((struct skinny_device_options *)item)
  5933. #define CDEV ((struct skinny_device *)item)
  5934. static void config_parse_variables(int type, void *item, struct ast_variable *vptr)
  5935. {
  5936. struct ast_variable *v;
  5937. int lineInstance = 1;
  5938. int speeddialInstance = 1;
  5939. while(vptr) {
  5940. v = vptr;
  5941. vptr = vptr->next;
  5942. if (type & (TYPE_GENERAL)) {
  5943. char newcontexts[AST_MAX_CONTEXT];
  5944. char oldcontexts[AST_MAX_CONTEXT];
  5945. char *stringp, *context, *oldregcontext;
  5946. if (!ast_jb_read_conf(&global_jbconf, v->name, v->value)) {
  5947. v = v->next;
  5948. continue;
  5949. }
  5950. if (!strcasecmp(v->name, "bindaddr")) {
  5951. if (!(hp = ast_gethostbyname(v->value, &ahp))) {
  5952. ast_log(LOG_WARNING, "Invalid address: %s\n", v->value);
  5953. } else {
  5954. memcpy(&bindaddr.sin_addr, hp->h_addr, sizeof(bindaddr.sin_addr));
  5955. }
  5956. continue;
  5957. } else if (!strcasecmp(v->name, "keepalive")) {
  5958. keep_alive = atoi(v->value);
  5959. continue;
  5960. } else if (!strcasecmp(v->name, "authtimeout")) {
  5961. int timeout = atoi(v->value);
  5962. if (timeout < 1) {
  5963. ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
  5964. auth_timeout = DEFAULT_AUTH_TIMEOUT;
  5965. } else {
  5966. auth_timeout = timeout;
  5967. }
  5968. continue;
  5969. } else if (!strcasecmp(v->name, "authlimit")) {
  5970. int limit = atoi(v->value);
  5971. if (limit < 1) {
  5972. ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
  5973. auth_limit = DEFAULT_AUTH_LIMIT;
  5974. } else {
  5975. auth_limit = limit;
  5976. }
  5977. continue;
  5978. } else if (!strcasecmp(v->name, "regcontext")) {
  5979. ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
  5980. stringp = newcontexts;
  5981. /* Initialize copy of current global_regcontext for later use in removing stale contexts */
  5982. ast_copy_string(oldcontexts, regcontext, sizeof(oldcontexts));
  5983. oldregcontext = oldcontexts;
  5984. /* Let's remove any contexts that are no longer defined in regcontext */
  5985. cleanup_stale_contexts(stringp, oldregcontext);
  5986. /* Create contexts if they don't exist already */
  5987. while ((context = strsep(&stringp, "&"))) {
  5988. ast_copy_string(used_context, context, sizeof(used_context));
  5989. ast_context_find_or_create(NULL, NULL, context, "Skinny");
  5990. }
  5991. ast_copy_string(regcontext, v->value, sizeof(regcontext));
  5992. continue;
  5993. } else if (!strcasecmp(v->name, "dateformat")) {
  5994. memcpy(date_format, v->value, sizeof(date_format));
  5995. continue;
  5996. } else if (!strcasecmp(v->name, "tos")) {
  5997. if (ast_str2tos(v->value, &qos.tos))
  5998. ast_log(LOG_WARNING, "Invalid tos value at line %d, refer to QoS documentation\n", v->lineno);
  5999. continue;
  6000. } else if (!strcasecmp(v->name, "tos_audio")) {
  6001. if (ast_str2tos(v->value, &qos.tos_audio))
  6002. ast_log(LOG_WARNING, "Invalid tos_audio value at line %d, refer to QoS documentation\n", v->lineno);
  6003. continue;
  6004. } else if (!strcasecmp(v->name, "tos_video")) {
  6005. if (ast_str2tos(v->value, &qos.tos_video))
  6006. ast_log(LOG_WARNING, "Invalid tos_video value at line %d, refer to QoS documentation\n", v->lineno);
  6007. continue;
  6008. } else if (!strcasecmp(v->name, "cos")) {
  6009. if (ast_str2cos(v->value, &qos.cos))
  6010. ast_log(LOG_WARNING, "Invalid cos value at line %d, refer to QoS documentation\n", v->lineno);
  6011. continue;
  6012. } else if (!strcasecmp(v->name, "cos_audio")) {
  6013. if (ast_str2cos(v->value, &qos.cos_audio))
  6014. ast_log(LOG_WARNING, "Invalid cos_audio value at line %d, refer to QoS documentation\n", v->lineno);
  6015. continue;
  6016. } else if (!strcasecmp(v->name, "cos_video")) {
  6017. if (ast_str2cos(v->value, &qos.cos_video))
  6018. ast_log(LOG_WARNING, "Invalid cos_video value at line %d, refer to QoS documentation\n", v->lineno);
  6019. continue;
  6020. } else if (!strcasecmp(v->name, "bindport")) {
  6021. if (sscanf(v->value, "%5d", &ourport) == 1) {
  6022. bindaddr.sin_port = htons(ourport);
  6023. } else {
  6024. ast_log(LOG_WARNING, "Invalid bindport '%s' at line %d of %s\n", v->value, v->lineno, config);
  6025. }
  6026. continue;
  6027. } else if (!strcasecmp(v->name, "allow")) {
  6028. ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1);
  6029. continue;
  6030. } else if (!strcasecmp(v->name, "disallow")) {
  6031. ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 0);
  6032. continue;
  6033. }
  6034. }
  6035. if (!strcasecmp(v->name, "transfer")) {
  6036. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6037. CDEV_OPTS->transfer = ast_true(v->value);
  6038. continue;
  6039. } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6040. CLINE_OPTS->transfer = ast_true(v->value);
  6041. continue;
  6042. }
  6043. } else if (!strcasecmp(v->name, "callwaiting")) {
  6044. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6045. CDEV_OPTS->callwaiting = ast_true(v->value);
  6046. continue;
  6047. } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6048. CLINE_OPTS->callwaiting = ast_true(v->value);
  6049. continue;
  6050. }
  6051. } else if (!strcasecmp(v->name, "directmedia") || !strcasecmp(v->name, "canreinvite")) {
  6052. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6053. CLINE_OPTS->directmedia = ast_true(v->value);
  6054. continue;
  6055. }
  6056. } else if (!strcasecmp(v->name, "nat")) {
  6057. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6058. CLINE_OPTS->nat = ast_true(v->value);
  6059. continue;
  6060. }
  6061. } else if (!strcasecmp(v->name, "context")) {
  6062. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6063. ast_copy_string(CLINE_OPTS->context, v->value, sizeof(CLINE_OPTS->context));
  6064. continue;
  6065. }
  6066. }else if (!strcasecmp(v->name, "vmexten")) {
  6067. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6068. ast_copy_string(CDEV_OPTS->vmexten, v->value, sizeof(CDEV_OPTS->vmexten));
  6069. continue;
  6070. } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6071. ast_copy_string(CLINE_OPTS->vmexten, v->value, sizeof(CLINE_OPTS->vmexten));
  6072. continue;
  6073. }
  6074. } else if (!strcasecmp(v->name, "mwiblink")) {
  6075. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6076. CDEV_OPTS->mwiblink = ast_true(v->value);
  6077. continue;
  6078. } else if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6079. CLINE_OPTS->mwiblink = ast_true(v->value);
  6080. continue;
  6081. }
  6082. } else if (!strcasecmp(v->name, "linelabel")) {
  6083. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6084. ast_copy_string(CLINE_OPTS->label, v->value, sizeof(CLINE_OPTS->label));
  6085. continue;
  6086. }
  6087. } else if (!strcasecmp(v->name, "callerid")) {
  6088. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6089. if (!strcasecmp(v->value, "asreceived")) {
  6090. CLINE_OPTS->cid_num[0] = '\0';
  6091. CLINE_OPTS->cid_name[0] = '\0';
  6092. } else {
  6093. ast_callerid_split(v->value, CLINE_OPTS->cid_name, sizeof(CLINE_OPTS->cid_name), CLINE_OPTS->cid_num, sizeof(CLINE_OPTS->cid_num));
  6094. }
  6095. continue;
  6096. }
  6097. } else if (!strcasecmp(v->name, "amaflags")) {
  6098. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6099. int tempamaflags = ast_cdr_amaflags2int(v->value);
  6100. if (tempamaflags < 0) {
  6101. ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
  6102. } else {
  6103. CLINE_OPTS->amaflags = tempamaflags;
  6104. }
  6105. continue;
  6106. }
  6107. } else if (!strcasecmp(v->name, "regexten")) {
  6108. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6109. ast_copy_string(CLINE_OPTS->regexten, v->value, sizeof(CLINE_OPTS->regexten));
  6110. continue;
  6111. }
  6112. } else if (!strcasecmp(v->name, "language")) {
  6113. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6114. ast_copy_string(CLINE_OPTS->language, v->value, sizeof(CLINE_OPTS->language));
  6115. continue;
  6116. }
  6117. } else if (!strcasecmp(v->name, "accountcode")) {
  6118. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6119. ast_copy_string(CLINE_OPTS->accountcode, v->value, sizeof(CLINE_OPTS->accountcode));
  6120. continue;
  6121. }
  6122. } else if (!strcasecmp(v->name, "mohinterpret") || !strcasecmp(v->name, "musiconhold")) {
  6123. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6124. ast_copy_string(CLINE_OPTS->mohinterpret, v->value, sizeof(CLINE_OPTS->mohinterpret));
  6125. continue;
  6126. }
  6127. } else if (!strcasecmp(v->name, "mohsuggest")) {
  6128. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6129. ast_copy_string(CLINE_OPTS->mohsuggest, v->value, sizeof(CLINE_OPTS->mohsuggest));
  6130. continue;
  6131. }
  6132. } else if (!strcasecmp(v->name, "callgroup")) {
  6133. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6134. CLINE_OPTS->callgroup = ast_get_group(v->value);
  6135. continue;
  6136. }
  6137. } else if (!strcasecmp(v->name, "pickupgroup")) {
  6138. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6139. CLINE_OPTS->pickupgroup = ast_get_group(v->value);
  6140. continue;
  6141. }
  6142. } else if (!strcasecmp(v->name, "immediate")) {
  6143. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE | TYPE_DEF_LINE | TYPE_LINE)) {
  6144. CLINE_OPTS->immediate = ast_true(v->value);
  6145. continue;
  6146. }
  6147. } else if (!strcasecmp(v->name, "cancallforward")) {
  6148. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6149. CLINE_OPTS->cancallforward = ast_true(v->value);
  6150. continue;
  6151. }
  6152. } else if (!strcasecmp(v->name, "mailbox")) {
  6153. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6154. ast_copy_string(CLINE_OPTS->mailbox, v->value, sizeof(CLINE_OPTS->mailbox));
  6155. continue;
  6156. }
  6157. } else if ( !strcasecmp(v->name, "parkinglot")) {
  6158. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6159. ast_copy_string(CLINE_OPTS->parkinglot, v->value, sizeof(CLINE_OPTS->parkinglot));
  6160. continue;
  6161. }
  6162. } else if (!strcasecmp(v->name, "hasvoicemail")) {
  6163. if (type & (TYPE_LINE)) {
  6164. if (ast_true(v->value) && ast_strlen_zero(CLINE->mailbox)) {
  6165. ast_copy_string(CLINE->mailbox, CLINE->name, sizeof(CLINE->mailbox));
  6166. }
  6167. continue;
  6168. }
  6169. } else if (!strcasecmp(v->name, "callreturn")) {
  6170. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6171. CLINE_OPTS->callreturn = ast_true(v->value);
  6172. continue;
  6173. }
  6174. } else if (!strcasecmp(v->name, "threewaycalling")) {
  6175. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6176. CLINE_OPTS->threewaycalling = ast_true(v->value);
  6177. continue;
  6178. }
  6179. } else if (!strcasecmp(v->name, "setvar")) {
  6180. if (type & (TYPE_LINE)) {
  6181. CLINE->chanvars = add_var(v->value, CLINE->chanvars);
  6182. continue;
  6183. }
  6184. } else if (!strcasecmp(v->name, "earlyrtp")) {
  6185. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6186. CDEV_OPTS->earlyrtp = ast_true(v->value);
  6187. continue;
  6188. }
  6189. } else if (!strcasecmp(v->name, "host")) {
  6190. if (type & (TYPE_DEVICE)) {
  6191. struct ast_sockaddr CDEV_addr_tmp;
  6192. CDEV_addr_tmp.ss.ss_family = AF_INET;
  6193. if (ast_get_ip(&CDEV_addr_tmp, v->value)) {
  6194. ast_log(LOG_WARNING, "Bad IP '%s' at line %d.\n", v->value, v->lineno);
  6195. }
  6196. ast_sockaddr_to_sin(&CDEV_addr_tmp,
  6197. &CDEV->addr);
  6198. continue;
  6199. }
  6200. } else if (!strcasecmp(v->name, "port")) {
  6201. if (type & (TYPE_DEF_DEVICE)) {
  6202. CDEV->addr.sin_port = htons(atoi(v->value));
  6203. continue;
  6204. }
  6205. } else if (!strcasecmp(v->name, "device")) {
  6206. if (type & (TYPE_DEVICE)) {
  6207. ast_copy_string(CDEV_OPTS->id, v->value, sizeof(CDEV_OPTS->id));
  6208. continue;
  6209. }
  6210. } else if (!strcasecmp(v->name, "permit") || !strcasecmp(v->name, "deny")) {
  6211. if (type & (TYPE_DEVICE)) {
  6212. CDEV->ha = ast_append_ha(v->name, v->value, CDEV->ha, NULL);
  6213. continue;
  6214. }
  6215. } else if (!strcasecmp(v->name, "allow")) {
  6216. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6217. ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 1);
  6218. continue;
  6219. }
  6220. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6221. ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 1);
  6222. continue;
  6223. }
  6224. } else if (!strcasecmp(v->name, "disallow")) {
  6225. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6226. ast_parse_allow_disallow(&CDEV_OPTS->confprefs, &CDEV_OPTS->confcapability, v->value, 0);
  6227. continue;
  6228. }
  6229. if (type & (TYPE_DEF_LINE | TYPE_LINE)) {
  6230. ast_parse_allow_disallow(&CLINE_OPTS->confprefs, &CLINE_OPTS->confcapability, v->value, 0);
  6231. continue;
  6232. }
  6233. } else if (!strcasecmp(v->name, "version")) {
  6234. if (type & (TYPE_DEF_DEVICE | TYPE_DEVICE)) {
  6235. ast_copy_string(CDEV_OPTS->version_id, v->value, sizeof(CDEV_OPTS->version_id));
  6236. continue;
  6237. }
  6238. } else if (!strcasecmp(v->name, "line")) {
  6239. if (type & (TYPE_DEVICE)) {
  6240. struct skinny_line *l;
  6241. AST_LIST_TRAVERSE(&lines, l, all) {
  6242. if (!strcasecmp(v->value, l->name) && !l->prune) {
  6243. /* FIXME: temp solution about line conflicts */
  6244. struct skinny_device *d;
  6245. struct skinny_line *l2;
  6246. int lineinuse = 0;
  6247. AST_LIST_TRAVERSE(&devices, d, list) {
  6248. AST_LIST_TRAVERSE(&d->lines, l2, list) {
  6249. if (l2 == l && strcasecmp(d->id, CDEV->id)) {
  6250. ast_log(LOG_WARNING, "Line %s already used by %s. Not connecting to %s.\n", l->name, d->name, CDEV->name);
  6251. lineinuse++;
  6252. }
  6253. }
  6254. }
  6255. if (!lineinuse) {
  6256. if (!AST_LIST_FIRST(&CDEV->lines)) {
  6257. CDEV->activeline = l;
  6258. }
  6259. lineInstance++;
  6260. AST_LIST_INSERT_HEAD(&CDEV->lines, l, list);
  6261. }
  6262. break;
  6263. }
  6264. }
  6265. continue;
  6266. }
  6267. } else if (!strcasecmp(v->name, "speeddial")) {
  6268. if (type & (TYPE_DEVICE)) {
  6269. struct skinny_speeddial *sd;
  6270. if (!(sd = ast_calloc(1, sizeof(*sd)))) {
  6271. ast_log(LOG_WARNING, "Unable to allocate memory for speeddial %s. Ignoring speeddial.\n", v->name);
  6272. continue;
  6273. } else {
  6274. char buf[256];
  6275. char *stringp = buf, *exten, *context, *label;
  6276. ast_copy_string(buf, v->value, sizeof(buf));
  6277. exten = strsep(&stringp, ",");
  6278. if ((context = strchr(exten, '@'))) {
  6279. *context++ = '\0';
  6280. }
  6281. label = stringp;
  6282. ast_mutex_init(&sd->lock);
  6283. ast_copy_string(sd->exten, exten, sizeof(sd->exten));
  6284. if (!ast_strlen_zero(context)) {
  6285. sd->isHint = 1;
  6286. sd->instance = lineInstance++;
  6287. ast_copy_string(sd->context, context, sizeof(sd->context));
  6288. } else {
  6289. sd->isHint = 0;
  6290. sd->instance = speeddialInstance++;
  6291. sd->context[0] = '\0';
  6292. }
  6293. ast_copy_string(sd->label, S_OR(label, exten), sizeof(sd->label));
  6294. sd->parent = CDEV;
  6295. AST_LIST_INSERT_HEAD(&CDEV->speeddials, sd, list);
  6296. }
  6297. continue;
  6298. }
  6299. } else if (!strcasecmp(v->name, "addon")) {
  6300. if (type & (TYPE_DEVICE)) {
  6301. struct skinny_addon *a;
  6302. if (!(a = ast_calloc(1, sizeof(*a)))) {
  6303. ast_log(LOG_WARNING, "Unable to allocate memory for addon %s. Ignoring addon.\n", v->name);
  6304. continue;
  6305. } else {
  6306. ast_mutex_init(&a->lock);
  6307. ast_copy_string(a->type, v->value, sizeof(a->type));
  6308. AST_LIST_INSERT_HEAD(&CDEV->addons, a, list);
  6309. }
  6310. continue;
  6311. }
  6312. } else {
  6313. ast_log(LOG_WARNING, "Don't know keyword '%s' at line %d\n", v->name, v->lineno);
  6314. continue;
  6315. }
  6316. ast_log(LOG_WARNING, "Invalid category used: %s at line %d\n", v->name, v->lineno);
  6317. }
  6318. }
  6319. static struct skinny_line *config_line(const char *lname, struct ast_variable *v)
  6320. {
  6321. struct skinny_line *l, *temp;
  6322. int update = 0;
  6323. ast_log(LOG_NOTICE, "Configuring skinny line %s.\n", lname);
  6324. /* We find the old line and remove it just before the new
  6325. line is created */
  6326. AST_LIST_LOCK(&lines);
  6327. AST_LIST_TRAVERSE(&lines, temp, all) {
  6328. if (!strcasecmp(lname, temp->name) && temp->prune) {
  6329. update = 1;
  6330. break;
  6331. }
  6332. }
  6333. if (!(l=ast_calloc(1, sizeof(*l)))) {
  6334. ast_verb(1, "Unable to allocate memory for line %s.\n", lname);
  6335. AST_LIST_UNLOCK(&lines);
  6336. return NULL;
  6337. }
  6338. memcpy(l, default_line, sizeof(*default_line));
  6339. ast_mutex_init(&l->lock);
  6340. ast_copy_string(l->name, lname, sizeof(l->name));
  6341. AST_LIST_INSERT_TAIL(&lines, l, all);
  6342. ast_mutex_lock(&l->lock);
  6343. AST_LIST_UNLOCK(&lines);
  6344. config_parse_variables(TYPE_LINE, l, v);
  6345. if (!ast_strlen_zero(l->mailbox)) {
  6346. char *cfg_mailbox, *cfg_context;
  6347. cfg_context = cfg_mailbox = ast_strdupa(l->mailbox);
  6348. ast_verb(3, "Setting mailbox '%s' on line %s\n", cfg_mailbox, l->name);
  6349. strsep(&cfg_context, "@");
  6350. if (ast_strlen_zero(cfg_context))
  6351. cfg_context = "default";
  6352. l->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, "skinny MWI subsciption", l,
  6353. AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, cfg_mailbox,
  6354. AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, cfg_context,
  6355. AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
  6356. AST_EVENT_IE_END);
  6357. }
  6358. ast_mutex_unlock(&l->lock);
  6359. /* We do not want to unlink or free the line yet, it needs
  6360. to be available to detect a device reconfig when we load the
  6361. devices. Old lines will be pruned after the reload completes */
  6362. ast_verb(3, "%s config for line '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), l->name);
  6363. return l;
  6364. }
  6365. static struct skinny_device *config_device(const char *dname, struct ast_variable *v)
  6366. {
  6367. struct skinny_device *d, *temp;
  6368. struct skinny_line *l, *ltemp;
  6369. struct skinny_subchannel *sub;
  6370. int update = 0;
  6371. ast_log(LOG_NOTICE, "Configuring skinny device %s.\n", dname);
  6372. AST_LIST_LOCK(&devices);
  6373. AST_LIST_TRAVERSE(&devices, temp, list) {
  6374. if (!strcasecmp(dname, temp->name) && temp->prune) {
  6375. update = 1;
  6376. break;
  6377. }
  6378. }
  6379. if (!(d = ast_calloc(1, sizeof(*d)))) {
  6380. ast_verb(1, "Unable to allocate memory for device %s.\n", dname);
  6381. AST_LIST_UNLOCK(&devices);
  6382. return NULL;
  6383. }
  6384. memcpy(d, default_device, sizeof(*default_device));
  6385. ast_mutex_init(&d->lock);
  6386. ast_copy_string(d->name, dname, sizeof(d->name));
  6387. AST_LIST_INSERT_TAIL(&devices, d, list);
  6388. ast_mutex_lock(&d->lock);
  6389. AST_LIST_UNLOCK(&devices);
  6390. config_parse_variables(TYPE_DEVICE, d, v);
  6391. if (!AST_LIST_FIRST(&d->lines)) {
  6392. ast_log(LOG_ERROR, "A Skinny device must have at least one line!\n");
  6393. ast_mutex_unlock(&d->lock);
  6394. return NULL;
  6395. }
  6396. if (/*d->addr.sin_addr.s_addr && */!ntohs(d->addr.sin_port)) {
  6397. d->addr.sin_port = htons(DEFAULT_SKINNY_PORT);
  6398. }
  6399. if (skinnyreload){
  6400. AST_LIST_LOCK(&devices);
  6401. AST_LIST_TRAVERSE(&devices, temp, list) {
  6402. if (strcasecmp(d->id, temp->id) || !temp->prune || !temp->session) {
  6403. continue;
  6404. }
  6405. ast_mutex_lock(&d->lock);
  6406. d->session = temp->session;
  6407. d->session->device = d;
  6408. AST_LIST_LOCK(&d->lines);
  6409. AST_LIST_TRAVERSE(&d->lines, l, list){
  6410. l->device = d;
  6411. AST_LIST_LOCK(&temp->lines);
  6412. AST_LIST_TRAVERSE(&temp->lines, ltemp, list) {
  6413. if (strcasecmp(l->name, ltemp->name)) {
  6414. continue;
  6415. }
  6416. ast_mutex_lock(&ltemp->lock);
  6417. l->instance = ltemp->instance;
  6418. l->hookstate = ltemp->hookstate;
  6419. if (!AST_LIST_EMPTY(&ltemp->sub)) {
  6420. ast_mutex_lock(&l->lock);
  6421. l->sub = ltemp->sub;
  6422. AST_LIST_TRAVERSE(&l->sub, sub, list) {
  6423. sub->parent = l;
  6424. }
  6425. ast_mutex_unlock(&l->lock);
  6426. }
  6427. ast_mutex_unlock(&ltemp->lock);
  6428. }
  6429. AST_LIST_UNLOCK(&temp->lines);
  6430. }
  6431. AST_LIST_UNLOCK(&d->lines);
  6432. ast_mutex_unlock(&d->lock);
  6433. }
  6434. AST_LIST_UNLOCK(&devices);
  6435. }
  6436. ast_mutex_unlock(&d->lock);
  6437. ast_verb(3, "%s config for device '%s'\n", update ? "Updated" : (skinnyreload ? "Reloaded" : "Created"), d->name);
  6438. return d;
  6439. }
  6440. static int config_load(void)
  6441. {
  6442. int on = 1;
  6443. struct ast_config *cfg;
  6444. char *cat;
  6445. int oldport = ntohs(bindaddr.sin_port);
  6446. struct ast_flags config_flags = { 0 };
  6447. ast_log(LOG_NOTICE, "Configuring skinny from %s\n", config);
  6448. if (gethostname(ourhost, sizeof(ourhost))) {
  6449. ast_log(LOG_WARNING, "Unable to get hostname, Skinny disabled.\n");
  6450. return 0;
  6451. }
  6452. cfg = ast_config_load(config, config_flags);
  6453. /* We *must* have a config file otherwise stop immediately */
  6454. if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
  6455. ast_log(LOG_NOTICE, "Unable to load config %s, Skinny disabled.\n", config);
  6456. return -1;
  6457. }
  6458. memset(&bindaddr, 0, sizeof(bindaddr));
  6459. memset(&default_prefs, 0, sizeof(default_prefs));
  6460. /* Copy the default jb config over global_jbconf */
  6461. memcpy(&global_jbconf, &default_jbconf, sizeof(struct ast_jb_conf));
  6462. /* load the general section */
  6463. cat = ast_category_browse(cfg, "general");
  6464. config_parse_variables(TYPE_GENERAL, NULL, ast_variable_browse(cfg, "general"));
  6465. if (ntohl(bindaddr.sin_addr.s_addr)) {
  6466. __ourip = bindaddr.sin_addr;
  6467. } else {
  6468. hp = ast_gethostbyname(ourhost, &ahp);
  6469. if (!hp) {
  6470. ast_log(LOG_WARNING, "Unable to get our IP address, Skinny disabled\n");
  6471. ast_config_destroy(cfg);
  6472. return 0;
  6473. }
  6474. memcpy(&__ourip, hp->h_addr, sizeof(__ourip));
  6475. }
  6476. if (!ntohs(bindaddr.sin_port)) {
  6477. bindaddr.sin_port = htons(DEFAULT_SKINNY_PORT);
  6478. }
  6479. bindaddr.sin_family = AF_INET;
  6480. /* load the lines sections */
  6481. default_line->confcapability = default_capability;
  6482. default_line->confprefs = default_prefs;
  6483. config_parse_variables(TYPE_DEF_LINE, default_line, ast_variable_browse(cfg, "lines"));
  6484. cat = ast_category_browse(cfg, "lines");
  6485. while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "devices")) {
  6486. config_line(cat, ast_variable_browse(cfg, cat));
  6487. cat = ast_category_browse(cfg, cat);
  6488. }
  6489. /* load the devices sections */
  6490. default_device->confcapability = default_capability;
  6491. default_device->confprefs = default_prefs;
  6492. config_parse_variables(TYPE_DEF_DEVICE, default_device, ast_variable_browse(cfg, "devices"));
  6493. cat = ast_category_browse(cfg, "devices");
  6494. while (cat && strcasecmp(cat, "general") && strcasecmp(cat, "lines")) {
  6495. config_device(cat, ast_variable_browse(cfg, cat));
  6496. cat = ast_category_browse(cfg, cat);
  6497. }
  6498. ast_mutex_lock(&netlock);
  6499. if ((skinnysock > -1) && (ntohs(bindaddr.sin_port) != oldport)) {
  6500. close(skinnysock);
  6501. skinnysock = -1;
  6502. }
  6503. if (skinnysock < 0) {
  6504. skinnysock = socket(AF_INET, SOCK_STREAM, 0);
  6505. if(setsockopt(skinnysock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
  6506. ast_log(LOG_ERROR, "Set Socket Options failed: errno %d, %s\n", errno, strerror(errno));
  6507. ast_config_destroy(cfg);
  6508. ast_mutex_unlock(&netlock);
  6509. return 0;
  6510. }
  6511. if (skinnysock < 0) {
  6512. ast_log(LOG_WARNING, "Unable to create Skinny socket: %s\n", strerror(errno));
  6513. } else {
  6514. if (bind(skinnysock, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
  6515. ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n",
  6516. ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
  6517. strerror(errno));
  6518. close(skinnysock);
  6519. skinnysock = -1;
  6520. ast_config_destroy(cfg);
  6521. ast_mutex_unlock(&netlock);
  6522. return 0;
  6523. }
  6524. if (listen(skinnysock, DEFAULT_SKINNY_BACKLOG)) {
  6525. ast_log(LOG_WARNING, "Failed to start listening to %s:%d: %s\n",
  6526. ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port),
  6527. strerror(errno));
  6528. close(skinnysock);
  6529. skinnysock = -1;
  6530. ast_config_destroy(cfg);
  6531. ast_mutex_unlock(&netlock);
  6532. return 0;
  6533. }
  6534. ast_verb(2, "Skinny listening on %s:%d\n",
  6535. ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port));
  6536. ast_netsock_set_qos(skinnysock, qos.tos, qos.cos, "Skinny");
  6537. ast_pthread_create_background(&accept_t, NULL, accept_thread, NULL);
  6538. }
  6539. }
  6540. ast_mutex_unlock(&netlock);
  6541. ast_config_destroy(cfg);
  6542. return 1;
  6543. }
  6544. static void delete_devices(void)
  6545. {
  6546. struct skinny_device *d;
  6547. struct skinny_line *l;
  6548. struct skinny_speeddial *sd;
  6549. struct skinny_addon *a;
  6550. AST_LIST_LOCK(&devices);
  6551. AST_LIST_LOCK(&lines);
  6552. /* Delete all devices */
  6553. while ((d = AST_LIST_REMOVE_HEAD(&devices, list))) {
  6554. /* Delete all lines for this device */
  6555. while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
  6556. AST_LIST_REMOVE(&lines, l, all);
  6557. free(l);
  6558. }
  6559. /* Delete all speeddials for this device */
  6560. while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
  6561. free(sd);
  6562. }
  6563. /* Delete all addons for this device */
  6564. while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
  6565. free(a);
  6566. }
  6567. free(d);
  6568. }
  6569. AST_LIST_UNLOCK(&lines);
  6570. AST_LIST_UNLOCK(&devices);
  6571. }
  6572. int skinny_reload(void)
  6573. {
  6574. struct skinny_device *d;
  6575. struct skinny_line *l;
  6576. struct skinny_speeddial *sd;
  6577. struct skinny_addon *a;
  6578. struct skinny_req *req;
  6579. if (skinnyreload) {
  6580. ast_verb(3, "Chan_skinny is already reloading.\n");
  6581. return 0;
  6582. }
  6583. skinnyreload = 1;
  6584. /* Mark all devices and lines as candidates to be pruned */
  6585. AST_LIST_LOCK(&devices);
  6586. AST_LIST_TRAVERSE(&devices, d, list) {
  6587. d->prune = 1;
  6588. }
  6589. AST_LIST_UNLOCK(&devices);
  6590. AST_LIST_LOCK(&lines);
  6591. AST_LIST_TRAVERSE(&lines, l, all) {
  6592. l->prune = 1;
  6593. }
  6594. AST_LIST_UNLOCK(&lines);
  6595. config_load();
  6596. /* Remove any devices that no longer exist in the config */
  6597. AST_LIST_LOCK(&devices);
  6598. AST_LIST_TRAVERSE_SAFE_BEGIN(&devices, d, list) {
  6599. if (!d->prune) {
  6600. continue;
  6601. }
  6602. ast_verb(3, "Removing device '%s'\n", d->name);
  6603. /* Delete all lines for this device.
  6604. We do not want to free the line here, that
  6605. will happen below. */
  6606. while ((l = AST_LIST_REMOVE_HEAD(&d->lines, list))) {
  6607. }
  6608. /* Delete all speeddials for this device */
  6609. while ((sd = AST_LIST_REMOVE_HEAD(&d->speeddials, list))) {
  6610. free(sd);
  6611. }
  6612. /* Delete all addons for this device */
  6613. while ((a = AST_LIST_REMOVE_HEAD(&d->addons, list))) {
  6614. free(a);
  6615. }
  6616. AST_LIST_REMOVE_CURRENT(list);
  6617. free(d);
  6618. }
  6619. AST_LIST_TRAVERSE_SAFE_END;
  6620. AST_LIST_UNLOCK(&devices);
  6621. AST_LIST_LOCK(&lines);
  6622. AST_LIST_TRAVERSE_SAFE_BEGIN(&lines, l, all) {
  6623. if (l->prune) {
  6624. AST_LIST_REMOVE_CURRENT(all);
  6625. free(l);
  6626. }
  6627. }
  6628. AST_LIST_TRAVERSE_SAFE_END;
  6629. AST_LIST_UNLOCK(&lines);
  6630. AST_LIST_TRAVERSE(&devices, d, list) {
  6631. /* Do a soft reset to re-register the devices after
  6632. cleaning up the removed devices and lines */
  6633. if (d->session) {
  6634. ast_verb(3, "Restarting device '%s'\n", d->name);
  6635. if ((req = req_alloc(sizeof(struct reset_message), RESET_MESSAGE))) {
  6636. req->data.reset.resetType = 2;
  6637. transmit_response(d, req);
  6638. }
  6639. }
  6640. }
  6641. skinnyreload = 0;
  6642. return 0;
  6643. }
  6644. static int load_module(void)
  6645. {
  6646. int res = 0;
  6647. for (; res < ARRAY_LEN(soft_key_template_default); res++) {
  6648. soft_key_template_default[res].softKeyEvent = htolel(soft_key_template_default[res].softKeyEvent);
  6649. }
  6650. /* load and parse config */
  6651. res = config_load();
  6652. if (res == -1) {
  6653. return AST_MODULE_LOAD_DECLINE;
  6654. }
  6655. /* Make sure we can register our skinny channel type */
  6656. if (ast_channel_register(&skinny_tech)) {
  6657. ast_log(LOG_ERROR, "Unable to register channel class 'Skinny'\n");
  6658. return -1;
  6659. }
  6660. ast_rtp_glue_register(&skinny_rtp_glue);
  6661. ast_cli_register_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
  6662. ast_manager_register_xml("SKINNYdevices", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_devices);
  6663. ast_manager_register_xml("SKINNYshowdevice", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_device);
  6664. ast_manager_register_xml("SKINNYlines", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_lines);
  6665. ast_manager_register_xml("SKINNYshowline", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_skinny_show_line);
  6666. sched = sched_context_create();
  6667. if (!sched) {
  6668. ast_log(LOG_WARNING, "Unable to create schedule context\n");
  6669. }
  6670. io = io_context_create();
  6671. if (!io) {
  6672. ast_log(LOG_WARNING, "Unable to create I/O context\n");
  6673. }
  6674. /* And start the monitor for the first time */
  6675. restart_monitor();
  6676. return AST_MODULE_LOAD_SUCCESS;
  6677. }
  6678. static int unload_module(void)
  6679. {
  6680. struct skinnysession *s;
  6681. struct skinny_device *d;
  6682. struct skinny_line *l;
  6683. struct skinny_subchannel *sub;
  6684. struct ast_context *con;
  6685. ast_rtp_glue_unregister(&skinny_rtp_glue);
  6686. ast_channel_unregister(&skinny_tech);
  6687. ast_cli_unregister_multiple(cli_skinny, ARRAY_LEN(cli_skinny));
  6688. ast_manager_unregister("SKINNYdevices");
  6689. ast_manager_unregister("SKINNYshowdevice");
  6690. ast_manager_unregister("SKINNYlines");
  6691. ast_manager_unregister("SKINNYshowline");
  6692. AST_LIST_LOCK(&sessions);
  6693. /* Destroy all the interfaces and free their memory */
  6694. while((s = AST_LIST_REMOVE_HEAD(&sessions, list))) {
  6695. d = s->device;
  6696. AST_LIST_TRAVERSE(&d->lines, l, list){
  6697. ast_mutex_lock(&l->lock);
  6698. AST_LIST_TRAVERSE(&l->sub, sub, list) {
  6699. ast_mutex_lock(&sub->lock);
  6700. if (sub->owner) {
  6701. sub->alreadygone = 1;
  6702. ast_softhangup(sub->owner, AST_SOFTHANGUP_APPUNLOAD);
  6703. }
  6704. ast_mutex_unlock(&sub->lock);
  6705. }
  6706. if (l->mwi_event_sub)
  6707. ast_event_unsubscribe(l->mwi_event_sub);
  6708. ast_mutex_unlock(&l->lock);
  6709. manager_event(EVENT_FLAG_SYSTEM, "PeerStatus", "ChannelType: Skinny\r\nPeer: Skinny/%s@%s\r\nPeerStatus: Unregistered\r\n", l->name, d->name);
  6710. unregister_exten(l);
  6711. }
  6712. if (s->fd > -1)
  6713. close(s->fd);
  6714. pthread_cancel(s->t);
  6715. pthread_kill(s->t, SIGURG);
  6716. pthread_join(s->t, NULL);
  6717. free(s);
  6718. }
  6719. AST_LIST_UNLOCK(&sessions);
  6720. delete_devices();
  6721. ast_mutex_lock(&monlock);
  6722. if ((monitor_thread != AST_PTHREADT_NULL) && (monitor_thread != AST_PTHREADT_STOP)) {
  6723. pthread_cancel(monitor_thread);
  6724. pthread_kill(monitor_thread, SIGURG);
  6725. pthread_join(monitor_thread, NULL);
  6726. }
  6727. monitor_thread = AST_PTHREADT_STOP;
  6728. ast_mutex_unlock(&monlock);
  6729. ast_mutex_lock(&netlock);
  6730. if (accept_t && (accept_t != AST_PTHREADT_STOP)) {
  6731. pthread_cancel(accept_t);
  6732. pthread_kill(accept_t, SIGURG);
  6733. pthread_join(accept_t, NULL);
  6734. }
  6735. accept_t = AST_PTHREADT_STOP;
  6736. ast_mutex_unlock(&netlock);
  6737. close(skinnysock);
  6738. if (sched)
  6739. sched_context_destroy(sched);
  6740. con = ast_context_find(used_context);
  6741. if (con)
  6742. ast_context_destroy(con, "Skinny");
  6743. return 0;
  6744. }
  6745. static int reload(void)
  6746. {
  6747. skinny_reload();
  6748. return 0;
  6749. }
  6750. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Skinny Client Control Protocol (Skinny)",
  6751. .load = load_module,
  6752. .unload = unload_module,
  6753. .reload = reload,
  6754. .load_pri = AST_MODPRI_CHANNEL_DRIVER,
  6755. );