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