app_qcall.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /** @file app_qcall.c
  2. *
  3. * Asterisk -- A telephony toolkit for Linux.
  4. *
  5. * Call back a party and connect them to a running pbx thread
  6. *
  7. * Copyright (C) 1999, Mark Spencer
  8. *
  9. * Mark Spencer <markster@linux-support.net>
  10. *
  11. * This program is free software, distributed under the terms of
  12. * the GNU General Public License
  13. *
  14. * Call a user from a file contained within a queue (/var/spool/asterisk/qcall)
  15. *
  16. * The queue is a directory containing files with the call request information
  17. * as a single line of text as follows:
  18. *
  19. * Dialstring Caller-ID Extension Maxsecs [Identifier] [Required-response]
  20. *
  21. * Dialstring -- A Dial String (The number to be called) in the
  22. * format Technology/Number, such IAX/mysys/1234 or Zap/g1/1234
  23. *
  24. * Caller-ID -- A Standard nomalized representation of the Caller-ID of
  25. * the number being dialed (generally 10 digits in the US). Leave as
  26. * "asreceived" to use the default Caller*ID
  27. *
  28. * Extension -- The Extension (optionally Extension@context) that the
  29. * user should be "transferred" to after acceptance of the call.
  30. *
  31. * Maxsecs -- The Maximum time of the call in seconds. Specify 0 for infinite.
  32. *
  33. * Identifier -- The "Identifier" of the request. This is used to determine
  34. * the names of the audio prompt files played. The first prompt, the one that
  35. * asks for the input, is just the exact string specified as the identifier.
  36. * The second prompt, the one that is played after the correct input is given,
  37. * (generally a "thank you" recording), is the specified string with "-ok"
  38. * added to the end. So, if you specify "foo" as the identifier, your first
  39. * prompt file that will be played will be "foo" and the second one will be
  40. * "foo-ok". If omitted no prompt is given
  41. *
  42. * Required-Response (Optional) -- Specify a digit string to be used as the
  43. * acceptance "code" if you desire it to be something other then "1". This
  44. * can be used to implement some sort of PIN or security system. It may be
  45. * more then a single character.
  46. *
  47. * NOTE: It is important to remember that the process that creates these
  48. * files needs keep and maintain a write lock (using flock with the LOCK_EX
  49. * option) when writing these files.
  50. *
  51. */
  52. #include <asterisk/lock.h>
  53. #include <asterisk/utils.h>
  54. #include <asterisk/file.h>
  55. #include <asterisk/logger.h>
  56. #include <asterisk/channel.h>
  57. #include <asterisk/pbx.h>
  58. #include <asterisk/module.h>
  59. #include <asterisk/translate.h>
  60. #include <asterisk/options.h>
  61. #include <stdio.h>
  62. #include <unistd.h>
  63. #include <string.h>
  64. #include <stdlib.h>
  65. #include <sys/types.h>
  66. #include <sys/stat.h>
  67. #include <errno.h>
  68. #include <dirent.h>
  69. #include <ctype.h>
  70. #include <sys/stat.h>
  71. #include <sys/time.h>
  72. #include <sys/file.h>
  73. #include "../astconf.h"
  74. static char qdir[255];
  75. static char *tdesc = "Call from Queue";
  76. static pthread_t qcall_thread;
  77. static int debug = 0;
  78. STANDARD_LOCAL_USER;
  79. LOCAL_USER_DECL;
  80. #define OLDESTOK 14400 /* not any more then this number of secs old */
  81. #define INITIALONE 1 /* initial wait before the first one in secs */
  82. #define NEXTONE 600 /* wait before trying it again in secs */
  83. #define MAXWAITFORANSWER 45000 /* max call time before answer */
  84. /* define either one or both of these two if your application requires it */
  85. #if 0
  86. #define ACCTCODE "SOMETHING" /* Account code */
  87. #define AMAFLAGS AST_CDR_BILLING /* AMA flags */
  88. #endif
  89. /* define this if you want to have a particular CLID display on the user's
  90. phone when they receive the call */
  91. #if 0
  92. #define OURCLID "2564286275" /* The callerid to be displayed when calling */
  93. #endif
  94. static void *qcall_do(void *arg);
  95. static void *qcall(void *ignore)
  96. {
  97. pthread_t dialer_thread;
  98. DIR *dirp;
  99. FILE *fp;
  100. struct dirent *dp;
  101. char fname[80];
  102. struct stat mystat;
  103. time_t t;
  104. void *arg;
  105. pthread_attr_t attr;
  106. time(&t);
  107. if (debug) printf("@@@@ qcall starting at %s",ctime(&t));
  108. for(;;)
  109. {
  110. time(&t);
  111. dirp = opendir(qdir);
  112. if (!dirp)
  113. {
  114. perror("app_qcall:Cannot open queue directory");
  115. break;
  116. }
  117. while((dp = readdir(dirp)) != NULL)
  118. {
  119. if (dp->d_name[0] == '.') continue;
  120. snprintf(fname, sizeof(fname), "%s/%s", qdir, dp->d_name);
  121. if (stat(fname,&mystat) == -1)
  122. {
  123. perror("app_qcall:stat");
  124. fprintf(stderr,"%s\n",fname);
  125. continue;
  126. }
  127. /* if not a regular file, skip it */
  128. if ((mystat.st_mode & S_IFMT) != S_IFREG) continue;
  129. /* if not yet .... */
  130. if (mystat.st_atime == mystat.st_mtime)
  131. { /* first time */
  132. if ((mystat.st_atime + INITIALONE) > t)
  133. continue;
  134. }
  135. else
  136. { /* already looked at once */
  137. if ((mystat.st_atime + NEXTONE) > t) continue;
  138. }
  139. /* if too old */
  140. if (mystat.st_mtime < (t - OLDESTOK))
  141. {
  142. /* kill it, its too old */
  143. unlink(fname);
  144. continue;
  145. }
  146. /* "touch" file's access time */
  147. fp = fopen(fname,"r");
  148. if (fp) fclose(fp);
  149. /* make a copy of the filename string, so that we
  150. may go on and use the buffer */
  151. arg = (void *) strdup(fname);
  152. pthread_attr_init(&attr);
  153. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  154. if (ast_pthread_create(&dialer_thread,&attr,qcall_do,arg) == -1)
  155. {
  156. perror("qcall: Cannot create thread");
  157. continue;
  158. }
  159. }
  160. closedir(dirp);
  161. sleep(1);
  162. }
  163. pthread_exit(NULL);
  164. }
  165. /* single thread with one file (request) to dial */
  166. static void *qcall_do(void *arg)
  167. {
  168. char fname[300] = "";
  169. char dialstr[300];
  170. char extstr[300];
  171. char ident[300] = "";
  172. char reqinp[300] = "";
  173. char buf[300];
  174. char clid[300],*tele,*context;
  175. FILE *fp;
  176. int ms = MAXWAITFORANSWER,maxsecs;
  177. struct ast_channel *channel;
  178. time_t t;
  179. /* get the filename from the arg */
  180. strncpy(fname,(char *)arg, sizeof(fname) - 1);
  181. free(arg);
  182. time(&t);
  183. fp = fopen(fname,"r");
  184. if (!fp) /* if cannot open request file */
  185. {
  186. perror("qcall_do:fopen");
  187. fprintf(stderr,"%s\n",fname);
  188. unlink(fname);
  189. pthread_exit(NULL);
  190. }
  191. /* lock the file */
  192. if (flock(fileno(fp),LOCK_EX) == -1)
  193. {
  194. perror("qcall_do:flock");
  195. fprintf(stderr,"%s\n",fname);
  196. pthread_exit(NULL);
  197. }
  198. /* default required input for acknowledgement */
  199. reqinp[0] = '1';
  200. reqinp[1] = '\0';
  201. /* default no ident */
  202. ident[0] = '\0'; /* default no ident */
  203. if (fscanf(fp,"%s %s %s %d %s %s",dialstr,clid,
  204. extstr,&maxsecs,ident,reqinp) < 4)
  205. {
  206. fprintf(stderr,"qcall_do:file line invalid in file %s:\n",fname);
  207. pthread_exit(NULL);
  208. }
  209. flock(fileno(fp),LOCK_UN);
  210. fclose(fp);
  211. tele = strchr(dialstr,'/');
  212. if (!tele)
  213. {
  214. fprintf(stderr,"qcall_do:Dial number must be in format tech/number\n");
  215. unlink(fname);
  216. pthread_exit(NULL);
  217. }
  218. *tele++ = 0;
  219. channel = ast_request(dialstr,AST_FORMAT_SLINEAR,tele);
  220. if (channel)
  221. {
  222. ast_set_read_format(channel,AST_FORMAT_SLINEAR);
  223. ast_set_write_format(channel,AST_FORMAT_SLINEAR);
  224. #ifdef OURCLID
  225. if (channel->callerid)
  226. free(channel->callerid);
  227. channel->callerid = strdup(OURCLID);
  228. if (channel->ani)
  229. free(channel->ani);
  230. channel->ani = strdup(OURCLID);
  231. #endif
  232. channel->whentohangup = 0;
  233. channel->appl = "AppQcall";
  234. channel->data = "(Outgoing Line)";
  235. if (option_verbose > 2)
  236. ast_verbose(VERBOSE_PREFIX_3 "Qcall initiating call to %s/%s on %s (%s)\n",
  237. dialstr,tele,channel->name,fname);
  238. ast_call(channel,tele,MAXWAITFORANSWER);
  239. }
  240. else
  241. {
  242. fprintf(stderr,"qcall_do:Sorry unable to obtain channel\n");
  243. pthread_exit(NULL);
  244. }
  245. if (strcasecmp(clid, "asreceived")) {
  246. if (channel->callerid) free(channel->callerid);
  247. channel->callerid = NULL;
  248. if (channel->ani) free(channel->ani);
  249. channel->ani = NULL;
  250. }
  251. if (channel->_state == AST_STATE_UP)
  252. if (debug) printf("@@@@ Autodial:Line is Up\n");
  253. if (option_verbose > 2)
  254. ast_verbose(VERBOSE_PREFIX_3 "Qcall waiting for answer on %s\n",
  255. channel->name);
  256. while(ms > 0){
  257. struct ast_frame *f;
  258. ms = ast_waitfor(channel,ms);
  259. f = ast_read(channel);
  260. if (!f)
  261. {
  262. if (debug) printf("@@@@ qcall_do:Hung Up\n");
  263. unlink(fname);
  264. break;
  265. }
  266. if (f->frametype == AST_FRAME_CONTROL)
  267. {
  268. if (f->subclass == AST_CONTROL_HANGUP)
  269. {
  270. if (debug) printf("@@@@ qcall_do:Hung Up\n");
  271. unlink(fname);
  272. ast_frfree(f);
  273. break;
  274. }
  275. if (f->subclass == AST_CONTROL_ANSWER)
  276. {
  277. if (debug) printf("@@@@ qcall_do:Phone Answered\n");
  278. if (channel->_state == AST_STATE_UP)
  279. {
  280. unlink(fname);
  281. if (option_verbose > 2)
  282. ast_verbose(VERBOSE_PREFIX_3 "Qcall got answer on %s\n",
  283. channel->name);
  284. usleep(1500000);
  285. if (strlen(ident)) {
  286. ast_streamfile(channel,ident,0);
  287. if (ast_readstring(channel,buf,strlen(reqinp),10000,5000,"#"))
  288. {
  289. ast_stopstream(channel);
  290. if (debug) printf("@@@@ qcall_do: timeout or hangup in dtmf read\n");
  291. ast_frfree(f);
  292. break;
  293. }
  294. ast_stopstream(channel);
  295. if (strcmp(buf,reqinp)) /* if not match */
  296. {
  297. if (debug) printf("@@@@ qcall_do: response (%s) does not match required (%s)\n",buf,reqinp);
  298. ast_frfree(f);
  299. break;
  300. }
  301. ast_frfree(f);
  302. }
  303. /* okay, now we go for it */
  304. context = strchr(extstr,'@');
  305. if (!context) context = "default";
  306. else *context++ = 0;
  307. if (option_verbose > 2)
  308. ast_verbose(VERBOSE_PREFIX_3 "Qcall got accept, now putting through to %s@%s on %s\n",
  309. extstr,context,channel->name);
  310. if (strlen(ident)) {
  311. strncat(ident,"-ok", sizeof(ident) - strlen(ident) - 1);
  312. /* if file existent, play it */
  313. if (!ast_streamfile(channel,ident,0))
  314. {
  315. ast_waitstream(channel,"");
  316. ast_stopstream(channel);
  317. }
  318. }
  319. if (strcasecmp(clid, "asreceived")) {
  320. channel->callerid = strdup(clid);
  321. channel->ani = strdup(clid);
  322. }
  323. channel->language[0] = 0;
  324. channel->dnid = strdup(extstr);
  325. #ifdef AMAFLAGS
  326. channel->amaflags = AMAFLAGS;
  327. #endif
  328. #ifdef ACCTCODE
  329. strncpy(channel->accountcode, ACCTCODE, sizeof(chan->accountcode) - 1);
  330. #else
  331. channel->accountcode[0] = 0;
  332. #endif
  333. if (maxsecs) /* if finite length call */
  334. {
  335. time(&channel->whentohangup);
  336. channel->whentohangup += maxsecs;
  337. }
  338. strncpy(channel->exten, extstr, sizeof(channel->exten) - 1);
  339. strncpy(channel->context, context, sizeof(channel->context) - 1);
  340. channel->priority = 1;
  341. if(debug) printf("Caller ID is %s\n", channel->callerid);
  342. ast_pbx_run(channel);
  343. pthread_exit(NULL);
  344. }
  345. }
  346. else if(f->subclass==AST_CONTROL_RINGING)
  347. if (debug) printf("@@@@ qcall_do:Phone Ringing end\n");
  348. }
  349. ast_frfree(f);
  350. }
  351. ast_hangup(channel);
  352. if (debug) printf("@@@@ qcall_do:Hung up channel\n");
  353. pthread_exit(NULL);
  354. return NULL;
  355. }
  356. int unload_module(void)
  357. {
  358. STANDARD_HANGUP_LOCALUSERS;
  359. return 0;
  360. }
  361. int load_module(void)
  362. {
  363. snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "qcall");
  364. mkdir(qdir,0760);
  365. ast_pthread_create(&qcall_thread,NULL,qcall,NULL);
  366. return 0;
  367. }
  368. char *description(void)
  369. {
  370. return tdesc;
  371. }
  372. int usecount(void)
  373. {
  374. int res;
  375. STANDARD_USECOUNT(res);
  376. return res;
  377. }
  378. char *key()
  379. {
  380. return ASTERISK_GPL_KEY;
  381. }