12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242 |
- #include "asterisk.h"
- ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
- #include <sys/time.h>
- #include <sys/signal.h>
- #include <sys/stat.h>
- #include <netinet/in.h>
- #include "asterisk/paths.h"
- #include "asterisk/lock.h"
- #include "asterisk/file.h"
- #include "asterisk/channel.h"
- #include "asterisk/pbx.h"
- #include "asterisk/module.h"
- #include "asterisk/translate.h"
- #include "asterisk/say.h"
- #include "asterisk/config.h"
- #include "asterisk/features.h"
- #include "asterisk/musiconhold.h"
- #include "asterisk/callerid.h"
- #include "asterisk/utils.h"
- #include "asterisk/app.h"
- #include "asterisk/causes.h"
- #include "asterisk/rtp_engine.h"
- #include "asterisk/manager.h"
- #include "asterisk/privacy.h"
- #include "asterisk/stringfields.h"
- #include "asterisk/global_datastores.h"
- #include "asterisk/dsp.h"
- #include "asterisk/aoc.h"
- #include "asterisk/ccss.h"
- #include "asterisk/indications.h"
- #include "asterisk/framehook.h"
- #include "asterisk/dial.h"
- #include "asterisk/stasis_channels.h"
- #include "asterisk/bridge_after.h"
- #include "asterisk/features_config.h"
- static const char app[] = "Dial";
- static const char rapp[] = "RetryDial";
- enum {
- OPT_ANNOUNCE = (1 << 0),
- OPT_RESETCDR = (1 << 1),
- OPT_DTMF_EXIT = (1 << 2),
- OPT_SENDDTMF = (1 << 3),
- OPT_FORCECLID = (1 << 4),
- OPT_GO_ON = (1 << 5),
- OPT_CALLEE_HANGUP = (1 << 6),
- OPT_CALLER_HANGUP = (1 << 7),
- OPT_ORIGINAL_CLID = (1 << 8),
- OPT_DURATION_LIMIT = (1 << 9),
- OPT_MUSICBACK = (1 << 10),
- OPT_CALLEE_MACRO = (1 << 11),
- OPT_SCREEN_NOINTRO = (1 << 12),
- OPT_SCREEN_NOCALLERID = (1 << 13),
- OPT_IGNORE_CONNECTEDLINE = (1 << 14),
- OPT_SCREENING = (1 << 15),
- OPT_PRIVACY = (1 << 16),
- OPT_RINGBACK = (1 << 17),
- OPT_DURATION_STOP = (1 << 18),
- OPT_CALLEE_TRANSFER = (1 << 19),
- OPT_CALLER_TRANSFER = (1 << 20),
- OPT_CALLEE_MONITOR = (1 << 21),
- OPT_CALLER_MONITOR = (1 << 22),
- OPT_GOTO = (1 << 23),
- OPT_OPERMODE = (1 << 24),
- OPT_CALLEE_PARK = (1 << 25),
- OPT_CALLER_PARK = (1 << 26),
- OPT_IGNORE_FORWARDING = (1 << 27),
- OPT_CALLEE_GOSUB = (1 << 28),
- OPT_CALLEE_MIXMONITOR = (1 << 29),
- OPT_CALLER_MIXMONITOR = (1 << 30),
- };
- #define DIAL_STILLGOING (1LLU << 31)
- #define DIAL_NOFORWARDHTML (1LLU << 32)
- #define DIAL_CALLERID_ABSENT (1LLU << 33) /* TRUE if caller id is not available for connected line. */
- #define OPT_CANCEL_ELSEWHERE (1LLU << 34)
- #define OPT_PEER_H (1LLU << 35)
- #define OPT_CALLEE_GO_ON (1LLU << 36)
- #define OPT_CANCEL_TIMEOUT (1LLU << 37)
- #define OPT_FORCE_CID_TAG (1LLU << 38)
- #define OPT_FORCE_CID_PRES (1LLU << 39)
- #define OPT_CALLER_ANSWER (1LLU << 40)
- #define OPT_PREDIAL_CALLEE (1LLU << 41)
- #define OPT_PREDIAL_CALLER (1LLU << 42)
- enum {
- OPT_ARG_ANNOUNCE = 0,
- OPT_ARG_SENDDTMF,
- OPT_ARG_GOTO,
- OPT_ARG_DURATION_LIMIT,
- OPT_ARG_MUSICBACK,
- OPT_ARG_CALLEE_MACRO,
- OPT_ARG_RINGBACK,
- OPT_ARG_CALLEE_GOSUB,
- OPT_ARG_CALLEE_GO_ON,
- OPT_ARG_PRIVACY,
- OPT_ARG_DURATION_STOP,
- OPT_ARG_OPERMODE,
- OPT_ARG_SCREEN_NOINTRO,
- OPT_ARG_ORIGINAL_CLID,
- OPT_ARG_FORCECLID,
- OPT_ARG_FORCE_CID_TAG,
- OPT_ARG_FORCE_CID_PRES,
- OPT_ARG_PREDIAL_CALLEE,
- OPT_ARG_PREDIAL_CALLER,
- /* note: this entry _MUST_ be the last one in the enum */
- OPT_ARG_ARRAY_SIZE,
- };
- AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
- AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
- AST_APP_OPTION('a', OPT_CALLER_ANSWER),
- AST_APP_OPTION_ARG('b', OPT_PREDIAL_CALLEE, OPT_ARG_PREDIAL_CALLEE),
- AST_APP_OPTION_ARG('B', OPT_PREDIAL_CALLER, OPT_ARG_PREDIAL_CALLER),
- AST_APP_OPTION('C', OPT_RESETCDR),
- AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
- AST_APP_OPTION('d', OPT_DTMF_EXIT),
- AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
- AST_APP_OPTION('e', OPT_PEER_H),
- AST_APP_OPTION_ARG('f', OPT_FORCECLID, OPT_ARG_FORCECLID),
- AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
- AST_APP_OPTION('g', OPT_GO_ON),
- AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO),
- AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
- AST_APP_OPTION('H', OPT_CALLER_HANGUP),
- AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
- AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
- AST_APP_OPTION('k', OPT_CALLEE_PARK),
- AST_APP_OPTION('K', OPT_CALLER_PARK),
- AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
- AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
- AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
- AST_APP_OPTION_ARG('n', OPT_SCREEN_NOINTRO, OPT_ARG_SCREEN_NOINTRO),
- AST_APP_OPTION('N', OPT_SCREEN_NOCALLERID),
- AST_APP_OPTION_ARG('o', OPT_ORIGINAL_CLID, OPT_ARG_ORIGINAL_CLID),
- AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
- AST_APP_OPTION('p', OPT_SCREENING),
- AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
- AST_APP_OPTION_ARG('r', OPT_RINGBACK, OPT_ARG_RINGBACK),
- AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
- AST_APP_OPTION_ARG('s', OPT_FORCE_CID_TAG, OPT_ARG_FORCE_CID_TAG),
- AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
- AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
- AST_APP_OPTION_ARG('u', OPT_FORCE_CID_PRES, OPT_ARG_FORCE_CID_PRES),
- AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
- AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
- AST_APP_OPTION('W', OPT_CALLER_MONITOR),
- AST_APP_OPTION('x', OPT_CALLEE_MIXMONITOR),
- AST_APP_OPTION('X', OPT_CALLER_MIXMONITOR),
- AST_APP_OPTION('z', OPT_CANCEL_TIMEOUT),
- END_OPTIONS );
- #define CAN_EARLY_BRIDGE(flags,chan,peer) (!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \
- OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \
- OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | \
- OPT_CALLER_PARK | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB) && \
- !ast_channel_audiohooks(chan) && !ast_channel_audiohooks(peer) && \
- ast_framehook_list_is_empty(ast_channel_framehooks(chan)) && ast_framehook_list_is_empty(ast_channel_framehooks(peer)))
- /*
- * The list of active channels
- */
- struct chanlist {
- AST_LIST_ENTRY(chanlist) node;
- struct ast_channel *chan;
- /*! Channel interface dialing string (is tech/number). (Stored in stuff[]) */
- const char *interface;
- /*! Channel technology name. (Stored in stuff[]) */
- const char *tech;
- /*! Channel device addressing. (Stored in stuff[]) */
- const char *number;
- uint64_t flags;
- /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
- struct ast_party_connected_line connected;
- /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
- unsigned int pending_connected_update:1;
- struct ast_aoc_decoded *aoc_s_rate_list;
- /*! The interface, tech, and number strings are stuffed here. */
- char stuff[0];
- };
- AST_LIST_HEAD_NOLOCK(dial_head, chanlist);
- static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode);
- static void chanlist_free(struct chanlist *outgoing)
- {
- ast_party_connected_line_free(&outgoing->connected);
- ast_aoc_destroy_decoded(outgoing->aoc_s_rate_list);
- ast_free(outgoing);
- }
- static void hanguptree(struct dial_head *out_chans, struct ast_channel *exception, int answered_elsewhere)
- {
-
- struct chanlist *outgoing;
- while ((outgoing = AST_LIST_REMOVE_HEAD(out_chans, node))) {
-
- if (outgoing->chan && (outgoing->chan != exception)) {
- if (answered_elsewhere) {
-
- ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
- }
- ast_hangup(outgoing->chan);
- }
- chanlist_free(outgoing);
- }
- }
- #define AST_MAX_WATCHERS 256
- struct cause_args {
- struct ast_channel *chan;
- int busy;
- int congestion;
- int nochan;
- };
- static void handle_cause(int cause, struct cause_args *num)
- {
- switch(cause) {
- case AST_CAUSE_BUSY:
- num->busy++;
- break;
- case AST_CAUSE_CONGESTION:
- num->congestion++;
- break;
- case AST_CAUSE_NO_ROUTE_DESTINATION:
- case AST_CAUSE_UNREGISTERED:
- num->nochan++;
- break;
- case AST_CAUSE_NO_ANSWER:
- case AST_CAUSE_NORMAL_CLEARING:
- break;
- default:
- num->nochan++;
- break;
- }
- }
- static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri)
- {
- char rexten[2] = { exten, '\0' };
- if (context) {
- if (!ast_goto_if_exists(chan, context, rexten, pri))
- return 1;
- } else {
- if (!ast_goto_if_exists(chan, ast_channel_context(chan), rexten, pri))
- return 1;
- else if (!ast_strlen_zero(ast_channel_macrocontext(chan))) {
- if (!ast_goto_if_exists(chan, ast_channel_macrocontext(chan), rexten, pri))
- return 1;
- }
- }
- return 0;
- }
- static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
- {
- const char *context;
- const char *exten;
- ast_channel_lock(chan);
- context = ast_strdupa(S_OR(ast_channel_macrocontext(chan), ast_channel_context(chan)));
- exten = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
- ast_channel_unlock(chan);
- return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
- }
- static void do_forward(struct chanlist *o, struct cause_args *num,
- struct ast_flags64 *peerflags, int single, int caller_entertained, int *to,
- struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)
- {
- char tmpchan[256];
- struct ast_channel *original = o->chan;
- struct ast_channel *c = o->chan;
- struct ast_channel *in = num->chan;
- char *stuff;
- char *tech;
- int cause;
- struct ast_party_caller caller;
- ast_copy_string(tmpchan, ast_channel_call_forward(c), sizeof(tmpchan));
- if ((stuff = strchr(tmpchan, '/'))) {
- *stuff++ = '\0';
- tech = tmpchan;
- } else {
- const char *forward_context;
- ast_channel_lock(c);
- forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT");
- if (ast_strlen_zero(forward_context)) {
- forward_context = NULL;
- }
- snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(c), forward_context ? forward_context : ast_channel_context(c));
- ast_channel_unlock(c);
- stuff = tmpchan;
- tech = "Local";
- }
- if (!strcasecmp(tech, "Local")) {
-
- ast_clear_flag64(o, OPT_IGNORE_CONNECTEDLINE);
- }
-
- ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", ast_channel_name(in), tech, stuff, ast_channel_name(c));
-
- if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
- ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", ast_channel_name(in), tech, stuff);
- c = o->chan = NULL;
- cause = AST_CAUSE_BUSY;
- } else {
-
- c = o->chan = ast_request(tech, ast_channel_nativeformats(in), NULL, in, stuff, &cause);
- if (c) {
- if (single && !caller_entertained) {
- ast_channel_make_compatible(in, o->chan);
- }
- ast_channel_lock_both(in, o->chan);
- ast_channel_inherit_variables(in, o->chan);
- ast_channel_datastore_inherit(in, o->chan);
- ast_channel_unlock(in);
- ast_channel_unlock(o->chan);
-
- ast_ignore_cc(o->chan);
- ast_log(LOG_NOTICE, "Not accepting call completion offers from call-forward recipient %s\n", ast_channel_name(o->chan));
- } else
- ast_log(LOG_NOTICE,
- "Forwarding failed to create channel to dial '%s/%s' (cause = %d)\n",
- tech, stuff, cause);
- }
- if (!c) {
- ast_clear_flag64(o, DIAL_STILLGOING);
- handle_cause(cause, num);
- ast_hangup(original);
- } else {
- ast_channel_lock_both(c, original);
- ast_party_redirecting_copy(ast_channel_redirecting(c),
- ast_channel_redirecting(original));
- ast_channel_unlock(c);
- ast_channel_unlock(original);
- ast_channel_lock_both(c, in);
- if (single && !caller_entertained && CAN_EARLY_BRIDGE(peerflags, c, in)) {
- ast_rtp_instance_early_bridge_make_compatible(c, in);
- }
- if (!ast_channel_redirecting(c)->from.number.valid
- || ast_strlen_zero(ast_channel_redirecting(c)->from.number.str)) {
-
- ast_party_number_free(&ast_channel_redirecting(c)->from.number);
- ast_party_number_init(&ast_channel_redirecting(c)->from.number);
- ast_channel_redirecting(c)->from.number.valid = 1;
- ast_channel_redirecting(c)->from.number.str =
- ast_strdup(S_OR(ast_channel_macroexten(in), ast_channel_exten(in)));
- }
- ast_channel_dialed(c)->transit_network_select = ast_channel_dialed(in)->transit_network_select;
-
- ast_party_caller_set_init(&caller, ast_channel_caller(c));
- if (ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
- caller.id = *stored_clid;
- ast_channel_set_caller_event(c, &caller, NULL);
- ast_set_flag64(o, DIAL_CALLERID_ABSENT);
- } else if (ast_strlen_zero(S_COR(ast_channel_caller(c)->id.number.valid,
- ast_channel_caller(c)->id.number.str, NULL))) {
-
- caller.id = *stored_clid;
- ast_channel_set_caller_event(c, &caller, NULL);
- ast_set_flag64(o, DIAL_CALLERID_ABSENT);
- } else {
- ast_clear_flag64(o, DIAL_CALLERID_ABSENT);
- }
-
- if (ast_test_flag64(o, OPT_FORCECLID)) {
- struct ast_party_connected_line connected;
- ast_party_connected_line_init(&connected);
- connected.id = *forced_clid;
- ast_party_connected_line_copy(ast_channel_connected(c), &connected);
- } else {
- ast_connected_line_copy_from_caller(ast_channel_connected(c), ast_channel_caller(in));
- }
- ast_channel_accountcode_set(c, ast_channel_accountcode(in));
- ast_channel_appl_set(c, "AppDial");
- ast_channel_data_set(c, "(Outgoing Line)");
- ast_channel_publish_snapshot(c);
- ast_channel_unlock(in);
- if (single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
- struct ast_party_redirecting redirecting;
-
- ast_party_redirecting_init(&redirecting);
- ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(c));
- ast_channel_unlock(c);
- if (ast_channel_redirecting_sub(c, in, &redirecting, 0) &&
- ast_channel_redirecting_macro(c, in, &redirecting, 1, 0)) {
- ast_channel_update_redirecting(in, &redirecting, NULL);
- }
- ast_party_redirecting_free(&redirecting);
- } else {
- ast_channel_unlock(c);
- }
- if (ast_test_flag64(peerflags, OPT_CANCEL_TIMEOUT)) {
- *to = -1;
- }
- if (ast_call(c, stuff, 0)) {
- ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
- tech, stuff);
- ast_clear_flag64(o, DIAL_STILLGOING);
- ast_hangup(original);
- ast_hangup(c);
- c = o->chan = NULL;
- num->nochan++;
- } else {
- ast_channel_publish_dial(in, c, stuff, NULL);
- ast_channel_publish_dial_forward(in, original, c, NULL, "CANCEL",
- ast_channel_call_forward(original));
-
- ast_hangup(original);
- }
- if (single && !caller_entertained) {
- ast_indicate(in, -1);
- }
- }
- }
- struct privacy_args {
- int sentringing;
- int privdb_val;
- char privcid[256];
- char privintro[1024];
- char status[256];
- };
- static void publish_dial_end_event(struct ast_channel *in, struct dial_head *out_chans, struct ast_channel *exception, const char *status)
- {
- struct chanlist *outgoing;
- AST_LIST_TRAVERSE(out_chans, outgoing, node) {
- if (!outgoing->chan || outgoing->chan == exception) {
- continue;
- }
- ast_channel_publish_dial(in, outgoing->chan, NULL, status);
- }
- }
- static struct ast_channel *wait_for_answer(struct ast_channel *in,
- struct dial_head *out_chans, int *to, struct ast_flags64 *peerflags,
- char *opt_args[],
- struct privacy_args *pa,
- const struct cause_args *num_in, int *result, char *dtmf_progress,
- const int ignore_cc,
- struct ast_party_id *forced_clid, struct ast_party_id *stored_clid)
- {
- struct cause_args num = *num_in;
- int prestart = num.busy + num.congestion + num.nochan;
- int orig = *to;
- struct ast_channel *peer = NULL;
- #ifdef HAVE_EPOLL
- struct chanlist *epollo;
- #endif
- struct chanlist *outgoing = AST_LIST_FIRST(out_chans);
-
- int single = outgoing && !AST_LIST_NEXT(outgoing, node);
- int caller_entertained = outgoing
- && ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
- struct ast_party_connected_line connected_caller;
- struct ast_str *featurecode = ast_str_alloca(AST_FEATURE_MAX_LEN + 1);
- int cc_recall_core_id;
- int is_cc_recall;
- int cc_frame_received = 0;
- int num_ringing = 0;
- struct timeval start = ast_tvnow();
- ast_party_connected_line_init(&connected_caller);
- if (single) {
-
- if (!caller_entertained) {
- ast_deactivate_generator(in);
-
-
- if (ast_channel_make_compatible(in, outgoing->chan) < 0) {
-
- *to = -1;
- strcpy(pa->status, "CONGESTION");
- ast_channel_publish_dial(in, outgoing->chan, NULL, pa->status);
- return NULL;
- }
- }
- if (!ast_test_flag64(outgoing, OPT_IGNORE_CONNECTEDLINE)
- && !ast_test_flag64(outgoing, DIAL_CALLERID_ABSENT)) {
- ast_channel_lock(outgoing->chan);
- ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(outgoing->chan));
- ast_channel_unlock(outgoing->chan);
- connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(outgoing->chan, in, &connected_caller, 0) &&
- ast_channel_connected_line_macro(outgoing->chan, in, &connected_caller, 1, 0)) {
- ast_channel_update_connected_line(in, &connected_caller, NULL);
- }
- ast_party_connected_line_free(&connected_caller);
- }
- }
- is_cc_recall = ast_cc_is_recall(in, &cc_recall_core_id, NULL);
- #ifdef HAVE_EPOLL
- AST_LIST_TRAVERSE(out_chans, epollo, node) {
- ast_poll_channel_add(in, epollo->chan);
- }
- #endif
- while ((*to = ast_remaining_ms(start, orig)) && !peer) {
- struct chanlist *o;
- int pos = 0;
- int numlines = prestart;
- struct ast_channel *winner;
- struct ast_channel *watchers[AST_MAX_WATCHERS];
- watchers[pos++] = in;
- AST_LIST_TRAVERSE(out_chans, o, node) {
-
- if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan)
- watchers[pos++] = o->chan;
- numlines++;
- }
- if (pos == 1) {
- if (numlines == (num.busy + num.congestion + num.nochan)) {
- ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
- if (num.busy)
- strcpy(pa->status, "BUSY");
- else if (num.congestion)
- strcpy(pa->status, "CONGESTION");
- else if (num.nochan)
- strcpy(pa->status, "CHANUNAVAIL");
- } else {
- ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
- }
- *to = 0;
- if (is_cc_recall) {
- ast_cc_failed(cc_recall_core_id, "Everyone is busy/congested for the recall. How sad");
- }
- return NULL;
- }
- winner = ast_waitfor_n(watchers, pos, to);
- AST_LIST_TRAVERSE(out_chans, o, node) {
- struct ast_frame *f;
- struct ast_channel *c = o->chan;
- if (c == NULL)
- continue;
- if (ast_test_flag64(o, DIAL_STILLGOING) && ast_channel_state(c) == AST_STATE_UP) {
- if (!peer) {
- ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in));
- if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
- if (o->pending_connected_update) {
- if (ast_channel_connected_line_sub(c, in, &o->connected, 0) &&
- ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
- ast_channel_update_connected_line(in, &o->connected, NULL);
- }
- } else if (!ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
- ast_channel_lock(c);
- ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(c));
- ast_channel_unlock(c);
- connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(c, in, &connected_caller, 0) &&
- ast_channel_connected_line_macro(c, in, &connected_caller, 1, 0)) {
- ast_channel_update_connected_line(in, &connected_caller, NULL);
- }
- ast_party_connected_line_free(&connected_caller);
- }
- }
- if (o->aoc_s_rate_list) {
- size_t encoded_size;
- struct ast_aoc_encoded *encoded;
- if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
- ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
- ast_aoc_destroy_encoded(encoded);
- }
- }
- peer = c;
- ast_copy_flags64(peerflags, o,
- OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
- OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
- OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
- OPT_CALLEE_PARK | OPT_CALLER_PARK |
- OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
- DIAL_NOFORWARDHTML);
- ast_channel_dialcontext_set(c, "");
- ast_channel_exten_set(c, "");
- }
- continue;
- }
- if (c != winner)
- continue;
-
- if (!ast_strlen_zero(ast_channel_call_forward(c))) {
- pa->sentringing = 0;
- if (!ignore_cc && (f = ast_read(c))) {
- if (f->frametype == AST_FRAME_CONTROL && f->subclass.integer == AST_CONTROL_CC) {
-
- ast_handle_cc_control_frame(in, c, f->data.ptr);
- }
- ast_frfree(f);
- }
- if (o->pending_connected_update) {
-
- o->pending_connected_update = 0;
- ast_channel_lock(in);
- ast_party_connected_line_copy(&o->connected, ast_channel_connected(in));
- ast_channel_unlock(in);
- }
- do_forward(o, &num, peerflags, single, caller_entertained, &orig,
- forced_clid, stored_clid);
- if (single && o->chan
- && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)
- && !ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
- ast_channel_lock(o->chan);
- ast_connected_line_copy_from_caller(&connected_caller,
- ast_channel_caller(o->chan));
- ast_channel_unlock(o->chan);
- connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
- ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
- ast_channel_update_connected_line(in, &connected_caller, NULL);
- }
- ast_party_connected_line_free(&connected_caller);
- }
- continue;
- }
- f = ast_read(winner);
- if (!f) {
- ast_channel_hangupcause_set(in, ast_channel_hangupcause(c));
- #ifdef HAVE_EPOLL
- ast_poll_channel_del(in, c);
- #endif
- ast_channel_publish_dial(in, c, NULL, ast_hangup_cause_to_dial_status(ast_channel_hangupcause(c)));
- ast_hangup(c);
- c = o->chan = NULL;
- ast_clear_flag64(o, DIAL_STILLGOING);
- handle_cause(ast_channel_hangupcause(in), &num);
- continue;
- }
- switch (f->frametype) {
- case AST_FRAME_CONTROL:
- switch (f->subclass.integer) {
- case AST_CONTROL_ANSWER:
-
- if (!peer) {
- ast_verb(3, "%s answered %s\n", ast_channel_name(c), ast_channel_name(in));
- if (!single && !ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
- if (o->pending_connected_update) {
- if (ast_channel_connected_line_sub(c, in, &o->connected, 0) &&
- ast_channel_connected_line_macro(c, in, &o->connected, 1, 0)) {
- ast_channel_update_connected_line(in, &o->connected, NULL);
- }
- } else if (!ast_test_flag64(o, DIAL_CALLERID_ABSENT)) {
- ast_channel_lock(c);
- ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(c));
- ast_channel_unlock(c);
- connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
- if (ast_channel_connected_line_sub(c, in, &connected_caller, 0) &&
- ast_channel_connected_line_macro(c, in, &connected_caller, 1, 0)) {
- ast_channel_update_connected_line(in, &connected_caller, NULL);
- }
- ast_party_connected_line_free(&connected_caller);
- }
- }
- if (o->aoc_s_rate_list) {
- size_t encoded_size;
- struct ast_aoc_encoded *encoded;
- if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
- ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
- ast_aoc_destroy_encoded(encoded);
- }
- }
- peer = c;
-
- publish_dial_end_event(in, out_chans, peer, "CANCEL");
- ast_copy_flags64(peerflags, o,
- OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
- OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
- OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
- OPT_CALLEE_PARK | OPT_CALLER_PARK |
- OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
- DIAL_NOFORWARDHTML);
- ast_channel_dialcontext_set(c, "");
- ast_channel_exten_set(c, "");
- if (CAN_EARLY_BRIDGE(peerflags, in, peer)) {
-
- ast_channel_early_bridge(in, peer);
- }
- }
-
- ast_channel_hangupcause_set(in, AST_CAUSE_NORMAL_CLEARING);
- ast_channel_hangupcause_set(c, AST_CAUSE_NORMAL_CLEARING);
- break;
- case AST_CONTROL_BUSY:
- ast_verb(3, "%s is busy\n", ast_channel_name(c));
- ast_channel_hangupcause_set(in, ast_channel_hangupcause(c));
- ast_channel_publish_dial(in, c, NULL, "BUSY");
- ast_hangup(c);
- c = o->chan = NULL;
- ast_clear_flag64(o, DIAL_STILLGOING);
- handle_cause(AST_CAUSE_BUSY, &num);
- break;
- case AST_CONTROL_CONGESTION:
- ast_verb(3, "%s is circuit-busy\n", ast_channel_name(c));
- ast_channel_hangupcause_set(in, ast_channel_hangupcause(c));
- ast_channel_publish_dial(in, c, NULL, "CONGESTION");
- ast_hangup(c);
- c = o->chan = NULL;
- ast_clear_flag64(o, DIAL_STILLGOING);
- handle_cause(AST_CAUSE_CONGESTION, &num);
- break;
- case AST_CONTROL_RINGING:
-
- ++num_ringing;
- if (ignore_cc || cc_frame_received || num_ringing == numlines) {
- ast_verb(3, "%s is ringing\n", ast_channel_name(c));
-
- if (single && !caller_entertained
- && CAN_EARLY_BRIDGE(peerflags, in, c)) {
- ast_channel_early_bridge(in, c);
- }
- if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK) && ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) {
- ast_indicate(in, AST_CONTROL_RINGING);
- pa->sentringing++;
- }
- }
- break;
- case AST_CONTROL_PROGRESS:
- ast_verb(3, "%s is making progress passing it to %s\n", ast_channel_name(c), ast_channel_name(in));
-
- if (single && !caller_entertained
- && CAN_EARLY_BRIDGE(peerflags, in, c)) {
- ast_channel_early_bridge(in, c);
- }
- if (!ast_test_flag64(outgoing, OPT_RINGBACK)) {
- if (single || (!single && !pa->sentringing)) {
- ast_indicate(in, AST_CONTROL_PROGRESS);
- }
- }
- if (!ast_strlen_zero(dtmf_progress)) {
- ast_verb(3,
- "Sending DTMF '%s' to the called party as result of receiving a PROGRESS message.\n",
- dtmf_progress);
- ast_dtmf_stream(c, in, dtmf_progress, 250, 0);
- }
- break;
- case AST_CONTROL_VIDUPDATE:
- case AST_CONTROL_SRCUPDATE:
- case AST_CONTROL_SRCCHANGE:
- if (!single || caller_entertained) {
- break;
- }
- ast_verb(3, "%s requested media update control %d, passing it to %s\n",
- ast_channel_name(c), f->subclass.integer, ast_channel_name(in));
- ast_indicate(in, f->subclass.integer);
- break;
- case AST_CONTROL_CONNECTED_LINE:
- if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
- ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(in));
- break;
- }
- if (!single) {
- struct ast_party_connected_line connected;
- ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n",
- ast_channel_name(c), ast_channel_name(in));
- ast_party_connected_line_set_init(&connected, &o->connected);
- ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
- ast_party_connected_line_set(&o->connected, &connected, NULL);
- ast_party_connected_line_free(&connected);
- o->pending_connected_update = 1;
- break;
- }
- if (ast_channel_connected_line_sub(c, in, f, 1) &&
- ast_channel_connected_line_macro(c, in, f, 1, 1)) {
- ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
- }
- break;
- case AST_CONTROL_AOC:
- {
- struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
- if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
- ast_aoc_destroy_decoded(o->aoc_s_rate_list);
- o->aoc_s_rate_list = decoded;
- } else {
- ast_aoc_destroy_decoded(decoded);
- }
- }
- break;
- case AST_CONTROL_REDIRECTING:
- if (!single) {
-
- break;
- }
- if (ast_test_flag64(o, OPT_IGNORE_CONNECTEDLINE)) {
- ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(in));
- break;
- }
- ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
- ast_channel_name(c), ast_channel_name(in));
- if (ast_channel_redirecting_sub(c, in, f, 1) &&
- ast_channel_redirecting_macro(c, in, f, 1, 1)) {
- ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
- }
- pa->sentringing = 0;
- break;
- case AST_CONTROL_PROCEEDING:
- ast_verb(3, "%s is proceeding passing it to %s\n", ast_channel_name(c), ast_channel_name(in));
- if (single && !caller_entertained
- && CAN_EARLY_BRIDGE(peerflags, in, c)) {
- ast_channel_early_bridge(in, c);
- }
- if (!ast_test_flag64(outgoing, OPT_RINGBACK))
- ast_indicate(in, AST_CONTROL_PROCEEDING);
- break;
- case AST_CONTROL_HOLD:
-
- ast_verb(3, "Call on %s placed on hold\n", ast_channel_name(c));
- ast_indicate_data(in, AST_CONTROL_HOLD, f->data.ptr, f->datalen);
- break;
- case AST_CONTROL_UNHOLD:
-
- ast_verb(3, "Call on %s left from hold\n", ast_channel_name(c));
- ast_indicate(in, AST_CONTROL_UNHOLD);
- break;
- case AST_CONTROL_OFFHOOK:
- case AST_CONTROL_FLASH:
-
- break;
- case AST_CONTROL_CC:
- if (!ignore_cc) {
- ast_handle_cc_control_frame(in, c, f->data.ptr);
- cc_frame_received = 1;
- }
- break;
- case AST_CONTROL_PVT_CAUSE_CODE:
- ast_indicate_data(in, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen);
- break;
- case -1:
- if (single && !caller_entertained) {
- ast_verb(3, "%s stopped sounds\n", ast_channel_name(c));
- ast_indicate(in, -1);
- pa->sentringing = 0;
- }
- break;
- default:
- ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
- break;
- }
- break;
- case AST_FRAME_VOICE:
- case AST_FRAME_IMAGE:
- if (caller_entertained) {
- break;
- }
-
- case AST_FRAME_TEXT:
- if (single && ast_write(in, f)) {
- ast_log(LOG_WARNING, "Unable to write frametype: %u\n",
- f->frametype);
- }
- break;
- case AST_FRAME_HTML:
- if (single && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)
- && ast_channel_sendhtml(in, f->subclass.integer, f->data.ptr, f->datalen) == -1) {
- ast_log(LOG_WARNING, "Unable to send URL\n");
- }
- break;
- default:
- break;
- }
- ast_frfree(f);
- }
- if (winner == in) {
- struct ast_frame *f = ast_read(in);
- #if 0
- if (f && (f->frametype != AST_FRAME_VOICE))
- printf("Frame type: %d, %d\n", f->frametype, f->subclass);
- else if (!f || (f->frametype != AST_FRAME_VOICE))
- printf("Hangup received on %s\n", in->name);
- #endif
- if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
-
- *to = -1;
- strcpy(pa->status, "CANCEL");
- publish_dial_end_event(in, out_chans, NULL, pa->status);
- if (f) {
- if (f->data.uint32) {
- ast_channel_hangupcause_set(in, f->data.uint32);
- }
- ast_frfree(f);
- }
- if (is_cc_recall) {
- ast_cc_completed(in, "CC completed, although the caller hung up (cancelled)");
- }
- return NULL;
- }
-
- if (f->frametype == AST_FRAME_DTMF) {
- if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) {
- const char *context;
- ast_channel_lock(in);
- context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
- if (onedigit_goto(in, context, (char) f->subclass.integer, 1)) {
- ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
- *to = 0;
- *result = f->subclass.integer;
- strcpy(pa->status, "CANCEL");
- publish_dial_end_event(in, out_chans, NULL, pa->status);
- ast_frfree(f);
- ast_channel_unlock(in);
- if (is_cc_recall) {
- ast_cc_completed(in, "CC completed, but the caller used DTMF to exit");
- }
- return NULL;
- }
- ast_channel_unlock(in);
- }
- if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
- detect_disconnect(in, f->subclass.integer, &featurecode)) {
- ast_verb(3, "User requested call disconnect.\n");
- *to = 0;
- strcpy(pa->status, "CANCEL");
- publish_dial_end_event(in, out_chans, NULL, pa->status);
- ast_frfree(f);
- if (is_cc_recall) {
- ast_cc_completed(in, "CC completed, but the caller hung up with DTMF");
- }
- return NULL;
- }
- }
-
- AST_LIST_TRAVERSE(out_chans, o, node) {
- if (!o->chan || !ast_test_flag64(o, DIAL_STILLGOING)) {
-
- continue;
- }
- switch (f->frametype) {
- case AST_FRAME_HTML:
-
- if (!ast_test_flag64(o, DIAL_NOFORWARDHTML)
- && ast_channel_sendhtml(o->chan, f->subclass.integer, f->data.ptr, f->datalen) == -1) {
- ast_log(LOG_WARNING, "Unable to send URL\n");
- }
- break;
- case AST_FRAME_VOICE:
- case AST_FRAME_IMAGE:
- if (!single || caller_entertained) {
-
- goto skip_frame;
- }
-
- case AST_FRAME_TEXT:
- case AST_FRAME_DTMF_BEGIN:
- case AST_FRAME_DTMF_END:
- if (ast_write(o->chan, f)) {
- ast_log(LOG_WARNING, "Unable to forward frametype: %u\n",
- f->frametype);
- }
- break;
- case AST_FRAME_CONTROL:
- switch (f->subclass.integer) {
- case AST_CONTROL_HOLD:
- ast_verb(3, "Call on %s placed on hold\n", ast_channel_name(o->chan));
- ast_indicate_data(o->chan, AST_CONTROL_HOLD, f->data.ptr, f->datalen);
- break;
- case AST_CONTROL_UNHOLD:
- ast_verb(3, "Call on %s left from hold\n", ast_channel_name(o->chan));
- ast_indicate(o->chan, AST_CONTROL_UNHOLD);
- break;
- case AST_CONTROL_VIDUPDATE:
- case AST_CONTROL_SRCUPDATE:
- case AST_CONTROL_SRCCHANGE:
- if (!single || caller_entertained) {
-
- goto skip_frame;
- }
- ast_verb(3, "%s requested media update control %d, passing it to %s\n",
- ast_channel_name(in), f->subclass.integer, ast_channel_name(o->chan));
- ast_indicate(o->chan, f->subclass.integer);
- break;
- case AST_CONTROL_CONNECTED_LINE:
- if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
- ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
- ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
- }
- break;
- case AST_CONTROL_REDIRECTING:
- if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
- ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
- ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
- }
- break;
- default:
-
- goto skip_frame;
- }
- break;
- default:
-
- goto skip_frame;
- }
- }
- skip_frame:;
- ast_frfree(f);
- }
- }
- if (!*to || ast_check_hangup(in)) {
- ast_verb(3, "Nobody picked up in %d ms\n", orig);
- publish_dial_end_event(in, out_chans, NULL, "NOANSWER");
- }
- #ifdef HAVE_EPOLL
- AST_LIST_TRAVERSE(out_chans, epollo, node) {
- if (epollo->chan)
- ast_poll_channel_del(in, epollo->chan);
- }
- #endif
- if (is_cc_recall) {
- ast_cc_completed(in, "Recall completed!");
- }
- return peer;
- }
- static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str **featurecode)
- {
- char disconnect_code[AST_FEATURE_MAX_LEN];
- int res;
- ast_str_append(featurecode, 1, "%c", code);
- res = ast_get_builtin_feature(chan, "disconnect", disconnect_code, sizeof(disconnect_code));
- if (res) {
- ast_str_reset(*featurecode);
- return 0;
- }
- if (strlen(disconnect_code) > ast_str_strlen(*featurecode)) {
-
- if (strncmp(disconnect_code, ast_str_buffer(*featurecode), ast_str_strlen(*featurecode))) {
- ast_str_reset(*featurecode);
- }
- return 0;
- }
- if (strcmp(disconnect_code, ast_str_buffer(*featurecode))) {
- ast_str_reset(*featurecode);
- return 0;
- }
- return 1;
- }
- static int valid_priv_reply(struct ast_flags64 *opts, int res)
- {
- if (res < '1')
- return 0;
- if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5')
- return 1;
- if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4')
- return 1;
- return 0;
- }
- static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
- struct ast_flags64 *opts, char **opt_args, struct privacy_args *pa)
- {
- int res2;
- int loopcount = 0;
-
-
- if (ast_test_flag64(opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
- char *original_moh = ast_strdupa(ast_channel_musicclass(chan));
- ast_indicate(chan, -1);
- ast_channel_musicclass_set(chan, opt_args[OPT_ARG_MUSICBACK]);
- ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
- ast_channel_musicclass_set(chan, original_moh);
- } else if (ast_test_flag64(opts, OPT_RINGBACK)) {
- ast_indicate(chan, AST_CONTROL_RINGING);
- pa->sentringing++;
- }
-
- res2 = ast_autoservice_start(chan);
-
- for (loopcount = 0; loopcount < 3; loopcount++) {
- if (res2 && loopcount == 0)
- break;
- if (!res2)
- res2 = ast_play_and_wait(peer, "priv-callpending");
- if (!valid_priv_reply(opts, res2))
- res2 = 0;
-
- if (!res2)
- res2 = ast_play_and_wait(peer, pa->privintro);
- if (!valid_priv_reply(opts, res2))
- res2 = 0;
-
- if (!res2) {
-
- if (ast_test_flag64(opts, OPT_PRIVACY))
- res2 = ast_play_and_wait(peer, "priv-callee-options");
- if (ast_test_flag64(opts, OPT_SCREENING))
- res2 = ast_play_and_wait(peer, "screen-callee-options");
- }
-
- if (valid_priv_reply(opts, res2))
- break;
-
- res2 = ast_play_and_wait(peer, "vm-sorry");
- }
- if (ast_test_flag64(opts, OPT_MUSICBACK)) {
- ast_moh_stop(chan);
- } else if (ast_test_flag64(opts, OPT_RINGBACK)) {
- ast_indicate(chan, -1);
- pa->sentringing = 0;
- }
- ast_autoservice_stop(chan);
- if (ast_test_flag64(opts, OPT_PRIVACY) && (res2 >= '1' && res2 <= '5')) {
-
- static const char * const _val[] = { "ALLOW", "DENY", "TORTURE", "KILL", "ALLOW" };
- static const int _flag[] = { AST_PRIVACY_ALLOW, AST_PRIVACY_DENY, AST_PRIVACY_TORTURE, AST_PRIVACY_KILL, AST_PRIVACY_ALLOW};
- int i = res2 - '1';
- ast_verb(3, "--Set privacy database entry %s/%s to %s\n",
- opt_args[OPT_ARG_PRIVACY], pa->privcid, _val[i]);
- ast_privacy_set(opt_args[OPT_ARG_PRIVACY], pa->privcid, _flag[i]);
- }
- switch (res2) {
- case '1':
- break;
- case '2':
- ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status));
- break;
- case '3':
- ast_copy_string(pa->status, "TORTURE", sizeof(pa->status));
- break;
- case '4':
- ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status));
- break;
- case '5':
-
- if (ast_test_flag64(opts, OPT_PRIVACY))
- break;
-
- default:
-
-
-
- ast_log(LOG_NOTICE, "privacy: no valid response from the callee. Sending the caller to voicemail, the callee isn't responding\n");
-
-
- break;
- }
- if (res2 == '1') {
-
- if (strncmp(pa->privcid, "NOCALLERID", 10) == 0 || ast_test_flag64(opts, OPT_SCREEN_NOINTRO)) {
- ast_filedelete(pa->privintro, NULL);
- if (ast_fileexists(pa->privintro, NULL, NULL) > 0)
- ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro);
- else
- ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro);
- }
- return 0;
- } else {
-
- ast_autoservice_chan_hangup_peer(chan, peer);
- return -1;
- }
- }
- static int setup_privacy_args(struct privacy_args *pa,
- struct ast_flags64 *opts, char *opt_args[], struct ast_channel *chan)
- {
- char callerid[60];
- int res;
- char *l;
- if (ast_channel_caller(chan)->id.number.valid
- && !ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
- l = ast_strdupa(ast_channel_caller(chan)->id.number.str);
- ast_shrink_phone_number(l);
- if (ast_test_flag64(opts, OPT_PRIVACY) ) {
- ast_verb(3, "Privacy DB is '%s', clid is '%s'\n", opt_args[OPT_ARG_PRIVACY], l);
- pa->privdb_val = ast_privacy_check(opt_args[OPT_ARG_PRIVACY], l);
- } else {
- ast_verb(3, "Privacy Screening, clid is '%s'\n", l);
- pa->privdb_val = AST_PRIVACY_UNKNOWN;
- }
- } else {
- char *tnam, *tn2;
- tnam = ast_strdupa(ast_channel_name(chan));
-
- for (tn2 = tnam; *tn2; tn2++) {
- if (*tn2 == '/')
- *tn2 = '=';
- }
- ast_verb(3, "Privacy-- callerid is empty\n");
- snprintf(callerid, sizeof(callerid), "NOCALLERID_%s%s", ast_channel_exten(chan), tnam);
- l = callerid;
- pa->privdb_val = AST_PRIVACY_UNKNOWN;
- }
- ast_copy_string(pa->privcid, l, sizeof(pa->privcid));
- if (strncmp(pa->privcid, "NOCALLERID", 10) != 0 && ast_test_flag64(opts, OPT_SCREEN_NOCALLERID)) {
-
- ast_verb(3, "CallerID set (%s); N option set; Screening should be off\n", pa->privcid);
- pa->privdb_val = AST_PRIVACY_ALLOW;
- } else if (ast_test_flag64(opts, OPT_SCREEN_NOCALLERID) && strncmp(pa->privcid, "NOCALLERID", 10) == 0) {
- ast_verb(3, "CallerID blank; N option set; Screening should happen; dbval is %d\n", pa->privdb_val);
- }
- if (pa->privdb_val == AST_PRIVACY_DENY) {
- ast_verb(3, "Privacy DB reports PRIVACY_DENY for this callerid. Dial reports unavailable\n");
- ast_copy_string(pa->status, "NOANSWER", sizeof(pa->status));
- return 0;
- } else if (pa->privdb_val == AST_PRIVACY_KILL) {
- ast_copy_string(pa->status, "DONTCALL", sizeof(pa->status));
- return 0;
- } else if (pa->privdb_val == AST_PRIVACY_TORTURE) {
- ast_copy_string(pa->status, "TORTURE", sizeof(pa->status));
- return 0;
- } else if (pa->privdb_val == AST_PRIVACY_UNKNOWN) {
-
-
- snprintf(pa->privintro, sizeof(pa->privintro), "%s/sounds/priv-callerintros", ast_config_AST_DATA_DIR);
- if ((res = ast_mkdir(pa->privintro, 0755))) {
- ast_log(LOG_WARNING, "privacy: can't create directory priv-callerintros: %s\n", strerror(res));
- return -1;
- }
- snprintf(pa->privintro, sizeof(pa->privintro), "priv-callerintros/%s", pa->privcid);
- if (ast_fileexists(pa->privintro, NULL, NULL ) > 0 && strncmp(pa->privcid, "NOCALLERID", 10) != 0) {
-
- } else {
- int duration;
-
-
- int silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
- ast_answer(chan);
- res = ast_play_and_record(chan, "priv-recordintro", pa->privintro, 4, "sln", &duration, NULL, silencethreshold, 2000, 0);
-
- if (res == -1) {
-
- ast_filedelete(pa->privintro, NULL);
- if (ast_fileexists(pa->privintro, NULL, NULL) > 0)
- ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa->privintro);
- else
- ast_verb(3, "Successfully deleted %s intro file\n", pa->privintro);
- return -1;
- }
- if (!ast_streamfile(chan, "vm-dialout", ast_channel_language(chan)) )
- ast_waitstream(chan, "");
- }
- }
- return 1;
- }
- static void end_bridge_callback(void *data)
- {
- char buf[80];
- time_t end;
- struct ast_channel *chan = data;
- time(&end);
- ast_channel_lock(chan);
- ast_channel_stage_snapshot(chan);
- snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
- pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
- snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
- pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
- ast_channel_stage_snapshot_done(chan);
- ast_channel_unlock(chan);
- }
- static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator) {
- bconfig->end_bridge_callback_data = originator;
- }
- static int dial_handle_playtones(struct ast_channel *chan, const char *data)
- {
- struct ast_tone_zone_sound *ts = NULL;
- int res;
- const char *str = data;
- if (ast_strlen_zero(str)) {
- ast_debug(1,"Nothing to play\n");
- return -1;
- }
- ts = ast_get_indication_tone(ast_channel_zone(chan), str);
- if (ts && ts->data[0]) {
- res = ast_playtones_start(chan, 0, ts->data, 0);
- } else {
- res = -1;
- }
- if (ts) {
- ts = ast_tone_zone_sound_unref(ts);
- }
- if (res) {
- ast_log(LOG_WARNING, "Unable to start playtone \'%s\'\n", str);
- }
- return res;
- }
- static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags64 *opts, char *opt_args[])
- {
- const char *context;
- const char *extension;
- int priority;
- if (ast_test_flag64(opts, OPT_PEER_H)) {
- ast_channel_lock(chan);
- context = ast_strdupa(ast_channel_context(chan));
- ast_channel_unlock(chan);
- ast_bridge_set_after_h(peer, context);
- } else if (ast_test_flag64(opts, OPT_CALLEE_GO_ON)) {
- ast_channel_lock(chan);
- context = ast_strdupa(ast_channel_context(chan));
- extension = ast_strdupa(ast_channel_exten(chan));
- priority = ast_channel_priority(chan);
- ast_channel_unlock(chan);
- ast_bridge_set_after_go_on(peer, context, extension, priority,
- opt_args[OPT_ARG_CALLEE_GO_ON]);
- }
- }
- static int dial_exec_full(struct ast_channel *chan, const char *data, struct ast_flags64 *peerflags, int *continue_exec)
- {
- int res = -1;
- char *rest, *cur;
- struct dial_head out_chans = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
- struct chanlist *outgoing;
- struct chanlist *tmp;
- struct ast_channel *peer;
- int to;
- struct cause_args num = { chan, 0, 0, 0 };
- int cause;
- struct ast_bridge_config config = { { 0, } };
- struct timeval calldurationlimit = { 0, };
- char *dtmfcalled = NULL, *dtmfcalling = NULL, *dtmf_progress=NULL;
- struct privacy_args pa = {
- .sentringing = 0,
- .privdb_val = 0,
- .status = "INVALIDARGS",
- };
- int sentringing = 0, moh = 0;
- const char *outbound_group = NULL;
- int result = 0;
- char *parse;
- int opermode = 0;
- int delprivintro = 0;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(peers);
- AST_APP_ARG(timeout);
- AST_APP_ARG(options);
- AST_APP_ARG(url);
- );
- struct ast_flags64 opts = { 0, };
- char *opt_args[OPT_ARG_ARRAY_SIZE];
- struct ast_datastore *datastore = NULL;
- int fulldial = 0, num_dialed = 0;
- int ignore_cc = 0;
- char device_name[AST_CHANNEL_NAME];
- char forced_clid_name[AST_MAX_EXTENSION];
- char stored_clid_name[AST_MAX_EXTENSION];
- int force_forwards_only;
-
- struct ast_party_id forced_clid;
-
- struct ast_party_id stored_clid;
-
- struct ast_party_caller caller;
-
- ast_channel_lock(chan);
- ast_channel_stage_snapshot(chan);
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", "");
- pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", "");
- pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", "");
- pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", "");
- pbx_builtin_setvar_helper(chan, "DIALEDTIME", "");
- ast_channel_stage_snapshot_done(chan);
- ast_channel_unlock(chan);
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
- return -1;
- }
- parse = ast_strdupa(data);
- AST_STANDARD_APP_ARGS(args, parse);
- if (!ast_strlen_zero(args.options) &&
- ast_app_parse_options64(dial_exec_options, &opts, opt_args, args.options)) {
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
- goto done;
- }
- if (ast_strlen_zero(args.peers)) {
- ast_log(LOG_WARNING, "Dial requires an argument (technology/resource)\n");
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
- goto done;
- }
- if (ast_cc_call_init(chan, &ignore_cc)) {
- goto done;
- }
- if (ast_test_flag64(&opts, OPT_SCREEN_NOINTRO) && !ast_strlen_zero(opt_args[OPT_ARG_SCREEN_NOINTRO])) {
- delprivintro = atoi(opt_args[OPT_ARG_SCREEN_NOINTRO]);
- if (delprivintro < 0 || delprivintro > 1) {
- ast_log(LOG_WARNING, "Unknown argument %d specified to n option, ignoring\n", delprivintro);
- delprivintro = 0;
- }
- }
- if (!ast_test_flag64(&opts, OPT_RINGBACK)) {
- opt_args[OPT_ARG_RINGBACK] = NULL;
- }
- if (ast_test_flag64(&opts, OPT_OPERMODE)) {
- opermode = ast_strlen_zero(opt_args[OPT_ARG_OPERMODE]) ? 1 : atoi(opt_args[OPT_ARG_OPERMODE]);
- ast_verb(3, "Setting operator services mode to %d.\n", opermode);
- }
- if (ast_test_flag64(&opts, OPT_DURATION_STOP) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_STOP])) {
- calldurationlimit.tv_sec = atoi(opt_args[OPT_ARG_DURATION_STOP]);
- if (!calldurationlimit.tv_sec) {
- ast_log(LOG_WARNING, "Dial does not accept S(%s), hanging up.\n", opt_args[OPT_ARG_DURATION_STOP]);
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
- goto done;
- }
- ast_verb(3, "Setting call duration limit to %.3lf seconds.\n", calldurationlimit.tv_sec + calldurationlimit.tv_usec / 1000000.0);
- }
- if (ast_test_flag64(&opts, OPT_SENDDTMF) && !ast_strlen_zero(opt_args[OPT_ARG_SENDDTMF])) {
- dtmf_progress = opt_args[OPT_ARG_SENDDTMF];
- dtmfcalled = strsep(&dtmf_progress, ":");
- dtmfcalling = strsep(&dtmf_progress, ":");
- }
- if (ast_test_flag64(&opts, OPT_DURATION_LIMIT) && !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])) {
- if (ast_bridge_timelimit(chan, &config, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit))
- goto done;
- }
-
- ast_party_id_init(&forced_clid);
- force_forwards_only = 0;
- if (ast_test_flag64(&opts, OPT_FORCECLID)) {
- if (ast_strlen_zero(opt_args[OPT_ARG_FORCECLID])) {
- ast_channel_lock(chan);
- forced_clid.number.str = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
- ast_channel_unlock(chan);
- forced_clid_name[0] = '\0';
- forced_clid.name.str = (char *) get_cid_name(forced_clid_name,
- sizeof(forced_clid_name), chan);
- force_forwards_only = 1;
- } else {
-
- ast_callerid_parse(opt_args[OPT_ARG_FORCECLID], &forced_clid.name.str,
- &forced_clid.number.str);
- }
- if (!ast_strlen_zero(forced_clid.name.str)) {
- forced_clid.name.valid = 1;
- }
- if (!ast_strlen_zero(forced_clid.number.str)) {
- forced_clid.number.valid = 1;
- }
- }
- if (ast_test_flag64(&opts, OPT_FORCE_CID_TAG)
- && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CID_TAG])) {
- forced_clid.tag = opt_args[OPT_ARG_FORCE_CID_TAG];
- }
- forced_clid.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN;
- if (ast_test_flag64(&opts, OPT_FORCE_CID_PRES)
- && !ast_strlen_zero(opt_args[OPT_ARG_FORCE_CID_PRES])) {
- int pres;
- pres = ast_parse_caller_presentation(opt_args[OPT_ARG_FORCE_CID_PRES]);
- if (0 <= pres) {
- forced_clid.number.presentation = pres;
- }
- }
-
- ast_party_id_init(&stored_clid);
- if (ast_test_flag64(&opts, OPT_ORIGINAL_CLID)) {
- if (ast_strlen_zero(opt_args[OPT_ARG_ORIGINAL_CLID])) {
- ast_channel_lock(chan);
- ast_party_id_set_init(&stored_clid, &ast_channel_caller(chan)->id);
- if (!ast_strlen_zero(ast_channel_caller(chan)->id.name.str)) {
- stored_clid.name.str = ast_strdupa(ast_channel_caller(chan)->id.name.str);
- }
- if (!ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
- stored_clid.number.str = ast_strdupa(ast_channel_caller(chan)->id.number.str);
- }
- if (!ast_strlen_zero(ast_channel_caller(chan)->id.subaddress.str)) {
- stored_clid.subaddress.str = ast_strdupa(ast_channel_caller(chan)->id.subaddress.str);
- }
- if (!ast_strlen_zero(ast_channel_caller(chan)->id.tag)) {
- stored_clid.tag = ast_strdupa(ast_channel_caller(chan)->id.tag);
- }
- ast_channel_unlock(chan);
- } else {
-
- ast_callerid_parse(opt_args[OPT_ARG_ORIGINAL_CLID], &stored_clid.name.str,
- &stored_clid.number.str);
- if (!ast_strlen_zero(stored_clid.name.str)) {
- stored_clid.name.valid = 1;
- }
- if (!ast_strlen_zero(stored_clid.number.str)) {
- stored_clid.number.valid = 1;
- }
- }
- } else {
-
- stored_clid_name[0] = '\0';
- stored_clid.name.str = (char *) get_cid_name(stored_clid_name,
- sizeof(stored_clid_name), chan);
- if (ast_strlen_zero(stored_clid.name.str)) {
- stored_clid.name.str = NULL;
- } else {
- stored_clid.name.valid = 1;
- }
- ast_channel_lock(chan);
- stored_clid.number.str = ast_strdupa(S_OR(ast_channel_macroexten(chan), ast_channel_exten(chan)));
- stored_clid.number.valid = 1;
- ast_channel_unlock(chan);
- }
- if (ast_test_flag64(&opts, OPT_RESETCDR)) {
- ast_cdr_reset(ast_channel_name(chan), 0);
- }
- if (ast_test_flag64(&opts, OPT_PRIVACY) && ast_strlen_zero(opt_args[OPT_ARG_PRIVACY]))
- opt_args[OPT_ARG_PRIVACY] = ast_strdupa(ast_channel_exten(chan));
- if (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) {
- res = setup_privacy_args(&pa, &opts, opt_args, chan);
- if (res <= 0)
- goto out;
- res = -1;
- }
- if (continue_exec)
- *continue_exec = 0;
-
- ast_channel_lock(chan);
- if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP_ONCE"))) {
- outbound_group = ast_strdupa(outbound_group);
- pbx_builtin_setvar_helper(chan, "OUTBOUND_GROUP_ONCE", NULL);
- } else if ((outbound_group = pbx_builtin_getvar_helper(chan, "OUTBOUND_GROUP"))) {
- outbound_group = ast_strdupa(outbound_group);
- }
- ast_channel_unlock(chan);
-
- ast_copy_flags64(peerflags, &opts, OPT_DTMF_EXIT | OPT_GO_ON | OPT_ORIGINAL_CLID
- | OPT_CALLER_HANGUP | OPT_IGNORE_FORWARDING | OPT_CANCEL_TIMEOUT
- | OPT_ANNOUNCE | OPT_CALLEE_MACRO | OPT_CALLEE_GOSUB | OPT_FORCECLID);
-
- if (ast_test_flag64(&opts, OPT_PREDIAL_CALLER)
- && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLER]);
- ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
- }
-
- rest = args.peers;
- while ((cur = strsep(&rest, "&")) ) {
- struct ast_channel *tc;
-
- char *number = cur;
- char *tech = strsep(&number, "/");
- size_t tech_len;
- size_t number_len;
-
- struct ast_dialed_interface *di;
- AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
- num_dialed++;
- if (ast_strlen_zero(number)) {
- ast_log(LOG_WARNING, "Dial argument takes format (technology/resource)\n");
- goto out;
- }
- tech_len = strlen(tech) + 1;
- number_len = strlen(number) + 1;
- tmp = ast_calloc(1, sizeof(*tmp) + (2 * tech_len) + number_len);
- if (!tmp) {
- goto out;
- }
-
- cur = tmp->stuff;
- strcpy(cur, tech);
- tmp->tech = cur;
- cur += tech_len;
- strcpy(cur, tech);
- cur[tech_len - 1] = '/';
- tmp->interface = cur;
- cur += tech_len;
- strcpy(cur, number);
- tmp->number = cur;
- if (opts.flags) {
-
- ast_copy_flags64(tmp, &opts,
- OPT_CANCEL_ELSEWHERE |
- OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
- OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
- OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
- OPT_CALLEE_PARK | OPT_CALLER_PARK |
- OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
- OPT_RINGBACK | OPT_MUSICBACK | OPT_FORCECLID | OPT_IGNORE_CONNECTEDLINE);
- ast_set2_flag64(tmp, args.url, DIAL_NOFORWARDHTML);
- }
-
- ast_channel_lock(chan);
- datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
-
- ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(chan));
- ast_channel_unlock(chan);
- if (datastore)
- dialed_interfaces = datastore->data;
- else {
- if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
- ast_log(LOG_WARNING, "Unable to create channel datastore for dialed interfaces. Aborting!\n");
- chanlist_free(tmp);
- goto out;
- }
- datastore->inheritance = DATASTORE_INHERIT_FOREVER;
- if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
- ast_datastore_free(datastore);
- chanlist_free(tmp);
- goto out;
- }
- datastore->data = dialed_interfaces;
- AST_LIST_HEAD_INIT(dialed_interfaces);
- ast_channel_lock(chan);
- ast_channel_datastore_add(chan, datastore);
- ast_channel_unlock(chan);
- }
- AST_LIST_LOCK(dialed_interfaces);
- AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
- if (!strcasecmp(di->interface, tmp->interface)) {
- ast_log(LOG_WARNING, "Skipping dialing interface '%s' again since it has already been dialed\n",
- di->interface);
- break;
- }
- }
- AST_LIST_UNLOCK(dialed_interfaces);
- if (di) {
- fulldial++;
- chanlist_free(tmp);
- continue;
- }
-
- if (strcasecmp(tmp->tech, "Local")) {
- if (!(di = ast_calloc(1, sizeof(*di) + strlen(tmp->interface)))) {
- chanlist_free(tmp);
- goto out;
- }
- strcpy(di->interface, tmp->interface);
- AST_LIST_LOCK(dialed_interfaces);
- AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
- AST_LIST_UNLOCK(dialed_interfaces);
- }
- tc = ast_request(tmp->tech, ast_channel_nativeformats(chan), NULL, chan, tmp->number, &cause);
- if (!tc) {
-
- ast_log(LOG_WARNING, "Unable to create channel of type '%s' (cause %d - %s)\n",
- tmp->tech, cause, ast_cause2str(cause));
- handle_cause(cause, &num);
- if (!rest) {
-
- ast_channel_hangupcause_set(chan, cause);
- }
- if (!ignore_cc && (cause == AST_CAUSE_BUSY || cause == AST_CAUSE_CONGESTION)) {
- if (!ast_cc_callback(chan, tmp->tech, tmp->number, ast_cc_busy_interface)) {
- ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, "");
- }
- }
- chanlist_free(tmp);
- continue;
- }
- ast_channel_lock(tc);
- ast_channel_stage_snapshot(tc);
- ast_channel_unlock(tc);
- ast_channel_get_device_name(tc, device_name, sizeof(device_name));
- if (!ignore_cc) {
- ast_cc_extension_monitor_add_dialstring(chan, tmp->interface, device_name);
- }
- ast_channel_lock_both(tc, chan);
- pbx_builtin_setvar_helper(tc, "DIALEDPEERNUMBER", tmp->number);
-
- if (!AST_LIST_FIRST(&out_chans) && !rest && CAN_EARLY_BRIDGE(peerflags, chan, tc)) {
-
- ast_rtp_instance_early_bridge_make_compatible(tc, chan);
- }
-
- ast_channel_inherit_variables(chan, tc);
- ast_channel_datastore_inherit(chan, tc);
- ast_channel_appl_set(tc, "AppDial");
- ast_channel_data_set(tc, "(Outgoing Line)");
- ast_channel_publish_snapshot(tc);
- memset(ast_channel_whentohangup(tc), 0, sizeof(*ast_channel_whentohangup(tc)));
-
- ast_party_caller_set_init(&caller, ast_channel_caller(tc));
- if (ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
- caller.id = stored_clid;
- ast_channel_set_caller_event(tc, &caller, NULL);
- ast_set_flag64(tmp, DIAL_CALLERID_ABSENT);
- } else if (ast_strlen_zero(S_COR(ast_channel_caller(tc)->id.number.valid,
- ast_channel_caller(tc)->id.number.str, NULL))) {
-
- caller.id = stored_clid;
- if (!caller.id.name.valid
- && !ast_strlen_zero(S_COR(ast_channel_connected(chan)->id.name.valid,
- ast_channel_connected(chan)->id.name.str, NULL))) {
-
- caller.id.name.valid = 1;
- caller.id.name = ast_channel_connected(chan)->id.name;
- }
- ast_channel_set_caller_event(tc, &caller, NULL);
- ast_set_flag64(tmp, DIAL_CALLERID_ABSENT);
- } else if (ast_strlen_zero(S_COR(ast_channel_caller(tc)->id.name.valid, ast_channel_caller(tc)->id.name.str,
- NULL))) {
-
- if (!ast_strlen_zero(S_COR(ast_channel_connected(chan)->id.name.valid,
- ast_channel_connected(chan)->id.name.str, NULL))) {
-
- caller.id.name.valid = 1;
- caller.id.name = ast_channel_connected(chan)->id.name;
- ast_channel_set_caller_event(tc, &caller, NULL);
- }
- }
-
- if (ast_test_flag64(peerflags, OPT_FORCECLID) && !force_forwards_only) {
- struct ast_party_connected_line connected;
- ast_party_connected_line_set_init(&connected, ast_channel_connected(tc));
- connected.id = forced_clid;
- ast_channel_set_connected_line(tc, &connected, NULL);
- } else {
- ast_connected_line_copy_from_caller(ast_channel_connected(tc), ast_channel_caller(chan));
- }
- ast_party_redirecting_copy(ast_channel_redirecting(tc), ast_channel_redirecting(chan));
- ast_channel_dialed(tc)->transit_network_select = ast_channel_dialed(chan)->transit_network_select;
- if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
- ast_channel_accountcode_set(tc, ast_channel_accountcode(chan));
- }
- if (ast_strlen_zero(ast_channel_musicclass(tc))) {
- ast_channel_musicclass_set(tc, ast_channel_musicclass(chan));
- }
-
- ast_channel_adsicpe_set(tc, ast_channel_adsicpe(chan));
- ast_channel_transfercapability_set(tc, ast_channel_transfercapability(chan));
-
- if (outbound_group)
- ast_app_group_set_channel(tc, outbound_group);
-
- if (ast_channel_hangupcause(chan) == AST_CAUSE_ANSWERED_ELSEWHERE)
- ast_channel_hangupcause_set(tc, AST_CAUSE_ANSWERED_ELSEWHERE);
-
- if (ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE))
- ast_channel_hangupcause_set(tc, AST_CAUSE_ANSWERED_ELSEWHERE);
-
- ast_channel_dialcontext_set(tc, ast_strlen_zero(ast_channel_macrocontext(chan)) ? ast_channel_context(chan) : ast_channel_macrocontext(chan));
- if (!ast_strlen_zero(ast_channel_macroexten(chan)))
- ast_channel_exten_set(tc, ast_channel_macroexten(chan));
- else
- ast_channel_exten_set(tc, ast_channel_exten(chan));
- ast_channel_stage_snapshot_done(tc);
- ast_channel_unlock(tc);
- ast_channel_unlock(chan);
-
- tmp->chan = tc;
- AST_LIST_INSERT_TAIL(&out_chans, tmp, node);
- }
-
- if (ast_test_flag64(&opts, OPT_PREDIAL_CALLEE)
- && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])
- && !AST_LIST_EMPTY(&out_chans)) {
- const char *predial_callee;
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_PREDIAL_CALLEE]);
- predial_callee = ast_app_expand_sub_args(chan, opt_args[OPT_ARG_PREDIAL_CALLEE]);
- if (predial_callee) {
- ast_autoservice_start(chan);
- AST_LIST_TRAVERSE(&out_chans, tmp, node) {
- ast_pre_call(tmp->chan, predial_callee);
- }
- ast_autoservice_stop(chan);
- ast_free((char *) predial_callee);
- }
- }
-
- AST_LIST_TRAVERSE_SAFE_BEGIN(&out_chans, tmp, node) {
- res = ast_call(tmp->chan, tmp->number, 0);
- ast_channel_lock(chan);
-
- if (res) {
-
- ast_debug(1, "ast call on peer returned %d\n", res);
- ast_verb(3, "Couldn't call %s\n", tmp->interface);
- if (ast_channel_hangupcause(tmp->chan)) {
- ast_channel_hangupcause_set(chan, ast_channel_hangupcause(tmp->chan));
- }
- ast_channel_unlock(chan);
- ast_cc_call_failed(chan, tmp->chan, tmp->interface);
- ast_hangup(tmp->chan);
- tmp->chan = NULL;
- AST_LIST_REMOVE_CURRENT(node);
- chanlist_free(tmp);
- continue;
- }
- ast_channel_publish_dial(chan, tmp->chan, tmp->number, NULL);
- ast_channel_unlock(chan);
- ast_verb(3, "Called %s\n", tmp->interface);
- ast_set_flag64(tmp, DIAL_STILLGOING);
-
- if (ast_channel_state(tmp->chan) == AST_STATE_UP) {
- break;
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- if (ast_strlen_zero(args.timeout)) {
- to = -1;
- } else {
- to = atoi(args.timeout);
- if (to > 0)
- to *= 1000;
- else {
- ast_log(LOG_WARNING, "Invalid timeout specified: '%s'. Setting timeout to infinite\n", args.timeout);
- to = -1;
- }
- }
- outgoing = AST_LIST_FIRST(&out_chans);
- if (!outgoing) {
- strcpy(pa.status, "CHANUNAVAIL");
- if (fulldial == num_dialed) {
- res = -1;
- goto out;
- }
- } else {
-
- strcpy(pa.status, "NOANSWER");
- if (ast_test_flag64(outgoing, OPT_MUSICBACK)) {
- moh = 1;
- if (!ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
- char *original_moh = ast_strdupa(ast_channel_musicclass(chan));
- ast_channel_musicclass_set(chan, opt_args[OPT_ARG_MUSICBACK]);
- ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
- ast_channel_musicclass_set(chan, original_moh);
- } else {
- ast_moh_start(chan, NULL, NULL);
- }
- ast_indicate(chan, AST_CONTROL_PROGRESS);
- } else if (ast_test_flag64(outgoing, OPT_RINGBACK)) {
- if (!ast_strlen_zero(opt_args[OPT_ARG_RINGBACK])) {
- if (dial_handle_playtones(chan, opt_args[OPT_ARG_RINGBACK])){
- ast_indicate(chan, AST_CONTROL_RINGING);
- sentringing++;
- } else {
- ast_indicate(chan, AST_CONTROL_PROGRESS);
- }
- } else {
- ast_indicate(chan, AST_CONTROL_RINGING);
- sentringing++;
- }
- }
- }
- peer = wait_for_answer(chan, &out_chans, &to, peerflags, opt_args, &pa, &num, &result,
- dtmf_progress, ignore_cc, &forced_clid, &stored_clid);
-
- ast_channel_lock(chan);
- datastore = ast_channel_datastore_find(chan, &dialed_interface_info, NULL);
- if (datastore && !ast_channel_datastore_remove(chan, datastore)) {
- ast_datastore_free(datastore);
- }
- ast_channel_unlock(chan);
- if (!peer) {
- if (result) {
- res = result;
- } else if (to) {
- res = -1;
- } else {
- res = 0;
- }
- } else {
- const char *number;
- if (ast_test_flag64(&opts, OPT_CALLER_ANSWER))
- ast_answer(chan);
- strcpy(pa.status, "ANSWER");
- ast_channel_stage_snapshot(chan);
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
-
- hanguptree(&out_chans, peer, 1);
-
- if (ast_channel_name(peer))
- pbx_builtin_setvar_helper(chan, "DIALEDPEERNAME", ast_channel_name(peer));
- ast_channel_lock(peer);
- number = pbx_builtin_getvar_helper(peer, "DIALEDPEERNUMBER");
- if (ast_strlen_zero(number)) {
- number = NULL;
- } else {
- number = ast_strdupa(number);
- }
- ast_channel_unlock(peer);
- ast_channel_lock(chan);
- pbx_builtin_setvar_helper(chan, "DIALEDPEERNUMBER", number);
- ast_channel_stage_snapshot_done(chan);
- ast_channel_unlock(chan);
- if (!ast_strlen_zero(args.url) && ast_channel_supports_html(peer) ) {
- ast_debug(1, "app_dial: sendurl=%s.\n", args.url);
- ast_channel_sendurl( peer, args.url );
- }
- if ( (ast_test_flag64(&opts, OPT_PRIVACY) || ast_test_flag64(&opts, OPT_SCREENING)) && pa.privdb_val == AST_PRIVACY_UNKNOWN) {
- if (do_privacy(chan, peer, &opts, opt_args, &pa)) {
- ast_channel_publish_dial(chan, peer, NULL, pa.status);
- res = 0;
- goto out;
- }
- }
- if (!ast_test_flag64(&opts, OPT_ANNOUNCE) || ast_strlen_zero(opt_args[OPT_ARG_ANNOUNCE])) {
- res = 0;
- } else {
- int digit = 0;
- struct ast_channel *chans[2];
- struct ast_channel *active_chan;
- chans[0] = chan;
- chans[1] = peer;
-
-
- res = ast_streamfile(peer, opt_args[OPT_ARG_ANNOUNCE], ast_channel_language(peer));
- if (res) {
- res = 0;
- ast_log(LOG_ERROR, "error streaming file '%s' to callee\n", opt_args[OPT_ARG_ANNOUNCE]);
- }
- ast_set_flag(ast_channel_flags(peer), AST_FLAG_END_DTMF_ONLY);
- while (ast_channel_stream(peer)) {
- int ms;
- ms = ast_sched_wait(ast_channel_sched(peer));
- if (ms < 0 && !ast_channel_timingfunc(peer)) {
- ast_stopstream(peer);
- break;
- }
- if (ms < 0)
- ms = 1000;
- active_chan = ast_waitfor_n(chans, 2, &ms);
- if (active_chan) {
- struct ast_frame *fr = ast_read(active_chan);
- if (!fr) {
- ast_autoservice_chan_hangup_peer(chan, peer);
- res = -1;
- goto done;
- }
- switch(fr->frametype) {
- case AST_FRAME_DTMF_END:
- digit = fr->subclass.integer;
- if (active_chan == peer && strchr(AST_DIGIT_ANY, res)) {
- ast_stopstream(peer);
- res = ast_senddigit(chan, digit, 0);
- }
- break;
- case AST_FRAME_CONTROL:
- switch (fr->subclass.integer) {
- case AST_CONTROL_HANGUP:
- ast_frfree(fr);
- ast_autoservice_chan_hangup_peer(chan, peer);
- res = -1;
- goto done;
- default:
- break;
- }
- break;
- default:
-
- break;
- }
- ast_frfree(fr);
- }
- ast_sched_runq(ast_channel_sched(peer));
- }
- ast_clear_flag(ast_channel_flags(peer), AST_FLAG_END_DTMF_ONLY);
- }
- if (chan && peer && ast_test_flag64(&opts, OPT_GOTO) && !ast_strlen_zero(opt_args[OPT_ARG_GOTO])) {
-
- ast_clear_flag(ast_channel_flags(chan), AST_FLAG_OUTGOING);
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_GOTO]);
- ast_parseable_goto(chan, opt_args[OPT_ARG_GOTO]);
-
- ast_channel_lock(peer);
- ast_channel_stage_snapshot(peer);
- ast_clear_flag(ast_channel_flags(peer), AST_FLAG_OUTGOING);
- ast_channel_context_set(peer, ast_channel_context(chan));
- ast_channel_exten_set(peer, ast_channel_exten(chan));
- ast_channel_priority_set(peer, ast_channel_priority(chan) + 2);
- ast_channel_stage_snapshot_done(peer);
- ast_channel_unlock(peer);
- if (ast_pbx_start(peer)) {
- ast_autoservice_chan_hangup_peer(chan, peer);
- }
- hanguptree(&out_chans, NULL, ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0);
- if (continue_exec)
- *continue_exec = 1;
- res = 0;
- ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
- goto done;
- }
- if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
- const char *macro_result_peer;
-
- ast_channel_lock_both(chan, peer);
- ast_channel_context_set(peer, ast_channel_context(chan));
- ast_channel_exten_set(peer, ast_channel_exten(chan));
- ast_channel_unlock(peer);
- ast_channel_unlock(chan);
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
- res = ast_app_exec_macro(chan, peer, opt_args[OPT_ARG_CALLEE_MACRO]);
- ast_channel_lock(peer);
- if (!res && (macro_result_peer = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
- char *macro_result = ast_strdupa(macro_result_peer);
- char *macro_transfer_dest;
- ast_channel_unlock(peer);
- if (!strcasecmp(macro_result, "BUSY")) {
- ast_copy_string(pa.status, macro_result, sizeof(pa.status));
- ast_set_flag64(peerflags, OPT_GO_ON);
- res = -1;
- } else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
- ast_copy_string(pa.status, macro_result, sizeof(pa.status));
- ast_set_flag64(peerflags, OPT_GO_ON);
- res = -1;
- } else if (!strcasecmp(macro_result, "CONTINUE")) {
-
- ast_set_flag64(peerflags, OPT_GO_ON);
- res = -1;
- } else if (!strcasecmp(macro_result, "ABORT")) {
-
- res = -1;
- } else if (!strncasecmp(macro_result, "GOTO:", 5)) {
- macro_transfer_dest = macro_result + 5;
- res = -1;
-
- if (strchr(macro_transfer_dest, '^')) {
- ast_replace_subargument_delimiter(macro_transfer_dest);
- }
- if (!ast_parseable_goto(chan, macro_transfer_dest)) {
- ast_set_flag64(peerflags, OPT_GO_ON);
- }
- }
- ast_channel_publish_dial(chan, peer, NULL, macro_result);
- } else {
- ast_channel_unlock(peer);
- }
- }
- if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) {
- const char *gosub_result_peer;
- char *gosub_argstart;
- char *gosub_args = NULL;
- int res9 = -1;
- ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
- gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ',');
- if (gosub_argstart) {
- const char *what_is_s = "s";
- *gosub_argstart = 0;
- if (!ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
- ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
- what_is_s = "~~s~~";
- }
- if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], what_is_s, gosub_argstart + 1) < 0) {
- gosub_args = NULL;
- }
- *gosub_argstart = ',';
- } else {
- const char *what_is_s = "s";
- if (!ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
- ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
- what_is_s = "~~s~~";
- }
- if (ast_asprintf(&gosub_args, "%s,%s,1", opt_args[OPT_ARG_CALLEE_GOSUB], what_is_s) < 0) {
- gosub_args = NULL;
- }
- }
- if (gosub_args) {
- res9 = ast_app_exec_sub(chan, peer, gosub_args, 0);
- ast_free(gosub_args);
- } else {
- ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
- }
- ast_channel_lock_both(chan, peer);
- if (!res9 && (gosub_result_peer = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) {
- char *gosub_transfer_dest;
- char *gosub_result = ast_strdupa(gosub_result_peer);
- const char *gosub_retval = pbx_builtin_getvar_helper(peer, "GOSUB_RETVAL");
-
- if (gosub_retval) {
- pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", gosub_retval);
- }
- ast_channel_unlock(peer);
- ast_channel_unlock(chan);
- if (!strcasecmp(gosub_result, "BUSY")) {
- ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
- ast_set_flag64(peerflags, OPT_GO_ON);
- res = -1;
- } else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) {
- ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
- ast_set_flag64(peerflags, OPT_GO_ON);
- res = -1;
- } else if (!strcasecmp(gosub_result, "CONTINUE")) {
-
- ast_set_flag64(peerflags, OPT_GO_ON);
- res = -1;
- } else if (!strcasecmp(gosub_result, "ABORT")) {
-
- res = -1;
- } else if (!strncasecmp(gosub_result, "GOTO:", 5)) {
- gosub_transfer_dest = gosub_result + 5;
- res = -1;
-
- if (strchr(gosub_transfer_dest, '^')) {
- ast_replace_subargument_delimiter(gosub_transfer_dest);
- }
- if (!ast_parseable_goto(chan, gosub_transfer_dest)) {
- ast_set_flag64(peerflags, OPT_GO_ON);
- }
- }
- ast_channel_publish_dial(chan, peer, NULL, gosub_result);
- } else {
- ast_channel_unlock(peer);
- ast_channel_unlock(chan);
- }
- }
- if (!res) {
-
- ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
- if (!ast_tvzero(calldurationlimit)) {
- struct timeval whentohangup = ast_tvadd(ast_tvnow(), calldurationlimit);
- ast_channel_lock(peer);
- ast_channel_whentohangup_set(peer, &whentohangup);
- ast_channel_unlock(peer);
- }
- if (!ast_strlen_zero(dtmfcalled)) {
- ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled);
- res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0);
- }
- if (!ast_strlen_zero(dtmfcalling)) {
- ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling);
- res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0);
- }
- }
- if (res) {
- if (!ast_check_hangup(chan) && ast_check_hangup(peer)) {
- ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
- }
- setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
- if (ast_bridge_setup_after_goto(peer)
- || ast_pbx_start(peer)) {
- ast_autoservice_chan_hangup_peer(chan, peer);
- }
- res = -1;
- } else {
- if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER))
- ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
- if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER))
- ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
- if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP))
- ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
- if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP))
- ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
- if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR))
- ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
- if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR))
- ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
- if (ast_test_flag64(peerflags, OPT_CALLEE_PARK))
- ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
- if (ast_test_flag64(peerflags, OPT_CALLER_PARK))
- ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
- if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR))
- ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
- if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
- ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
- config.end_bridge_callback = end_bridge_callback;
- config.end_bridge_callback_data = chan;
- config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
- if (moh) {
- moh = 0;
- ast_moh_stop(chan);
- } else if (sentringing) {
- sentringing = 0;
- ast_indicate(chan, -1);
- }
-
- ast_deactivate_generator(chan);
- ast_channel_visible_indication_set(chan, 0);
-
- res = ast_channel_make_compatible(chan, peer);
- if (res < 0) {
- ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(chan), ast_channel_name(peer));
- ast_autoservice_chan_hangup_peer(chan, peer);
- res = -1;
- goto done;
- }
- if (opermode) {
- struct oprmode oprmode;
- oprmode.peer = peer;
- oprmode.mode = opermode;
- ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
- }
- setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
- res = ast_bridge_call(chan, peer, &config);
- }
- }
- out:
- if (moh) {
- moh = 0;
- ast_moh_stop(chan);
- } else if (sentringing) {
- sentringing = 0;
- ast_indicate(chan, -1);
- }
- if (delprivintro && ast_fileexists(pa.privintro, NULL, NULL) > 0) {
- ast_filedelete(pa.privintro, NULL);
- if (ast_fileexists(pa.privintro, NULL, NULL) > 0) {
- ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa.privintro);
- } else {
- ast_verb(3, "Successfully deleted %s intro file\n", pa.privintro);
- }
- }
- ast_channel_early_bridge(chan, NULL);
- hanguptree(&out_chans, NULL, ast_channel_hangupcause(chan)==AST_CAUSE_ANSWERED_ELSEWHERE || ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE) ? 1 : 0 );
- pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
- ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
- if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) {
- if (!ast_tvzero(calldurationlimit))
- memset(ast_channel_whentohangup(chan), 0, sizeof(*ast_channel_whentohangup(chan)));
- res = 0;
- }
- done:
- if (config.warning_sound) {
- ast_free((char *)config.warning_sound);
- }
- if (config.end_sound) {
- ast_free((char *)config.end_sound);
- }
- if (config.start_sound) {
- ast_free((char *)config.start_sound);
- }
- ast_ignore_cc(chan);
- return res;
- }
- static int dial_exec(struct ast_channel *chan, const char *data)
- {
- struct ast_flags64 peerflags;
- memset(&peerflags, 0, sizeof(peerflags));
- return dial_exec_full(chan, data, &peerflags, NULL);
- }
- static int retrydial_exec(struct ast_channel *chan, const char *data)
- {
- char *parse;
- const char *context = NULL;
- int sleepms = 0, loops = 0, res = -1;
- struct ast_flags64 peerflags = { 0, };
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(announce);
- AST_APP_ARG(sleep);
- AST_APP_ARG(retries);
- AST_APP_ARG(dialdata);
- );
- if (ast_strlen_zero(data)) {
- ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
- return -1;
- }
- parse = ast_strdupa(data);
- AST_STANDARD_APP_ARGS(args, parse);
- if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep)))
- sleepms *= 1000;
- if (!ast_strlen_zero(args.retries)) {
- loops = atoi(args.retries);
- }
- if (!args.dialdata) {
- ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp);
- goto done;
- }
- if (sleepms < 1000)
- sleepms = 10000;
- if (!loops)
- loops = -1;
- ast_channel_lock(chan);
- context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
- context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL;
- ast_channel_unlock(chan);
- res = 0;
- while (loops) {
- int continue_exec;
- ast_channel_data_set(chan, "Retrying");
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
- ast_moh_stop(chan);
- res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec);
- if (continue_exec)
- break;
- if (res == 0) {
- if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) {
- if (!ast_strlen_zero(args.announce)) {
- if (ast_fileexists(args.announce, NULL, ast_channel_language(chan)) > 0) {
- if (!(res = ast_streamfile(chan, args.announce, ast_channel_language(chan))))
- ast_waitstream(chan, AST_DIGIT_ANY);
- } else
- ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
- }
- if (!res && sleepms) {
- if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
- ast_moh_start(chan, NULL, NULL);
- res = ast_waitfordigit(chan, sleepms);
- }
- } else {
- if (!ast_strlen_zero(args.announce)) {
- if (ast_fileexists(args.announce, NULL, ast_channel_language(chan)) > 0) {
- if (!(res = ast_streamfile(chan, args.announce, ast_channel_language(chan))))
- res = ast_waitstream(chan, "");
- } else
- ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
- }
- if (sleepms) {
- if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
- ast_moh_start(chan, NULL, NULL);
- if (!res)
- res = ast_waitfordigit(chan, sleepms);
- }
- }
- }
- if (res < 0 || res == AST_PBX_INCOMPLETE) {
- break;
- } else if (res > 0) {
- if (onedigit_goto(chan, context, (char) res, 1)) {
- res = 0;
- break;
- }
- }
- loops--;
- }
- if (loops == 0)
- res = 0;
- else if (res == 1)
- res = 0;
- if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
- ast_moh_stop(chan);
- done:
- return res;
- }
- static int unload_module(void)
- {
- int res;
- res = ast_unregister_application(app);
- res |= ast_unregister_application(rapp);
- return res;
- }
- static int load_module(void)
- {
- int res;
- res = ast_register_application_xml(app, dial_exec);
- res |= ast_register_application_xml(rapp, retrydial_exec);
- return res;
- }
- AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialing Application");
|