app_followme.c 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * A full-featured Find-Me/Follow-Me Application
  5. *
  6. * Copyright (C) 2005-2006, BJ Weschke All Rights Reserved.
  7. *
  8. * BJ Weschke <bweschke@btwtech.com>
  9. *
  10. * This code is released by the author with no restrictions on usage.
  11. *
  12. * See http://www.asterisk.org for more information about
  13. * the Asterisk project. Please do not directly contact
  14. * any of the maintainers of this project for assistance;
  15. * the project provides a web site, mailing lists and IRC
  16. * channels for your use.
  17. *
  18. */
  19. /*! \file
  20. *
  21. * \brief Find-Me Follow-Me application
  22. *
  23. * \author BJ Weschke <bweschke@btwtech.com>
  24. *
  25. * \ingroup applications
  26. */
  27. /*! \li \ref app_followme.c uses the configuration file \ref followme.conf
  28. * \addtogroup configuration_file Configuration Files
  29. */
  30. /*!
  31. * \page followme.conf followme.conf
  32. * \verbinclude followme.conf.sample
  33. */
  34. /*** MODULEINFO
  35. <support_level>core</support_level>
  36. ***/
  37. #include "asterisk.h"
  38. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  39. #include <signal.h>
  40. #include "asterisk/paths.h" /* use ast_config_AST_SPOOL_DIR */
  41. #include "asterisk/lock.h"
  42. #include "asterisk/file.h"
  43. #include "asterisk/channel.h"
  44. #include "asterisk/pbx.h"
  45. #include "asterisk/module.h"
  46. #include "asterisk/translate.h"
  47. #include "asterisk/say.h"
  48. #include "asterisk/features.h"
  49. #include "asterisk/musiconhold.h"
  50. #include "asterisk/cli.h"
  51. #include "asterisk/manager.h"
  52. #include "asterisk/config.h"
  53. #include "asterisk/utils.h"
  54. #include "asterisk/causes.h"
  55. #include "asterisk/astdb.h"
  56. #include "asterisk/dsp.h"
  57. #include "asterisk/app.h"
  58. #include "asterisk/stasis_channels.h"
  59. /*** DOCUMENTATION
  60. <application name="FollowMe" language="en_US">
  61. <synopsis>
  62. Find-Me/Follow-Me application.
  63. </synopsis>
  64. <syntax>
  65. <parameter name="followmeid" required="true" />
  66. <parameter name="options">
  67. <optionlist>
  68. <option name="a">
  69. <para>Record the caller's name so it can be announced to the
  70. callee on each step.</para>
  71. </option>
  72. <option name="B" argsep="^">
  73. <para>Before initiating the outgoing call(s), Gosub to the specified
  74. location using the current channel.</para>
  75. <argument name="context" required="false" />
  76. <argument name="exten" required="false" />
  77. <argument name="priority" required="true" hasparams="optional" argsep="^">
  78. <argument name="arg1" multiple="true" required="true" />
  79. <argument name="argN" />
  80. </argument>
  81. </option>
  82. <option name="b" argsep="^">
  83. <para>Before initiating an outgoing call, Gosub to the specified
  84. location using the newly created channel. The Gosub will be
  85. executed for each destination channel.</para>
  86. <argument name="context" required="false" />
  87. <argument name="exten" required="false" />
  88. <argument name="priority" required="true" hasparams="optional" argsep="^">
  89. <argument name="arg1" multiple="true" required="true" />
  90. <argument name="argN" />
  91. </argument>
  92. </option>
  93. <option name="d">
  94. <para>Disable the 'Please hold while we try to connect your call' announcement.</para>
  95. </option>
  96. <option name="I">
  97. <para>Asterisk will ignore any connected line update requests
  98. it may receive on this dial attempt.</para>
  99. </option>
  100. <option name="l">
  101. <para>Disable local call optimization so that applications with
  102. audio hooks between the local bridge don't get dropped when the
  103. calls get joined directly.</para>
  104. </option>
  105. <option name="N">
  106. <para>Don't answer the incoming call until we're ready to
  107. connect the caller or give up.</para>
  108. <note>
  109. <para>This option is ignored if the call is already answered.</para>
  110. </note>
  111. <note>
  112. <para>If the call is not already answered, the 'a' and 's'
  113. options are ignored while the 'd' option is implicitly enabled.</para>
  114. </note>
  115. </option>
  116. <option name="n">
  117. <para>Playback the unreachable status message if we've run out
  118. of steps or the callee has elected not to be reachable.</para>
  119. </option>
  120. <option name="s">
  121. <para>Playback the incoming status message prior to starting
  122. the follow-me step(s)</para>
  123. </option>
  124. </optionlist>
  125. </parameter>
  126. </syntax>
  127. <description>
  128. <para>This application performs Find-Me/Follow-Me functionality for the caller
  129. as defined in the profile matching the <replaceable>followmeid</replaceable> parameter in
  130. <filename>followme.conf</filename>. If the specified <replaceable>followmeid</replaceable>
  131. profile doesn't exist in <filename>followme.conf</filename>, execution will be returned
  132. to the dialplan and call execution will continue at the next priority.</para>
  133. <para>Returns -1 on hangup.</para>
  134. </description>
  135. </application>
  136. ***/
  137. static char *app = "FollowMe";
  138. /*! Maximum accept/decline DTMF string plus terminator. */
  139. #define MAX_YN_STRING 20
  140. /*! \brief Number structure */
  141. struct number {
  142. char number[512]; /*!< Phone Number(s) and/or Extension(s) */
  143. long timeout; /*!< Dial Timeout, if used. */
  144. int order; /*!< The order to dial in */
  145. AST_LIST_ENTRY(number) entry; /*!< Next Number record */
  146. };
  147. /*! \brief Data structure for followme scripts */
  148. struct call_followme {
  149. ast_mutex_t lock;
  150. char name[AST_MAX_EXTENSION]; /*!< Name - FollowMeID */
  151. char moh[MAX_MUSICCLASS]; /*!< Music On Hold Class to be used */
  152. char context[AST_MAX_CONTEXT]; /*!< Context to dial from */
  153. unsigned int active; /*!< Profile is active (1), or disabled (0). */
  154. int realtime; /*!< Cached from realtime */
  155. char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */
  156. char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */
  157. char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
  158. char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */
  159. char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */
  160. char plsholdprompt[PATH_MAX]; /*!< Sound prompt name and path */
  161. char statusprompt[PATH_MAX]; /*!< Sound prompt name and path */
  162. char sorryprompt[PATH_MAX]; /*!< Sound prompt name and path */
  163. AST_LIST_HEAD_NOLOCK(numbers, number) numbers; /*!< Head of the list of follow-me numbers */
  164. AST_LIST_HEAD_NOLOCK(blnumbers, number) blnumbers; /*!< Head of the list of black-listed numbers */
  165. AST_LIST_HEAD_NOLOCK(wlnumbers, number) wlnumbers; /*!< Head of the list of white-listed numbers */
  166. AST_LIST_ENTRY(call_followme) entry; /*!< Next Follow-Me record */
  167. };
  168. struct fm_args {
  169. char *mohclass;
  170. AST_LIST_HEAD_NOLOCK(cnumbers, number) cnumbers;
  171. /*! Gosub app arguments for outgoing calls. NULL if not supplied. */
  172. const char *predial_callee;
  173. /*! Accumulated connected line information from inbound call. */
  174. struct ast_party_connected_line connected_in;
  175. /*! Accumulated connected line information from outbound call. */
  176. struct ast_party_connected_line connected_out;
  177. /*! TRUE if connected line information from inbound call changed. */
  178. unsigned int pending_in_connected_update:1;
  179. /*! TRUE if connected line information from outbound call is available. */
  180. unsigned int pending_out_connected_update:1;
  181. /*! TRUE if caller has a pending hold request for the winning call. */
  182. unsigned int pending_hold:1;
  183. /*! Music On Hold Class suggested by caller hold for winning call. */
  184. char suggested_moh[MAX_MUSICCLASS];
  185. char context[AST_MAX_CONTEXT];
  186. char namerecloc[PATH_MAX];
  187. char takecall[MAX_YN_STRING]; /*!< Digit mapping to take a call */
  188. char nextindp[MAX_YN_STRING]; /*!< Digit mapping to decline a call */
  189. char callfromprompt[PATH_MAX]; /*!< Sound prompt name and path */
  190. char norecordingprompt[PATH_MAX]; /*!< Sound prompt name and path */
  191. char optionsprompt[PATH_MAX]; /*!< Sound prompt name and path */
  192. char plsholdprompt[PATH_MAX]; /*!< Sound prompt name and path */
  193. char statusprompt[PATH_MAX]; /*!< Sound prompt name and path */
  194. char sorryprompt[PATH_MAX]; /*!< Sound prompt name and path */
  195. struct ast_flags followmeflags;
  196. };
  197. struct findme_user {
  198. struct ast_channel *ochan;
  199. /*! Accumulated connected line information from outgoing call. */
  200. struct ast_party_connected_line connected;
  201. long digts;
  202. int ynidx;
  203. int state;
  204. char dialarg[256];
  205. /*! Collected digits to accept/decline the call. */
  206. char yn[MAX_YN_STRING];
  207. /*! TRUE if the outgoing call is answered. */
  208. unsigned int answered:1;
  209. /*! TRUE if connected line information is available. */
  210. unsigned int pending_connected_update:1;
  211. AST_LIST_ENTRY(findme_user) entry;
  212. };
  213. enum {
  214. FOLLOWMEFLAG_STATUSMSG = (1 << 0),
  215. FOLLOWMEFLAG_RECORDNAME = (1 << 1),
  216. FOLLOWMEFLAG_UNREACHABLEMSG = (1 << 2),
  217. FOLLOWMEFLAG_DISABLEHOLDPROMPT = (1 << 3),
  218. FOLLOWMEFLAG_NOANSWER = (1 << 4),
  219. FOLLOWMEFLAG_DISABLEOPTIMIZATION = (1 << 5),
  220. FOLLOWMEFLAG_IGNORE_CONNECTEDLINE = (1 << 6),
  221. FOLLOWMEFLAG_PREDIAL_CALLER = (1 << 7),
  222. FOLLOWMEFLAG_PREDIAL_CALLEE = (1 << 8),
  223. };
  224. enum {
  225. FOLLOWMEFLAG_ARG_PREDIAL_CALLER,
  226. FOLLOWMEFLAG_ARG_PREDIAL_CALLEE,
  227. /* note: this entry _MUST_ be the last one in the enum */
  228. FOLLOWMEFLAG_ARG_ARRAY_SIZE
  229. };
  230. AST_APP_OPTIONS(followme_opts, {
  231. AST_APP_OPTION('a', FOLLOWMEFLAG_RECORDNAME),
  232. AST_APP_OPTION_ARG('B', FOLLOWMEFLAG_PREDIAL_CALLER, FOLLOWMEFLAG_ARG_PREDIAL_CALLER),
  233. AST_APP_OPTION_ARG('b', FOLLOWMEFLAG_PREDIAL_CALLEE, FOLLOWMEFLAG_ARG_PREDIAL_CALLEE),
  234. AST_APP_OPTION('d', FOLLOWMEFLAG_DISABLEHOLDPROMPT),
  235. AST_APP_OPTION('I', FOLLOWMEFLAG_IGNORE_CONNECTEDLINE),
  236. AST_APP_OPTION('l', FOLLOWMEFLAG_DISABLEOPTIMIZATION),
  237. AST_APP_OPTION('N', FOLLOWMEFLAG_NOANSWER),
  238. AST_APP_OPTION('n', FOLLOWMEFLAG_UNREACHABLEMSG),
  239. AST_APP_OPTION('s', FOLLOWMEFLAG_STATUSMSG),
  240. });
  241. static const char *featuredigittostr;
  242. static int featuredigittimeout = 5000; /*!< Feature Digit Timeout */
  243. static const char *defaultmoh = "default"; /*!< Default Music-On-Hold Class */
  244. static char takecall[MAX_YN_STRING] = "1";
  245. static char nextindp[MAX_YN_STRING] = "2";
  246. static char callfromprompt[PATH_MAX] = "followme/call-from";
  247. static char norecordingprompt[PATH_MAX] = "followme/no-recording";
  248. static char optionsprompt[PATH_MAX] = "followme/options";
  249. static char plsholdprompt[PATH_MAX] = "followme/pls-hold-while-try";
  250. static char statusprompt[PATH_MAX] = "followme/status";
  251. static char sorryprompt[PATH_MAX] = "followme/sorry";
  252. static AST_RWLIST_HEAD_STATIC(followmes, call_followme);
  253. AST_LIST_HEAD_NOLOCK(findme_user_listptr, findme_user);
  254. static void free_numbers(struct call_followme *f)
  255. {
  256. /* Free numbers attached to the profile */
  257. struct number *prev;
  258. while ((prev = AST_LIST_REMOVE_HEAD(&f->numbers, entry)))
  259. /* Free the number */
  260. ast_free(prev);
  261. AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
  262. while ((prev = AST_LIST_REMOVE_HEAD(&f->blnumbers, entry)))
  263. /* Free the blacklisted number */
  264. ast_free(prev);
  265. AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
  266. while ((prev = AST_LIST_REMOVE_HEAD(&f->wlnumbers, entry)))
  267. /* Free the whitelisted number */
  268. ast_free(prev);
  269. AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
  270. }
  271. /*! \brief Allocate and initialize followme profile */
  272. static struct call_followme *alloc_profile(const char *fmname)
  273. {
  274. struct call_followme *f;
  275. if (!(f = ast_calloc(1, sizeof(*f))))
  276. return NULL;
  277. ast_mutex_init(&f->lock);
  278. ast_copy_string(f->name, fmname, sizeof(f->name));
  279. f->moh[0] = '\0';
  280. f->context[0] = '\0';
  281. ast_copy_string(f->takecall, takecall, sizeof(f->takecall));
  282. ast_copy_string(f->nextindp, nextindp, sizeof(f->nextindp));
  283. ast_copy_string(f->callfromprompt, callfromprompt, sizeof(f->callfromprompt));
  284. ast_copy_string(f->norecordingprompt, norecordingprompt, sizeof(f->norecordingprompt));
  285. ast_copy_string(f->optionsprompt, optionsprompt, sizeof(f->optionsprompt));
  286. ast_copy_string(f->plsholdprompt, plsholdprompt, sizeof(f->plsholdprompt));
  287. ast_copy_string(f->statusprompt, statusprompt, sizeof(f->statusprompt));
  288. ast_copy_string(f->sorryprompt, sorryprompt, sizeof(f->sorryprompt));
  289. AST_LIST_HEAD_INIT_NOLOCK(&f->numbers);
  290. AST_LIST_HEAD_INIT_NOLOCK(&f->blnumbers);
  291. AST_LIST_HEAD_INIT_NOLOCK(&f->wlnumbers);
  292. return f;
  293. }
  294. static void init_profile(struct call_followme *f)
  295. {
  296. f->active = 1;
  297. ast_copy_string(f->moh, defaultmoh, sizeof(f->moh));
  298. }
  299. /*! \brief Set parameter in profile from configuration file */
  300. static void profile_set_param(struct call_followme *f, const char *param, const char *val, int linenum, int failunknown)
  301. {
  302. if (!strcasecmp(param, "musicclass") || !strcasecmp(param, "musiconhold") || !strcasecmp(param, "music"))
  303. ast_copy_string(f->moh, val, sizeof(f->moh));
  304. else if (!strcasecmp(param, "context"))
  305. ast_copy_string(f->context, val, sizeof(f->context));
  306. else if (!strcasecmp(param, "takecall"))
  307. ast_copy_string(f->takecall, val, sizeof(f->takecall));
  308. else if (!strcasecmp(param, "declinecall"))
  309. ast_copy_string(f->nextindp, val, sizeof(f->nextindp));
  310. else if (!strcasecmp(param, "call-from-prompt") || !strcasecmp(param, "call_from_prompt"))
  311. ast_copy_string(f->callfromprompt, val, sizeof(f->callfromprompt));
  312. else if (!strcasecmp(param, "followme-norecording-prompt") || !strcasecmp(param, "norecording_prompt"))
  313. ast_copy_string(f->norecordingprompt, val, sizeof(f->norecordingprompt));
  314. else if (!strcasecmp(param, "followme-options-prompt") || !strcasecmp(param, "options_prompt"))
  315. ast_copy_string(f->optionsprompt, val, sizeof(f->optionsprompt));
  316. else if (!strcasecmp(param, "followme-pls-hold-prompt") || !strcasecmp(param, "pls_hold_prompt"))
  317. ast_copy_string(f->plsholdprompt, val, sizeof(f->plsholdprompt));
  318. else if (!strcasecmp(param, "followme-status-prompt") || !strcasecmp(param, "status_prompt"))
  319. ast_copy_string(f->statusprompt, val, sizeof(f->statusprompt));
  320. else if (!strcasecmp(param, "followme-sorry-prompt") || !strcasecmp(param, "sorry_prompt"))
  321. ast_copy_string(f->sorryprompt, val, sizeof(f->sorryprompt));
  322. else if (failunknown) {
  323. if (linenum >= 0)
  324. ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s at line %d of followme.conf\n", f->name, param, linenum);
  325. else
  326. ast_log(LOG_WARNING, "Unknown keyword in profile '%s': %s\n", f->name, param);
  327. }
  328. }
  329. /*! \brief Add a new number */
  330. static struct number *create_followme_number(const char *number, int timeout, int numorder)
  331. {
  332. struct number *cur;
  333. char *buf = ast_strdupa(number);
  334. char *tmp;
  335. if (!(cur = ast_calloc(1, sizeof(*cur))))
  336. return NULL;
  337. cur->timeout = timeout;
  338. if ((tmp = strchr(buf, ',')))
  339. *tmp = '\0';
  340. ast_copy_string(cur->number, buf, sizeof(cur->number));
  341. cur->order = numorder;
  342. ast_debug(1, "Created a number, %s, order of , %d, with a timeout of %ld.\n", cur->number, cur->order, cur->timeout);
  343. return cur;
  344. }
  345. /*! \brief Reload followme application module */
  346. static int reload_followme(int reload)
  347. {
  348. struct call_followme *f;
  349. struct ast_config *cfg;
  350. char *cat = NULL, *tmp;
  351. struct ast_variable *var;
  352. struct number *cur, *nm;
  353. char *numberstr;
  354. int timeout;
  355. int numorder;
  356. const char *takecallstr;
  357. const char *declinecallstr;
  358. const char *tmpstr;
  359. struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
  360. if (!(cfg = ast_config_load("followme.conf", config_flags))) {
  361. ast_log(LOG_WARNING, "No follow me config file (followme.conf), so no follow me\n");
  362. return 0;
  363. } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
  364. return 0;
  365. } else if (cfg == CONFIG_STATUS_FILEINVALID) {
  366. ast_log(LOG_ERROR, "Config file followme.conf is in an invalid format. Aborting.\n");
  367. return 0;
  368. }
  369. AST_RWLIST_WRLOCK(&followmes);
  370. /* Reset Global Var Values */
  371. featuredigittimeout = 5000;
  372. /* Mark all profiles as inactive for the moment */
  373. AST_RWLIST_TRAVERSE(&followmes, f, entry) {
  374. f->active = 0;
  375. }
  376. featuredigittostr = ast_variable_retrieve(cfg, "general", "featuredigittimeout");
  377. if (!ast_strlen_zero(featuredigittostr)) {
  378. if (!sscanf(featuredigittostr, "%30d", &featuredigittimeout))
  379. featuredigittimeout = 5000;
  380. }
  381. if ((takecallstr = ast_variable_retrieve(cfg, "general", "takecall")) && !ast_strlen_zero(takecallstr)) {
  382. ast_copy_string(takecall, takecallstr, sizeof(takecall));
  383. }
  384. if ((declinecallstr = ast_variable_retrieve(cfg, "general", "declinecall")) && !ast_strlen_zero(declinecallstr)) {
  385. ast_copy_string(nextindp, declinecallstr, sizeof(nextindp));
  386. }
  387. if ((tmpstr = ast_variable_retrieve(cfg, "general", "call-from-prompt")) && !ast_strlen_zero(tmpstr)) {
  388. ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
  389. } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "call_from_prompt")) && !ast_strlen_zero(tmpstr)) {
  390. ast_copy_string(callfromprompt, tmpstr, sizeof(callfromprompt));
  391. }
  392. if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording-prompt")) && !ast_strlen_zero(tmpstr)) {
  393. ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
  394. } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "norecording_prompt")) && !ast_strlen_zero(tmpstr)) {
  395. ast_copy_string(norecordingprompt, tmpstr, sizeof(norecordingprompt));
  396. }
  397. if ((tmpstr = ast_variable_retrieve(cfg, "general", "options-prompt")) && !ast_strlen_zero(tmpstr)) {
  398. ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
  399. } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "options_prompt")) && !ast_strlen_zero(tmpstr)) {
  400. ast_copy_string(optionsprompt, tmpstr, sizeof(optionsprompt));
  401. }
  402. if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls-hold-prompt")) && !ast_strlen_zero(tmpstr)) {
  403. ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
  404. } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "pls_hold_prompt")) && !ast_strlen_zero(tmpstr)) {
  405. ast_copy_string(plsholdprompt, tmpstr, sizeof(plsholdprompt));
  406. }
  407. if ((tmpstr = ast_variable_retrieve(cfg, "general", "status-prompt")) && !ast_strlen_zero(tmpstr)) {
  408. ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
  409. } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "status_prompt")) && !ast_strlen_zero(tmpstr)) {
  410. ast_copy_string(statusprompt, tmpstr, sizeof(statusprompt));
  411. }
  412. if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry-prompt")) && !ast_strlen_zero(tmpstr)) {
  413. ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
  414. } else if ((tmpstr = ast_variable_retrieve(cfg, "general", "sorry_prompt")) && !ast_strlen_zero(tmpstr)) {
  415. ast_copy_string(sorryprompt, tmpstr, sizeof(sorryprompt));
  416. }
  417. /* Chug through config file */
  418. while ((cat = ast_category_browse(cfg, cat))) {
  419. int new = 0;
  420. if (!strcasecmp(cat, "general"))
  421. continue;
  422. /* Look for an existing one */
  423. AST_LIST_TRAVERSE(&followmes, f, entry) {
  424. if (!strcasecmp(f->name, cat))
  425. break;
  426. }
  427. ast_debug(1, "New profile %s.\n", cat);
  428. if (!f) {
  429. /* Make one then */
  430. f = alloc_profile(cat);
  431. new = 1;
  432. }
  433. /* Totally fail if we fail to find/create an entry */
  434. if (!f)
  435. continue;
  436. if (!new)
  437. ast_mutex_lock(&f->lock);
  438. /* Re-initialize the profile */
  439. init_profile(f);
  440. free_numbers(f);
  441. var = ast_variable_browse(cfg, cat);
  442. while (var) {
  443. if (!strcasecmp(var->name, "number")) {
  444. int idx = 0;
  445. /* Add a new number */
  446. numberstr = ast_strdupa(var->value);
  447. if ((tmp = strchr(numberstr, ','))) {
  448. *tmp++ = '\0';
  449. timeout = atoi(tmp);
  450. if (timeout < 0) {
  451. timeout = 25;
  452. }
  453. if ((tmp = strchr(tmp, ','))) {
  454. *tmp++ = '\0';
  455. numorder = atoi(tmp);
  456. if (numorder < 0)
  457. numorder = 0;
  458. } else
  459. numorder = 0;
  460. } else {
  461. timeout = 25;
  462. numorder = 0;
  463. }
  464. if (!numorder) {
  465. idx = 1;
  466. AST_LIST_TRAVERSE(&f->numbers, nm, entry)
  467. idx++;
  468. numorder = idx;
  469. }
  470. cur = create_followme_number(numberstr, timeout, numorder);
  471. if (cur) {
  472. AST_LIST_INSERT_TAIL(&f->numbers, cur, entry);
  473. }
  474. } else {
  475. profile_set_param(f, var->name, var->value, var->lineno, 1);
  476. ast_debug(2, "Logging parameter %s with value %s from lineno %d\n", var->name, var->value, var->lineno);
  477. }
  478. var = var->next;
  479. } /* End while(var) loop */
  480. if (!new)
  481. ast_mutex_unlock(&f->lock);
  482. else
  483. AST_RWLIST_INSERT_HEAD(&followmes, f, entry);
  484. }
  485. ast_config_destroy(cfg);
  486. AST_RWLIST_UNLOCK(&followmes);
  487. return 1;
  488. }
  489. static void publish_dial_end_event(struct ast_channel *in, struct findme_user_listptr *findme_user_list, struct ast_channel *exception, const char *status)
  490. {
  491. struct findme_user *tmpuser;
  492. AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
  493. if (tmpuser->ochan && tmpuser->ochan != exception) {
  494. ast_channel_publish_dial(in, tmpuser->ochan, NULL, status);
  495. }
  496. }
  497. }
  498. static void clear_caller(struct findme_user *tmpuser)
  499. {
  500. struct ast_channel *outbound;
  501. if (!tmpuser->ochan) {
  502. /* Call already cleared. */
  503. return;
  504. }
  505. outbound = tmpuser->ochan;
  506. ast_hangup(outbound);
  507. tmpuser->ochan = NULL;
  508. }
  509. static void clear_unanswered_calls(struct findme_user_listptr *findme_user_list)
  510. {
  511. struct findme_user *tmpuser;
  512. AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
  513. if (!tmpuser->answered) {
  514. clear_caller(tmpuser);
  515. }
  516. }
  517. }
  518. static void destroy_calling_node(struct findme_user *node)
  519. {
  520. clear_caller(node);
  521. ast_party_connected_line_free(&node->connected);
  522. ast_free(node);
  523. }
  524. static void destroy_calling_tree(struct findme_user_listptr *findme_user_list)
  525. {
  526. struct findme_user *fmuser;
  527. while ((fmuser = AST_LIST_REMOVE_HEAD(findme_user_list, entry))) {
  528. destroy_calling_node(fmuser);
  529. }
  530. }
  531. static struct ast_channel *wait_for_winner(struct findme_user_listptr *findme_user_list, struct number *nm, struct ast_channel *caller, struct fm_args *tpargs)
  532. {
  533. struct ast_party_connected_line connected;
  534. struct ast_channel *watchers[256];
  535. int pos;
  536. struct ast_channel *winner;
  537. struct ast_frame *f;
  538. struct findme_user *tmpuser;
  539. int to = 0;
  540. int livechannels;
  541. int tmpto;
  542. long totalwait = 0, wtd = 0, towas = 0;
  543. char *callfromname;
  544. char *pressbuttonname;
  545. /* ------------ wait_for_winner_channel start --------------- */
  546. callfromname = ast_strdupa(tpargs->callfromprompt);
  547. pressbuttonname = ast_strdupa(tpargs->optionsprompt);
  548. totalwait = nm->timeout * 1000;
  549. for (;;) {
  550. to = 1000;
  551. pos = 1;
  552. livechannels = 0;
  553. watchers[0] = caller;
  554. winner = NULL;
  555. AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
  556. if (!tmpuser->ochan) {
  557. continue;
  558. }
  559. if (tmpuser->state == 3) {
  560. tmpuser->digts += (towas - wtd);
  561. }
  562. if (tmpuser->digts && (tmpuser->digts > featuredigittimeout)) {
  563. ast_verb(3, "<%s> We've been waiting for digits longer than we should have.\n",
  564. ast_channel_name(tmpuser->ochan));
  565. if (!ast_strlen_zero(tpargs->namerecloc)) {
  566. tmpuser->state = 1;
  567. tmpuser->digts = 0;
  568. if (!ast_streamfile(tmpuser->ochan, callfromname, ast_channel_language(tmpuser->ochan))) {
  569. ast_sched_runq(ast_channel_sched(tmpuser->ochan));
  570. } else {
  571. ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
  572. clear_caller(tmpuser);
  573. continue;
  574. }
  575. } else {
  576. tmpuser->state = 2;
  577. tmpuser->digts = 0;
  578. if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
  579. ast_sched_runq(ast_channel_sched(tmpuser->ochan));
  580. else {
  581. ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
  582. clear_caller(tmpuser);
  583. continue;
  584. }
  585. }
  586. }
  587. if (ast_channel_stream(tmpuser->ochan)) {
  588. ast_sched_runq(ast_channel_sched(tmpuser->ochan));
  589. tmpto = ast_sched_wait(ast_channel_sched(tmpuser->ochan));
  590. if (tmpto > 0 && tmpto < to)
  591. to = tmpto;
  592. else if (tmpto < 0 && !ast_channel_timingfunc(tmpuser->ochan)) {
  593. ast_stopstream(tmpuser->ochan);
  594. switch (tmpuser->state) {
  595. case 1:
  596. ast_verb(3, "<%s> Playback of the call-from file appears to be done.\n",
  597. ast_channel_name(tmpuser->ochan));
  598. if (!ast_streamfile(tmpuser->ochan, tpargs->namerecloc, ast_channel_language(tmpuser->ochan))) {
  599. tmpuser->state = 2;
  600. } else {
  601. ast_log(LOG_NOTICE, "<%s> Unable to playback %s. Maybe the caller didn't record their name?\n",
  602. ast_channel_name(tmpuser->ochan), tpargs->namerecloc);
  603. memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
  604. tmpuser->ynidx = 0;
  605. if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan)))
  606. tmpuser->state = 3;
  607. else {
  608. ast_log(LOG_WARNING, "Unable to playback %s.\n", pressbuttonname);
  609. clear_caller(tmpuser);
  610. continue;
  611. }
  612. }
  613. break;
  614. case 2:
  615. ast_verb(3, "<%s> Playback of name file appears to be done.\n",
  616. ast_channel_name(tmpuser->ochan));
  617. memset(tmpuser->yn, 0, sizeof(tmpuser->yn));
  618. tmpuser->ynidx = 0;
  619. if (!ast_streamfile(tmpuser->ochan, pressbuttonname, ast_channel_language(tmpuser->ochan))) {
  620. tmpuser->state = 3;
  621. } else {
  622. clear_caller(tmpuser);
  623. continue;
  624. }
  625. break;
  626. case 3:
  627. ast_verb(3, "<%s> Playback of the next step file appears to be done.\n",
  628. ast_channel_name(tmpuser->ochan));
  629. tmpuser->digts = 0;
  630. break;
  631. default:
  632. break;
  633. }
  634. }
  635. }
  636. watchers[pos++] = tmpuser->ochan;
  637. livechannels++;
  638. }
  639. if (!livechannels) {
  640. ast_verb(3, "No live channels left for this step.\n");
  641. return NULL;
  642. }
  643. tmpto = to;
  644. if (to < 0) {
  645. to = 1000;
  646. tmpto = 1000;
  647. }
  648. towas = to;
  649. winner = ast_waitfor_n(watchers, pos, &to);
  650. tmpto -= to;
  651. totalwait -= tmpto;
  652. wtd = to;
  653. if (totalwait <= 0) {
  654. ast_verb(3, "We've hit our timeout for this step. Dropping unanswered calls and starting the next step.\n");
  655. clear_unanswered_calls(findme_user_list);
  656. return NULL;
  657. }
  658. if (winner) {
  659. /* Need to find out which channel this is */
  660. if (winner != caller) {
  661. /* The winner is an outgoing channel. */
  662. AST_LIST_TRAVERSE(findme_user_list, tmpuser, entry) {
  663. if (tmpuser->ochan == winner) {
  664. break;
  665. }
  666. }
  667. } else {
  668. tmpuser = NULL;
  669. }
  670. f = ast_read(winner);
  671. if (f) {
  672. if (f->frametype == AST_FRAME_CONTROL) {
  673. switch (f->subclass.integer) {
  674. case AST_CONTROL_HANGUP:
  675. ast_verb(3, "%s received a hangup frame.\n", ast_channel_name(winner));
  676. if (f->data.uint32) {
  677. ast_channel_hangupcause_set(winner, f->data.uint32);
  678. }
  679. if (!tmpuser) {
  680. ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
  681. publish_dial_end_event(caller, findme_user_list, NULL, "CANCEL");
  682. ast_frfree(f);
  683. return NULL;
  684. }
  685. clear_caller(tmpuser);
  686. break;
  687. case AST_CONTROL_ANSWER:
  688. if (!tmpuser) {
  689. /* The caller answered? We want an outgoing channel to answer. */
  690. break;
  691. }
  692. ast_verb(3, "%s answered %s\n", ast_channel_name(winner), ast_channel_name(caller));
  693. ast_channel_publish_dial(caller, winner, NULL, "ANSWER");
  694. publish_dial_end_event(caller, findme_user_list, winner, "CANCEL");
  695. tmpuser->answered = 1;
  696. /* If call has been answered, then the eventual hangup is likely to be normal hangup */
  697. ast_channel_hangupcause_set(winner, AST_CAUSE_NORMAL_CLEARING);
  698. ast_channel_hangupcause_set(caller, AST_CAUSE_NORMAL_CLEARING);
  699. ast_verb(3, "Starting playback of %s\n", callfromname);
  700. if (!ast_strlen_zero(tpargs->namerecloc)) {
  701. if (!ast_streamfile(winner, callfromname, ast_channel_language(winner))) {
  702. ast_sched_runq(ast_channel_sched(winner));
  703. tmpuser->state = 1;
  704. } else {
  705. ast_log(LOG_WARNING, "Unable to playback %s.\n", callfromname);
  706. clear_caller(tmpuser);
  707. }
  708. } else {
  709. tmpuser->state = 2;
  710. if (!ast_streamfile(tmpuser->ochan, tpargs->norecordingprompt, ast_channel_language(tmpuser->ochan)))
  711. ast_sched_runq(ast_channel_sched(tmpuser->ochan));
  712. else {
  713. ast_log(LOG_WARNING, "Unable to playback %s.\n", tpargs->norecordingprompt);
  714. clear_caller(tmpuser);
  715. }
  716. }
  717. break;
  718. case AST_CONTROL_BUSY:
  719. ast_verb(3, "%s is busy\n", ast_channel_name(winner));
  720. if (tmpuser) {
  721. /* Outbound call was busy. Drop it. */
  722. ast_channel_publish_dial(caller, winner, NULL, "BUSY");
  723. clear_caller(tmpuser);
  724. }
  725. break;
  726. case AST_CONTROL_CONGESTION:
  727. ast_verb(3, "%s is circuit-busy\n", ast_channel_name(winner));
  728. if (tmpuser) {
  729. /* Outbound call was congested. Drop it. */
  730. ast_channel_publish_dial(caller, winner, NULL, "CONGESTION");
  731. clear_caller(tmpuser);
  732. }
  733. break;
  734. case AST_CONTROL_RINGING:
  735. ast_verb(3, "%s is ringing\n", ast_channel_name(winner));
  736. break;
  737. case AST_CONTROL_PROGRESS:
  738. ast_verb(3, "%s is making progress\n", ast_channel_name(winner));
  739. break;
  740. case AST_CONTROL_VIDUPDATE:
  741. ast_verb(3, "%s requested a video update\n", ast_channel_name(winner));
  742. break;
  743. case AST_CONTROL_SRCUPDATE:
  744. ast_verb(3, "%s requested a source update\n", ast_channel_name(winner));
  745. break;
  746. case AST_CONTROL_PROCEEDING:
  747. ast_verb(3, "%s is proceeding\n", ast_channel_name(winner));
  748. break;
  749. case AST_CONTROL_HOLD:
  750. ast_verb(3, "%s placed call on hold\n", ast_channel_name(winner));
  751. if (!tmpuser) {
  752. /* Caller placed outgoing calls on hold. */
  753. tpargs->pending_hold = 1;
  754. if (f->data.ptr) {
  755. ast_copy_string(tpargs->suggested_moh, f->data.ptr,
  756. sizeof(tpargs->suggested_moh));
  757. } else {
  758. tpargs->suggested_moh[0] = '\0';
  759. }
  760. } else {
  761. /*
  762. * Outgoing call placed caller on hold.
  763. *
  764. * Ignore because the outgoing call should not be able to place
  765. * the caller on hold until after they are bridged.
  766. */
  767. }
  768. break;
  769. case AST_CONTROL_UNHOLD:
  770. ast_verb(3, "%s removed call from hold\n", ast_channel_name(winner));
  771. if (!tmpuser) {
  772. /* Caller removed outgoing calls from hold. */
  773. tpargs->pending_hold = 0;
  774. } else {
  775. /*
  776. * Outgoing call removed caller from hold.
  777. *
  778. * Ignore because the outgoing call should not be able to place
  779. * the caller on hold until after they are bridged.
  780. */
  781. }
  782. break;
  783. case AST_CONTROL_OFFHOOK:
  784. case AST_CONTROL_FLASH:
  785. /* Ignore going off hook and flash */
  786. break;
  787. case AST_CONTROL_CONNECTED_LINE:
  788. if (!tmpuser) {
  789. /*
  790. * Hold connected line update from caller until we have a
  791. * winner.
  792. */
  793. ast_verb(3,
  794. "%s connected line has changed. Saving it until we have a winner.\n",
  795. ast_channel_name(winner));
  796. ast_party_connected_line_set_init(&connected, &tpargs->connected_in);
  797. if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
  798. ast_party_connected_line_set(&tpargs->connected_in,
  799. &connected, NULL);
  800. tpargs->pending_in_connected_update = 1;
  801. }
  802. ast_party_connected_line_free(&connected);
  803. break;
  804. }
  805. if (ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_IGNORE_CONNECTEDLINE)) {
  806. ast_verb(3, "Connected line update from %s prevented.\n",
  807. ast_channel_name(winner));
  808. } else {
  809. ast_verb(3,
  810. "%s connected line has changed. Saving it until answer.\n",
  811. ast_channel_name(winner));
  812. ast_party_connected_line_set_init(&connected, &tmpuser->connected);
  813. if (!ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected)) {
  814. ast_party_connected_line_set(&tmpuser->connected,
  815. &connected, NULL);
  816. tmpuser->pending_connected_update = 1;
  817. }
  818. ast_party_connected_line_free(&connected);
  819. }
  820. break;
  821. case AST_CONTROL_REDIRECTING:
  822. /*
  823. * Ignore because we are masking the FollowMe search progress to
  824. * the caller.
  825. */
  826. break;
  827. case AST_CONTROL_PVT_CAUSE_CODE:
  828. ast_indicate_data(caller, f->subclass.integer, f->data.ptr, f->datalen);
  829. break;
  830. case -1:
  831. ast_verb(3, "%s stopped sounds\n", ast_channel_name(winner));
  832. break;
  833. default:
  834. ast_debug(1, "Dunno what to do with control type %d from %s\n",
  835. f->subclass.integer, ast_channel_name(winner));
  836. break;
  837. }
  838. }
  839. if (tmpuser && tmpuser->state == 3 && f->frametype == AST_FRAME_DTMF) {
  840. int cmp_len;
  841. if (ast_channel_stream(winner))
  842. ast_stopstream(winner);
  843. tmpuser->digts = 0;
  844. ast_debug(1, "DTMF received: %c\n", (char) f->subclass.integer);
  845. if (tmpuser->ynidx < ARRAY_LEN(tmpuser->yn) - 1) {
  846. tmpuser->yn[tmpuser->ynidx++] = f->subclass.integer;
  847. } else {
  848. /* Discard oldest digit. */
  849. memmove(tmpuser->yn, tmpuser->yn + 1,
  850. sizeof(tmpuser->yn) - 2 * sizeof(tmpuser->yn[0]));
  851. tmpuser->yn[ARRAY_LEN(tmpuser->yn) - 2] = f->subclass.integer;
  852. }
  853. ast_debug(1, "DTMF string: %s\n", tmpuser->yn);
  854. cmp_len = strlen(tpargs->takecall);
  855. if (cmp_len <= tmpuser->ynidx
  856. && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->takecall)) {
  857. ast_debug(1, "Match to take the call!\n");
  858. ast_frfree(f);
  859. return tmpuser->ochan;
  860. }
  861. cmp_len = strlen(tpargs->nextindp);
  862. if (cmp_len <= tmpuser->ynidx
  863. && !strcmp(tmpuser->yn + (tmpuser->ynidx - cmp_len), tpargs->nextindp)) {
  864. ast_debug(1, "Declined to take the call.\n");
  865. clear_caller(tmpuser);
  866. }
  867. }
  868. ast_frfree(f);
  869. } else {
  870. ast_debug(1, "we didn't get a frame. hanging up.\n");
  871. if (!tmpuser) {
  872. /* Caller hung up. */
  873. ast_verb(3, "The calling channel hungup. Need to drop everyone.\n");
  874. return NULL;
  875. }
  876. /* Outgoing channel hung up. */
  877. ast_channel_publish_dial(caller, winner, NULL, "NOANSWER");
  878. clear_caller(tmpuser);
  879. }
  880. } else {
  881. ast_debug(1, "timed out waiting for action\n");
  882. }
  883. }
  884. /* Unreachable. */
  885. }
  886. /*!
  887. * \internal
  888. * \brief Find an extension willing to take the call.
  889. *
  890. * \param tpargs Active Followme config.
  891. * \param caller Channel initiating the outgoing calls.
  892. *
  893. * \retval winner Winning outgoing call.
  894. * \retval NULL if could not find someone to take the call.
  895. */
  896. static struct ast_channel *findmeexec(struct fm_args *tpargs, struct ast_channel *caller)
  897. {
  898. struct number *nm;
  899. struct ast_channel *winner = NULL;
  900. char num[512];
  901. int dg, idx;
  902. char *rest, *number;
  903. struct findme_user *tmpuser;
  904. struct findme_user *fmuser;
  905. struct findme_user_listptr findme_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
  906. struct findme_user_listptr new_user_list = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
  907. for (idx = 1; !ast_check_hangup(caller); ++idx) {
  908. /* Find next followme numbers to dial. */
  909. AST_LIST_TRAVERSE(&tpargs->cnumbers, nm, entry) {
  910. if (nm->order == idx) {
  911. break;
  912. }
  913. }
  914. if (!nm) {
  915. ast_verb(3, "No more steps left.\n");
  916. break;
  917. }
  918. ast_debug(2, "Number(s) %s timeout %ld\n", nm->number, nm->timeout);
  919. /*
  920. * Put all active outgoing channels into autoservice.
  921. *
  922. * This needs to be done because ast_exists_extension() may put
  923. * the caller into autoservice.
  924. */
  925. AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
  926. if (tmpuser->ochan) {
  927. ast_autoservice_start(tmpuser->ochan);
  928. }
  929. }
  930. /* Create all new outgoing calls */
  931. ast_copy_string(num, nm->number, sizeof(num));
  932. for (number = num; number; number = rest) {
  933. struct ast_channel *outbound;
  934. rest = strchr(number, '&');
  935. if (rest) {
  936. *rest++ = 0;
  937. }
  938. /* We check if the extension exists, before creating the ast_channel struct */
  939. if (!ast_exists_extension(caller, tpargs->context, number, 1, S_COR(ast_channel_caller(caller)->id.number.valid, ast_channel_caller(caller)->id.number.str, NULL))) {
  940. ast_log(LOG_ERROR, "Extension '%s@%s' doesn't exist\n", number, tpargs->context);
  941. continue;
  942. }
  943. tmpuser = ast_calloc(1, sizeof(*tmpuser));
  944. if (!tmpuser) {
  945. continue;
  946. }
  947. if (ast_strlen_zero(tpargs->context)) {
  948. snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s%s",
  949. number,
  950. ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION)
  951. ? "/n" : "/m");
  952. } else {
  953. snprintf(tmpuser->dialarg, sizeof(tmpuser->dialarg), "%s@%s%s",
  954. number, tpargs->context,
  955. ast_test_flag(&tpargs->followmeflags, FOLLOWMEFLAG_DISABLEOPTIMIZATION)
  956. ? "/n" : "/m");
  957. }
  958. outbound = ast_request("Local", ast_channel_nativeformats(caller), NULL, caller,
  959. tmpuser->dialarg, &dg);
  960. if (!outbound) {
  961. ast_log(LOG_WARNING, "Unable to allocate a channel for Local/%s cause: %s\n",
  962. tmpuser->dialarg, ast_cause2str(dg));
  963. ast_free(tmpuser);
  964. continue;
  965. }
  966. ast_channel_lock_both(caller, outbound);
  967. ast_connected_line_copy_from_caller(ast_channel_connected(outbound), ast_channel_caller(caller));
  968. ast_channel_inherit_variables(caller, outbound);
  969. ast_channel_datastore_inherit(caller, outbound);
  970. ast_channel_language_set(outbound, ast_channel_language(caller));
  971. ast_channel_req_accountcodes(outbound, caller, AST_CHANNEL_REQUESTOR_BRIDGE_PEER);
  972. ast_channel_musicclass_set(outbound, ast_channel_musicclass(caller));
  973. ast_channel_unlock(outbound);
  974. ast_channel_unlock(caller);
  975. tmpuser->ochan = outbound;
  976. tmpuser->state = 0;
  977. AST_LIST_INSERT_TAIL(&new_user_list, tmpuser, entry);
  978. }
  979. /*
  980. * PREDIAL: Run gosub on all of the new callee channels
  981. *
  982. * We run the callee predial before ast_call() in case the user
  983. * wishes to do something on the newly created channels before
  984. * the channel does anything important.
  985. */
  986. if (tpargs->predial_callee && !AST_LIST_EMPTY(&new_user_list)) {
  987. /* Put caller into autoservice. */
  988. ast_autoservice_start(caller);
  989. /* Run predial on all new outgoing calls. */
  990. AST_LIST_TRAVERSE(&new_user_list, tmpuser, entry) {
  991. ast_pre_call(tmpuser->ochan, tpargs->predial_callee);
  992. }
  993. /* Take caller out of autoservice. */
  994. if (ast_autoservice_stop(caller)) {
  995. /*
  996. * Caller hungup.
  997. *
  998. * Destoy all new outgoing calls.
  999. */
  1000. while ((tmpuser = AST_LIST_REMOVE_HEAD(&new_user_list, entry))) {
  1001. destroy_calling_node(tmpuser);
  1002. }
  1003. /* Take all active outgoing channels out of autoservice. */
  1004. AST_LIST_TRAVERSE(&findme_user_list, tmpuser, entry) {
  1005. if (tmpuser->ochan) {
  1006. ast_autoservice_stop(tmpuser->ochan);
  1007. }
  1008. }
  1009. break;
  1010. }
  1011. }
  1012. /* Start all new outgoing calls */
  1013. AST_LIST_TRAVERSE_SAFE_BEGIN(&new_user_list, tmpuser, entry) {
  1014. ast_verb(3, "calling Local/%s\n", tmpuser->dialarg);
  1015. if (ast_call(tmpuser->ochan, tmpuser->dialarg, 0)) {
  1016. ast_verb(3, "couldn't reach at this number.\n");
  1017. AST_LIST_REMOVE_CURRENT(entry);
  1018. /* Destroy this failed new outgoing call. */
  1019. destroy_calling_node(tmpuser);
  1020. continue;
  1021. }
  1022. ast_channel_publish_dial(caller, tmpuser->ochan, tmpuser->dialarg, NULL);
  1023. }
  1024. AST_LIST_TRAVERSE_SAFE_END;
  1025. /* Take all active outgoing channels out of autoservice. */
  1026. AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
  1027. if (tmpuser->ochan && ast_autoservice_stop(tmpuser->ochan)) {
  1028. /* Existing outgoing call hungup. */
  1029. AST_LIST_REMOVE_CURRENT(entry);
  1030. destroy_calling_node(tmpuser);
  1031. }
  1032. }
  1033. AST_LIST_TRAVERSE_SAFE_END;
  1034. if (AST_LIST_EMPTY(&new_user_list)) {
  1035. /* No new channels remain at this order level. If there were any at all. */
  1036. continue;
  1037. }
  1038. /* Add new outgoing channels to the findme list. */
  1039. AST_LIST_APPEND_LIST(&findme_user_list, &new_user_list, entry);
  1040. winner = wait_for_winner(&findme_user_list, nm, caller, tpargs);
  1041. if (!winner) {
  1042. /* Remove all dead outgoing nodes. */
  1043. AST_LIST_TRAVERSE_SAFE_BEGIN(&findme_user_list, tmpuser, entry) {
  1044. if (!tmpuser->ochan) {
  1045. AST_LIST_REMOVE_CURRENT(entry);
  1046. destroy_calling_node(tmpuser);
  1047. }
  1048. }
  1049. AST_LIST_TRAVERSE_SAFE_END;
  1050. continue;
  1051. }
  1052. /* Destroy losing calls up to the winner. The rest will be destroyed later. */
  1053. while ((fmuser = AST_LIST_REMOVE_HEAD(&findme_user_list, entry))) {
  1054. if (fmuser->ochan == winner) {
  1055. /*
  1056. * Pass any connected line info up.
  1057. *
  1058. * NOTE: This code must be in line with destroy_calling_node().
  1059. */
  1060. tpargs->connected_out = fmuser->connected;
  1061. tpargs->pending_out_connected_update = fmuser->pending_connected_update;
  1062. ast_free(fmuser);
  1063. break;
  1064. } else {
  1065. /* Destroy losing call. */
  1066. destroy_calling_node(fmuser);
  1067. }
  1068. }
  1069. break;
  1070. }
  1071. destroy_calling_tree(&findme_user_list);
  1072. return winner;
  1073. }
  1074. static struct call_followme *find_realtime(const char *name)
  1075. {
  1076. struct ast_variable *var;
  1077. struct ast_variable *v;
  1078. struct ast_config *cfg;
  1079. const char *catg;
  1080. struct call_followme *new_follower;
  1081. struct ast_str *str;
  1082. str = ast_str_create(16);
  1083. if (!str) {
  1084. return NULL;
  1085. }
  1086. var = ast_load_realtime("followme", "name", name, SENTINEL);
  1087. if (!var) {
  1088. ast_free(str);
  1089. return NULL;
  1090. }
  1091. if (!(new_follower = alloc_profile(name))) {
  1092. ast_variables_destroy(var);
  1093. ast_free(str);
  1094. return NULL;
  1095. }
  1096. for (v = var; v; v = v->next) {
  1097. if (!strcasecmp(v->name, "active")) {
  1098. if (ast_false(v->value)) {
  1099. ast_mutex_destroy(&new_follower->lock);
  1100. ast_free(new_follower);
  1101. ast_variables_destroy(var);
  1102. ast_free(str);
  1103. return NULL;
  1104. }
  1105. } else {
  1106. profile_set_param(new_follower, v->name, v->value, 0, 0);
  1107. }
  1108. }
  1109. ast_variables_destroy(var);
  1110. new_follower->realtime = 1;
  1111. /* Load numbers */
  1112. cfg = ast_load_realtime_multientry("followme_numbers", "ordinal LIKE", "%", "name",
  1113. name, SENTINEL);
  1114. if (!cfg) {
  1115. ast_mutex_destroy(&new_follower->lock);
  1116. ast_free(new_follower);
  1117. ast_free(str);
  1118. return NULL;
  1119. }
  1120. for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
  1121. const char *numstr;
  1122. const char *timeoutstr;
  1123. const char *ordstr;
  1124. int timeout;
  1125. struct number *cur;
  1126. if (!(numstr = ast_variable_retrieve(cfg, catg, "phonenumber"))) {
  1127. continue;
  1128. }
  1129. if (!(timeoutstr = ast_variable_retrieve(cfg, catg, "timeout"))
  1130. || sscanf(timeoutstr, "%30d", &timeout) != 1
  1131. || timeout < 1) {
  1132. timeout = 25;
  1133. }
  1134. /* This one has to exist; it was part of the query */
  1135. ordstr = ast_variable_retrieve(cfg, catg, "ordinal");
  1136. ast_str_set(&str, 0, "%s", numstr);
  1137. if ((cur = create_followme_number(ast_str_buffer(str), timeout, atoi(ordstr)))) {
  1138. AST_LIST_INSERT_TAIL(&new_follower->numbers, cur, entry);
  1139. }
  1140. }
  1141. ast_config_destroy(cfg);
  1142. ast_free(str);
  1143. return new_follower;
  1144. }
  1145. static void end_bridge_callback(void *data)
  1146. {
  1147. char buf[80];
  1148. time_t end;
  1149. struct ast_channel *chan = data;
  1150. time(&end);
  1151. ast_channel_lock(chan);
  1152. snprintf(buf, sizeof(buf), "%d", ast_channel_get_up_time(chan));
  1153. pbx_builtin_setvar_helper(chan, "ANSWEREDTIME", buf);
  1154. snprintf(buf, sizeof(buf), "%d", ast_channel_get_duration(chan));
  1155. pbx_builtin_setvar_helper(chan, "DIALEDTIME", buf);
  1156. ast_channel_unlock(chan);
  1157. }
  1158. static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
  1159. {
  1160. bconfig->end_bridge_callback_data = originator;
  1161. }
  1162. static int app_exec(struct ast_channel *chan, const char *data)
  1163. {
  1164. struct fm_args *targs;
  1165. struct ast_bridge_config config;
  1166. struct call_followme *f;
  1167. struct number *nm, *newnm;
  1168. int res = 0;
  1169. char *argstr;
  1170. struct ast_channel *caller;
  1171. struct ast_channel *outbound;
  1172. AST_DECLARE_APP_ARGS(args,
  1173. AST_APP_ARG(followmeid);
  1174. AST_APP_ARG(options);
  1175. );
  1176. char *opt_args[FOLLOWMEFLAG_ARG_ARRAY_SIZE];
  1177. if (ast_strlen_zero(data)) {
  1178. ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
  1179. return -1;
  1180. }
  1181. argstr = ast_strdupa((char *) data);
  1182. AST_STANDARD_APP_ARGS(args, argstr);
  1183. if (ast_strlen_zero(args.followmeid)) {
  1184. ast_log(LOG_WARNING, "%s requires an argument (followmeid)\n", app);
  1185. return -1;
  1186. }
  1187. targs = ast_calloc(1, sizeof(*targs));
  1188. if (!targs) {
  1189. return -1;
  1190. }
  1191. AST_RWLIST_RDLOCK(&followmes);
  1192. AST_RWLIST_TRAVERSE(&followmes, f, entry) {
  1193. if (!strcasecmp(f->name, args.followmeid) && (f->active))
  1194. break;
  1195. }
  1196. AST_RWLIST_UNLOCK(&followmes);
  1197. ast_debug(1, "New profile %s.\n", args.followmeid);
  1198. if (!f) {
  1199. f = find_realtime(args.followmeid);
  1200. }
  1201. if (!f) {
  1202. ast_log(LOG_WARNING, "Profile requested, %s, not found in the configuration.\n", args.followmeid);
  1203. ast_free(targs);
  1204. return 0;
  1205. }
  1206. /* XXX TODO: Reinsert the db check value to see whether or not follow-me is on or off */
  1207. if (args.options) {
  1208. ast_app_parse_options(followme_opts, &targs->followmeflags, opt_args, args.options);
  1209. }
  1210. /* Lock the profile lock and copy out everything we need to run with before unlocking it again */
  1211. ast_mutex_lock(&f->lock);
  1212. targs->mohclass = ast_strdupa(f->moh);
  1213. ast_copy_string(targs->context, f->context, sizeof(targs->context));
  1214. ast_copy_string(targs->takecall, f->takecall, sizeof(targs->takecall));
  1215. ast_copy_string(targs->nextindp, f->nextindp, sizeof(targs->nextindp));
  1216. ast_copy_string(targs->callfromprompt, f->callfromprompt, sizeof(targs->callfromprompt));
  1217. ast_copy_string(targs->norecordingprompt, f->norecordingprompt, sizeof(targs->norecordingprompt));
  1218. ast_copy_string(targs->optionsprompt, f->optionsprompt, sizeof(targs->optionsprompt));
  1219. ast_copy_string(targs->plsholdprompt, f->plsholdprompt, sizeof(targs->plsholdprompt));
  1220. ast_copy_string(targs->statusprompt, f->statusprompt, sizeof(targs->statusprompt));
  1221. ast_copy_string(targs->sorryprompt, f->sorryprompt, sizeof(targs->sorryprompt));
  1222. /* Copy the numbers we're going to use into another list in case the master list should get modified
  1223. (and locked) while we're trying to do a follow-me */
  1224. AST_LIST_HEAD_INIT_NOLOCK(&targs->cnumbers);
  1225. AST_LIST_TRAVERSE(&f->numbers, nm, entry) {
  1226. newnm = create_followme_number(nm->number, nm->timeout, nm->order);
  1227. if (newnm) {
  1228. AST_LIST_INSERT_TAIL(&targs->cnumbers, newnm, entry);
  1229. }
  1230. }
  1231. ast_mutex_unlock(&f->lock);
  1232. /* PREDIAL: Preprocess any callee gosub arguments. */
  1233. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLEE)
  1234. && !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE])) {
  1235. ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE]);
  1236. targs->predial_callee =
  1237. ast_app_expand_sub_args(chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLEE]);
  1238. }
  1239. /* PREDIAL: Run gosub on the caller's channel */
  1240. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_PREDIAL_CALLER)
  1241. && !ast_strlen_zero(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER])) {
  1242. ast_replace_subargument_delimiter(opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER]);
  1243. ast_app_exec_sub(NULL, chan, opt_args[FOLLOWMEFLAG_ARG_PREDIAL_CALLER], 0);
  1244. }
  1245. /* Forget the 'N' option if the call is already up. */
  1246. if (ast_channel_state(chan) == AST_STATE_UP) {
  1247. ast_clear_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER);
  1248. }
  1249. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
  1250. ast_indicate(chan, AST_CONTROL_RINGING);
  1251. } else {
  1252. /* Answer the call */
  1253. if (ast_channel_state(chan) != AST_STATE_UP) {
  1254. ast_answer(chan);
  1255. }
  1256. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_STATUSMSG)) {
  1257. ast_stream_and_wait(chan, targs->statusprompt, "");
  1258. }
  1259. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_RECORDNAME)) {
  1260. int duration = 5;
  1261. snprintf(targs->namerecloc, sizeof(targs->namerecloc), "%s/followme.%s",
  1262. ast_config_AST_SPOOL_DIR, ast_channel_uniqueid(chan));
  1263. if (ast_play_and_record(chan, "vm-rec-name", targs->namerecloc, 5, "sln", &duration,
  1264. NULL, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE), 0, NULL) < 0) {
  1265. goto outrun;
  1266. }
  1267. if (!ast_fileexists(targs->namerecloc, NULL, ast_channel_language(chan))) {
  1268. targs->namerecloc[0] = '\0';
  1269. }
  1270. }
  1271. if (!ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_DISABLEHOLDPROMPT)) {
  1272. if (ast_streamfile(chan, targs->plsholdprompt, ast_channel_language(chan))) {
  1273. goto outrun;
  1274. }
  1275. if (ast_waitstream(chan, "") < 0)
  1276. goto outrun;
  1277. }
  1278. ast_moh_start(chan, targs->mohclass, NULL);
  1279. }
  1280. ast_channel_lock(chan);
  1281. ast_connected_line_copy_from_caller(&targs->connected_in, ast_channel_caller(chan));
  1282. ast_channel_unlock(chan);
  1283. outbound = findmeexec(targs, chan);
  1284. if (!outbound) {
  1285. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
  1286. if (ast_channel_state(chan) != AST_STATE_UP) {
  1287. ast_answer(chan);
  1288. }
  1289. } else {
  1290. ast_moh_stop(chan);
  1291. }
  1292. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_UNREACHABLEMSG)) {
  1293. ast_stream_and_wait(chan, targs->sorryprompt, "");
  1294. }
  1295. res = 0;
  1296. } else {
  1297. caller = chan;
  1298. /* Bridge the two channels. */
  1299. memset(&config, 0, sizeof(config));
  1300. ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
  1301. ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
  1302. ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
  1303. config.end_bridge_callback = end_bridge_callback;
  1304. config.end_bridge_callback_data = chan;
  1305. config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
  1306. /* Update connected line to caller if available. */
  1307. if (targs->pending_out_connected_update) {
  1308. if (ast_channel_connected_line_sub(outbound, caller, &targs->connected_out, 0) &&
  1309. ast_channel_connected_line_macro(outbound, caller, &targs->connected_out, 1, 0)) {
  1310. ast_channel_update_connected_line(caller, &targs->connected_out, NULL);
  1311. }
  1312. }
  1313. if (ast_test_flag(&targs->followmeflags, FOLLOWMEFLAG_NOANSWER)) {
  1314. if (ast_channel_state(caller) != AST_STATE_UP) {
  1315. ast_answer(caller);
  1316. }
  1317. } else {
  1318. ast_moh_stop(caller);
  1319. }
  1320. /* Be sure no generators are left on it */
  1321. ast_deactivate_generator(caller);
  1322. /* Make sure channels are compatible */
  1323. res = ast_channel_make_compatible(caller, outbound);
  1324. if (res < 0) {
  1325. ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(caller), ast_channel_name(outbound));
  1326. ast_autoservice_chan_hangup_peer(caller, outbound);
  1327. goto outrun;
  1328. }
  1329. /* Update connected line to winner if changed. */
  1330. if (targs->pending_in_connected_update) {
  1331. if (ast_channel_connected_line_sub(caller, outbound, &targs->connected_in, 0) &&
  1332. ast_channel_connected_line_macro(caller, outbound, &targs->connected_in, 0, 0)) {
  1333. ast_channel_update_connected_line(outbound, &targs->connected_in, NULL);
  1334. }
  1335. }
  1336. /* Put winner on hold if caller requested. */
  1337. if (targs->pending_hold) {
  1338. if (ast_strlen_zero(targs->suggested_moh)) {
  1339. ast_indicate_data(outbound, AST_CONTROL_HOLD, NULL, 0);
  1340. } else {
  1341. ast_indicate_data(outbound, AST_CONTROL_HOLD,
  1342. targs->suggested_moh, strlen(targs->suggested_moh) + 1);
  1343. }
  1344. }
  1345. res = ast_bridge_call(caller, outbound, &config);
  1346. }
  1347. outrun:
  1348. while ((nm = AST_LIST_REMOVE_HEAD(&targs->cnumbers, entry))) {
  1349. ast_free(nm);
  1350. }
  1351. if (!ast_strlen_zero(targs->namerecloc)) {
  1352. unlink(targs->namerecloc);
  1353. }
  1354. ast_free((char *) targs->predial_callee);
  1355. ast_party_connected_line_free(&targs->connected_in);
  1356. ast_party_connected_line_free(&targs->connected_out);
  1357. ast_free(targs);
  1358. if (f->realtime) {
  1359. /* Not in list */
  1360. free_numbers(f);
  1361. ast_free(f);
  1362. }
  1363. return res;
  1364. }
  1365. static int unload_module(void)
  1366. {
  1367. struct call_followme *f;
  1368. ast_unregister_application(app);
  1369. /* Free Memory. Yeah! I'm free! */
  1370. AST_RWLIST_WRLOCK(&followmes);
  1371. while ((f = AST_RWLIST_REMOVE_HEAD(&followmes, entry))) {
  1372. free_numbers(f);
  1373. ast_free(f);
  1374. }
  1375. AST_RWLIST_UNLOCK(&followmes);
  1376. return 0;
  1377. }
  1378. /*!
  1379. * \brief Load the module
  1380. *
  1381. * Module loading including tests for configuration or dependencies.
  1382. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
  1383. * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
  1384. * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
  1385. * configuration file or other non-critical problem return
  1386. * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
  1387. */
  1388. static int load_module(void)
  1389. {
  1390. if(!reload_followme(0))
  1391. return AST_MODULE_LOAD_DECLINE;
  1392. return ast_register_application_xml(app, app_exec);
  1393. }
  1394. static int reload(void)
  1395. {
  1396. reload_followme(1);
  1397. return 0;
  1398. }
  1399. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Find-Me/Follow-Me Application",
  1400. .support_level = AST_MODULE_SUPPORT_CORE,
  1401. .load = load_module,
  1402. .unload = unload_module,
  1403. .reload = reload,
  1404. );