app.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 1999 - 2005, Digium, Inc.
  5. *
  6. * Mark Spencer <markster@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Convenient Application Routines
  21. *
  22. */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/time.h>
  27. #include <signal.h>
  28. #include <errno.h>
  29. #include <unistd.h>
  30. #include <dirent.h>
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <regex.h>
  34. #include "asterisk.h"
  35. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  36. #include "asterisk/channel.h"
  37. #include "asterisk/pbx.h"
  38. #include "asterisk/file.h"
  39. #include "asterisk/app.h"
  40. #include "asterisk/dsp.h"
  41. #include "asterisk/logger.h"
  42. #include "asterisk/options.h"
  43. #include "asterisk/utils.h"
  44. #include "asterisk/lock.h"
  45. #include "asterisk/indications.h"
  46. #include "asterisk/linkedlists.h"
  47. #define MAX_OTHER_FORMATS 10
  48. static AST_LIST_HEAD_STATIC(groups, ast_group_info);
  49. /* !
  50. This function presents a dialtone and reads an extension into 'collect'
  51. which must be a pointer to a **pre-initilized** array of char having a
  52. size of 'size' suitable for writing to. It will collect no more than the smaller
  53. of 'maxlen' or 'size' minus the original strlen() of collect digits.
  54. \return 0 if extension does not exist, 1 if extension exists
  55. */
  56. int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
  57. {
  58. struct tone_zone_sound *ts;
  59. int res=0, x=0;
  60. if(maxlen > size)
  61. maxlen = size;
  62. if(!timeout && chan->pbx)
  63. timeout = chan->pbx->dtimeout;
  64. else if(!timeout)
  65. timeout = 5;
  66. ts = ast_get_indication_tone(chan->zone,"dial");
  67. if (ts && ts->data[0])
  68. res = ast_playtones_start(chan, 0, ts->data, 0);
  69. else
  70. ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
  71. for (x = strlen(collect); strlen(collect) < maxlen; ) {
  72. res = ast_waitfordigit(chan, timeout);
  73. if (!ast_ignore_pattern(context, collect))
  74. ast_playtones_stop(chan);
  75. if (res < 1)
  76. break;
  77. if (res == '#')
  78. break;
  79. collect[x++] = res;
  80. if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num))
  81. break;
  82. }
  83. if (res >= 0) {
  84. if (ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num))
  85. res = 1;
  86. else
  87. res = 0;
  88. }
  89. return res;
  90. }
  91. /*! \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
  92. "ludicrous time" (essentially never times out) */
  93. int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
  94. {
  95. int res,to,fto;
  96. /* XXX Merge with full version? XXX */
  97. if (maxlen)
  98. s[0] = '\0';
  99. if (prompt) {
  100. res = ast_streamfile(c, prompt, c->language);
  101. if (res < 0)
  102. return res;
  103. }
  104. fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
  105. to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
  106. if (timeout > 0)
  107. fto = to = timeout;
  108. if (timeout < 0)
  109. fto = to = 1000000000;
  110. res = ast_readstring(c, s, maxlen, to, fto, "#");
  111. return res;
  112. }
  113. int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
  114. {
  115. int res,to,fto;
  116. if (prompt) {
  117. res = ast_streamfile(c, prompt, c->language);
  118. if (res < 0)
  119. return res;
  120. }
  121. fto = 6000;
  122. to = 2000;
  123. if (timeout > 0)
  124. fto = to = timeout;
  125. if (timeout < 0)
  126. fto = to = 1000000000;
  127. res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
  128. return res;
  129. }
  130. int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
  131. {
  132. int res;
  133. struct ast_filestream *writer;
  134. int rfmt;
  135. int totalms=0, total;
  136. struct ast_frame *f;
  137. struct ast_dsp *sildet;
  138. /* Play prompt if requested */
  139. if (prompt) {
  140. res = ast_streamfile(c, prompt, c->language);
  141. if (res < 0)
  142. return res;
  143. res = ast_waitstream(c,"");
  144. if (res < 0)
  145. return res;
  146. }
  147. rfmt = c->readformat;
  148. res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
  149. if (res < 0) {
  150. ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
  151. return -1;
  152. }
  153. sildet = ast_dsp_new();
  154. if (!sildet) {
  155. ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
  156. return -1;
  157. }
  158. writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
  159. if (!writer) {
  160. ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
  161. ast_dsp_free(sildet);
  162. return -1;
  163. }
  164. for(;;) {
  165. if ((res = ast_waitfor(c, 2000)) < 0) {
  166. ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
  167. break;
  168. }
  169. if (res) {
  170. f = ast_read(c);
  171. if (!f) {
  172. ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
  173. break;
  174. }
  175. if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
  176. /* Ended happily with DTMF */
  177. ast_frfree(f);
  178. break;
  179. } else if (f->frametype == AST_FRAME_VOICE) {
  180. ast_dsp_silence(sildet, f, &total);
  181. if (total > silence) {
  182. /* Ended happily with silence */
  183. ast_frfree(f);
  184. break;
  185. }
  186. totalms += f->samples / 8;
  187. if (totalms > maxsec * 1000) {
  188. /* Ended happily with too much stuff */
  189. ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
  190. ast_frfree(f);
  191. break;
  192. }
  193. res = ast_writestream(writer, f);
  194. if (res < 0) {
  195. ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
  196. ast_frfree(f);
  197. break;
  198. }
  199. }
  200. ast_frfree(f);
  201. }
  202. }
  203. res = ast_set_read_format(c, rfmt);
  204. if (res)
  205. ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
  206. ast_dsp_free(sildet);
  207. ast_closestream(writer);
  208. return 0;
  209. }
  210. static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
  211. static int (*ast_messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
  212. void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
  213. int (*messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs))
  214. {
  215. ast_has_voicemail_func = has_voicemail_func;
  216. ast_messagecount_func = messagecount_func;
  217. }
  218. void ast_uninstall_vm_functions(void)
  219. {
  220. ast_has_voicemail_func = NULL;
  221. ast_messagecount_func = NULL;
  222. }
  223. int ast_app_has_voicemail(const char *mailbox, const char *folder)
  224. {
  225. static int warned = 0;
  226. if (ast_has_voicemail_func)
  227. return ast_has_voicemail_func(mailbox, folder);
  228. if ((option_verbose > 2) && !warned) {
  229. ast_verbose(VERBOSE_PREFIX_3 "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
  230. warned++;
  231. }
  232. return 0;
  233. }
  234. int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
  235. {
  236. static int warned = 0;
  237. if (newmsgs)
  238. *newmsgs = 0;
  239. if (oldmsgs)
  240. *oldmsgs = 0;
  241. if (ast_messagecount_func)
  242. return ast_messagecount_func(mailbox, newmsgs, oldmsgs);
  243. if (!warned && (option_verbose > 2)) {
  244. warned++;
  245. ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
  246. }
  247. return 0;
  248. }
  249. int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between)
  250. {
  251. char *ptr;
  252. int res = 0;
  253. struct ast_frame f;
  254. if (!between)
  255. between = 100;
  256. if (peer)
  257. res = ast_autoservice_start(peer);
  258. if (!res) {
  259. res = ast_waitfor(chan,100);
  260. if (res > -1) {
  261. for (ptr=digits; *ptr; ptr++) {
  262. if (*ptr == 'w') {
  263. res = ast_safe_sleep(chan, 500);
  264. if (res)
  265. break;
  266. continue;
  267. }
  268. memset(&f, 0, sizeof(f));
  269. f.frametype = AST_FRAME_DTMF;
  270. f.subclass = *ptr;
  271. f.src = "ast_dtmf_stream";
  272. if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
  273. ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
  274. } else {
  275. res = ast_write(chan, &f);
  276. if (res)
  277. break;
  278. /* pause between digits */
  279. res = ast_safe_sleep(chan,between);
  280. if (res)
  281. break;
  282. }
  283. }
  284. }
  285. if (peer) {
  286. /* Stop autoservice on the peer channel, but don't overwrite any error condition
  287. that has occurred previously while acting on the primary channel */
  288. if (ast_autoservice_stop(peer) && !res)
  289. res = -1;
  290. }
  291. }
  292. return res;
  293. }
  294. struct linear_state {
  295. int fd;
  296. int autoclose;
  297. int allowoverride;
  298. int origwfmt;
  299. };
  300. static void linear_release(struct ast_channel *chan, void *params)
  301. {
  302. struct linear_state *ls = params;
  303. if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
  304. ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
  305. }
  306. if (ls->autoclose)
  307. close(ls->fd);
  308. free(params);
  309. }
  310. static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
  311. {
  312. struct ast_frame f;
  313. short buf[2048 + AST_FRIENDLY_OFFSET / 2];
  314. struct linear_state *ls = data;
  315. int res;
  316. len = samples * 2;
  317. if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
  318. ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
  319. len = sizeof(buf) - AST_FRIENDLY_OFFSET;
  320. }
  321. memset(&f, 0, sizeof(f));
  322. res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
  323. if (res > 0) {
  324. f.frametype = AST_FRAME_VOICE;
  325. f.subclass = AST_FORMAT_SLINEAR;
  326. f.data = buf + AST_FRIENDLY_OFFSET/2;
  327. f.datalen = res;
  328. f.samples = res / 2;
  329. f.offset = AST_FRIENDLY_OFFSET;
  330. ast_write(chan, &f);
  331. if (res == len)
  332. return 0;
  333. }
  334. return -1;
  335. }
  336. static void *linear_alloc(struct ast_channel *chan, void *params)
  337. {
  338. struct linear_state *ls;
  339. /* In this case, params is already malloc'd */
  340. if (params) {
  341. ls = params;
  342. if (ls->allowoverride)
  343. ast_set_flag(chan, AST_FLAG_WRITE_INT);
  344. else
  345. ast_clear_flag(chan, AST_FLAG_WRITE_INT);
  346. ls->origwfmt = chan->writeformat;
  347. if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
  348. ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
  349. free(ls);
  350. ls = params = NULL;
  351. }
  352. }
  353. return params;
  354. }
  355. static struct ast_generator linearstream =
  356. {
  357. alloc: linear_alloc,
  358. release: linear_release,
  359. generate: linear_generator,
  360. };
  361. int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
  362. {
  363. struct linear_state *lin;
  364. char tmpf[256];
  365. int res = -1;
  366. int autoclose = 0;
  367. if (fd < 0) {
  368. if (ast_strlen_zero(filename))
  369. return -1;
  370. autoclose = 1;
  371. if (filename[0] == '/')
  372. ast_copy_string(tmpf, filename, sizeof(tmpf));
  373. else
  374. snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
  375. fd = open(tmpf, O_RDONLY);
  376. if (fd < 0){
  377. ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
  378. return -1;
  379. }
  380. }
  381. lin = malloc(sizeof(struct linear_state));
  382. if (lin) {
  383. memset(lin, 0, sizeof(lin));
  384. lin->fd = fd;
  385. lin->allowoverride = allowoverride;
  386. lin->autoclose = autoclose;
  387. res = ast_activate_generator(chan, &linearstream, lin);
  388. }
  389. return res;
  390. }
  391. int ast_control_streamfile(struct ast_channel *chan, const char *file,
  392. const char *fwd, const char *rev,
  393. const char *stop, const char *pause,
  394. const char *restart, int skipms)
  395. {
  396. char *breaks = NULL;
  397. char *end = NULL;
  398. int blen = 2;
  399. int res;
  400. long pause_restart_point = 0;
  401. if (stop)
  402. blen += strlen(stop);
  403. if (pause)
  404. blen += strlen(pause);
  405. if (restart)
  406. blen += strlen(restart);
  407. if (blen > 2) {
  408. breaks = alloca(blen + 1);
  409. breaks[0] = '\0';
  410. if (stop)
  411. strcat(breaks, stop);
  412. if (pause)
  413. strcat(breaks, pause);
  414. if (restart)
  415. strcat(breaks, restart);
  416. }
  417. if (chan->_state != AST_STATE_UP)
  418. res = ast_answer(chan);
  419. if (file) {
  420. if ((end = strchr(file,':'))) {
  421. if (!strcasecmp(end, ":end")) {
  422. *end = '\0';
  423. end++;
  424. }
  425. }
  426. }
  427. for (;;) {
  428. ast_stopstream(chan);
  429. res = ast_streamfile(chan, file, chan->language);
  430. if (!res) {
  431. if (pause_restart_point) {
  432. ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
  433. pause_restart_point = 0;
  434. }
  435. else if (end) {
  436. ast_seekstream(chan->stream, 0, SEEK_END);
  437. end = NULL;
  438. };
  439. res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
  440. }
  441. if (res < 1)
  442. break;
  443. /* We go at next loop if we got the restart char */
  444. if (restart && strchr(restart, res)) {
  445. ast_log(LOG_DEBUG, "we'll restart the stream here at next loop\n");
  446. pause_restart_point = 0;
  447. continue;
  448. }
  449. if (pause && strchr(pause, res)) {
  450. pause_restart_point = ast_tellstream(chan->stream);
  451. for (;;) {
  452. ast_stopstream(chan);
  453. res = ast_waitfordigit(chan, 1000);
  454. if (!res)
  455. continue;
  456. else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
  457. break;
  458. }
  459. if (res == *pause) {
  460. res = 0;
  461. continue;
  462. }
  463. }
  464. if (res == -1)
  465. break;
  466. /* if we get one of our stop chars, return it to the calling function */
  467. if (stop && strchr(stop, res))
  468. break;
  469. }
  470. ast_stopstream(chan);
  471. return res;
  472. }
  473. int ast_play_and_wait(struct ast_channel *chan, const char *fn)
  474. {
  475. int d;
  476. d = ast_streamfile(chan, fn, chan->language);
  477. if (d)
  478. return d;
  479. d = ast_waitstream(chan, AST_DIGIT_ANY);
  480. ast_stopstream(chan);
  481. return d;
  482. }
  483. static int global_silence_threshold = 128;
  484. static int global_maxsilence = 0;
  485. int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
  486. {
  487. int d;
  488. char *fmts;
  489. char comment[256];
  490. int x, fmtcnt=1, res=-1,outmsg=0;
  491. struct ast_frame *f;
  492. struct ast_filestream *others[MAX_OTHER_FORMATS];
  493. char *sfmt[MAX_OTHER_FORMATS];
  494. char *stringp=NULL;
  495. time_t start, end;
  496. struct ast_dsp *sildet=NULL; /* silence detector dsp */
  497. int totalsilence = 0;
  498. int dspsilence = 0;
  499. int rfmt=0;
  500. struct ast_silence_generator *silgen = NULL;
  501. if (silencethreshold < 0)
  502. silencethreshold = global_silence_threshold;
  503. if (maxsilence < 0)
  504. maxsilence = global_maxsilence;
  505. /* barf if no pointer passed to store duration in */
  506. if (duration == NULL) {
  507. ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
  508. return -1;
  509. }
  510. ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
  511. snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
  512. if (playfile) {
  513. d = ast_play_and_wait(chan, playfile);
  514. if (d > -1)
  515. d = ast_streamfile(chan, "beep",chan->language);
  516. if (!d)
  517. d = ast_waitstream(chan,"");
  518. if (d < 0)
  519. return -1;
  520. }
  521. fmts = ast_strdupa(fmt);
  522. stringp=fmts;
  523. strsep(&stringp, "|");
  524. ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
  525. sfmt[0] = ast_strdupa(fmts);
  526. while((fmt = strsep(&stringp, "|"))) {
  527. if (fmtcnt > MAX_OTHER_FORMATS - 1) {
  528. ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
  529. break;
  530. }
  531. sfmt[fmtcnt++] = ast_strdupa(fmt);
  532. }
  533. time(&start);
  534. end=start; /* pre-initialize end to be same as start in case we never get into loop */
  535. for (x=0;x<fmtcnt;x++) {
  536. others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
  537. ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
  538. if (!others[x]) {
  539. break;
  540. }
  541. }
  542. if (path)
  543. ast_unlock_path(path);
  544. if (maxsilence > 0) {
  545. sildet = ast_dsp_new(); /* Create the silence detector */
  546. if (!sildet) {
  547. ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
  548. return -1;
  549. }
  550. ast_dsp_set_threshold(sildet, silencethreshold);
  551. rfmt = chan->readformat;
  552. res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
  553. if (res < 0) {
  554. ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
  555. ast_dsp_free(sildet);
  556. return -1;
  557. }
  558. }
  559. /* Request a video update */
  560. ast_indicate(chan, AST_CONTROL_VIDUPDATE);
  561. if (option_transmit_silence_during_record)
  562. silgen = ast_channel_start_silence_generator(chan);
  563. if (x == fmtcnt) {
  564. /* Loop forever, writing the packets we read to the writer(s), until
  565. we read a # or get a hangup */
  566. f = NULL;
  567. for(;;) {
  568. res = ast_waitfor(chan, 2000);
  569. if (!res) {
  570. ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
  571. /* Try one more time in case of masq */
  572. res = ast_waitfor(chan, 2000);
  573. if (!res) {
  574. ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
  575. res = -1;
  576. }
  577. }
  578. if (res < 0) {
  579. f = NULL;
  580. break;
  581. }
  582. f = ast_read(chan);
  583. if (!f)
  584. break;
  585. if (f->frametype == AST_FRAME_VOICE) {
  586. /* write each format */
  587. for (x=0;x<fmtcnt;x++) {
  588. res = ast_writestream(others[x], f);
  589. }
  590. /* Silence Detection */
  591. if (maxsilence > 0) {
  592. dspsilence = 0;
  593. ast_dsp_silence(sildet, f, &dspsilence);
  594. if (dspsilence)
  595. totalsilence = dspsilence;
  596. else
  597. totalsilence = 0;
  598. if (totalsilence > maxsilence) {
  599. /* Ended happily with silence */
  600. if (option_verbose > 2)
  601. ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
  602. ast_frfree(f);
  603. res = 'S';
  604. outmsg=2;
  605. break;
  606. }
  607. }
  608. /* Exit on any error */
  609. if (res) {
  610. ast_log(LOG_WARNING, "Error writing frame\n");
  611. ast_frfree(f);
  612. break;
  613. }
  614. } else if (f->frametype == AST_FRAME_VIDEO) {
  615. /* Write only once */
  616. ast_writestream(others[0], f);
  617. } else if (f->frametype == AST_FRAME_DTMF) {
  618. if (strchr(acceptdtmf, f->subclass)) {
  619. if (option_verbose > 2)
  620. ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
  621. res = f->subclass;
  622. outmsg = 2;
  623. ast_frfree(f);
  624. break;
  625. }
  626. if (strchr(canceldtmf, f->subclass)) {
  627. if (option_verbose > 2)
  628. ast_verbose(VERBOSE_PREFIX_3 "User cancelled message by pressing %c\n", f->subclass);
  629. res = f->subclass;
  630. outmsg = 0;
  631. ast_frfree(f);
  632. break;
  633. }
  634. }
  635. if (maxtime) {
  636. time(&end);
  637. if (maxtime < (end - start)) {
  638. if (option_verbose > 2)
  639. ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
  640. outmsg = 2;
  641. res = 't';
  642. ast_frfree(f);
  643. break;
  644. }
  645. }
  646. ast_frfree(f);
  647. }
  648. if (end == start) time(&end);
  649. if (!f) {
  650. if (option_verbose > 2)
  651. ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
  652. res = -1;
  653. outmsg=1;
  654. }
  655. } else {
  656. ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
  657. }
  658. if (silgen)
  659. ast_channel_stop_silence_generator(chan, silgen);
  660. *duration = end - start;
  661. for (x=0;x<fmtcnt;x++) {
  662. if (!others[x])
  663. break;
  664. if (res > 0) {
  665. if (totalsilence)
  666. ast_stream_rewind(others[x], totalsilence-200);
  667. else
  668. ast_stream_rewind(others[x], 200);
  669. }
  670. ast_truncstream(others[x]);
  671. ast_closestream(others[x]);
  672. }
  673. if (rfmt) {
  674. if (ast_set_read_format(chan, rfmt)) {
  675. ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
  676. }
  677. }
  678. if (outmsg > 1) {
  679. /* Let them know recording is stopped */
  680. if(!ast_streamfile(chan, "auth-thankyou", chan->language))
  681. ast_waitstream(chan, "");
  682. }
  683. if (sildet)
  684. ast_dsp_free(sildet);
  685. return res;
  686. }
  687. static char default_acceptdtmf[] = "#";
  688. static char default_canceldtmf[] = "0";
  689. int ast_play_and_record(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
  690. {
  691. return ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path, default_acceptdtmf, default_canceldtmf);
  692. }
  693. int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
  694. {
  695. int d = 0;
  696. char *fmts;
  697. char comment[256];
  698. int x, fmtcnt=1, res=-1,outmsg=0;
  699. struct ast_frame *f;
  700. struct ast_filestream *others[MAX_OTHER_FORMATS];
  701. struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
  702. char *sfmt[MAX_OTHER_FORMATS];
  703. char *stringp=NULL;
  704. time_t start, end;
  705. struct ast_dsp *sildet; /* silence detector dsp */
  706. int totalsilence = 0;
  707. int dspsilence = 0;
  708. int rfmt=0;
  709. char prependfile[80];
  710. if (silencethreshold < 0)
  711. silencethreshold = global_silence_threshold;
  712. if (maxsilence < 0)
  713. maxsilence = global_maxsilence;
  714. /* barf if no pointer passed to store duration in */
  715. if (duration == NULL) {
  716. ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
  717. return -1;
  718. }
  719. ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
  720. snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
  721. if (playfile || beep) {
  722. if (!beep)
  723. d = ast_play_and_wait(chan, playfile);
  724. if (d > -1)
  725. d = ast_streamfile(chan, "beep",chan->language);
  726. if (!d)
  727. d = ast_waitstream(chan,"");
  728. if (d < 0)
  729. return -1;
  730. }
  731. ast_copy_string(prependfile, recordfile, sizeof(prependfile));
  732. strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
  733. fmts = ast_strdupa(fmt);
  734. stringp=fmts;
  735. strsep(&stringp, "|");
  736. ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
  737. sfmt[0] = ast_strdupa(fmts);
  738. while((fmt = strsep(&stringp, "|"))) {
  739. if (fmtcnt > MAX_OTHER_FORMATS - 1) {
  740. ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
  741. break;
  742. }
  743. sfmt[fmtcnt++] = ast_strdupa(fmt);
  744. }
  745. time(&start);
  746. end=start; /* pre-initialize end to be same as start in case we never get into loop */
  747. for (x=0;x<fmtcnt;x++) {
  748. others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
  749. ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
  750. if (!others[x]) {
  751. break;
  752. }
  753. }
  754. sildet = ast_dsp_new(); /* Create the silence detector */
  755. if (!sildet) {
  756. ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
  757. return -1;
  758. }
  759. ast_dsp_set_threshold(sildet, silencethreshold);
  760. if (maxsilence > 0) {
  761. rfmt = chan->readformat;
  762. res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
  763. if (res < 0) {
  764. ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
  765. ast_dsp_free(sildet);
  766. return -1;
  767. }
  768. }
  769. if (x == fmtcnt) {
  770. /* Loop forever, writing the packets we read to the writer(s), until
  771. we read a # or get a hangup */
  772. f = NULL;
  773. for(;;) {
  774. res = ast_waitfor(chan, 2000);
  775. if (!res) {
  776. ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
  777. /* Try one more time in case of masq */
  778. res = ast_waitfor(chan, 2000);
  779. if (!res) {
  780. ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
  781. res = -1;
  782. }
  783. }
  784. if (res < 0) {
  785. f = NULL;
  786. break;
  787. }
  788. f = ast_read(chan);
  789. if (!f)
  790. break;
  791. if (f->frametype == AST_FRAME_VOICE) {
  792. /* write each format */
  793. for (x=0;x<fmtcnt;x++) {
  794. if (!others[x])
  795. break;
  796. res = ast_writestream(others[x], f);
  797. }
  798. /* Silence Detection */
  799. if (maxsilence > 0) {
  800. dspsilence = 0;
  801. ast_dsp_silence(sildet, f, &dspsilence);
  802. if (dspsilence)
  803. totalsilence = dspsilence;
  804. else
  805. totalsilence = 0;
  806. if (totalsilence > maxsilence) {
  807. /* Ended happily with silence */
  808. if (option_verbose > 2)
  809. ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
  810. ast_frfree(f);
  811. res = 'S';
  812. outmsg=2;
  813. break;
  814. }
  815. }
  816. /* Exit on any error */
  817. if (res) {
  818. ast_log(LOG_WARNING, "Error writing frame\n");
  819. ast_frfree(f);
  820. break;
  821. }
  822. } else if (f->frametype == AST_FRAME_VIDEO) {
  823. /* Write only once */
  824. ast_writestream(others[0], f);
  825. } else if (f->frametype == AST_FRAME_DTMF) {
  826. /* stop recording with any digit */
  827. if (option_verbose > 2)
  828. ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
  829. res = 't';
  830. outmsg = 2;
  831. ast_frfree(f);
  832. break;
  833. }
  834. if (maxtime) {
  835. time(&end);
  836. if (maxtime < (end - start)) {
  837. if (option_verbose > 2)
  838. ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
  839. res = 't';
  840. outmsg=2;
  841. ast_frfree(f);
  842. break;
  843. }
  844. }
  845. ast_frfree(f);
  846. }
  847. if (end == start) time(&end);
  848. if (!f) {
  849. if (option_verbose > 2)
  850. ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
  851. res = -1;
  852. outmsg=1;
  853. #if 0
  854. /* delete all the prepend files */
  855. for (x=0;x<fmtcnt;x++) {
  856. if (!others[x])
  857. break;
  858. ast_closestream(others[x]);
  859. ast_filedelete(prependfile, sfmt[x]);
  860. }
  861. #endif
  862. }
  863. } else {
  864. ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
  865. }
  866. ast_dsp_free(sildet);
  867. *duration = end - start;
  868. #if 0
  869. if (outmsg > 1) {
  870. #else
  871. if (outmsg) {
  872. #endif
  873. struct ast_frame *fr;
  874. for (x=0;x<fmtcnt;x++) {
  875. snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
  876. realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
  877. if (!others[x] || !realfiles[x])
  878. break;
  879. if (totalsilence)
  880. ast_stream_rewind(others[x], totalsilence-200);
  881. else
  882. ast_stream_rewind(others[x], 200);
  883. ast_truncstream(others[x]);
  884. /* add the original file too */
  885. while ((fr = ast_readframe(realfiles[x]))) {
  886. ast_writestream(others[x],fr);
  887. }
  888. ast_closestream(others[x]);
  889. ast_closestream(realfiles[x]);
  890. ast_filerename(prependfile, recordfile, sfmt[x]);
  891. #if 0
  892. ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
  893. #endif
  894. ast_filedelete(prependfile, sfmt[x]);
  895. }
  896. }
  897. if (rfmt) {
  898. if (ast_set_read_format(chan, rfmt)) {
  899. ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
  900. }
  901. }
  902. if (outmsg) {
  903. if (outmsg > 1) {
  904. /* Let them know it worked */
  905. ast_streamfile(chan, "auth-thankyou", chan->language);
  906. ast_waitstream(chan, "");
  907. }
  908. }
  909. return res;
  910. }
  911. /* Channel group core functions */
  912. int ast_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max)
  913. {
  914. int res=0;
  915. char tmp[256];
  916. char *grp=NULL, *cat=NULL;
  917. if (!ast_strlen_zero(data)) {
  918. ast_copy_string(tmp, data, sizeof(tmp));
  919. grp = tmp;
  920. cat = strchr(tmp, '@');
  921. if (cat) {
  922. *cat = '\0';
  923. cat++;
  924. }
  925. }
  926. if (!ast_strlen_zero(grp))
  927. ast_copy_string(group, grp, group_max);
  928. else
  929. res = -1;
  930. if (!ast_strlen_zero(cat))
  931. ast_copy_string(category, cat, category_max);
  932. return res;
  933. }
  934. int ast_app_group_set_channel(struct ast_channel *chan, char *data)
  935. {
  936. int res = 0;
  937. char group[80] = "", category[80] = "";
  938. struct ast_group_info *gi = NULL;
  939. size_t len = 0;
  940. if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category)))
  941. return -1;
  942. /* Calculate memory we will need if this is new */
  943. len = sizeof(*gi) + strlen(group) + 1;
  944. if (!ast_strlen_zero(category))
  945. len += strlen(category) + 1;
  946. AST_LIST_LOCK(&groups);
  947. AST_LIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
  948. if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
  949. AST_LIST_REMOVE_CURRENT(&groups, list);
  950. free(gi);
  951. break;
  952. }
  953. }
  954. AST_LIST_TRAVERSE_SAFE_END
  955. if ((gi = calloc(1, len))) {
  956. gi->chan = chan;
  957. gi->group = (char *) gi + sizeof(*gi);
  958. strcpy(gi->group, group);
  959. if (!ast_strlen_zero(category)) {
  960. gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
  961. strcpy(gi->category, category);
  962. }
  963. AST_LIST_INSERT_TAIL(&groups, gi, list);
  964. } else {
  965. res = -1;
  966. }
  967. AST_LIST_UNLOCK(&groups);
  968. return res;
  969. }
  970. int ast_app_group_get_count(char *group, char *category)
  971. {
  972. struct ast_group_info *gi = NULL;
  973. int count = 0;
  974. if (ast_strlen_zero(group))
  975. return 0;
  976. AST_LIST_LOCK(&groups);
  977. AST_LIST_TRAVERSE(&groups, gi, list) {
  978. if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))))
  979. count++;
  980. }
  981. AST_LIST_UNLOCK(&groups);
  982. return count;
  983. }
  984. int ast_app_group_match_get_count(char *groupmatch, char *category)
  985. {
  986. struct ast_group_info *gi = NULL;
  987. regex_t regexbuf;
  988. int count = 0;
  989. if (ast_strlen_zero(groupmatch))
  990. return 0;
  991. /* if regex compilation fails, return zero matches */
  992. if (regcomp(&regexbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
  993. return 0;
  994. AST_LIST_LOCK(&groups);
  995. AST_LIST_TRAVERSE(&groups, gi, list) {
  996. if (!regexec(&regexbuf, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))))
  997. count++;
  998. }
  999. AST_LIST_UNLOCK(&groups);
  1000. regfree(&regexbuf);
  1001. return count;
  1002. }
  1003. int ast_app_group_update(struct ast_channel *old, struct ast_channel *new)
  1004. {
  1005. struct ast_group_info *gi = NULL;
  1006. AST_LIST_LOCK(&groups);
  1007. AST_LIST_TRAVERSE(&groups, gi, list) {
  1008. if (gi->chan == old)
  1009. gi->chan = new;
  1010. }
  1011. AST_LIST_UNLOCK(&groups);
  1012. return 0;
  1013. }
  1014. int ast_app_group_discard(struct ast_channel *chan)
  1015. {
  1016. struct ast_group_info *gi = NULL;
  1017. AST_LIST_LOCK(&groups);
  1018. AST_LIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
  1019. if (gi->chan == chan) {
  1020. AST_LIST_REMOVE_CURRENT(&groups, list);
  1021. free(gi);
  1022. }
  1023. }
  1024. AST_LIST_TRAVERSE_SAFE_END
  1025. AST_LIST_UNLOCK(&groups);
  1026. return 0;
  1027. }
  1028. int ast_app_group_list_lock(void)
  1029. {
  1030. return AST_LIST_LOCK(&groups);
  1031. }
  1032. struct ast_group_info *ast_app_group_list_head(void)
  1033. {
  1034. return AST_LIST_FIRST(&groups);
  1035. }
  1036. int ast_app_group_list_unlock(void)
  1037. {
  1038. return AST_LIST_UNLOCK(&groups);
  1039. }
  1040. unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
  1041. {
  1042. int argc;
  1043. char *scan;
  1044. int paren = 0;
  1045. if (!buf || !array || !arraylen)
  1046. return 0;
  1047. memset(array, 0, arraylen * sizeof(*array));
  1048. scan = buf;
  1049. for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
  1050. array[argc] = scan;
  1051. for (; *scan; scan++) {
  1052. if (*scan == '(')
  1053. paren++;
  1054. else if (*scan == ')') {
  1055. if (paren)
  1056. paren--;
  1057. } else if ((*scan == delim) && !paren) {
  1058. *scan++ = '\0';
  1059. break;
  1060. }
  1061. }
  1062. }
  1063. if (*scan)
  1064. array[argc++] = scan;
  1065. return argc;
  1066. }
  1067. enum AST_LOCK_RESULT ast_lock_path(const char *path)
  1068. {
  1069. char *s;
  1070. char *fs;
  1071. int res;
  1072. int fd;
  1073. time_t start;
  1074. s = alloca(strlen(path) + 10);
  1075. fs = alloca(strlen(path) + 20);
  1076. if (!fs || !s) {
  1077. ast_log(LOG_WARNING, "Out of memory!\n");
  1078. return AST_LOCK_FAILURE;
  1079. }
  1080. snprintf(fs, strlen(path) + 19, "%s/.lock-%08x", path, rand());
  1081. fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
  1082. if (fd < 0) {
  1083. ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
  1084. return AST_LOCK_PATH_NOT_FOUND;
  1085. }
  1086. close(fd);
  1087. snprintf(s, strlen(path) + 9, "%s/.lock", path);
  1088. time(&start);
  1089. while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
  1090. usleep(1);
  1091. unlink(fs);
  1092. if (res) {
  1093. ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
  1094. return AST_LOCK_TIMEOUT;
  1095. } else {
  1096. ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
  1097. return AST_LOCK_SUCCESS;
  1098. }
  1099. }
  1100. int ast_unlock_path(const char *path)
  1101. {
  1102. char *s;
  1103. int res;
  1104. s = alloca(strlen(path) + 10);
  1105. if (!s) {
  1106. ast_log(LOG_WARNING, "Out of memory!\n");
  1107. return -1;
  1108. }
  1109. snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
  1110. if ((res = unlink(s)))
  1111. ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
  1112. else
  1113. ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
  1114. return res;
  1115. }
  1116. int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
  1117. {
  1118. int silencethreshold = 128;
  1119. int maxsilence=0;
  1120. int res = 0;
  1121. int cmd = 0;
  1122. int max_attempts = 3;
  1123. int attempts = 0;
  1124. int recorded = 0;
  1125. int message_exists = 0;
  1126. /* Note that urgent and private are for flagging messages as such in the future */
  1127. /* barf if no pointer passed to store duration in */
  1128. if (duration == NULL) {
  1129. ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
  1130. return -1;
  1131. }
  1132. cmd = '3'; /* Want to start by recording */
  1133. while ((cmd >= 0) && (cmd != 't')) {
  1134. switch (cmd) {
  1135. case '1':
  1136. if (!message_exists) {
  1137. /* In this case, 1 is to record a message */
  1138. cmd = '3';
  1139. break;
  1140. } else {
  1141. ast_streamfile(chan, "vm-msgsaved", chan->language);
  1142. ast_waitstream(chan, "");
  1143. cmd = 't';
  1144. return res;
  1145. }
  1146. case '2':
  1147. /* Review */
  1148. ast_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n");
  1149. ast_streamfile(chan, recordfile, chan->language);
  1150. cmd = ast_waitstream(chan, AST_DIGIT_ANY);
  1151. break;
  1152. case '3':
  1153. message_exists = 0;
  1154. /* Record */
  1155. if (recorded == 1)
  1156. ast_verbose(VERBOSE_PREFIX_3 "Re-recording\n");
  1157. else
  1158. ast_verbose(VERBOSE_PREFIX_3 "Recording\n");
  1159. recorded = 1;
  1160. cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
  1161. if (cmd == -1) {
  1162. /* User has hung up, no options to give */
  1163. return cmd;
  1164. }
  1165. if (cmd == '0') {
  1166. break;
  1167. } else if (cmd == '*') {
  1168. break;
  1169. }
  1170. else {
  1171. /* If all is well, a message exists */
  1172. message_exists = 1;
  1173. cmd = 0;
  1174. }
  1175. break;
  1176. case '4':
  1177. case '5':
  1178. case '6':
  1179. case '7':
  1180. case '8':
  1181. case '9':
  1182. case '*':
  1183. case '#':
  1184. cmd = ast_play_and_wait(chan, "vm-sorry");
  1185. break;
  1186. default:
  1187. if (message_exists) {
  1188. cmd = ast_play_and_wait(chan, "vm-review");
  1189. }
  1190. else {
  1191. cmd = ast_play_and_wait(chan, "vm-torerecord");
  1192. if (!cmd)
  1193. cmd = ast_waitfordigit(chan, 600);
  1194. }
  1195. if (!cmd)
  1196. cmd = ast_waitfordigit(chan, 6000);
  1197. if (!cmd) {
  1198. attempts++;
  1199. }
  1200. if (attempts > max_attempts) {
  1201. cmd = 't';
  1202. }
  1203. }
  1204. }
  1205. if (cmd == 't')
  1206. cmd = 0;
  1207. return cmd;
  1208. }
  1209. #define RES_UPONE (1 << 16)
  1210. #define RES_EXIT (1 << 17)
  1211. #define RES_REPEAT (1 << 18)
  1212. #define RES_RESTART ((1 << 19) | RES_REPEAT)
  1213. static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
  1214. static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
  1215. {
  1216. int res;
  1217. int (*ivr_func)(struct ast_channel *, void *);
  1218. char *c;
  1219. char *n;
  1220. switch(option->action) {
  1221. case AST_ACTION_UPONE:
  1222. return RES_UPONE;
  1223. case AST_ACTION_EXIT:
  1224. return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
  1225. case AST_ACTION_REPEAT:
  1226. return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
  1227. case AST_ACTION_RESTART:
  1228. return RES_RESTART ;
  1229. case AST_ACTION_NOOP:
  1230. return 0;
  1231. case AST_ACTION_BACKGROUND:
  1232. res = ast_streamfile(chan, (char *)option->adata, chan->language);
  1233. if (!res) {
  1234. res = ast_waitstream(chan, AST_DIGIT_ANY);
  1235. } else {
  1236. ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
  1237. res = 0;
  1238. }
  1239. return res;
  1240. case AST_ACTION_PLAYBACK:
  1241. res = ast_streamfile(chan, (char *)option->adata, chan->language);
  1242. if (!res) {
  1243. res = ast_waitstream(chan, "");
  1244. } else {
  1245. ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
  1246. res = 0;
  1247. }
  1248. return res;
  1249. case AST_ACTION_MENU:
  1250. res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
  1251. /* Do not pass entry errors back up, treaat ast though ti was an "UPONE" */
  1252. if (res == -2)
  1253. res = 0;
  1254. return res;
  1255. case AST_ACTION_WAITOPTION:
  1256. res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
  1257. if (!res)
  1258. return 't';
  1259. return res;
  1260. case AST_ACTION_CALLBACK:
  1261. ivr_func = option->adata;
  1262. res = ivr_func(chan, cbdata);
  1263. return res;
  1264. case AST_ACTION_TRANSFER:
  1265. res = ast_parseable_goto(chan, option->adata);
  1266. return 0;
  1267. case AST_ACTION_PLAYLIST:
  1268. case AST_ACTION_BACKLIST:
  1269. res = 0;
  1270. c = ast_strdupa(option->adata);
  1271. if (c) {
  1272. while((n = strsep(&c, ";")))
  1273. if ((res = ast_streamfile(chan, n, chan->language)) || (res = ast_waitstream(chan, (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
  1274. break;
  1275. ast_stopstream(chan);
  1276. }
  1277. return res;
  1278. default:
  1279. ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
  1280. return 0;
  1281. };
  1282. return -1;
  1283. }
  1284. static int option_exists(struct ast_ivr_menu *menu, char *option)
  1285. {
  1286. int x;
  1287. for (x=0;menu->options[x].option;x++)
  1288. if (!strcasecmp(menu->options[x].option, option))
  1289. return x;
  1290. return -1;
  1291. }
  1292. static int option_matchmore(struct ast_ivr_menu *menu, char *option)
  1293. {
  1294. int x;
  1295. for (x=0;menu->options[x].option;x++)
  1296. if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
  1297. (menu->options[x].option[strlen(option)]))
  1298. return x;
  1299. return -1;
  1300. }
  1301. static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
  1302. {
  1303. int res=0;
  1304. int ms;
  1305. while(option_matchmore(menu, exten)) {
  1306. ms = chan->pbx ? chan->pbx->dtimeout : 5000;
  1307. if (strlen(exten) >= maxexten - 1)
  1308. break;
  1309. res = ast_waitfordigit(chan, ms);
  1310. if (res < 1)
  1311. break;
  1312. exten[strlen(exten) + 1] = '\0';
  1313. exten[strlen(exten)] = res;
  1314. }
  1315. return res > 0 ? 0 : res;
  1316. }
  1317. static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
  1318. {
  1319. /* Execute an IVR menu structure */
  1320. int res=0;
  1321. int pos = 0;
  1322. int retries = 0;
  1323. char exten[AST_MAX_EXTENSION] = "s";
  1324. if (option_exists(menu, "s") < 0) {
  1325. strcpy(exten, "g");
  1326. if (option_exists(menu, "g") < 0) {
  1327. ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
  1328. return -1;
  1329. }
  1330. }
  1331. while(!res) {
  1332. while(menu->options[pos].option) {
  1333. if (!strcasecmp(menu->options[pos].option, exten)) {
  1334. res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
  1335. ast_log(LOG_DEBUG, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
  1336. if (res < 0)
  1337. break;
  1338. else if (res & RES_UPONE)
  1339. return 0;
  1340. else if (res & RES_EXIT)
  1341. return res;
  1342. else if (res & RES_REPEAT) {
  1343. int maxretries = res & 0xffff;
  1344. if ((res & RES_RESTART) == RES_RESTART) {
  1345. retries = 0;
  1346. } else
  1347. retries++;
  1348. if (!maxretries)
  1349. maxretries = 3;
  1350. if ((maxretries > 0) && (retries >= maxretries)) {
  1351. ast_log(LOG_DEBUG, "Max retries %d exceeded\n", maxretries);
  1352. return -2;
  1353. } else {
  1354. if (option_exists(menu, "g") > -1)
  1355. strcpy(exten, "g");
  1356. else if (option_exists(menu, "s") > -1)
  1357. strcpy(exten, "s");
  1358. }
  1359. pos=0;
  1360. continue;
  1361. } else if (res && strchr(AST_DIGIT_ANY, res)) {
  1362. ast_log(LOG_DEBUG, "Got start of extension, %c\n", res);
  1363. exten[1] = '\0';
  1364. exten[0] = res;
  1365. if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
  1366. break;
  1367. if (option_exists(menu, exten) < 0) {
  1368. if (option_exists(menu, "i")) {
  1369. ast_log(LOG_DEBUG, "Invalid extension entered, going to 'i'!\n");
  1370. strcpy(exten, "i");
  1371. pos = 0;
  1372. continue;
  1373. } else {
  1374. ast_log(LOG_DEBUG, "Aborting on invalid entry, with no 'i' option!\n");
  1375. res = -2;
  1376. break;
  1377. }
  1378. } else {
  1379. ast_log(LOG_DEBUG, "New existing extension: %s\n", exten);
  1380. pos = 0;
  1381. continue;
  1382. }
  1383. }
  1384. }
  1385. pos++;
  1386. }
  1387. ast_log(LOG_DEBUG, "Stopping option '%s', res is %d\n", exten, res);
  1388. pos = 0;
  1389. if (!strcasecmp(exten, "s"))
  1390. strcpy(exten, "g");
  1391. else
  1392. break;
  1393. }
  1394. return res;
  1395. }
  1396. int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
  1397. {
  1398. int res;
  1399. res = ast_ivr_menu_run_internal(chan, menu, cbdata);
  1400. /* Hide internal coding */
  1401. if (res > 0)
  1402. res = 0;
  1403. return res;
  1404. }
  1405. char *ast_read_textfile(const char *filename)
  1406. {
  1407. int fd;
  1408. char *output=NULL;
  1409. struct stat filesize;
  1410. int count=0;
  1411. int res;
  1412. if(stat(filename,&filesize)== -1){
  1413. ast_log(LOG_WARNING,"Error can't stat %s\n", filename);
  1414. return NULL;
  1415. }
  1416. count=filesize.st_size + 1;
  1417. fd = open(filename, O_RDONLY);
  1418. if (fd < 0) {
  1419. ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
  1420. return NULL;
  1421. }
  1422. output=(char *)malloc(count);
  1423. if (output) {
  1424. res = read(fd, output, count - 1);
  1425. if (res == count - 1) {
  1426. output[res] = '\0';
  1427. } else {
  1428. ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
  1429. free(output);
  1430. output = NULL;
  1431. }
  1432. } else
  1433. ast_log(LOG_WARNING, "Out of memory!\n");
  1434. close(fd);
  1435. return output;
  1436. }
  1437. int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
  1438. {
  1439. char *s;
  1440. int curarg;
  1441. unsigned int argloc;
  1442. char *arg;
  1443. int res = 0;
  1444. ast_clear_flag(flags, AST_FLAGS_ALL);
  1445. if (!optstr)
  1446. return 0;
  1447. s = optstr;
  1448. while (*s) {
  1449. curarg = *s++ & 0x7f;
  1450. ast_set_flag(flags, options[curarg].flag);
  1451. argloc = options[curarg].arg_index;
  1452. if (*s == '(') {
  1453. /* Has argument */
  1454. arg = ++s;
  1455. while (*s && (*s != ')'))
  1456. s++;
  1457. if (*s) {
  1458. if (argloc)
  1459. args[argloc - 1] = arg;
  1460. *s++ = '\0';
  1461. } else {
  1462. ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
  1463. res = -1;
  1464. }
  1465. } else if (argloc) {
  1466. args[argloc - 1] = NULL;
  1467. }
  1468. }
  1469. return res;
  1470. }