app_adsiprog.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Program Asterisk ADSI Scripts into phone
  5. *
  6. * Copyright (C) 1999, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <sys/types.h>
  14. #include <asterisk/file.h>
  15. #include <asterisk/logger.h>
  16. #include <asterisk/channel.h>
  17. #include <asterisk/pbx.h>
  18. #include <asterisk/module.h>
  19. #include <asterisk/adsi.h>
  20. #include <asterisk/options.h>
  21. #include <asterisk/utils.h>
  22. #include <asterisk/lock.h>
  23. #include <netinet/in.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <ctype.h>
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include "../asterisk.h"
  32. #include "../astconf.h"
  33. static char *tdesc = "Asterisk ADSI Programming Application";
  34. static char *app = "ADSIProg";
  35. static char *synopsis = "Load Asterisk ADSI Scripts into phone";
  36. /* #define DUMP_MESSAGES */
  37. static char *descrip =
  38. " ADSIProg(script): Programs an ADSI Phone with the given script.\n"
  39. "If none is specified, the default is used. Returns 0 unless CPE\n"
  40. "is hungup.\n";
  41. STANDARD_LOCAL_USER;
  42. LOCAL_USER_DECL;
  43. struct adsi_event {
  44. int id;
  45. char *name;
  46. };
  47. static struct adsi_event events[] = {
  48. { 1, "CALLERID" },
  49. { 2, "VMWI" },
  50. { 3, "NEARANSWER" },
  51. { 4, "FARANSWER" },
  52. { 5, "ENDOFRING" },
  53. { 6, "IDLE" },
  54. { 7, "OFFHOOK" },
  55. { 8, "CIDCW" },
  56. { 9, "BUSY" },
  57. { 10, "FARRING" },
  58. { 11, "DIALTONE" },
  59. { 12, "RECALL" },
  60. { 13, "MESSAGE" },
  61. { 14, "REORDER" },
  62. { 15, "DISTINCTIVERING" },
  63. { 16, "RING" },
  64. { 17, "REMINDERRING" },
  65. { 18, "SPECIALRING" },
  66. { 19, "CODEDRING" },
  67. { 20, "TIMER" },
  68. { 21, "INUSE" },
  69. { 22, "EVENT22" },
  70. { 23, "EVENT23" },
  71. { 24, "CPEID" },
  72. };
  73. static struct adsi_event justify[] = {
  74. { 0, "CENTER" },
  75. { 1, "RIGHT" },
  76. { 2, "LEFT" },
  77. { 3, "INDENT" },
  78. };
  79. #define STATE_NORMAL 0
  80. #define STATE_INKEY 1
  81. #define STATE_INSUB 2
  82. #define STATE_INIF 3
  83. #define MAX_RET_CODE 20
  84. #define MAX_SUB_LEN 255
  85. #define MAX_MAIN_LEN 1600
  86. #define ARG_STRING (1 << 0)
  87. #define ARG_NUMBER (1 << 1)
  88. struct adsi_soft_key {
  89. char vname[40]; /* Which "variable" is associated with it */
  90. int retstrlen; /* Length of return string */
  91. int initlen; /* initial length */
  92. int id;
  93. int defined;
  94. char retstr[80]; /* Return string data */
  95. };
  96. struct adsi_subscript {
  97. char vname[40];
  98. int id;
  99. int defined;
  100. int datalen;
  101. int inscount;
  102. int ifinscount;
  103. char *ifdata;
  104. char data[2048];
  105. };
  106. struct adsi_state {
  107. char vname[40];
  108. int id;
  109. };
  110. struct adsi_flag {
  111. char vname[40];
  112. int id;
  113. };
  114. struct adsi_display {
  115. char vname[40];
  116. int id;
  117. char data[70];
  118. int datalen;
  119. };
  120. struct adsi_script {
  121. int state;
  122. int numkeys;
  123. int numsubs;
  124. int numstates;
  125. int numdisplays;
  126. int numflags;
  127. struct adsi_soft_key *key;
  128. struct adsi_subscript *sub;
  129. /* Pre-defined displays */
  130. struct adsi_display displays[63];
  131. /* ADSI States 1 (initial) - 254 */
  132. struct adsi_state states[256];
  133. /* Keys 2-63 */
  134. struct adsi_soft_key keys[62];
  135. /* Subscripts 0 (main) to 127 */
  136. struct adsi_subscript subs[128];
  137. /* Flags 1-7 */
  138. struct adsi_flag flags[7];
  139. /* Stuff from adsi script */
  140. char sec[5];
  141. char desc[19];
  142. char fdn[5];
  143. int ver;
  144. };
  145. static int process_token(void *out, char *src, int maxlen, int argtype)
  146. {
  147. if ((strlen(src) > 1) && src[0] == '\"') {
  148. /* This is a quoted string */
  149. if (!(argtype & ARG_STRING))
  150. return -1;
  151. src++;
  152. /* Don't take more than what's there */
  153. if (maxlen > strlen(src) - 1)
  154. maxlen = strlen(src) - 1;
  155. memcpy(out, src, maxlen);
  156. ((char *)out)[maxlen] = '\0';
  157. } else if (!ast_strlen_zero(src) && (src[0] == '\\')) {
  158. if (!(argtype & ARG_NUMBER))
  159. return -1;
  160. /* Octal value */
  161. if (sscanf(src, "%o", (int *)out) != 1)
  162. return -1;
  163. if (argtype & ARG_STRING) {
  164. /* Convert */
  165. *((unsigned int *)out) = htonl(*((unsigned int *)out));
  166. }
  167. } else if ((strlen(src) > 2) && (src[0] == '0') && (tolower(src[1]) == 'x')) {
  168. if (!(argtype & ARG_NUMBER))
  169. return -1;
  170. /* Hex value */
  171. if (sscanf(src + 2, "%x", (unsigned int *)out) != 1)
  172. return -1;
  173. if (argtype & ARG_STRING) {
  174. /* Convert */
  175. *((unsigned int *)out) = htonl(*((unsigned int *)out));
  176. }
  177. } else if ((!ast_strlen_zero(src) && isdigit(src[0]))) {
  178. if (!(argtype & ARG_NUMBER))
  179. return -1;
  180. /* Hex value */
  181. if (sscanf(src, "%d", (int *)out) != 1)
  182. return -1;
  183. if (argtype & ARG_STRING) {
  184. /* Convert */
  185. *((unsigned int *)out) = htonl(*((unsigned int *)out));
  186. }
  187. } else
  188. return -1;
  189. return 0;
  190. }
  191. static char *get_token(char **buf, char *script, int lineno)
  192. {
  193. char *tmp = *buf;
  194. char *keyword;
  195. int quoted = 0;
  196. /* Advance past any white space */
  197. while(*tmp && (*tmp < 33))
  198. tmp++;
  199. if (!*tmp)
  200. return NULL;
  201. keyword = tmp;
  202. while(*tmp && ((*tmp > 32) || quoted)) {
  203. if (*tmp == '\"') {
  204. quoted = !quoted;
  205. }
  206. tmp++;
  207. }
  208. if (quoted) {
  209. ast_log(LOG_WARNING, "Mismatched quotes at line %d of %s\n", lineno, script);
  210. return NULL;
  211. }
  212. *tmp = '\0';
  213. tmp++;
  214. while(*tmp && (*tmp < 33))
  215. tmp++;
  216. /* Note where we left off */
  217. *buf = tmp;
  218. return keyword;
  219. }
  220. static char *validdtmf = "123456789*0#ABCD";
  221. static int send_dtmf(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  222. {
  223. char dtmfstr[80];
  224. char *a;
  225. int bytes=0;
  226. a = get_token(&args, script, lineno);
  227. if (!a) {
  228. ast_log(LOG_WARNING, "Expecting something to send for SENDDTMF at line %d of %s\n", lineno, script);
  229. return 0;
  230. }
  231. if (process_token(dtmfstr, a, sizeof(dtmfstr) - 1, ARG_STRING)) {
  232. ast_log(LOG_WARNING, "Invalid token for SENDDTMF at line %d of %s\n", lineno, script);
  233. return 0;
  234. }
  235. a = dtmfstr;
  236. while(*a) {
  237. if (strchr(validdtmf, *a)) {
  238. *buf = *a;
  239. buf++;
  240. bytes++;
  241. } else
  242. ast_log(LOG_WARNING, "'%c' is not a valid DTMF tone at line %d of %s\n", *a, lineno, script);
  243. a++;
  244. }
  245. return bytes;
  246. }
  247. static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  248. {
  249. char *page;
  250. char *gline;
  251. int line;
  252. unsigned char cmd;
  253. page = get_token(&args, script, lineno);
  254. gline = get_token(&args, script, lineno);
  255. if (!page || !gline) {
  256. ast_log(LOG_WARNING, "Expecting page and line number for GOTOLINE at line %d of %s\n", lineno, script);
  257. return 0;
  258. }
  259. if (!strcasecmp(page, "INFO")) {
  260. cmd = 0;
  261. } else if (!strcasecmp(page, "COMM")) {
  262. cmd = 0x80;
  263. } else {
  264. ast_log(LOG_WARNING, "Expecting either 'INFO' or 'COMM' page, got got '%s' at line %d of %s\n", page, lineno, script);
  265. return 0;
  266. }
  267. if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
  268. ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
  269. return 0;
  270. }
  271. cmd |= line;
  272. buf[0] = 0x8b;
  273. buf[1] = cmd;
  274. return 2;
  275. }
  276. static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  277. {
  278. char *dir;
  279. char *gline;
  280. int line;
  281. unsigned char cmd;
  282. dir = get_token(&args, script, lineno);
  283. gline = get_token(&args, script, lineno);
  284. if (!dir || !gline) {
  285. ast_log(LOG_WARNING, "Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno, script);
  286. return 0;
  287. }
  288. if (!strcasecmp(dir, "UP")) {
  289. cmd = 0;
  290. } else if (!strcasecmp(dir, "DOWN")) {
  291. cmd = 0x20;
  292. } else {
  293. ast_log(LOG_WARNING, "Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir, lineno, script);
  294. return 0;
  295. }
  296. if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
  297. ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
  298. return 0;
  299. }
  300. cmd |= line;
  301. buf[0] = 0x8c;
  302. buf[1] = cmd;
  303. return 2;
  304. }
  305. static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  306. {
  307. char *gtime;
  308. int ms;
  309. gtime = get_token(&args, script, lineno);
  310. if (!gtime) {
  311. ast_log(LOG_WARNING, "Expecting number of milliseconds to wait at line %d of %s\n", lineno, script);
  312. return 0;
  313. }
  314. if (process_token(&ms, gtime, sizeof(ms), ARG_NUMBER)) {
  315. ast_log(LOG_WARNING, "Invalid delay milliseconds '%s' at line %d of %s\n", gtime, lineno, script);
  316. return 0;
  317. }
  318. buf[0] = 0x90;
  319. if (id == 11)
  320. buf[1] = ms / 100;
  321. else
  322. buf[1] = ms / 10;
  323. return 2;
  324. }
  325. static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  326. {
  327. char *gstate;
  328. int state;
  329. gstate = get_token(&args, script, lineno);
  330. if (!gstate) {
  331. ast_log(LOG_WARNING, "Expecting state number at line %d of %s\n", lineno, script);
  332. return 0;
  333. }
  334. if (process_token(&state, gstate, sizeof(state), ARG_NUMBER)) {
  335. ast_log(LOG_WARNING, "Invalid state number '%s' at line %d of %s\n", gstate, lineno, script);
  336. return 0;
  337. }
  338. buf[0] = id;
  339. buf[1] = state;
  340. return 2;
  341. }
  342. static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  343. {
  344. char *tok;
  345. tok = get_token(&args, script, lineno);
  346. if (tok)
  347. ast_log(LOG_WARNING, "Clearing timer requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
  348. buf[0] = id;
  349. /* For some reason the clear code is different slightly */
  350. if (id == 7)
  351. buf[1] = 0x10;
  352. else
  353. buf[1] = 0x00;
  354. return 2;
  355. }
  356. static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
  357. {
  358. int x;
  359. for (x=0;x<state->numflags;x++)
  360. if (!strcasecmp(state->flags[x].vname, name))
  361. return &state->flags[x];
  362. /* Return now if we're not allowed to create */
  363. if (!create)
  364. return NULL;
  365. if (state->numflags > 6) {
  366. ast_log(LOG_WARNING, "No more flag space at line %d of %s\n", lineno, script);
  367. return NULL;
  368. }
  369. strncpy(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname) - 1);
  370. state->flags[state->numflags].id = state->numflags + 1;
  371. state->numflags++;
  372. return &state->flags[state->numflags-1];
  373. }
  374. static int setflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  375. {
  376. char *tok;
  377. char sname[80];
  378. struct adsi_flag *flag;
  379. tok = get_token(&args, script, lineno);
  380. if (!tok) {
  381. ast_log(LOG_WARNING, "Setting flag requires a flag number at line %d of %s\n", lineno, script);
  382. return 0;
  383. }
  384. if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
  385. ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
  386. return 0;
  387. }
  388. flag = getflagbyname(state, sname, script, lineno, 0);
  389. if (!flag) {
  390. ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
  391. return 0;
  392. }
  393. buf[0] = id;
  394. buf[1] = ((flag->id & 0x7) << 4) | 1;
  395. return 2;
  396. }
  397. static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  398. {
  399. char *tok;
  400. struct adsi_flag *flag;
  401. char sname[80];
  402. tok = get_token(&args, script, lineno);
  403. if (!tok) {
  404. ast_log(LOG_WARNING, "Clearing flag requires a flag number at line %d of %s\n", lineno, script);
  405. return 0;
  406. }
  407. if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
  408. ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
  409. return 0;
  410. }
  411. flag = getflagbyname(state, sname, script, lineno, 0);
  412. if (!flag) {
  413. ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
  414. return 0;
  415. }
  416. buf[0] = id;
  417. buf[1] = ((flag->id & 0x7) << 4);
  418. return 2;
  419. }
  420. static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  421. {
  422. char *tok;
  423. int secs;
  424. tok = get_token(&args, script, lineno);
  425. if (!tok) {
  426. ast_log(LOG_WARNING, "Missing number of seconds at line %d of %s\n", lineno, script);
  427. return 0;
  428. }
  429. if (process_token(&secs, tok, sizeof(secs), ARG_NUMBER)) {
  430. ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
  431. return 0;
  432. }
  433. buf[0] = id;
  434. buf[1] = 0x1;
  435. buf[2] = secs;
  436. return 3;
  437. }
  438. static int geteventbyname(char *name)
  439. {
  440. int x;
  441. for (x=0;x<sizeof(events) / sizeof(events[0]); x++) {
  442. if (!strcasecmp(events[x].name, name))
  443. return events[x].id;
  444. }
  445. return 0;
  446. }
  447. static int getjustifybyname(char *name)
  448. {
  449. int x;
  450. for (x=0;x<sizeof(justify) / sizeof(justify[0]); x++) {
  451. if (!strcasecmp(justify[x].name, name))
  452. return justify[x].id;
  453. }
  454. return -1;
  455. }
  456. static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, char *script, int lineno)
  457. {
  458. int x;
  459. for (x=0;x<state->numkeys;x++)
  460. if (!strcasecmp(state->keys[x].vname, name))
  461. return &state->keys[x];
  462. if (state->numkeys > 61) {
  463. ast_log(LOG_WARNING, "No more key space at line %d of %s\n", lineno, script);
  464. return NULL;
  465. }
  466. strncpy(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname) - 1);
  467. state->keys[state->numkeys].id = state->numkeys + 2;
  468. state->numkeys++;
  469. return &state->keys[state->numkeys-1];
  470. }
  471. static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, char *script, int lineno)
  472. {
  473. int x;
  474. for (x=0;x<state->numsubs;x++)
  475. if (!strcasecmp(state->subs[x].vname, name))
  476. return &state->subs[x];
  477. if (state->numsubs > 127) {
  478. ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, script);
  479. return NULL;
  480. }
  481. strncpy(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname) - 1);
  482. state->subs[state->numsubs].id = state->numsubs;
  483. state->numsubs++;
  484. return &state->subs[state->numsubs-1];
  485. }
  486. static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
  487. {
  488. int x;
  489. for (x=0;x<state->numstates;x++)
  490. if (!strcasecmp(state->states[x].vname, name))
  491. return &state->states[x];
  492. /* Return now if we're not allowed to create */
  493. if (!create)
  494. return NULL;
  495. if (state->numstates > 253) {
  496. ast_log(LOG_WARNING, "No more state space at line %d of %s\n", lineno, script);
  497. return NULL;
  498. }
  499. strncpy(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname) - 1);
  500. state->states[state->numstates].id = state->numstates + 1;
  501. state->numstates++;
  502. return &state->states[state->numstates-1];
  503. }
  504. static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
  505. {
  506. int x;
  507. for (x=0;x<state->numdisplays;x++)
  508. if (!strcasecmp(state->displays[x].vname, name))
  509. return &state->displays[x];
  510. /* Return now if we're not allowed to create */
  511. if (!create)
  512. return NULL;
  513. if (state->numdisplays > 61) {
  514. ast_log(LOG_WARNING, "No more display space at line %d of %s\n", lineno, script);
  515. return NULL;
  516. }
  517. strncpy(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname) - 1);
  518. state->displays[state->numdisplays].id = state->numdisplays + 1;
  519. state->numdisplays++;
  520. return &state->displays[state->numdisplays-1];
  521. }
  522. static int showkeys(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  523. {
  524. char *tok;
  525. char newkey[80];
  526. int bytes;
  527. unsigned char keyid[6];
  528. int x;
  529. int flagid=0;
  530. struct adsi_soft_key *key;
  531. struct adsi_flag *flag;
  532. for (x=0;x<7;x++) {
  533. /* Up to 6 key arguments */
  534. tok = get_token(&args, script, lineno);
  535. if (!tok)
  536. break;
  537. if (!strcasecmp(tok, "UNLESS")) {
  538. /* Check for trailing UNLESS flag */
  539. tok = get_token(&args, script, lineno);
  540. if (!tok) {
  541. ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
  542. } else if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
  543. ast_log(LOG_WARNING, "Invalid flag name '%s' at line %d of %s\n", tok, lineno, script);
  544. } else if (!(flag = getflagbyname(state, newkey, script, lineno, 0))) {
  545. ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", newkey, lineno, script);
  546. } else
  547. flagid = flag->id;
  548. if ((tok = get_token(&args, script, lineno)))
  549. ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
  550. break;
  551. }
  552. if (x > 5) {
  553. ast_log(LOG_WARNING, "Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok, lineno, script);
  554. break;
  555. }
  556. if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
  557. ast_log(LOG_WARNING, "Invalid token for key name: %s\n", tok);
  558. continue;
  559. }
  560. key = getkeybyname(state, newkey, script, lineno);
  561. if (!key)
  562. break;
  563. keyid[x] = key->id;
  564. }
  565. buf[0] = id;
  566. buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
  567. for (bytes=0;bytes<x;bytes++) {
  568. buf[bytes + 2] = keyid[bytes];
  569. }
  570. return 2 + x;
  571. }
  572. static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  573. {
  574. char *tok;
  575. char dispname[80];
  576. int line=0;
  577. int flag=0;
  578. int cmd = 3;
  579. struct adsi_display *disp;
  580. /* Get display */
  581. tok = get_token(&args, script, lineno);
  582. if (!tok || process_token(dispname, tok, sizeof(dispname) - 1, ARG_STRING)) {
  583. ast_log(LOG_WARNING, "Invalid display name: %s at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
  584. return 0;
  585. }
  586. disp = getdisplaybyname(state, dispname, script, lineno, 0);
  587. if (!disp) {
  588. ast_log(LOG_WARNING, "Display '%s' is undefined at line %d of %s\n", dispname, lineno, script);
  589. return 0;
  590. }
  591. tok = get_token(&args, script, lineno);
  592. if (!tok || strcasecmp(tok, "AT")) {
  593. ast_log(LOG_WARNING, "Missing token 'AT' at line %d of %s\n", lineno, script);
  594. return 0;
  595. }
  596. /* Get line number */
  597. tok = get_token(&args, script, lineno);
  598. if (!tok || process_token(&line, tok, sizeof(line), ARG_NUMBER)) {
  599. ast_log(LOG_WARNING, "Invalid line: '%s' at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
  600. return 0;
  601. }
  602. tok = get_token(&args, script, lineno);
  603. if (tok && !strcasecmp(tok, "NOUPDATE")) {
  604. cmd = 1;
  605. tok = get_token(&args, script, lineno);
  606. }
  607. if (tok && !strcasecmp(tok, "UNLESS")) {
  608. /* Check for trailing UNLESS flag */
  609. tok = get_token(&args, script, lineno);
  610. if (!tok) {
  611. ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
  612. } else if (process_token(&flag, tok, sizeof(flag), ARG_NUMBER)) {
  613. ast_log(LOG_WARNING, "Invalid flag number '%s' at line %d of %s\n", tok, lineno, script);
  614. }
  615. if ((tok = get_token(&args, script, lineno)))
  616. ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
  617. }
  618. buf[0] = id;
  619. buf[1] = (cmd << 6) | (disp->id & 0x3f);
  620. buf[2] = ((line & 0x1f) << 3) | (flag & 0x7);
  621. return 3;
  622. }
  623. static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  624. {
  625. char *tok;
  626. tok = get_token(&args, script, lineno);
  627. if (tok)
  628. ast_log(LOG_WARNING, "Clearing display requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
  629. buf[0] = id;
  630. buf[1] = 0x00;
  631. return 2;
  632. }
  633. static int digitdirect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  634. {
  635. char *tok;
  636. tok = get_token(&args, script, lineno);
  637. if (tok)
  638. ast_log(LOG_WARNING, "Digitdirect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
  639. buf[0] = id;
  640. buf[1] = 0x7;
  641. return 2;
  642. }
  643. static int clearcbone(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  644. {
  645. char *tok;
  646. tok = get_token(&args, script, lineno);
  647. if (tok)
  648. ast_log(LOG_WARNING, "CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
  649. buf[0] = id;
  650. buf[1] = 0;
  651. return 2;
  652. }
  653. static int digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
  654. {
  655. char *tok;
  656. tok = get_token(&args, script, lineno);
  657. if (tok)
  658. ast_log(LOG_WARNING, "Digitcollect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
  659. buf[0] = id;
  660. buf[1] = 0xf;
  661. return 2;
  662. }
  663. static int subscript(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  664. {
  665. char *tok;
  666. char subscript[80];
  667. struct adsi_subscript *sub;
  668. tok = get_token(&args, script, lineno);
  669. if (!tok) {
  670. ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
  671. return 0;
  672. }
  673. if (process_token(subscript, tok, sizeof(subscript) - 1, ARG_STRING)) {
  674. ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
  675. return 0;
  676. }
  677. sub = getsubbyname(state, subscript, script, lineno);
  678. if (!sub)
  679. return 0;
  680. buf[0] = 0x9d;
  681. buf[1] = sub->id;
  682. return 2;
  683. }
  684. static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
  685. {
  686. char *tok;
  687. char subscript[80];
  688. char sname[80];
  689. int sawin=0;
  690. int event;
  691. int snums[8];
  692. int scnt = 0;
  693. int x;
  694. struct adsi_subscript *sub;
  695. tok = get_token(&args, script, lineno);
  696. if (!tok) {
  697. ast_log(LOG_WARNING, "Missing event for 'ONEVENT' at line %d of %s\n", lineno, script);
  698. return 0;
  699. }
  700. event = geteventbyname(tok);
  701. if (event < 1) {
  702. ast_log(LOG_WARNING, "'%s' is not a valid event name, at line %d of %s\n", args, lineno, script);
  703. return 0;
  704. }
  705. tok = get_token(&args, script, lineno);
  706. while ((!sawin && !strcasecmp(tok, "IN")) ||
  707. (sawin && !strcasecmp(tok, "OR"))) {
  708. sawin = 1;
  709. if (scnt > 7) {
  710. ast_log(LOG_WARNING, "No more than 8 states may be specified for inclusion at line %d of %s\n", lineno, script);
  711. return 0;
  712. }
  713. /* Process 'in' things */
  714. tok = get_token(&args, script, lineno);
  715. if (process_token(sname, tok, sizeof(sname), ARG_STRING)) {
  716. ast_log(LOG_WARNING, "'%s' is not a valid state name at line %d of %s\n", tok, lineno, script);
  717. return 0;
  718. }
  719. if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) < 0)) {
  720. ast_log(LOG_WARNING, "State '%s' not declared at line %d of %s\n", sname, lineno, script);
  721. return 0;
  722. }
  723. scnt++;
  724. tok = get_token(&args, script, lineno);
  725. if (!tok)
  726. break;
  727. }
  728. if (!tok || strcasecmp(tok, "GOTO")) {
  729. if (!tok)
  730. tok = "<nothing>";
  731. if (sawin)
  732. ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok, lineno, script);
  733. else
  734. ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok, lineno, script);
  735. }
  736. tok = get_token(&args, script, lineno);
  737. if (!tok) {
  738. ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
  739. return 0;
  740. }
  741. if (process_token(subscript, tok, sizeof(subscript) - 1, ARG_STRING)) {
  742. ast_log(LOG_WARNING, "Invalid subscript '%s' at line %d of %s\n", tok, lineno, script);
  743. return 0;
  744. }
  745. sub = getsubbyname(state, subscript, script, lineno);
  746. if (!sub)
  747. return 0;
  748. buf[0] = 8;
  749. buf[1] = event;
  750. buf[2] = sub->id | 0x80;
  751. for (x=0;x<scnt;x++)
  752. buf[3 + x] = snums[x];
  753. return 3 + scnt;
  754. }
  755. struct adsi_key_cmd {
  756. char *name;
  757. int id;
  758. int (*add_args)(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno);
  759. };
  760. static struct adsi_key_cmd kcmds[] = {
  761. { "SENDDTMF", 0, send_dtmf },
  762. /* Encoded DTMF would go here */
  763. { "ONHOOK", 0x81 },
  764. { "OFFHOOK", 0x82 },
  765. { "FLASH", 0x83 },
  766. { "WAITDIALTONE", 0x84 },
  767. /* Send line number */
  768. { "BLANK", 0x86 },
  769. { "SENDCHARS", 0x87 },
  770. { "CLEARCHARS", 0x88 },
  771. { "BACKSPACE", 0x89 },
  772. /* Tab column */
  773. { "GOTOLINE", 0x8b, goto_line },
  774. { "GOTOLINEREL", 0x8c, goto_line_rel },
  775. { "PAGEUP", 0x8d },
  776. { "PAGEDOWN", 0x8e },
  777. /* Extended DTMF */
  778. { "DELAY", 0x90, send_delay },
  779. { "DIALPULSEONE", 0x91 },
  780. { "DATAMODE", 0x92 },
  781. { "VOICEMODE", 0x93 },
  782. /* Display call buffer 'n' */
  783. /* Clear call buffer 'n' */
  784. { "CLEARCB1", 0x95, clearcbone },
  785. { "DIGITCOLLECT", 0x96, digitcollect },
  786. { "DIGITDIRECT", 0x96, digitdirect },
  787. { "CLEAR", 0x97 },
  788. { "SHOWDISPLAY", 0x98, showdisplay },
  789. { "CLEARDISPLAY", 0x98, cleardisplay },
  790. { "SHOWKEYS", 0x99, showkeys },
  791. { "SETSTATE", 0x9a, set_state },
  792. { "TIMERSTART", 0x9b, starttimer },
  793. { "TIMERCLEAR", 0x9b, cleartimer },
  794. { "SETFLAG", 0x9c, setflag },
  795. { "CLEARFLAG", 0x9c, clearflag },
  796. { "GOTO", 0x9d, subscript },
  797. { "EVENT22", 0x9e },
  798. { "EVENT23", 0x9f },
  799. { "EXIT", 0xa0 },
  800. };
  801. static struct adsi_key_cmd opcmds[] = {
  802. /* 1 - Branch on event -- handled specially */
  803. { "SHOWKEYS", 2, showkeys },
  804. /* Display Control */
  805. { "SHOWDISPLAY", 3, showdisplay },
  806. { "CLEARDISPLAY", 3, cleardisplay },
  807. { "CLEAR", 5 },
  808. { "SETSTATE", 6, set_state },
  809. { "TIMERSTART", 7, starttimer },
  810. { "TIMERCLEAR", 7, cleartimer },
  811. { "ONEVENT", 8, onevent },
  812. /* 9 - Subroutine label, treated specially */
  813. { "SETFLAG", 10, setflag },
  814. { "CLEARFLAG", 10, clearflag },
  815. { "DELAY", 11, send_delay },
  816. { "EXIT", 12 },
  817. };
  818. static int process_returncode(struct adsi_soft_key *key, char *code, char *args, struct adsi_script *state, char *script, int lineno)
  819. {
  820. int x;
  821. char *unused;
  822. int res;
  823. for (x=0;x<sizeof(kcmds) / sizeof(kcmds[0]);x++) {
  824. if ((kcmds[x].id > -1) && !strcasecmp(kcmds[x].name, code)) {
  825. if (kcmds[x].add_args) {
  826. res = kcmds[x].add_args(key->retstr + key->retstrlen,
  827. code, kcmds[x].id, args, state, script, lineno);
  828. if ((key->retstrlen + res - key->initlen) <= MAX_RET_CODE)
  829. key->retstrlen += res;
  830. else
  831. ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", kcmds[x].name, key->vname, lineno, script);
  832. } else {
  833. if ((unused = get_token(&args, script, lineno)))
  834. ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds[x].name, lineno, script, unused);
  835. if ((key->retstrlen + 1 - key->initlen) <= MAX_RET_CODE) {
  836. key->retstr[key->retstrlen] = kcmds[x].id;
  837. key->retstrlen++;
  838. } else
  839. ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", kcmds[x].name, key->vname, lineno, script);
  840. }
  841. return 0;
  842. }
  843. }
  844. return -1;
  845. }
  846. static int process_opcode(struct adsi_subscript *sub, char *code, char *args, struct adsi_script *state, char *script, int lineno)
  847. {
  848. int x;
  849. char *unused;
  850. int res;
  851. int max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
  852. for (x=0;x<sizeof(opcmds) / sizeof(opcmds[0]);x++) {
  853. if ((opcmds[x].id > -1) && !strcasecmp(opcmds[x].name, code)) {
  854. if (opcmds[x].add_args) {
  855. res = opcmds[x].add_args(sub->data + sub->datalen,
  856. code, opcmds[x].id, args, state, script, lineno);
  857. if ((sub->datalen + res + 1) <= max)
  858. sub->datalen += res;
  859. else {
  860. ast_log(LOG_WARNING, "No space for '%s' code in subscript '%s' at line %d of %s\n", opcmds[x].name, sub->vname, lineno, script);
  861. return -1;
  862. }
  863. } else {
  864. if ((unused = get_token(&args, script, lineno)))
  865. ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds[x].name, lineno, script, unused);
  866. if ((sub->datalen + 2) <= max) {
  867. sub->data[sub->datalen] = opcmds[x].id;
  868. sub->datalen++;
  869. } else {
  870. ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", opcmds[x].name, sub->vname, lineno, script);
  871. return -1;
  872. }
  873. }
  874. /* Separate commands with 0xff */
  875. sub->data[sub->datalen] = 0xff;
  876. sub->datalen++;
  877. sub->inscount++;
  878. return 0;
  879. }
  880. }
  881. return -1;
  882. }
  883. static int adsi_process(struct adsi_script *state, char *buf, char *script, int lineno)
  884. {
  885. char *keyword;
  886. char *args;
  887. char vname[256];
  888. char tmp[80];
  889. char tmp2[80];
  890. int lrci;
  891. int wi;
  892. int event;
  893. struct adsi_display *disp;
  894. struct adsi_subscript *newsub;
  895. /* Find the first keyword */
  896. keyword = get_token(&buf, script, lineno);
  897. if (!keyword)
  898. return 0;
  899. switch(state->state) {
  900. case STATE_NORMAL:
  901. if (!strcasecmp(keyword, "DESCRIPTION")) {
  902. args = get_token(&buf, script, lineno);
  903. if (args) {
  904. if (process_token(state->desc, args, sizeof(state->desc) - 1, ARG_STRING))
  905. ast_log(LOG_WARNING, "'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args, lineno, script);
  906. } else
  907. ast_log(LOG_WARNING, "Missing argument for DESCRIPTION at line %d of %s\n", lineno, script);
  908. } else if (!strcasecmp(keyword, "VERSION")) {
  909. args = get_token(&buf, script, lineno);
  910. if (args) {
  911. if (process_token(&state->ver, args, sizeof(state->ver) - 1, ARG_NUMBER))
  912. ast_log(LOG_WARNING, "'%s' is not a valid token for VERSION at line %d of %s\n", args, lineno, script);
  913. } else
  914. ast_log(LOG_WARNING, "Missing argument for VERSION at line %d of %s\n", lineno, script);
  915. } else if (!strcasecmp(keyword, "SECURITY")) {
  916. args = get_token(&buf, script, lineno);
  917. if (args) {
  918. if (process_token(state->sec, args, sizeof(state->sec) - 1, ARG_STRING | ARG_NUMBER))
  919. ast_log(LOG_WARNING, "'%s' is not a valid token for SECURITY at line %d of %s\n", args, lineno, script);
  920. } else
  921. ast_log(LOG_WARNING, "Missing argument for SECURITY at line %d of %s\n", lineno, script);
  922. } else if (!strcasecmp(keyword, "FDN")) {
  923. args = get_token(&buf, script, lineno);
  924. if (args) {
  925. if (process_token(state->fdn, args, sizeof(state->fdn) - 1, ARG_STRING | ARG_NUMBER))
  926. ast_log(LOG_WARNING, "'%s' is not a valid token for FDN at line %d of %s\n", args, lineno, script);
  927. } else
  928. ast_log(LOG_WARNING, "Missing argument for FDN at line %d of %s\n", lineno, script);
  929. } else if (!strcasecmp(keyword, "KEY")) {
  930. args = get_token(&buf, script, lineno);
  931. if (!args) {
  932. ast_log(LOG_WARNING, "KEY definition missing name at line %d of %s\n", lineno, script);
  933. break;
  934. }
  935. if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
  936. ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
  937. break;
  938. }
  939. state->key = getkeybyname(state, vname, script, lineno);
  940. if (!state->key) {
  941. ast_log(LOG_WARNING, "Out of key space at line %d of %s\n", lineno, script);
  942. break;
  943. }
  944. if (state->key->defined) {
  945. ast_log(LOG_WARNING, "Cannot redefine key '%s' at line %d of %s\n", vname, lineno, script);
  946. break;
  947. }
  948. args = get_token(&buf, script, lineno);
  949. if (!args || strcasecmp(args, "IS")) {
  950. ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
  951. break;
  952. }
  953. args = get_token(&buf, script, lineno);
  954. if (!args) {
  955. ast_log(LOG_WARNING, "KEY definition missing short name at line %d of %s\n", lineno, script);
  956. break;
  957. }
  958. if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
  959. ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY short name at line %d of %s\n", args, lineno, script);
  960. break;
  961. }
  962. args = get_token(&buf, script, lineno);
  963. if (args) {
  964. if (strcasecmp(args, "OR")) {
  965. ast_log(LOG_WARNING, "Expecting 'OR' but got '%s' instead at line %d of %s\n", args, lineno, script);
  966. break;
  967. }
  968. args = get_token(&buf, script, lineno);
  969. if (!args) {
  970. ast_log(LOG_WARNING, "KEY definition missing optional long name at line %d of %s\n", lineno, script);
  971. break;
  972. }
  973. if (process_token(tmp2, args, sizeof(tmp2) - 1, ARG_STRING)) {
  974. ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY long name at line %d of %s\n", args, lineno, script);
  975. break;
  976. }
  977. } else {
  978. strncpy(tmp2, tmp, sizeof(tmp2) - 1);
  979. }
  980. if (strlen(tmp2) > 18) {
  981. ast_log(LOG_WARNING, "Truncating full name to 18 characters at line %d of %s\n", lineno, script);
  982. tmp2[18] = '\0';
  983. }
  984. if (strlen(tmp) > 7) {
  985. ast_log(LOG_WARNING, "Truncating short name to 7 bytes at line %d of %s\n", lineno, script);
  986. tmp[7] = '\0';
  987. }
  988. /* Setup initial stuff */
  989. state->key->retstr[0] = 128;
  990. /* 1 has the length */
  991. state->key->retstr[2] = state->key->id;
  992. /* Put the Full name in */
  993. memcpy(state->key->retstr + 3, tmp2, strlen(tmp2));
  994. /* Update length */
  995. state->key->retstrlen = strlen(tmp2) + 3;
  996. /* Put trailing 0xff */
  997. state->key->retstr[state->key->retstrlen++] = 0xff;
  998. /* Put the short name */
  999. memcpy(state->key->retstr + state->key->retstrlen, tmp, strlen(tmp));
  1000. /* Update length */
  1001. state->key->retstrlen += strlen(tmp);
  1002. /* Put trailing 0xff */
  1003. state->key->retstr[state->key->retstrlen++] = 0xff;
  1004. /* Record initial length */
  1005. state->key->initlen = state->key->retstrlen;
  1006. state->state = STATE_INKEY;
  1007. } else if (!strcasecmp(keyword, "SUB")) {
  1008. args = get_token(&buf, script, lineno);
  1009. if (!args) {
  1010. ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
  1011. break;
  1012. }
  1013. if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
  1014. ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
  1015. break;
  1016. }
  1017. state->sub = getsubbyname(state, vname, script, lineno);
  1018. if (!state->sub) {
  1019. ast_log(LOG_WARNING, "Out of subroutine space at line %d of %s\n", lineno, script);
  1020. break;
  1021. }
  1022. if (state->sub->defined) {
  1023. ast_log(LOG_WARNING, "Cannot redefine subroutine '%s' at line %d of %s\n", vname, lineno, script);
  1024. break;
  1025. }
  1026. /* Setup sub */
  1027. state->sub->data[0] = 130;
  1028. /* 1 is the length */
  1029. state->sub->data[2] = 0x0; /* Clear extensibility bit */
  1030. state->sub->datalen = 3;
  1031. if (state->sub->id) {
  1032. /* If this isn't the main subroutine, make a subroutine label for it */
  1033. state->sub->data[3] = 9;
  1034. state->sub->data[4] = state->sub->id;
  1035. /* 5 is length */
  1036. state->sub->data[6] = 0xff;
  1037. state->sub->datalen = 7;
  1038. }
  1039. args = get_token(&buf, script, lineno);
  1040. if (!args || strcasecmp(args, "IS")) {
  1041. ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
  1042. break;
  1043. }
  1044. state->state = STATE_INSUB;
  1045. } else if (!strcasecmp(keyword, "STATE")) {
  1046. args = get_token(&buf, script, lineno);
  1047. if (!args) {
  1048. ast_log(LOG_WARNING, "STATE definition missing name at line %d of %s\n", lineno, script);
  1049. break;
  1050. }
  1051. if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
  1052. ast_log(LOG_WARNING, "'%s' is not a valid token for a STATE name at line %d of %s\n", args, lineno, script);
  1053. break;
  1054. }
  1055. if (getstatebyname(state, vname, script, lineno, 0)) {
  1056. ast_log(LOG_WARNING, "State '%s' is already defined at line %d of %s\n", vname, lineno, script);
  1057. break;
  1058. }
  1059. getstatebyname(state, vname, script, lineno, 1);
  1060. } else if (!strcasecmp(keyword, "FLAG")) {
  1061. args = get_token(&buf, script, lineno);
  1062. if (!args) {
  1063. ast_log(LOG_WARNING, "FLAG definition missing name at line %d of %s\n", lineno, script);
  1064. break;
  1065. }
  1066. if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
  1067. ast_log(LOG_WARNING, "'%s' is not a valid token for a FLAG name at line %d of %s\n", args, lineno, script);
  1068. break;
  1069. }
  1070. if (getflagbyname(state, vname, script, lineno, 0)) {
  1071. ast_log(LOG_WARNING, "Flag '%s' is already defined\n", vname);
  1072. break;
  1073. }
  1074. getflagbyname(state, vname, script, lineno, 1);
  1075. } else if (!strcasecmp(keyword, "DISPLAY")) {
  1076. lrci = 0;
  1077. wi = 0;
  1078. args = get_token(&buf, script, lineno);
  1079. if (!args) {
  1080. ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
  1081. break;
  1082. }
  1083. if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
  1084. ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
  1085. break;
  1086. }
  1087. if (getdisplaybyname(state, vname, script, lineno, 0)) {
  1088. ast_log(LOG_WARNING, "State '%s' is already defined\n", vname);
  1089. break;
  1090. }
  1091. disp = getdisplaybyname(state, vname, script, lineno, 1);
  1092. if (!disp)
  1093. break;
  1094. args = get_token(&buf, script, lineno);
  1095. if (!args || strcasecmp(args, "IS")) {
  1096. ast_log(LOG_WARNING, "Missing 'IS' at line %d of %s\n", lineno, script);
  1097. break;
  1098. }
  1099. args = get_token(&buf, script, lineno);
  1100. if (!args) {
  1101. ast_log(LOG_WARNING, "Missing Column 1 text at line %d of %s\n", lineno, script);
  1102. break;
  1103. }
  1104. if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
  1105. ast_log(LOG_WARNING, "Token '%s' is not valid column 1 text at line %d of %s\n", args, lineno, script);
  1106. break;
  1107. }
  1108. if (strlen(tmp) > 20) {
  1109. ast_log(LOG_WARNING, "Truncating column one to 20 characters at line %d of %s\n", lineno, script);
  1110. tmp[20] = '\0';
  1111. }
  1112. memcpy(disp->data + 5, tmp, strlen(tmp));
  1113. disp->datalen = strlen(tmp) + 5;
  1114. disp->data[disp->datalen++] = 0xff;
  1115. args = get_token(&buf, script, lineno);
  1116. if (args && !process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
  1117. /* Got a column two */
  1118. if (strlen(tmp) > 20) {
  1119. ast_log(LOG_WARNING, "Truncating column two to 20 characters at line %d of %s\n", lineno, script);
  1120. tmp[20] = '\0';
  1121. }
  1122. memcpy(disp->data + disp->datalen, tmp, strlen(tmp));
  1123. disp->datalen += strlen(tmp);
  1124. args = get_token(&buf, script, lineno);
  1125. }
  1126. while(args) {
  1127. if (!strcasecmp(args, "JUSTIFY")) {
  1128. args = get_token(&buf, script, lineno);
  1129. if (!args) {
  1130. ast_log(LOG_WARNING, "Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno, script);
  1131. break;
  1132. }
  1133. lrci = getjustifybyname(args);
  1134. if (lrci < 0) {
  1135. ast_log(LOG_WARNING, "'%s' is not a valid justification at line %d of %s\n", args, lineno, script);
  1136. break;
  1137. }
  1138. } else if (!strcasecmp(args, "WRAP")) {
  1139. wi = 0x80;
  1140. } else {
  1141. ast_log(LOG_WARNING, "'%s' is not a known qualifier at line %d of %s\n", args, lineno, script);
  1142. break;
  1143. }
  1144. args = get_token(&buf, script, lineno);
  1145. }
  1146. if (args) {
  1147. /* Something bad happened */
  1148. break;
  1149. }
  1150. disp->data[0] = 129;
  1151. disp->data[1] = disp->datalen - 2;
  1152. disp->data[2] = ((lrci & 0x3) << 6) | disp->id;
  1153. disp->data[3] = wi;
  1154. disp->data[4] = 0xff;
  1155. } else {
  1156. ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in PROGRAM\n", keyword);
  1157. }
  1158. break;
  1159. case STATE_INKEY:
  1160. if (process_returncode(state->key, keyword, buf, state, script, lineno)) {
  1161. if (!strcasecmp(keyword, "ENDKEY")) {
  1162. /* Return to normal operation and increment current key */
  1163. state->state = STATE_NORMAL;
  1164. state->key->defined = 1;
  1165. state->key->retstr[1] = state->key->retstrlen - 2;
  1166. state->key = NULL;
  1167. } else {
  1168. ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword, lineno, script);
  1169. }
  1170. }
  1171. break;
  1172. case STATE_INIF:
  1173. if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
  1174. if (!strcasecmp(keyword, "ENDIF")) {
  1175. /* Return to normal SUB operation and increment current key */
  1176. state->state = STATE_INSUB;
  1177. state->sub->defined = 1;
  1178. /* Store the proper number of instructions */
  1179. state->sub->ifdata[2] = state->sub->ifinscount;
  1180. } else if (!strcasecmp(keyword, "GOTO")) {
  1181. args = get_token(&buf, script, lineno);
  1182. if (!args) {
  1183. ast_log(LOG_WARNING, "GOTO clause missing Subscript name at line %d of %s\n", lineno, script);
  1184. break;
  1185. }
  1186. if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
  1187. ast_log(LOG_WARNING, "'%s' is not a valid subscript name token at line %d of %s\n", args, lineno, script);
  1188. break;
  1189. }
  1190. newsub = getsubbyname(state, tmp, script, lineno);
  1191. if (!newsub)
  1192. break;
  1193. /* Somehow you use GOTO to go to another place */
  1194. state->sub->data[state->sub->datalen++] = 0x8;
  1195. state->sub->data[state->sub->datalen++] = state->sub->ifdata[1];
  1196. state->sub->data[state->sub->datalen++] = newsub->id;
  1197. /* Terminate */
  1198. state->sub->data[state->sub->datalen++] = 0xff;
  1199. /* Increment counters */
  1200. state->sub->inscount++;
  1201. state->sub->ifinscount++;
  1202. } else {
  1203. ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword, lineno, script);
  1204. }
  1205. } else
  1206. state->sub->ifinscount++;
  1207. break;
  1208. case STATE_INSUB:
  1209. if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
  1210. if (!strcasecmp(keyword, "ENDSUB")) {
  1211. /* Return to normal operation and increment current key */
  1212. state->state = STATE_NORMAL;
  1213. state->sub->defined = 1;
  1214. /* Store the proper length */
  1215. state->sub->data[1] = state->sub->datalen - 2;
  1216. if (state->sub->id) {
  1217. /* if this isn't main, store number of instructions, too */
  1218. state->sub->data[5] = state->sub->inscount;
  1219. }
  1220. state->sub = NULL;
  1221. } else if (!strcasecmp(keyword, "IFEVENT")) {
  1222. args = get_token(&buf, script, lineno);
  1223. if (!args) {
  1224. ast_log(LOG_WARNING, "IFEVENT clause missing Event name at line %d of %s\n", lineno, script);
  1225. break;
  1226. }
  1227. event = geteventbyname(args);
  1228. if (event < 1) {
  1229. ast_log(LOG_WARNING, "'%s' is not a valid event\n", args);
  1230. break;
  1231. }
  1232. args = get_token(&buf, script, lineno);
  1233. if (!args || strcasecmp(args, "THEN")) {
  1234. ast_log(LOG_WARNING, "IFEVENT clause missing 'THEN' at line %d of %s\n", lineno, script);
  1235. break;
  1236. }
  1237. state->sub->ifinscount = 0;
  1238. state->sub->ifdata = state->sub->data +
  1239. state->sub->datalen;
  1240. /* Reserve header and insert op codes */
  1241. state->sub->ifdata[0] = 0x1;
  1242. state->sub->ifdata[1] = event;
  1243. /* 2 is for the number of instructions */
  1244. state->sub->ifdata[3] = 0xff;
  1245. state->sub->datalen += 4;
  1246. /* Update Subscript instruction count */
  1247. state->sub->inscount++;
  1248. state->state = STATE_INIF;
  1249. } else {
  1250. ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword, lineno, script);
  1251. }
  1252. }
  1253. break;
  1254. default:
  1255. ast_log(LOG_WARNING, "Can't process keyword '%s' in weird state %d\n", keyword, state->state);
  1256. }
  1257. return 0;
  1258. }
  1259. static struct adsi_script *compile_script(char *script)
  1260. {
  1261. FILE *f;
  1262. char fn[256];
  1263. char buf[256];
  1264. char *c;
  1265. int lineno=0;
  1266. int x, err;
  1267. struct adsi_script *scr;
  1268. if (script[0] == '/')
  1269. strncpy(fn, script, sizeof(fn) - 1);
  1270. else
  1271. snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, script);
  1272. f = fopen(fn, "r");
  1273. if (!f) {
  1274. ast_log(LOG_WARNING, "Can't open file '%s'\n", fn);
  1275. return NULL;
  1276. }
  1277. scr = malloc(sizeof(struct adsi_script));
  1278. if (!scr) {
  1279. fclose(f);
  1280. ast_log(LOG_WARNING, "Out of memory loading script '%s'\n", fn);
  1281. return NULL;
  1282. }
  1283. memset(scr, 0, sizeof(struct adsi_script));
  1284. /* Create "main" as first subroutine */
  1285. getsubbyname(scr, "main", NULL, 0);
  1286. while(!feof(f)) {
  1287. fgets(buf, sizeof(buf), f);
  1288. if (!feof(f)) {
  1289. lineno++;
  1290. /* Trim off trailing return */
  1291. buf[strlen(buf) - 1] = '\0';
  1292. c = strchr(buf, ';');
  1293. /* Strip comments */
  1294. if (c)
  1295. *c = '\0';
  1296. if (!ast_strlen_zero(buf))
  1297. adsi_process(scr, buf, script, lineno);
  1298. }
  1299. }
  1300. fclose(f);
  1301. /* Make sure we're in the main routine again */
  1302. switch(scr->state) {
  1303. case STATE_NORMAL:
  1304. break;
  1305. case STATE_INSUB:
  1306. ast_log(LOG_WARNING, "Missing ENDSUB at end of file %s\n", script);
  1307. free(scr);
  1308. return NULL;
  1309. case STATE_INKEY:
  1310. ast_log(LOG_WARNING, "Missing ENDKEY at end of file %s\n", script);
  1311. free(scr);
  1312. return NULL;
  1313. }
  1314. err = 0;
  1315. /* Resolve all keys and record their lengths */
  1316. for (x=0;x<scr->numkeys;x++) {
  1317. if (!scr->keys[x].defined) {
  1318. ast_log(LOG_WARNING, "Key '%s' referenced but never defined in file %s\n", scr->keys[x].vname, fn);
  1319. err++;
  1320. }
  1321. }
  1322. /* Resolve all subs */
  1323. for (x=0;x<scr->numsubs;x++) {
  1324. if (!scr->subs[x].defined) {
  1325. ast_log(LOG_WARNING, "Subscript '%s' referenced but never defined in file %s\n", scr->subs[x].vname, fn);
  1326. err++;
  1327. }
  1328. if (x == (scr->numsubs - 1)) {
  1329. /* Clear out extension bit on last message */
  1330. scr->subs[x].data[2] = 0x80;
  1331. }
  1332. }
  1333. if (err) {
  1334. free(scr);
  1335. return NULL;
  1336. }
  1337. return scr;
  1338. }
  1339. #ifdef DUMP_MESSAGES
  1340. static void dump_message(char *type, char *vname, unsigned char *buf, int buflen)
  1341. {
  1342. int x;
  1343. printf("%s %s: [ ", type, vname);
  1344. for (x=0;x<buflen;x++)
  1345. printf("%02x ", buf[x]);
  1346. printf("]\n");
  1347. }
  1348. #endif
  1349. static int adsi_prog(struct ast_channel *chan, char *script)
  1350. {
  1351. struct adsi_script *scr;
  1352. int x;
  1353. char buf[1024];
  1354. int bytes;
  1355. scr = compile_script(script);
  1356. if (!scr)
  1357. return -1;
  1358. /* Start an empty ADSI Session */
  1359. if (adsi_load_session(chan, NULL, 0, 1) < 1)
  1360. return -1;
  1361. /* Now begin the download attempt */
  1362. if (adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
  1363. /* User rejected us for some reason */
  1364. if (option_verbose > 2)
  1365. ast_verbose(VERBOSE_PREFIX_3 "User rejected download attempt\n");
  1366. ast_log(LOG_NOTICE, "User rejected download on channel %s\n", chan->name);
  1367. free(scr);
  1368. return -1;
  1369. }
  1370. bytes = 0;
  1371. /* Start with key definitions */
  1372. for (x=0;x<scr->numkeys;x++) {
  1373. if (bytes + scr->keys[x].retstrlen > 253) {
  1374. /* Send what we've collected so far */
  1375. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
  1376. ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
  1377. return -1;
  1378. }
  1379. bytes =0;
  1380. }
  1381. memcpy(buf + bytes, scr->keys[x].retstr, scr->keys[x].retstrlen);
  1382. bytes += scr->keys[x].retstrlen;
  1383. #ifdef DUMP_MESSAGES
  1384. dump_message("Key", scr->keys[x].vname, scr->keys[x].retstr, scr->keys[x].retstrlen);
  1385. #endif
  1386. }
  1387. if (bytes) {
  1388. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
  1389. ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
  1390. return -1;
  1391. }
  1392. }
  1393. bytes = 0;
  1394. /* Continue with the display messages */
  1395. for (x=0;x<scr->numdisplays;x++) {
  1396. if (bytes + scr->displays[x].datalen > 253) {
  1397. /* Send what we've collected so far */
  1398. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
  1399. ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
  1400. return -1;
  1401. }
  1402. bytes =0;
  1403. }
  1404. memcpy(buf + bytes, scr->displays[x].data, scr->displays[x].datalen);
  1405. bytes += scr->displays[x].datalen;
  1406. #ifdef DUMP_MESSAGES
  1407. dump_message("Display", scr->displays[x].vname, scr->displays[x].data, scr->displays[x].datalen);
  1408. #endif
  1409. }
  1410. if (bytes) {
  1411. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
  1412. ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
  1413. return -1;
  1414. }
  1415. }
  1416. bytes = 0;
  1417. /* Send subroutines */
  1418. for (x=0;x<scr->numsubs;x++) {
  1419. if (bytes + scr->subs[x].datalen > 253) {
  1420. /* Send what we've collected so far */
  1421. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
  1422. ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
  1423. return -1;
  1424. }
  1425. bytes =0;
  1426. }
  1427. memcpy(buf + bytes, scr->subs[x].data, scr->subs[x].datalen);
  1428. bytes += scr->subs[x].datalen;
  1429. #ifdef DUMP_MESSAGES
  1430. dump_message("Sub", scr->subs[x].vname, scr->subs[x].data, scr->subs[x].datalen);
  1431. #endif
  1432. }
  1433. if (bytes) {
  1434. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
  1435. ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
  1436. return -1;
  1437. }
  1438. }
  1439. bytes = 0;
  1440. bytes += adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
  1441. bytes += adsi_set_line(buf, ADSI_INFO_PAGE, 1);
  1442. if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
  1443. return -1;
  1444. if (adsi_end_download(chan)) {
  1445. /* Download failed for some reason */
  1446. if (option_verbose > 2)
  1447. ast_verbose(VERBOSE_PREFIX_3 "Download attempt failed\n");
  1448. ast_log(LOG_NOTICE, "Download failed on %s\n", chan->name);
  1449. free(scr);
  1450. return -1;
  1451. }
  1452. free(scr);
  1453. adsi_unload_session(chan);
  1454. return 0;
  1455. }
  1456. static int adsi_exec(struct ast_channel *chan, void *data)
  1457. {
  1458. int res=0;
  1459. struct localuser *u;
  1460. if (!data || ast_strlen_zero(data))
  1461. data = "asterisk.adsi";
  1462. LOCAL_USER_ADD(u);
  1463. if (!adsi_available(chan)) {
  1464. if (option_verbose > 2)
  1465. ast_verbose(VERBOSE_PREFIX_3 "ADSI Unavailable on CPE. Not bothering to try.\n");
  1466. } else {
  1467. if (option_verbose > 2)
  1468. ast_verbose(VERBOSE_PREFIX_3 "ADSI Available on CPE. Attempting Upload.\n");
  1469. res = adsi_prog(chan, data);
  1470. }
  1471. LOCAL_USER_REMOVE(u);
  1472. return res;
  1473. }
  1474. int unload_module(void)
  1475. {
  1476. STANDARD_HANGUP_LOCALUSERS;
  1477. return ast_unregister_application(app);
  1478. }
  1479. int load_module(void)
  1480. {
  1481. return ast_register_application(app, adsi_exec, synopsis, descrip);
  1482. }
  1483. char *description(void)
  1484. {
  1485. return tdesc;
  1486. }
  1487. int usecount(void)
  1488. {
  1489. int res;
  1490. STANDARD_USECOUNT(res);
  1491. return res;
  1492. }
  1493. char *key()
  1494. {
  1495. return ASTERISK_GPL_KEY;
  1496. }