00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 426363 $")
00035
00036 #include <math.h>
00037 #include <signal.h>
00038 #include <sys/time.h>
00039 #include <sys/wait.h>
00040 #include <sys/stat.h>
00041 #include <pthread.h>
00042
00043 #include "asterisk/paths.h"
00044 #include "asterisk/network.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/module.h"
00049 #include "asterisk/astdb.h"
00050 #include "asterisk/callerid.h"
00051 #include "asterisk/cli.h"
00052 #include "asterisk/image.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/dsp.h"
00056 #include "asterisk/musiconhold.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/lock.h"
00059 #include "asterisk/strings.h"
00060 #include "asterisk/manager.h"
00061 #include "asterisk/ast_version.h"
00062 #include "asterisk/speech.h"
00063 #include "asterisk/manager.h"
00064 #include "asterisk/term.h"
00065 #include "asterisk/xmldoc.h"
00066 #include "asterisk/srv.h"
00067 #include "asterisk/test.h"
00068
00069 #define AST_API_MODULE
00070 #include "asterisk/agi.h"
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903 #define MAX_ARGS 128
00904 #define MAX_CMD_LEN 80
00905 #define AGI_NANDFS_RETRY 3
00906 #define AGI_BUF_LEN 2048
00907 #define SRV_PREFIX "_agi._tcp."
00908
00909 static char *app = "AGI";
00910
00911 static char *eapp = "EAGI";
00912
00913 static char *deadapp = "DeadAGI";
00914
00915 static int agidebug = 0;
00916
00917 #define TONE_BLOCK_SIZE 200
00918
00919
00920 #define MAX_AGI_CONNECT 2000
00921
00922 #define AGI_PORT 4573
00923
00924
00925 #define ASYNC_AGI_BREAK 3
00926
00927 enum agi_result {
00928 AGI_RESULT_FAILURE = -1,
00929 AGI_RESULT_SUCCESS,
00930 AGI_RESULT_SUCCESS_FAST,
00931 AGI_RESULT_SUCCESS_ASYNC,
00932 AGI_RESULT_NOTFOUND,
00933 AGI_RESULT_HANGUP,
00934 };
00935
00936 extern AST_LIST_HEAD(agimaskvars, ast_variable_list) agimaskvars;
00937
00938 static agi_command *find_command(const char * const cmds[], int exact);
00939
00940 AST_THREADSTORAGE(agi_buf);
00941 #define AGI_BUF_INITSIZE 256
00942
00943 int AST_OPTIONAL_API_NAME(ast_agi_send)(int fd, struct ast_channel *chan, char *fmt, ...)
00944 {
00945 int res = 0;
00946 va_list ap;
00947 struct ast_str *buf;
00948
00949 if (!(buf = ast_str_thread_get(&agi_buf, AGI_BUF_INITSIZE)))
00950 return -1;
00951
00952 va_start(ap, fmt);
00953 res = ast_str_set_va(&buf, 0, fmt, ap);
00954 va_end(ap);
00955
00956 if (res == -1) {
00957 ast_log(LOG_ERROR, "Out of memory\n");
00958 return -1;
00959 }
00960
00961 if (agidebug) {
00962 if (chan) {
00963 ast_verbose("<%s>AGI Tx >> %s", chan->name, ast_str_buffer(buf));
00964 } else {
00965 ast_verbose("AGI Tx >> %s", ast_str_buffer(buf));
00966 }
00967 }
00968
00969 return ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
00970 }
00971
00972
00973 struct agi_cmd {
00974 char *cmd_buffer;
00975 char *cmd_id;
00976 AST_LIST_ENTRY(agi_cmd) entry;
00977 };
00978
00979 static void free_agi_cmd(struct agi_cmd *cmd)
00980 {
00981 ast_free(cmd->cmd_buffer);
00982 ast_free(cmd->cmd_id);
00983 ast_free(cmd);
00984 }
00985
00986
00987 static void agi_destroy_commands_cb(void *data)
00988 {
00989 struct agi_cmd *cmd;
00990 AST_LIST_HEAD(, agi_cmd) *chan_cmds = data;
00991 AST_LIST_LOCK(chan_cmds);
00992 while ( (cmd = AST_LIST_REMOVE_HEAD(chan_cmds, entry)) ) {
00993 free_agi_cmd(cmd);
00994 }
00995 AST_LIST_UNLOCK(chan_cmds);
00996 AST_LIST_HEAD_DESTROY(chan_cmds);
00997 ast_free(chan_cmds);
00998 }
00999
01000
01001 static const struct ast_datastore_info agi_commands_datastore_info = {
01002 .type = "AsyncAGI",
01003 .destroy = agi_destroy_commands_cb
01004 };
01005
01006 static struct agi_cmd *get_agi_cmd(struct ast_channel *chan)
01007 {
01008 struct ast_datastore *store;
01009 struct agi_cmd *cmd;
01010 AST_LIST_HEAD(, agi_cmd) *agi_commands;
01011
01012 ast_channel_lock(chan);
01013 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01014 ast_channel_unlock(chan);
01015 if (!store) {
01016 ast_log(LOG_ERROR, "Huh? Async AGI datastore disappeared on Channel %s!\n",
01017 chan->name);
01018 return NULL;
01019 }
01020 agi_commands = store->data;
01021 AST_LIST_LOCK(agi_commands);
01022 cmd = AST_LIST_REMOVE_HEAD(agi_commands, entry);
01023 AST_LIST_UNLOCK(agi_commands);
01024 return cmd;
01025 }
01026
01027
01028 static int add_agi_cmd(struct ast_channel *chan, const char *cmd_buff, const char *cmd_id)
01029 {
01030 struct ast_datastore *store;
01031 struct agi_cmd *cmd;
01032 AST_LIST_HEAD(, agi_cmd) *agi_commands;
01033
01034 store = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01035 if (!store) {
01036 ast_log(LOG_WARNING, "Channel %s is not setup for Async AGI.\n", chan->name);
01037 return -1;
01038 }
01039 agi_commands = store->data;
01040 cmd = ast_calloc(1, sizeof(*cmd));
01041 if (!cmd) {
01042 return -1;
01043 }
01044 cmd->cmd_buffer = ast_strdup(cmd_buff);
01045 if (!cmd->cmd_buffer) {
01046 ast_free(cmd);
01047 return -1;
01048 }
01049 cmd->cmd_id = ast_strdup(cmd_id);
01050 if (!cmd->cmd_id) {
01051 ast_free(cmd->cmd_buffer);
01052 ast_free(cmd);
01053 return -1;
01054 }
01055 AST_LIST_LOCK(agi_commands);
01056 AST_LIST_INSERT_TAIL(agi_commands, cmd, entry);
01057 AST_LIST_UNLOCK(agi_commands);
01058 return 0;
01059 }
01060
01061 static int add_to_agi(struct ast_channel *chan)
01062 {
01063 struct ast_datastore *datastore;
01064 AST_LIST_HEAD(, agi_cmd) *agi_cmds_list;
01065
01066
01067 ast_channel_lock(chan);
01068 datastore = ast_channel_datastore_find(chan, &agi_commands_datastore_info, NULL);
01069 ast_channel_unlock(chan);
01070 if (datastore) {
01071
01072
01073 return 0;
01074 }
01075
01076
01077
01078 datastore = ast_datastore_alloc(&agi_commands_datastore_info, "AGI");
01079 if (!datastore) {
01080 return -1;
01081 }
01082 agi_cmds_list = ast_calloc(1, sizeof(*agi_cmds_list));
01083 if (!agi_cmds_list) {
01084 ast_log(LOG_ERROR, "Unable to allocate Async AGI commands list.\n");
01085 ast_datastore_free(datastore);
01086 return -1;
01087 }
01088 datastore->data = agi_cmds_list;
01089 AST_LIST_HEAD_INIT(agi_cmds_list);
01090 ast_channel_lock(chan);
01091 ast_channel_datastore_add(chan, datastore);
01092 ast_channel_unlock(chan);
01093 return 0;
01094 }
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105 static char *handle_cli_agi_add_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01106 {
01107 struct ast_channel *chan;
01108 switch (cmd) {
01109 case CLI_INIT:
01110 e->command = "agi exec";
01111 e->usage = "Usage: agi exec <channel name> <app and arguments> [id]\n"
01112 " Add AGI command to the execute queue of the specified channel in Async AGI\n";
01113 return NULL;
01114 case CLI_GENERATE:
01115 if (a->pos == 2)
01116 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
01117 return NULL;
01118 }
01119
01120 if (a->argc < 4) {
01121 return CLI_SHOWUSAGE;
01122 }
01123
01124 if (!(chan = ast_channel_get_by_name(a->argv[2]))) {
01125 ast_cli(a->fd, "Channel %s does not exist.\n", a->argv[2]);
01126 return CLI_FAILURE;
01127 }
01128
01129 ast_channel_lock(chan);
01130
01131 if (add_agi_cmd(chan, a->argv[3], (a->argc > 4 ? a->argv[4] : ""))) {
01132 ast_cli(a->fd, "Failed to add AGI command to queue of channel %s\n", chan->name);
01133 ast_channel_unlock(chan);
01134 chan = ast_channel_unref(chan);
01135 return CLI_FAILURE;
01136 }
01137
01138 ast_debug(1, "Added AGI command to channel %s queue\n", chan->name);
01139
01140 ast_channel_unlock(chan);
01141 chan = ast_channel_unref(chan);
01142
01143 return CLI_SUCCESS;
01144 }
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157 static int action_add_agi_cmd(struct mansession *s, const struct message *m)
01158 {
01159 const char *channel = astman_get_header(m, "Channel");
01160 const char *cmdbuff = astman_get_header(m, "Command");
01161 const char *cmdid = astman_get_header(m, "CommandID");
01162 struct ast_channel *chan;
01163 char buf[256];
01164
01165 if (ast_strlen_zero(channel) || ast_strlen_zero(cmdbuff)) {
01166 astman_send_error(s, m, "Both, Channel and Command are *required*");
01167 return 0;
01168 }
01169
01170 if (!(chan = ast_channel_get_by_name(channel))) {
01171 snprintf(buf, sizeof(buf), "Channel %s does not exist.", channel);
01172 astman_send_error(s, m, buf);
01173 return 0;
01174 }
01175
01176 ast_channel_lock(chan);
01177
01178 if (add_agi_cmd(chan, cmdbuff, cmdid)) {
01179 snprintf(buf, sizeof(buf), "Failed to add AGI command to channel %s queue", chan->name);
01180 astman_send_error(s, m, buf);
01181 ast_channel_unlock(chan);
01182 chan = ast_channel_unref(chan);
01183 return 0;
01184 }
01185
01186 ast_channel_unlock(chan);
01187 chan = ast_channel_unref(chan);
01188
01189 astman_send_ack(s, m, "Added AGI command to queue");
01190
01191 return 0;
01192 }
01193
01194 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead);
01195 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[]);
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207 static enum agi_result async_agi_read_frame(struct ast_channel *chan)
01208 {
01209 struct ast_frame *f;
01210
01211 f = ast_read(chan);
01212 if (!f) {
01213 ast_debug(3, "No frame read on channel %s, going out ...\n", chan->name);
01214 return AGI_RESULT_HANGUP;
01215 }
01216 if (f->frametype == AST_FRAME_CONTROL) {
01217
01218
01219
01220
01221 switch (f->subclass.integer) {
01222 case AST_CONTROL_HANGUP:
01223 ast_debug(3, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
01224 ast_frfree(f);
01225 return AGI_RESULT_HANGUP;
01226 default:
01227 break;
01228 }
01229 }
01230 ast_frfree(f);
01231
01232 return AGI_RESULT_SUCCESS;
01233 }
01234
01235 static enum agi_result launch_asyncagi(struct ast_channel *chan, char *argv[], int *efd)
01236 {
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254 #define AGI_BUF_SIZE 1024
01255 #define AMI_BUF_SIZE 2048
01256 enum agi_result cmd_status;
01257 struct agi_cmd *cmd;
01258 int res;
01259 int fds[2];
01260 int hungup;
01261 int timeout = 100;
01262 char agi_buffer[AGI_BUF_SIZE + 1];
01263 char ami_buffer[AMI_BUF_SIZE];
01264 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
01265 AGI async_agi;
01266
01267 if (efd) {
01268 ast_log(LOG_WARNING, "Async AGI does not support Enhanced AGI yet\n");
01269 return AGI_RESULT_FAILURE;
01270 }
01271
01272
01273 if (add_to_agi(chan)) {
01274 ast_log(LOG_ERROR, "Failed to start Async AGI on channel %s\n", chan->name);
01275 return AGI_RESULT_FAILURE;
01276 }
01277
01278
01279
01280 res = pipe(fds);
01281 if (res) {
01282 ast_log(LOG_ERROR, "Failed to create Async AGI pipe\n");
01283
01284
01285
01286
01287
01288 return AGI_RESULT_FAILURE;
01289 }
01290
01291
01292
01293 async_agi.fd = fds[1];
01294 async_agi.ctrl = fds[1];
01295 async_agi.audio = -1;
01296 async_agi.fast = 0;
01297 async_agi.speech = NULL;
01298
01299
01300
01301 setup_env(chan, "async", fds[1], 0, 0, NULL);
01302
01303 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01304 if (res <= 0) {
01305 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
01306 chan->name, res < 0 ? strerror(errno) : "EOF");
01307 returnstatus = AGI_RESULT_FAILURE;
01308 goto async_agi_abort;
01309 }
01310 agi_buffer[res] = '\0';
01311
01312
01313
01314 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01315 manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01316 "SubEvent: Start\r\n"
01317 "Channel: %s\r\n"
01318 "Env: %s\r\n", chan->name, ami_buffer);
01319 hungup = ast_check_hangup(chan);
01320 for (;;) {
01321
01322
01323
01324
01325 while (!hungup && (cmd = get_agi_cmd(chan))) {
01326
01327 cmd_status = agi_handle_command(chan, &async_agi, cmd->cmd_buffer, 0);
01328
01329
01330
01331
01332
01333 res = read(fds[0], agi_buffer, AGI_BUF_SIZE);
01334 if (res <= 0) {
01335 ast_log(LOG_ERROR, "Failed to read from Async AGI pipe on channel %s: %s\n",
01336 chan->name, res < 0 ? strerror(errno) : "EOF");
01337 free_agi_cmd(cmd);
01338 returnstatus = AGI_RESULT_FAILURE;
01339 goto async_agi_done;
01340 }
01341
01342
01343
01344
01345
01346 agi_buffer[res] = '\0';
01347 ast_uri_encode(agi_buffer, ami_buffer, AMI_BUF_SIZE, 1);
01348 if (ast_strlen_zero(cmd->cmd_id)) {
01349 manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01350 "SubEvent: Exec\r\n"
01351 "Channel: %s\r\n"
01352 "Result: %s\r\n", chan->name, ami_buffer);
01353 } else {
01354 manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01355 "SubEvent: Exec\r\n"
01356 "Channel: %s\r\n"
01357 "CommandID: %s\r\n"
01358 "Result: %s\r\n", chan->name, cmd->cmd_id, ami_buffer);
01359 }
01360 free_agi_cmd(cmd);
01361
01362
01363
01364
01365
01366 hungup = ast_check_hangup(chan);
01367 switch (cmd_status) {
01368 case AGI_RESULT_FAILURE:
01369 if (!hungup) {
01370
01371 returnstatus = AGI_RESULT_FAILURE;
01372 goto async_agi_done;
01373 }
01374 break;
01375 case AGI_RESULT_SUCCESS_ASYNC:
01376
01377 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01378 goto async_agi_done;
01379 default:
01380 break;
01381 }
01382 }
01383
01384 if (!hungup) {
01385
01386 res = ast_waitfor(chan, timeout);
01387 if (res < 0) {
01388 ast_debug(1, "ast_waitfor returned <= 0 on chan %s\n", chan->name);
01389 returnstatus = AGI_RESULT_FAILURE;
01390 break;
01391 }
01392 } else {
01393
01394
01395
01396
01397 res = 1;
01398 }
01399 if (0 < res) {
01400 do {
01401 cmd_status = async_agi_read_frame(chan);
01402 if (cmd_status != AGI_RESULT_SUCCESS) {
01403 returnstatus = cmd_status;
01404 goto async_agi_done;
01405 }
01406 hungup = ast_check_hangup(chan);
01407 } while (hungup);
01408 } else {
01409 hungup = ast_check_hangup(chan);
01410 }
01411 }
01412 async_agi_done:
01413
01414 if (async_agi.speech) {
01415 ast_speech_destroy(async_agi.speech);
01416 }
01417
01418
01419 manager_event(EVENT_FLAG_AGI, "AsyncAGI",
01420 "SubEvent: End\r\n"
01421 "Channel: %s\r\n", chan->name);
01422
01423 async_agi_abort:
01424
01425 close(fds[0]);
01426 close(fds[1]);
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436 if (returnstatus == AGI_RESULT_SUCCESS) {
01437 returnstatus = AGI_RESULT_SUCCESS_ASYNC;
01438 }
01439 return returnstatus;
01440
01441 #undef AGI_BUF_SIZE
01442 #undef AMI_BUF_SIZE
01443 }
01444
01445
01446
01447 static enum agi_result launch_netscript(char *agiurl, char *argv[], int *fds)
01448 {
01449 int s, flags, res, port = AGI_PORT;
01450 struct pollfd pfds[1];
01451 char *host, *c, *script;
01452 struct sockaddr_in addr_in;
01453 struct hostent *hp;
01454 struct ast_hostent ahp;
01455
01456
01457 host = ast_strdupa(agiurl + 6);
01458
01459 if ((script = strchr(host, '/'))) {
01460 *script++ = '\0';
01461 } else {
01462 script = "";
01463 }
01464
01465 if ((c = strchr(host, ':'))) {
01466 *c++ = '\0';
01467 port = atoi(c);
01468 }
01469 if (!(hp = ast_gethostbyname(host, &ahp))) {
01470 ast_log(LOG_WARNING, "Unable to locate host '%s'\n", host);
01471 return AGI_RESULT_FAILURE;
01472 }
01473 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
01474 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
01475 return AGI_RESULT_FAILURE;
01476 }
01477 if ((flags = fcntl(s, F_GETFL)) < 0) {
01478 ast_log(LOG_WARNING, "Fcntl(F_GETFL) failed: %s\n", strerror(errno));
01479 close(s);
01480 return AGI_RESULT_FAILURE;
01481 }
01482 if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0) {
01483 ast_log(LOG_WARNING, "Fnctl(F_SETFL) failed: %s\n", strerror(errno));
01484 close(s);
01485 return AGI_RESULT_FAILURE;
01486 }
01487 memset(&addr_in, 0, sizeof(addr_in));
01488 addr_in.sin_family = AF_INET;
01489 addr_in.sin_port = htons(port);
01490 memcpy(&addr_in.sin_addr, hp->h_addr, sizeof(addr_in.sin_addr));
01491 if (connect(s, (struct sockaddr *)&addr_in, sizeof(addr_in)) && (errno != EINPROGRESS)) {
01492 ast_log(LOG_WARNING, "Connect failed with unexpected error: %s\n", strerror(errno));
01493 close(s);
01494 return AGI_RESULT_FAILURE;
01495 }
01496
01497 pfds[0].fd = s;
01498 pfds[0].events = POLLOUT;
01499 while ((res = ast_poll(pfds, 1, MAX_AGI_CONNECT)) != 1) {
01500 if (errno != EINTR) {
01501 if (!res) {
01502 ast_log(LOG_WARNING, "FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds.\n",
01503 agiurl, MAX_AGI_CONNECT);
01504 } else
01505 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01506 close(s);
01507 return AGI_RESULT_FAILURE;
01508 }
01509 }
01510
01511 if (ast_agi_send(s, NULL, "agi_network: yes\n") < 0) {
01512 if (errno != EINTR) {
01513 ast_log(LOG_WARNING, "Connect to '%s' failed: %s\n", agiurl, strerror(errno));
01514 close(s);
01515 return AGI_RESULT_FAILURE;
01516 }
01517 }
01518
01519
01520
01521 if (!ast_strlen_zero(script))
01522 ast_agi_send(s, NULL, "agi_network_script: %s\n", script);
01523
01524 ast_debug(4, "Wow, connected!\n");
01525 fds[0] = s;
01526 fds[1] = s;
01527 return AGI_RESULT_SUCCESS_FAST;
01528 }
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549 static enum agi_result launch_ha_netscript(char *agiurl, char *argv[], int *fds)
01550 {
01551 char *host, *script;
01552 enum agi_result result;
01553 struct srv_context *context = NULL;
01554 int srv_ret;
01555 char service[256];
01556 char resolved_uri[1024];
01557 const char *srvhost;
01558 unsigned short srvport;
01559
01560
01561 if (strlen(agiurl) < 7) {
01562 ast_log(LOG_WARNING, "An error occurred parsing the AGI URI: %s", agiurl);
01563 return AGI_RESULT_FAILURE;
01564 }
01565 host = ast_strdupa(agiurl + 7);
01566
01567
01568 if ((script = strchr(host, '/'))) {
01569 *script++ = '\0';
01570 } else {
01571 script = "";
01572 }
01573
01574 if (strchr(host, ':')) {
01575 ast_log(LOG_WARNING, "Specifying a port number disables SRV lookups: %s\n", agiurl);
01576 return launch_netscript(agiurl + 1, argv, fds);
01577 }
01578
01579 snprintf(service, sizeof(service), "%s%s", SRV_PREFIX, host);
01580
01581 while (!(srv_ret = ast_srv_lookup(&context, service, &srvhost, &srvport))) {
01582 snprintf(resolved_uri, sizeof(resolved_uri), "agi://%s:%d/%s", srvhost, srvport, script);
01583 result = launch_netscript(resolved_uri, argv, fds);
01584 if (result == AGI_RESULT_FAILURE || result == AGI_RESULT_NOTFOUND) {
01585 ast_log(LOG_WARNING, "AGI request failed for host '%s' (%s:%d)\n", host, srvhost, srvport);
01586 } else {
01587
01588 ast_srv_cleanup(&context);
01589 return result;
01590 }
01591 }
01592
01593
01594
01595
01596 if (srv_ret < 0) {
01597 ast_log(LOG_WARNING, "SRV lookup failed for %s\n", agiurl);
01598 }
01599
01600 return AGI_RESULT_FAILURE;
01601 }
01602
01603 static enum agi_result launch_script(struct ast_channel *chan, char *script, char *argv[], int *fds, int *efd, int *opid)
01604 {
01605 char tmp[256];
01606 int pid, toast[2], fromast[2], audio[2], res;
01607 struct stat st;
01608
01609 if (!strncasecmp(script, "agi://", 6)) {
01610 return (efd == NULL) ? launch_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01611 }
01612 if (!strncasecmp(script, "hagi://", 7)) {
01613 return (efd == NULL) ? launch_ha_netscript(script, argv, fds) : AGI_RESULT_FAILURE;
01614 }
01615 if (!strncasecmp(script, "agi:async", sizeof("agi:async") - 1)) {
01616 return launch_asyncagi(chan, argv, efd);
01617 }
01618
01619 if (script[0] != '/') {
01620 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_AGI_DIR, script);
01621 script = tmp;
01622 }
01623
01624
01625 if (stat(script, &st)) {
01626 ast_log(LOG_WARNING, "Failed to execute '%s': File does not exist.\n", script);
01627 return AGI_RESULT_NOTFOUND;
01628 }
01629
01630 if (pipe(toast)) {
01631 ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
01632 return AGI_RESULT_FAILURE;
01633 }
01634 if (pipe(fromast)) {
01635 ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
01636 close(toast[0]);
01637 close(toast[1]);
01638 return AGI_RESULT_FAILURE;
01639 }
01640 if (efd) {
01641 if (pipe(audio)) {
01642 ast_log(LOG_WARNING, "unable to create audio pipe: %s\n", strerror(errno));
01643 close(fromast[0]);
01644 close(fromast[1]);
01645 close(toast[0]);
01646 close(toast[1]);
01647 return AGI_RESULT_FAILURE;
01648 }
01649 res = fcntl(audio[1], F_GETFL);
01650 if (res > -1)
01651 res = fcntl(audio[1], F_SETFL, res | O_NONBLOCK);
01652 if (res < 0) {
01653 ast_log(LOG_WARNING, "unable to set audio pipe parameters: %s\n", strerror(errno));
01654 close(fromast[0]);
01655 close(fromast[1]);
01656 close(toast[0]);
01657 close(toast[1]);
01658 close(audio[0]);
01659 close(audio[1]);
01660 return AGI_RESULT_FAILURE;
01661 }
01662 }
01663
01664 if ((pid = ast_safe_fork(1)) < 0) {
01665 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
01666 return AGI_RESULT_FAILURE;
01667 }
01668 if (!pid) {
01669
01670 setenv("AST_CONFIG_DIR", ast_config_AST_CONFIG_DIR, 1);
01671 setenv("AST_CONFIG_FILE", ast_config_AST_CONFIG_FILE, 1);
01672 setenv("AST_MODULE_DIR", ast_config_AST_MODULE_DIR, 1);
01673 setenv("AST_SPOOL_DIR", ast_config_AST_SPOOL_DIR, 1);
01674 setenv("AST_MONITOR_DIR", ast_config_AST_MONITOR_DIR, 1);
01675 setenv("AST_VAR_DIR", ast_config_AST_VAR_DIR, 1);
01676 setenv("AST_DATA_DIR", ast_config_AST_DATA_DIR, 1);
01677 setenv("AST_LOG_DIR", ast_config_AST_LOG_DIR, 1);
01678 setenv("AST_AGI_DIR", ast_config_AST_AGI_DIR, 1);
01679 setenv("AST_KEY_DIR", ast_config_AST_KEY_DIR, 1);
01680 setenv("AST_RUN_DIR", ast_config_AST_RUN_DIR, 1);
01681
01682
01683 ast_set_priority(0);
01684
01685
01686 dup2(fromast[0], STDIN_FILENO);
01687 dup2(toast[1], STDOUT_FILENO);
01688 if (efd)
01689 dup2(audio[0], STDERR_FILENO + 1);
01690 else
01691 close(STDERR_FILENO + 1);
01692
01693
01694 ast_close_fds_above_n(STDERR_FILENO + 1);
01695
01696
01697
01698 execv(script, argv);
01699
01700 ast_child_verbose(1, "Failed to execute '%s': %s", script, strerror(errno));
01701
01702 fprintf(stdout, "failure\n");
01703 fflush(stdout);
01704 _exit(1);
01705 }
01706 ast_verb(3, "Launched AGI Script %s\n", script);
01707 fds[0] = toast[0];
01708 fds[1] = fromast[1];
01709 if (efd)
01710 *efd = audio[1];
01711
01712 close(toast[1]);
01713 close(fromast[0]);
01714
01715 if (efd)
01716 close(audio[0]);
01717
01718 *opid = pid;
01719 return AGI_RESULT_SUCCESS;
01720 }
01721
01722 static void setup_env(struct ast_channel *chan, char *request, int fd, int enhanced, int argc, char *argv[])
01723 {
01724 int count;
01725
01726
01727
01728 ast_agi_send(fd, chan, "agi_request: %s\n", request);
01729 ast_agi_send(fd, chan, "agi_channel: %s\n", chan->name);
01730 ast_agi_send(fd, chan, "agi_language: %s\n", chan->language);
01731 ast_agi_send(fd, chan, "agi_type: %s\n", chan->tech->type);
01732 ast_agi_send(fd, chan, "agi_uniqueid: %s\n", chan->uniqueid);
01733 ast_agi_send(fd, chan, "agi_version: %s\n", ast_get_version());
01734
01735
01736 ast_agi_send(fd, chan, "agi_callerid: %s\n",
01737 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, "unknown"));
01738 ast_agi_send(fd, chan, "agi_calleridname: %s\n",
01739 S_COR(chan->caller.id.name.valid, chan->caller.id.name.str, "unknown"));
01740 ast_agi_send(fd, chan, "agi_callingpres: %d\n",
01741 ast_party_id_presentation(&chan->caller.id));
01742 ast_agi_send(fd, chan, "agi_callingani2: %d\n", chan->caller.ani2);
01743 ast_agi_send(fd, chan, "agi_callington: %d\n", chan->caller.id.number.plan);
01744 ast_agi_send(fd, chan, "agi_callingtns: %d\n", chan->dialed.transit_network_select);
01745 ast_agi_send(fd, chan, "agi_dnid: %s\n", S_OR(chan->dialed.number.str, "unknown"));
01746 ast_agi_send(fd, chan, "agi_rdnis: %s\n",
01747 S_COR(chan->redirecting.from.number.valid, chan->redirecting.from.number.str, "unknown"));
01748
01749
01750 ast_agi_send(fd, chan, "agi_context: %s\n", chan->context);
01751 ast_agi_send(fd, chan, "agi_extension: %s\n", chan->exten);
01752 ast_agi_send(fd, chan, "agi_priority: %d\n", chan->priority);
01753 ast_agi_send(fd, chan, "agi_enhanced: %s\n", enhanced ? "1.0" : "0.0");
01754
01755
01756 ast_agi_send(fd, chan, "agi_accountcode: %s\n", chan->accountcode ? chan->accountcode : "");
01757 ast_agi_send(fd, chan, "agi_threadid: %ld\n", (long)pthread_self());
01758
01759
01760
01761 for(count = 1; count < argc; count++)
01762 ast_agi_send(fd, chan, "agi_arg_%d: %s\n", count, argv[count]);
01763
01764
01765 ast_agi_send(fd, chan, "\n");
01766 }
01767
01768 static int handle_answer(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01769 {
01770 int res = 0;
01771
01772
01773 if (chan->_state != AST_STATE_UP)
01774 res = ast_answer(chan);
01775
01776 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01777 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01778 }
01779
01780 static int handle_asyncagi_break(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01781 {
01782 ast_agi_send(agi->fd, chan, "200 result=0\n");
01783 return ASYNC_AGI_BREAK;
01784 }
01785
01786 static int handle_waitfordigit(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01787 {
01788 int res, to;
01789
01790 if (argc != 4)
01791 return RESULT_SHOWUSAGE;
01792 if (sscanf(argv[3], "%30d", &to) != 1)
01793 return RESULT_SHOWUSAGE;
01794 res = ast_waitfordigit_full(chan, to, agi->audio, agi->ctrl);
01795 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01796 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01797 }
01798
01799 static int handle_sendtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01800 {
01801 int res;
01802
01803 if (argc != 3)
01804 return RESULT_SHOWUSAGE;
01805
01806
01807
01808
01809
01810
01811
01812
01813 res = ast_sendtext(chan, argv[2]);
01814 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01815 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01816 }
01817
01818 static int handle_recvchar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01819 {
01820 int res;
01821
01822 if (argc != 3)
01823 return RESULT_SHOWUSAGE;
01824
01825 res = ast_recvchar(chan,atoi(argv[2]));
01826 if (res == 0) {
01827 ast_agi_send(agi->fd, chan, "200 result=%d (timeout)\n", res);
01828 return RESULT_SUCCESS;
01829 }
01830 if (res > 0) {
01831 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01832 return RESULT_SUCCESS;
01833 }
01834 ast_agi_send(agi->fd, chan, "200 result=%d (hangup)\n", res);
01835 return RESULT_FAILURE;
01836 }
01837
01838 static int handle_recvtext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01839 {
01840 char *buf;
01841
01842 if (argc != 3)
01843 return RESULT_SHOWUSAGE;
01844
01845 buf = ast_recvtext(chan, atoi(argv[2]));
01846 if (buf) {
01847 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", buf);
01848 ast_free(buf);
01849 } else {
01850 ast_agi_send(agi->fd, chan, "200 result=-1\n");
01851 }
01852 return RESULT_SUCCESS;
01853 }
01854
01855 static int handle_tddmode(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01856 {
01857 int res, x;
01858
01859 if (argc != 3)
01860 return RESULT_SHOWUSAGE;
01861
01862 if (!strncasecmp(argv[2],"on",2)) {
01863 x = 1;
01864 } else {
01865 x = 0;
01866 }
01867 if (!strncasecmp(argv[2],"mate",4)) {
01868 x = 2;
01869 }
01870 if (!strncasecmp(argv[2],"tdd",3)) {
01871 x = 1;
01872 }
01873 res = ast_channel_setoption(chan, AST_OPTION_TDD, &x, sizeof(char), 0);
01874 if (res) {
01875
01876 ast_agi_send(agi->fd, chan, "200 result=0\n");
01877 } else {
01878 ast_agi_send(agi->fd, chan, "200 result=1\n");
01879 }
01880 return RESULT_SUCCESS;
01881 }
01882
01883 static int handle_sendimage(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01884 {
01885 int res;
01886
01887 if (argc != 3) {
01888 return RESULT_SHOWUSAGE;
01889 }
01890
01891 res = ast_send_image(chan, argv[2]);
01892 if (!ast_check_hangup(chan)) {
01893 res = 0;
01894 }
01895 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01896 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01897 }
01898
01899 static int handle_controlstreamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01900 {
01901 int res = 0, skipms = 3000;
01902 const char *fwd = "#", *rev = "*", *suspend = NULL, *stop = NULL;
01903
01904 if (argc < 5 || argc > 9) {
01905 return RESULT_SHOWUSAGE;
01906 }
01907
01908 if (!ast_strlen_zero(argv[4])) {
01909 stop = argv[4];
01910 }
01911
01912 if ((argc > 5) && (sscanf(argv[5], "%30d", &skipms) != 1)) {
01913 return RESULT_SHOWUSAGE;
01914 }
01915
01916 if (argc > 6 && !ast_strlen_zero(argv[6])) {
01917 fwd = argv[6];
01918 }
01919
01920 if (argc > 7 && !ast_strlen_zero(argv[7])) {
01921 rev = argv[7];
01922 }
01923
01924 if (argc > 8 && !ast_strlen_zero(argv[8])) {
01925 suspend = argv[8];
01926 }
01927
01928 res = ast_control_streamfile(chan, argv[3], fwd, rev, stop, suspend, NULL, skipms, NULL);
01929
01930 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
01931
01932 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01933 }
01934
01935 static int handle_streamfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01936 {
01937 int res;
01938 struct ast_filestream *fs, *vfs;
01939 long sample_offset = 0, max_length;
01940 const char *edigits = "";
01941
01942 if (argc < 4 || argc > 5)
01943 return RESULT_SHOWUSAGE;
01944
01945 if (argv[3])
01946 edigits = argv[3];
01947
01948 if ((argc > 4) && (sscanf(argv[4], "%30ld", &sample_offset) != 1))
01949 return RESULT_SHOWUSAGE;
01950
01951 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
01952 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
01953 return RESULT_FAILURE;
01954 }
01955
01956 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
01957 ast_debug(1, "Ooh, found a video stream, too\n");
01958
01959 ast_verb(3, "Playing '%s' (escape_digits=%s) (sample_offset %ld)\n", argv[2], edigits, sample_offset);
01960
01961 ast_seekstream(fs, 0, SEEK_END);
01962 max_length = ast_tellstream(fs);
01963 ast_seekstream(fs, sample_offset, SEEK_SET);
01964 res = ast_applystream(chan, fs);
01965 if (vfs)
01966 ast_applystream(chan, vfs);
01967 ast_playstream(fs);
01968 if (vfs)
01969 ast_playstream(vfs);
01970
01971 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
01972
01973
01974 sample_offset = (chan->stream) ? ast_tellstream(fs) : max_length;
01975 ast_stopstream(chan);
01976 if (res == 1) {
01977
01978 return RESULT_SUCCESS;
01979 }
01980 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
01981 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
01982 }
01983
01984
01985 static int handle_getoption(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
01986 {
01987 int res;
01988 struct ast_filestream *fs, *vfs;
01989 long sample_offset = 0, max_length;
01990 int timeout = 0;
01991 const char *edigits = "";
01992
01993 if ( argc < 4 || argc > 5 )
01994 return RESULT_SHOWUSAGE;
01995
01996 if ( argv[3] )
01997 edigits = argv[3];
01998
01999 if ( argc == 5 )
02000 timeout = atoi(argv[4]);
02001 else if (chan->pbx->dtimeoutms) {
02002
02003 timeout = chan->pbx->dtimeoutms;
02004 }
02005
02006 if (!(fs = ast_openstream(chan, argv[2], chan->language))) {
02007 ast_agi_send(agi->fd, chan, "200 result=-1 endpos=%ld\n", sample_offset);
02008 ast_log(LOG_WARNING, "Unable to open %s\n", argv[2]);
02009 return RESULT_FAILURE;
02010 }
02011
02012 if ((vfs = ast_openvstream(chan, argv[2], chan->language)))
02013 ast_debug(1, "Ooh, found a video stream, too\n");
02014
02015 ast_verb(3, "Playing '%s' (escape_digits=%s) (timeout %d)\n", argv[2], edigits, timeout);
02016
02017 ast_seekstream(fs, 0, SEEK_END);
02018 max_length = ast_tellstream(fs);
02019 ast_seekstream(fs, sample_offset, SEEK_SET);
02020 res = ast_applystream(chan, fs);
02021 if (vfs)
02022 ast_applystream(chan, vfs);
02023 ast_playstream(fs);
02024 if (vfs)
02025 ast_playstream(vfs);
02026
02027 res = ast_waitstream_full(chan, argv[3], agi->audio, agi->ctrl);
02028
02029
02030 sample_offset = (chan->stream)?ast_tellstream(fs):max_length;
02031 ast_stopstream(chan);
02032 if (res == 1) {
02033
02034 return RESULT_SUCCESS;
02035 }
02036
02037
02038 if (res == 0 ) {
02039 res = ast_waitfordigit_full(chan, timeout, agi->audio, agi->ctrl);
02040
02041 if ( !strchr(edigits,res) )
02042 res=0;
02043 }
02044
02045 ast_agi_send(agi->fd, chan, "200 result=%d endpos=%ld\n", res, sample_offset);
02046 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02047 }
02048
02049
02050
02051
02052
02053
02054 static int handle_saynumber(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02055 {
02056 int res, num;
02057
02058 if (argc < 4 || argc > 5)
02059 return RESULT_SHOWUSAGE;
02060 if (sscanf(argv[2], "%30d", &num) != 1)
02061 return RESULT_SHOWUSAGE;
02062 res = ast_say_number_full(chan, num, argv[3], chan->language, argc > 4 ? argv[4] : NULL, agi->audio, agi->ctrl);
02063 if (res == 1)
02064 return RESULT_SUCCESS;
02065 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02066 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02067 }
02068
02069 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02070 {
02071 int res, num;
02072
02073 if (argc != 4)
02074 return RESULT_SHOWUSAGE;
02075 if (sscanf(argv[2], "%30d", &num) != 1)
02076 return RESULT_SHOWUSAGE;
02077
02078 res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02079 if (res == 1)
02080 return RESULT_SUCCESS;
02081 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02082 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02083 }
02084
02085 static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02086 {
02087 int res;
02088
02089 if (argc != 4)
02090 return RESULT_SHOWUSAGE;
02091
02092 res = ast_say_character_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02093 if (res == 1)
02094 return RESULT_SUCCESS;
02095 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02096 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02097 }
02098
02099 static int handle_saydate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02100 {
02101 int res, num;
02102
02103 if (argc != 4)
02104 return RESULT_SHOWUSAGE;
02105 if (sscanf(argv[2], "%30d", &num) != 1)
02106 return RESULT_SHOWUSAGE;
02107 res = ast_say_date(chan, num, argv[3], chan->language);
02108 if (res == 1)
02109 return RESULT_SUCCESS;
02110 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02111 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02112 }
02113
02114 static int handle_saytime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02115 {
02116 int res, num;
02117
02118 if (argc != 4)
02119 return RESULT_SHOWUSAGE;
02120 if (sscanf(argv[2], "%30d", &num) != 1)
02121 return RESULT_SHOWUSAGE;
02122 res = ast_say_time(chan, num, argv[3], chan->language);
02123 if (res == 1)
02124 return RESULT_SUCCESS;
02125 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02126 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02127 }
02128
02129 static int handle_saydatetime(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02130 {
02131 int res = 0;
02132 time_t unixtime;
02133 const char *format, *zone = NULL;
02134
02135 if (argc < 4)
02136 return RESULT_SHOWUSAGE;
02137
02138 if (argc > 4) {
02139 format = argv[4];
02140 } else {
02141
02142 if (!strcasecmp(chan->language, "de")) {
02143 format = "A dBY HMS";
02144 } else {
02145 format = "ABdY 'digits/at' IMp";
02146 }
02147 }
02148
02149 if (argc > 5 && !ast_strlen_zero(argv[5]))
02150 zone = argv[5];
02151
02152 if (ast_get_time_t(argv[2], &unixtime, 0, NULL))
02153 return RESULT_SHOWUSAGE;
02154
02155 res = ast_say_date_with_format(chan, unixtime, argv[3], chan->language, format, zone);
02156 if (res == 1)
02157 return RESULT_SUCCESS;
02158
02159 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02160 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02161 }
02162
02163 static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02164 {
02165 int res;
02166
02167 if (argc != 4)
02168 return RESULT_SHOWUSAGE;
02169
02170 res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
02171 if (res == 1)
02172 return RESULT_SUCCESS;
02173 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02174 return (res >= 0) ? RESULT_SUCCESS : RESULT_FAILURE;
02175 }
02176
02177 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02178 {
02179 int res, max, timeout;
02180 char data[1024];
02181
02182 if (argc < 3)
02183 return RESULT_SHOWUSAGE;
02184 if (argc >= 4)
02185 timeout = atoi(argv[3]);
02186 else
02187 timeout = 0;
02188 if (argc >= 5)
02189 max = atoi(argv[4]);
02190 else
02191 max = 1024;
02192 res = ast_app_getdata_full(chan, argv[2], data, max, timeout, agi->audio, agi->ctrl);
02193 if (res == 2)
02194 return RESULT_SUCCESS;
02195 else if (res == 1)
02196 ast_agi_send(agi->fd, chan, "200 result=%s (timeout)\n", data);
02197 else if (res < 0 )
02198 ast_agi_send(agi->fd, chan, "200 result=-1\n");
02199 else
02200 ast_agi_send(agi->fd, chan, "200 result=%s\n", data);
02201 return RESULT_SUCCESS;
02202 }
02203
02204 static int handle_setcontext(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02205 {
02206
02207 if (argc != 3)
02208 return RESULT_SHOWUSAGE;
02209 ast_copy_string(chan->context, argv[2], sizeof(chan->context));
02210 ast_agi_send(agi->fd, chan, "200 result=0\n");
02211 return RESULT_SUCCESS;
02212 }
02213
02214 static int handle_setextension(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02215 {
02216 if (argc != 3)
02217 return RESULT_SHOWUSAGE;
02218 ast_copy_string(chan->exten, argv[2], sizeof(chan->exten));
02219 ast_agi_send(agi->fd, chan, "200 result=0\n");
02220 return RESULT_SUCCESS;
02221 }
02222
02223 static int handle_setpriority(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02224 {
02225 int pri;
02226
02227 if (argc != 3)
02228 return RESULT_SHOWUSAGE;
02229
02230 if (sscanf(argv[2], "%30d", &pri) != 1) {
02231 pri = ast_findlabel_extension(chan, chan->context, chan->exten, argv[2],
02232 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
02233 if (pri < 1)
02234 return RESULT_SHOWUSAGE;
02235 }
02236
02237 ast_explicit_goto(chan, NULL, NULL, pri);
02238 ast_agi_send(agi->fd, chan, "200 result=0\n");
02239 return RESULT_SUCCESS;
02240 }
02241
02242 static int handle_recordfile(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02243 {
02244 struct ast_filestream *fs;
02245 struct ast_frame *f;
02246 struct timeval start;
02247 long sample_offset = 0;
02248 int res = 0;
02249 int ms;
02250
02251 struct ast_dsp *sildet=NULL;
02252 int totalsilence = 0;
02253 int dspsilence = 0;
02254 int silence = 0;
02255 int gotsilence = 0;
02256 char *silencestr = NULL;
02257 int rfmt = 0;
02258
02259
02260
02261 if (argc < 6)
02262 return RESULT_SHOWUSAGE;
02263 if (sscanf(argv[5], "%30d", &ms) != 1)
02264 return RESULT_SHOWUSAGE;
02265
02266 if (argc > 6)
02267 silencestr = strchr(argv[6],'s');
02268 if ((argc > 7) && (!silencestr))
02269 silencestr = strchr(argv[7],'s');
02270 if ((argc > 8) && (!silencestr))
02271 silencestr = strchr(argv[8],'s');
02272
02273 if (silencestr) {
02274 if (strlen(silencestr) > 2) {
02275 if ((silencestr[0] == 's') && (silencestr[1] == '=')) {
02276 silencestr++;
02277 silencestr++;
02278 if (silencestr)
02279 silence = atoi(silencestr);
02280 if (silence > 0)
02281 silence *= 1000;
02282 }
02283 }
02284 }
02285
02286 if (silence > 0) {
02287 rfmt = chan->readformat;
02288 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
02289 if (res < 0) {
02290 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
02291 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02292 return RESULT_FAILURE;
02293 }
02294 sildet = ast_dsp_new();
02295 if (!sildet) {
02296 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
02297 ast_agi_send(agi->fd, chan, "200 result=-1\n");
02298 return RESULT_FAILURE;
02299 }
02300 ast_dsp_set_threshold(sildet, ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE));
02301 }
02302
02303
02304
02305
02306 if ((argc >6) && (sscanf(argv[6], "%30ld", &sample_offset) != 1) && (!strchr(argv[6], '=')))
02307 res = ast_streamfile(chan, "beep", chan->language);
02308
02309 if ((argc > 7) && (!strchr(argv[7], '=')))
02310 res = ast_streamfile(chan, "beep", chan->language);
02311
02312 if (!res)
02313 res = ast_waitstream(chan, argv[4]);
02314 if (res) {
02315 ast_agi_send(agi->fd, chan, "200 result=%d (randomerror) endpos=%ld\n", res, sample_offset);
02316 } else {
02317 fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_WRONLY | (sample_offset ? O_APPEND : 0), 0, AST_FILE_MODE);
02318 if (!fs) {
02319 res = -1;
02320 ast_agi_send(agi->fd, chan, "200 result=%d (writefile)\n", res);
02321 if (sildet)
02322 ast_dsp_free(sildet);
02323 return RESULT_FAILURE;
02324 }
02325
02326
02327 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
02328
02329 chan->stream = fs;
02330 ast_applystream(chan,fs);
02331
02332 ast_seekstream(fs, sample_offset, SEEK_SET);
02333 ast_truncstream(fs);
02334
02335 start = ast_tvnow();
02336 while ((ms < 0) || ast_tvdiff_ms(ast_tvnow(), start) < ms) {
02337 res = ast_waitfor(chan, ms - ast_tvdiff_ms(ast_tvnow(), start));
02338 if (res < 0) {
02339 ast_closestream(fs);
02340 ast_agi_send(agi->fd, chan, "200 result=%d (waitfor) endpos=%ld\n", res,sample_offset);
02341 if (sildet)
02342 ast_dsp_free(sildet);
02343 return RESULT_FAILURE;
02344 }
02345 f = ast_read(chan);
02346 if (!f) {
02347 ast_agi_send(agi->fd, chan, "200 result=%d (hangup) endpos=%ld\n", -1, sample_offset);
02348 ast_closestream(fs);
02349 if (sildet)
02350 ast_dsp_free(sildet);
02351 return RESULT_FAILURE;
02352 }
02353 switch(f->frametype) {
02354 case AST_FRAME_DTMF:
02355 if (strchr(argv[4], f->subclass.integer)) {
02356
02357
02358
02359 ast_stream_rewind(fs, 200);
02360 ast_truncstream(fs);
02361 sample_offset = ast_tellstream(fs);
02362 ast_agi_send(agi->fd, chan, "200 result=%d (dtmf) endpos=%ld\n", f->subclass.integer, sample_offset);
02363 ast_closestream(fs);
02364 ast_frfree(f);
02365 if (sildet)
02366 ast_dsp_free(sildet);
02367 return RESULT_SUCCESS;
02368 }
02369 break;
02370 case AST_FRAME_VOICE:
02371 ast_writestream(fs, f);
02372
02373
02374
02375 sample_offset = ast_tellstream(fs);
02376 if (silence > 0) {
02377 dspsilence = 0;
02378 ast_dsp_silence(sildet, f, &dspsilence);
02379 if (dspsilence) {
02380 totalsilence = dspsilence;
02381 } else {
02382 totalsilence = 0;
02383 }
02384 if (totalsilence > silence) {
02385
02386 gotsilence = 1;
02387 break;
02388 }
02389 }
02390 break;
02391 case AST_FRAME_VIDEO:
02392 ast_writestream(fs, f);
02393 default:
02394
02395 break;
02396 }
02397 ast_frfree(f);
02398 if (gotsilence)
02399 break;
02400 }
02401
02402 if (gotsilence) {
02403 ast_stream_rewind(fs, silence-1000);
02404 ast_truncstream(fs);
02405 sample_offset = ast_tellstream(fs);
02406 }
02407 ast_agi_send(agi->fd, chan, "200 result=%d (timeout) endpos=%ld\n", res, sample_offset);
02408 ast_closestream(fs);
02409 }
02410
02411 if (silence > 0) {
02412 res = ast_set_read_format(chan, rfmt);
02413 if (res)
02414 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
02415 ast_dsp_free(sildet);
02416 }
02417
02418 return RESULT_SUCCESS;
02419 }
02420
02421 static int handle_autohangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02422 {
02423 double timeout;
02424 struct timeval whentohangup = { 0, 0 };
02425
02426 if (argc != 3)
02427 return RESULT_SHOWUSAGE;
02428 if (sscanf(argv[2], "%30lf", &timeout) != 1)
02429 return RESULT_SHOWUSAGE;
02430 if (timeout < 0)
02431 timeout = 0;
02432 if (timeout) {
02433 whentohangup.tv_sec = timeout;
02434 whentohangup.tv_usec = (timeout - whentohangup.tv_sec) * 1000000.0;
02435 }
02436 ast_channel_setwhentohangup_tv(chan, whentohangup);
02437 ast_agi_send(agi->fd, chan, "200 result=0\n");
02438 return RESULT_SUCCESS;
02439 }
02440
02441 static int handle_hangup(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02442 {
02443 struct ast_channel *c;
02444
02445 if (argc == 1) {
02446
02447 ast_set_hangupsource(chan, "dialplan/agi", 0);
02448 ast_softhangup(chan,AST_SOFTHANGUP_EXPLICIT);
02449 ast_agi_send(agi->fd, chan, "200 result=1\n");
02450 return RESULT_SUCCESS;
02451 } else if (argc == 2) {
02452
02453 if ((c = ast_channel_get_by_name(argv[1]))) {
02454
02455 ast_set_hangupsource(c, "dialplan/agi", 0);
02456 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
02457 c = ast_channel_unref(c);
02458 ast_agi_send(agi->fd, chan, "200 result=1\n");
02459 return RESULT_SUCCESS;
02460 }
02461
02462 ast_agi_send(agi->fd, chan, "200 result=-1\n");
02463 return RESULT_SUCCESS;
02464 } else {
02465 return RESULT_SHOWUSAGE;
02466 }
02467 }
02468
02469 static int handle_exec(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02470 {
02471 int res, workaround;
02472 struct ast_app *app_to_exec;
02473
02474 if (argc < 2)
02475 return RESULT_SHOWUSAGE;
02476
02477 ast_verb(3, "AGI Script Executing Application: (%s) Options: (%s)\n", argv[1], argc >= 3 ? argv[2] : "");
02478
02479 if ((app_to_exec = pbx_findapp(argv[1]))) {
02480 if (!(workaround = ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS))) {
02481 ast_set_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02482 }
02483 if (ast_compat_res_agi && argc >= 3 && !ast_strlen_zero(argv[2])) {
02484 char *compat = ast_alloca(strlen(argv[2]) * 2 + 1), *cptr;
02485 const char *vptr;
02486 for (cptr = compat, vptr = argv[2]; *vptr; vptr++) {
02487 if (*vptr == ',') {
02488 *cptr++ = '\\';
02489 *cptr++ = ',';
02490 } else if (*vptr == '|') {
02491 *cptr++ = ',';
02492 } else {
02493 *cptr++ = *vptr;
02494 }
02495 }
02496 *cptr = '\0';
02497 res = pbx_exec(chan, app_to_exec, compat);
02498 } else {
02499 res = pbx_exec(chan, app_to_exec, argc == 2 ? "" : argv[2]);
02500 }
02501 if (!workaround) {
02502 ast_clear_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS);
02503 }
02504 } else {
02505 ast_log(LOG_WARNING, "Could not find application (%s)\n", argv[1]);
02506 res = -2;
02507 }
02508 ast_agi_send(agi->fd, chan, "200 result=%d\n", res);
02509
02510
02511 return res;
02512 }
02513
02514 static int handle_setcallerid(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02515 {
02516 char tmp[256]="";
02517 char *l = NULL, *n = NULL;
02518
02519 if (argv[2]) {
02520 ast_copy_string(tmp, argv[2], sizeof(tmp));
02521 ast_callerid_parse(tmp, &n, &l);
02522 if (l)
02523 ast_shrink_phone_number(l);
02524 else
02525 l = "";
02526 if (!n)
02527 n = "";
02528 ast_set_callerid(chan, l, n, NULL);
02529 }
02530
02531 ast_agi_send(agi->fd, chan, "200 result=1\n");
02532 return RESULT_SUCCESS;
02533 }
02534
02535 static int handle_channelstatus(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02536 {
02537 struct ast_channel *c;
02538 if (argc == 2) {
02539
02540 ast_agi_send(agi->fd, chan, "200 result=%u\n", chan->_state);
02541 return RESULT_SUCCESS;
02542 } else if (argc == 3) {
02543
02544 if ((c = ast_channel_get_by_name(argv[2]))) {
02545 ast_agi_send(agi->fd, chan, "200 result=%u\n", c->_state);
02546 c = ast_channel_unref(c);
02547 return RESULT_SUCCESS;
02548 }
02549
02550 ast_agi_send(agi->fd, chan, "200 result=-1\n");
02551 return RESULT_SUCCESS;
02552 } else {
02553 return RESULT_SHOWUSAGE;
02554 }
02555 }
02556
02557 static int handle_setvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02558 {
02559 if (argv[3])
02560 pbx_builtin_setvar_helper(chan, argv[2], argv[3]);
02561
02562 ast_agi_send(agi->fd, chan, "200 result=1\n");
02563 return RESULT_SUCCESS;
02564 }
02565
02566 static int handle_getvariable(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02567 {
02568 char *ret;
02569 char tempstr[1024] = "";
02570
02571 if (argc != 3)
02572 return RESULT_SHOWUSAGE;
02573
02574
02575 if (!ast_strlen_zero(argv[2]) && (argv[2][strlen(argv[2]) - 1] == ')')) {
02576 ret = ast_func_read(chan, argv[2], tempstr, sizeof(tempstr)) ? NULL : tempstr;
02577 } else {
02578 pbx_retrieve_variable(chan, argv[2], &ret, tempstr, sizeof(tempstr), NULL);
02579 }
02580
02581 if (ret)
02582 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ret);
02583 else
02584 ast_agi_send(agi->fd, chan, "200 result=0\n");
02585
02586 return RESULT_SUCCESS;
02587 }
02588
02589 static int handle_getvariablefull(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02590 {
02591 struct ast_channel *chan2 = NULL;
02592
02593 if (argc != 4 && argc != 5) {
02594 return RESULT_SHOWUSAGE;
02595 }
02596
02597 if (argc == 5) {
02598 chan2 = ast_channel_get_by_name(argv[4]);
02599 } else {
02600 chan2 = ast_channel_ref(chan);
02601 }
02602
02603 if (chan2) {
02604 struct ast_str *str = ast_str_create(16);
02605 if (!str) {
02606 ast_agi_send(agi->fd, chan, "200 result=0\n");
02607 return RESULT_SUCCESS;
02608 }
02609 ast_str_substitute_variables(&str, 0, chan2, argv[3]);
02610 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(str));
02611 ast_free(str);
02612 } else {
02613 ast_agi_send(agi->fd, chan, "200 result=0\n");
02614 }
02615
02616 if (chan2) {
02617 chan2 = ast_channel_unref(chan2);
02618 }
02619
02620 return RESULT_SUCCESS;
02621 }
02622
02623 static int handle_verbose(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02624 {
02625 int level = 0;
02626 char *tmpdata, *var;
02627 struct ast_variable_list *cur;
02628
02629 if (argc < 2)
02630 return RESULT_SHOWUSAGE;
02631
02632 if (argv[2])
02633 sscanf(argv[2], "%30d", &level);
02634
02635 if (VERBOSITY_ATLEAST(level)) {
02636 tmpdata = ast_strdupa(chan->data);
02637 char findstr[128];
02638 AST_LIST_TRAVERSE(&agimaskvars, cur, list) {
02639 ast_copy_string(findstr, cur->variable, sizeof(findstr));
02640 strncat(findstr, "=", sizeof(findstr));
02641 var = strstr(tmpdata, findstr);
02642 if (var)
02643 mask_string(var, agimaskvarini, agimaskvarend, 1);
02644 }
02645 ast_verb(level, "%s: %s\n", tmpdata, argv[1]);
02646 }
02647
02648 ast_agi_send(agi->fd, chan, "200 result=1\n");
02649
02650 return RESULT_SUCCESS;
02651 }
02652
02653 static int handle_dbget(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02654 {
02655 int res;
02656 struct ast_str *buf;
02657
02658 if (argc != 4)
02659 return RESULT_SHOWUSAGE;
02660
02661 if (!(buf = ast_str_create(16))) {
02662 ast_agi_send(agi->fd, chan, "200 result=-1\n");
02663 return RESULT_SUCCESS;
02664 }
02665
02666 do {
02667 res = ast_db_get(argv[2], argv[3], ast_str_buffer(buf), ast_str_size(buf));
02668 ast_str_update(buf);
02669 if (ast_str_strlen(buf) < ast_str_size(buf) - 1) {
02670 break;
02671 }
02672 if (ast_str_make_space(&buf, ast_str_size(buf) * 2)) {
02673 break;
02674 }
02675 } while (1);
02676
02677 if (res)
02678 ast_agi_send(agi->fd, chan, "200 result=0\n");
02679 else
02680 ast_agi_send(agi->fd, chan, "200 result=1 (%s)\n", ast_str_buffer(buf));
02681
02682 ast_free(buf);
02683 return RESULT_SUCCESS;
02684 }
02685
02686 static int handle_dbput(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02687 {
02688 int res;
02689
02690 if (argc != 5)
02691 return RESULT_SHOWUSAGE;
02692 res = ast_db_put(argv[2], argv[3], argv[4]);
02693 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02694 return RESULT_SUCCESS;
02695 }
02696
02697 static int handle_dbdel(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02698 {
02699 int res;
02700
02701 if (argc != 4)
02702 return RESULT_SHOWUSAGE;
02703 res = ast_db_del(argv[2], argv[3]);
02704 ast_agi_send(agi->fd, chan, "200 result=%c\n", res ? '0' : '1');
02705 return RESULT_SUCCESS;
02706 }
02707
02708 static int handle_dbdeltree(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02709 {
02710 int num_deleted;
02711
02712 if ((argc < 3) || (argc > 4)) {
02713 return RESULT_SHOWUSAGE;
02714 }
02715 if (argc == 4) {
02716 num_deleted = ast_db_deltree(argv[2], argv[3]);
02717 } else {
02718 num_deleted = ast_db_deltree(argv[2], NULL);
02719 }
02720
02721 ast_agi_send(agi->fd, chan, "200 result=%c\n", num_deleted > 0 ? '0' : '1');
02722 return RESULT_SUCCESS;
02723 }
02724
02725 static char *handle_cli_agi_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02726 {
02727 switch (cmd) {
02728 case CLI_INIT:
02729 e->command = "agi set debug [on|off]";
02730 e->usage =
02731 "Usage: agi set debug [on|off]\n"
02732 " Enables/disables dumping of AGI transactions for\n"
02733 " debugging purposes.\n";
02734 return NULL;
02735
02736 case CLI_GENERATE:
02737 return NULL;
02738 }
02739
02740 if (a->argc != e->args)
02741 return CLI_SHOWUSAGE;
02742
02743 if (strncasecmp(a->argv[3], "off", 3) == 0) {
02744 agidebug = 0;
02745 } else if (strncasecmp(a->argv[3], "on", 2) == 0) {
02746 agidebug = 1;
02747 } else {
02748 return CLI_SHOWUSAGE;
02749 }
02750 ast_cli(a->fd, "AGI Debugging %sabled\n", agidebug ? "En" : "Dis");
02751 return CLI_SUCCESS;
02752 }
02753
02754 static int handle_noop(struct ast_channel *chan, AGI *agi, int arg, const char * const argv[])
02755 {
02756 ast_agi_send(agi->fd, chan, "200 result=0\n");
02757 return RESULT_SUCCESS;
02758 }
02759
02760 static int handle_setmusic(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02761 {
02762 if (argc < 3) {
02763 return RESULT_SHOWUSAGE;
02764 }
02765 if (!strncasecmp(argv[2], "on", 2))
02766 ast_moh_start(chan, argc > 3 ? argv[3] : NULL, NULL);
02767 else if (!strncasecmp(argv[2], "off", 3))
02768 ast_moh_stop(chan);
02769 ast_agi_send(agi->fd, chan, "200 result=0\n");
02770 return RESULT_SUCCESS;
02771 }
02772
02773 static int handle_speechcreate(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02774 {
02775
02776 if (agi->speech) {
02777 ast_agi_send(agi->fd, chan, "200 result=0\n");
02778 return RESULT_SUCCESS;
02779 }
02780
02781 if ((agi->speech = ast_speech_new(argv[2], AST_FORMAT_SLINEAR)))
02782 ast_agi_send(agi->fd, chan, "200 result=1\n");
02783 else
02784 ast_agi_send(agi->fd, chan, "200 result=0\n");
02785
02786 return RESULT_SUCCESS;
02787 }
02788
02789 static int handle_speechset(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02790 {
02791
02792 if (argc != 4)
02793 return RESULT_SHOWUSAGE;
02794
02795
02796 if (!agi->speech) {
02797 ast_agi_send(agi->fd, chan, "200 result=0\n");
02798 return RESULT_SUCCESS;
02799 }
02800
02801 ast_speech_change(agi->speech, argv[2], argv[3]);
02802 ast_agi_send(agi->fd, chan, "200 result=1\n");
02803
02804 return RESULT_SUCCESS;
02805 }
02806
02807 static int handle_speechdestroy(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02808 {
02809 if (agi->speech) {
02810 ast_speech_destroy(agi->speech);
02811 agi->speech = NULL;
02812 ast_agi_send(agi->fd, chan, "200 result=1\n");
02813 } else {
02814 ast_agi_send(agi->fd, chan, "200 result=0\n");
02815 }
02816
02817 return RESULT_SUCCESS;
02818 }
02819
02820 static int handle_speechloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02821 {
02822 if (argc != 5)
02823 return RESULT_SHOWUSAGE;
02824
02825 if (!agi->speech) {
02826 ast_agi_send(agi->fd, chan, "200 result=0\n");
02827 return RESULT_SUCCESS;
02828 }
02829
02830 if (ast_speech_grammar_load(agi->speech, argv[3], argv[4]))
02831 ast_agi_send(agi->fd, chan, "200 result=0\n");
02832 else
02833 ast_agi_send(agi->fd, chan, "200 result=1\n");
02834
02835 return RESULT_SUCCESS;
02836 }
02837
02838 static int handle_speechunloadgrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02839 {
02840 if (argc != 4)
02841 return RESULT_SHOWUSAGE;
02842
02843 if (!agi->speech) {
02844 ast_agi_send(agi->fd, chan, "200 result=0\n");
02845 return RESULT_SUCCESS;
02846 }
02847
02848 if (ast_speech_grammar_unload(agi->speech, argv[3]))
02849 ast_agi_send(agi->fd, chan, "200 result=0\n");
02850 else
02851 ast_agi_send(agi->fd, chan, "200 result=1\n");
02852
02853 return RESULT_SUCCESS;
02854 }
02855
02856 static int handle_speechactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02857 {
02858 if (argc != 4)
02859 return RESULT_SHOWUSAGE;
02860
02861 if (!agi->speech) {
02862 ast_agi_send(agi->fd, chan, "200 result=0\n");
02863 return RESULT_SUCCESS;
02864 }
02865
02866 if (ast_speech_grammar_activate(agi->speech, argv[3]))
02867 ast_agi_send(agi->fd, chan, "200 result=0\n");
02868 else
02869 ast_agi_send(agi->fd, chan, "200 result=1\n");
02870
02871 return RESULT_SUCCESS;
02872 }
02873
02874 static int handle_speechdeactivategrammar(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02875 {
02876 if (argc != 4)
02877 return RESULT_SHOWUSAGE;
02878
02879 if (!agi->speech) {
02880 ast_agi_send(agi->fd, chan, "200 result=0\n");
02881 return RESULT_SUCCESS;
02882 }
02883
02884 if (ast_speech_grammar_deactivate(agi->speech, argv[3]))
02885 ast_agi_send(agi->fd, chan, "200 result=0\n");
02886 else
02887 ast_agi_send(agi->fd, chan, "200 result=1\n");
02888
02889 return RESULT_SUCCESS;
02890 }
02891
02892 static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang, int offset)
02893 {
02894 struct ast_filestream *fs = NULL;
02895
02896 if (!(fs = ast_openstream(chan, filename, preflang)))
02897 return -1;
02898
02899 if (offset)
02900 ast_seekstream(fs, offset, SEEK_SET);
02901
02902 if (ast_applystream(chan, fs))
02903 return -1;
02904
02905 if (ast_playstream(fs))
02906 return -1;
02907
02908 return 0;
02909 }
02910
02911 static int handle_speechrecognize(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[])
02912 {
02913 struct ast_speech *speech = agi->speech;
02914 const char *prompt;
02915 char dtmf = 0, tmp[4096] = "", *buf = tmp;
02916 int timeout = 0, offset = 0, res = 0, i = 0;
02917 long current_offset = 0;
02918 const char *reason = NULL;
02919 struct ast_frame *fr = NULL;
02920 struct ast_speech_result *result = NULL;
02921 size_t left = sizeof(tmp);
02922 time_t start = 0, current;
02923
02924 if (argc < 4)
02925 return RESULT_SHOWUSAGE;
02926
02927 if (!speech) {
02928 ast_agi_send(agi->fd, chan, "200 result=0\n");
02929 return RESULT_SUCCESS;
02930 }
02931
02932 prompt = argv[2];
02933 timeout = atoi(argv[3]);
02934
02935
02936 if (argc == 5)
02937 offset = atoi(argv[4]);
02938
02939
02940 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
02941 ast_agi_send(agi->fd, chan, "200 result=0\n");
02942 return RESULT_SUCCESS;
02943 }
02944
02945
02946 if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
02947 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
02948 ast_speech_start(speech);
02949 }
02950
02951
02952 speech_streamfile(chan, prompt, chan->language, offset);
02953
02954
02955 while (ast_strlen_zero(reason)) {
02956
02957 ast_sched_runq(chan->sched);
02958
02959
02960 if ((res = ast_sched_wait(chan->sched)) < 0)
02961 res = 1000;
02962
02963
02964 if (ast_waitfor(chan, res) > 0) {
02965 if (!(fr = ast_read(chan))) {
02966 reason = "hangup";
02967 break;
02968 }
02969 }
02970
02971
02972 if ((timeout > 0) && (start > 0)) {
02973 time(¤t);
02974 if ((current - start) >= timeout) {
02975 reason = "timeout";
02976 if (fr)
02977 ast_frfree(fr);
02978 break;
02979 }
02980 }
02981
02982
02983 ast_mutex_lock(&speech->lock);
02984
02985
02986 if (ast_test_flag(speech, AST_SPEECH_QUIET) && chan->stream) {
02987 current_offset = ast_tellstream(chan->stream);
02988 ast_stopstream(chan);
02989 ast_clear_flag(speech, AST_SPEECH_QUIET);
02990 }
02991
02992
02993 switch (speech->state) {
02994 case AST_SPEECH_STATE_READY:
02995
02996 if ((timeout > 0) && start == 0 && ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL))) {
02997 ast_stopstream(chan);
02998 time(&start);
02999 }
03000
03001 if (fr && fr->frametype == AST_FRAME_VOICE)
03002 ast_speech_write(speech, fr->data.ptr, fr->datalen);
03003 break;
03004 case AST_SPEECH_STATE_WAIT:
03005
03006 if ((!chan->stream) || (chan->streamid == -1 && chan->timingfunc == NULL)) {
03007 ast_stopstream(chan);
03008
03009 if (!ast_strlen_zero(speech->processing_sound) && strcasecmp(speech->processing_sound, "none"))
03010 speech_streamfile(chan, speech->processing_sound, chan->language, 0);
03011 }
03012 break;
03013 case AST_SPEECH_STATE_DONE:
03014
03015 speech->results = ast_speech_results_get(speech);
03016
03017 ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
03018 reason = "speech";
03019 break;
03020 default:
03021 break;
03022 }
03023 ast_mutex_unlock(&speech->lock);
03024
03025
03026 if (fr) {
03027 if (fr->frametype == AST_FRAME_DTMF) {
03028 reason = "dtmf";
03029 dtmf = fr->subclass.integer;
03030 } else if (fr->frametype == AST_FRAME_CONTROL && fr->subclass.integer == AST_CONTROL_HANGUP) {
03031 reason = "hangup";
03032 }
03033 ast_frfree(fr);
03034 }
03035 }
03036
03037 if (!strcasecmp(reason, "speech")) {
03038
03039 for (result = speech->results; result; result = AST_LIST_NEXT(result, list)) {
03040
03041 ast_build_string(&buf, &left, "%sscore%d=%d text%d=\"%s\" grammar%d=%s", (i > 0 ? " " : ""), i, result->score, i, result->text, i, result->grammar);
03042
03043 i++;
03044 }
03045
03046 ast_agi_send(agi->fd, chan, "200 result=1 (speech) endpos=%ld results=%d %s\n", current_offset, i, tmp);
03047 } else if (!strcasecmp(reason, "dtmf")) {
03048 ast_agi_send(agi->fd, chan, "200 result=1 (digit) digit=%c endpos=%ld\n", dtmf, current_offset);
03049 } else if (!strcasecmp(reason, "hangup") || !strcasecmp(reason, "timeout")) {
03050 ast_agi_send(agi->fd, chan, "200 result=1 (%s) endpos=%ld\n", reason, current_offset);
03051 } else {
03052 ast_agi_send(agi->fd, chan, "200 result=0 endpos=%ld\n", current_offset);
03053 }
03054
03055 return RESULT_SUCCESS;
03056 }
03057
03058
03059
03060
03061 static struct agi_command commands[] = {
03062 { { "answer", NULL }, handle_answer, NULL, NULL, 0 },
03063 { { "asyncagi", "break", NULL }, handle_asyncagi_break, NULL, NULL, 1 },
03064 { { "channel", "status", NULL }, handle_channelstatus, NULL, NULL, 0 },
03065 { { "database", "del", NULL }, handle_dbdel, NULL, NULL, 1 },
03066 { { "database", "deltree", NULL }, handle_dbdeltree, NULL, NULL, 1 },
03067 { { "database", "get", NULL }, handle_dbget, NULL, NULL, 1 },
03068 { { "database", "put", NULL }, handle_dbput, NULL, NULL, 1 },
03069 { { "exec", NULL }, handle_exec, NULL, NULL, 1 },
03070 { { "get", "data", NULL }, handle_getdata, NULL, NULL, 0 },
03071 { { "get", "full", "variable", NULL }, handle_getvariablefull, NULL, NULL, 1 },
03072 { { "get", "option", NULL }, handle_getoption, NULL, NULL, 0 },
03073 { { "get", "variable", NULL }, handle_getvariable, NULL, NULL, 1 },
03074 { { "hangup", NULL }, handle_hangup, NULL, NULL, 0 },
03075 { { "noop", NULL }, handle_noop, NULL, NULL, 1 },
03076 { { "receive", "char", NULL }, handle_recvchar, NULL, NULL, 0 },
03077 { { "receive", "text", NULL }, handle_recvtext, NULL, NULL, 0 },
03078 { { "record", "file", NULL }, handle_recordfile, NULL, NULL, 0 },
03079 { { "say", "alpha", NULL }, handle_sayalpha, NULL, NULL, 0},
03080 { { "say", "digits", NULL }, handle_saydigits, NULL, NULL, 0 },
03081 { { "say", "number", NULL }, handle_saynumber, NULL, NULL, 0 },
03082 { { "say", "phonetic", NULL }, handle_sayphonetic, NULL, NULL, 0},
03083 { { "say", "date", NULL }, handle_saydate, NULL, NULL, 0},
03084 { { "say", "time", NULL }, handle_saytime, NULL, NULL, 0},
03085 { { "say", "datetime", NULL }, handle_saydatetime, NULL, NULL, 0},
03086 { { "send", "image", NULL }, handle_sendimage, NULL, NULL, 0},
03087 { { "send", "text", NULL }, handle_sendtext, NULL, NULL, 0},
03088 { { "set", "autohangup", NULL }, handle_autohangup, NULL, NULL, 0},
03089 { { "set", "callerid", NULL }, handle_setcallerid, NULL, NULL, 0},
03090 { { "set", "context", NULL }, handle_setcontext, NULL, NULL, 0},
03091 { { "set", "extension", NULL }, handle_setextension, NULL, NULL, 0},
03092 { { "set", "music", NULL }, handle_setmusic, NULL, NULL, 0 },
03093 { { "set", "priority", NULL }, handle_setpriority, NULL, NULL, 0 },
03094 { { "set", "variable", NULL }, handle_setvariable, NULL, NULL, 1 },
03095 { { "stream", "file", NULL }, handle_streamfile, NULL, NULL, 0 },
03096 { { "control", "stream", "file", NULL }, handle_controlstreamfile, NULL, NULL, 0 },
03097 { { "tdd", "mode", NULL }, handle_tddmode, NULL, NULL, 0 },
03098 { { "verbose", NULL }, handle_verbose, NULL, NULL, 1 },
03099 { { "wait", "for", "digit", NULL }, handle_waitfordigit, NULL, NULL, 0 },
03100 { { "speech", "create", NULL }, handle_speechcreate, NULL, NULL, 0 },
03101 { { "speech", "set", NULL }, handle_speechset, NULL, NULL, 0 },
03102 { { "speech", "destroy", NULL }, handle_speechdestroy, NULL, NULL, 1 },
03103 { { "speech", "load", "grammar", NULL }, handle_speechloadgrammar, NULL, NULL, 0 },
03104 { { "speech", "unload", "grammar", NULL }, handle_speechunloadgrammar, NULL, NULL, 1 },
03105 { { "speech", "activate", "grammar", NULL }, handle_speechactivategrammar, NULL, NULL, 0 },
03106 { { "speech", "deactivate", "grammar", NULL }, handle_speechdeactivategrammar, NULL, NULL, 0 },
03107 { { "speech", "recognize", NULL }, handle_speechrecognize, NULL, NULL, 0 },
03108 };
03109
03110 static AST_RWLIST_HEAD_STATIC(agi_commands, agi_command);
03111
03112 static char *help_workhorse(int fd, const char * const match[])
03113 {
03114 char fullcmd[MAX_CMD_LEN], matchstr[MAX_CMD_LEN];
03115 struct agi_command *e;
03116
03117 if (match)
03118 ast_join(matchstr, sizeof(matchstr), match);
03119
03120 ast_cli(fd, "%5.5s %30.30s %s\n","Dead","Command","Description");
03121 AST_RWLIST_RDLOCK(&agi_commands);
03122 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03123 if (!e->cmda[0])
03124 break;
03125
03126 if ((e->cmda[0])[0] == '_')
03127 continue;
03128 ast_join(fullcmd, sizeof(fullcmd), e->cmda);
03129 if (match && strncasecmp(matchstr, fullcmd, strlen(matchstr)))
03130 continue;
03131 ast_cli(fd, "%5.5s %30.30s %s\n", e->dead ? "Yes" : "No" , fullcmd, S_OR(e->summary, "Not available"));
03132 }
03133 AST_RWLIST_UNLOCK(&agi_commands);
03134
03135 return CLI_SUCCESS;
03136 }
03137
03138 int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command *cmd)
03139 {
03140 char fullcmd[MAX_CMD_LEN];
03141
03142 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03143
03144 if (!find_command(cmd->cmda, 1)) {
03145 *((enum ast_doc_src *) &cmd->docsrc) = AST_STATIC_DOC;
03146 if (ast_strlen_zero(cmd->summary) && ast_strlen_zero(cmd->usage)) {
03147 #ifdef AST_XML_DOCS
03148 *((char **) &cmd->summary) = ast_xmldoc_build_synopsis("agi", fullcmd, NULL);
03149 *((char **) &cmd->usage) = ast_xmldoc_build_description("agi", fullcmd, NULL);
03150 *((char **) &cmd->syntax) = ast_xmldoc_build_syntax("agi", fullcmd, NULL);
03151 *((char **) &cmd->seealso) = ast_xmldoc_build_seealso("agi", fullcmd, NULL);
03152 *((enum ast_doc_src *) &cmd->docsrc) = AST_XML_DOC;
03153 #endif
03154 #ifndef HAVE_NULLSAFE_PRINTF
03155 if (!cmd->summary) {
03156 *((char **) &cmd->summary) = ast_strdup("");
03157 }
03158 if (!cmd->usage) {
03159 *((char **) &cmd->usage) = ast_strdup("");
03160 }
03161 if (!cmd->syntax) {
03162 *((char **) &cmd->syntax) = ast_strdup("");
03163 }
03164 if (!cmd->seealso) {
03165 *((char **) &cmd->seealso) = ast_strdup("");
03166 }
03167 #endif
03168 }
03169
03170 cmd->mod = mod;
03171 AST_RWLIST_WRLOCK(&agi_commands);
03172 AST_LIST_INSERT_TAIL(&agi_commands, cmd, list);
03173 AST_RWLIST_UNLOCK(&agi_commands);
03174 if (mod != ast_module_info->self)
03175 ast_module_ref(ast_module_info->self);
03176 ast_verb(2, "AGI Command '%s' registered\n",fullcmd);
03177 return 1;
03178 } else {
03179 ast_log(LOG_WARNING, "Command already registered!\n");
03180 return 0;
03181 }
03182 }
03183
03184 int AST_OPTIONAL_API_NAME(ast_agi_unregister)(struct ast_module *mod, agi_command *cmd)
03185 {
03186 struct agi_command *e;
03187 int unregistered = 0;
03188 char fullcmd[MAX_CMD_LEN];
03189
03190 ast_join(fullcmd, sizeof(fullcmd), cmd->cmda);
03191
03192 AST_RWLIST_WRLOCK(&agi_commands);
03193 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&agi_commands, e, list) {
03194 if (cmd == e) {
03195 AST_RWLIST_REMOVE_CURRENT(list);
03196 if (mod != ast_module_info->self)
03197 ast_module_unref(ast_module_info->self);
03198 #ifdef AST_XML_DOCS
03199 if (e->docsrc == AST_XML_DOC) {
03200 ast_free((char *) e->summary);
03201 ast_free((char *) e->usage);
03202 ast_free((char *) e->syntax);
03203 ast_free((char *) e->seealso);
03204 *((char **) &e->summary) = NULL;
03205 *((char **) &e->usage) = NULL;
03206 *((char **) &e->syntax) = NULL;
03207 *((char **) &e->seealso) = NULL;
03208 }
03209 #endif
03210 unregistered=1;
03211 break;
03212 }
03213 }
03214 AST_RWLIST_TRAVERSE_SAFE_END;
03215 AST_RWLIST_UNLOCK(&agi_commands);
03216 if (unregistered)
03217 ast_verb(2, "AGI Command '%s' unregistered\n",fullcmd);
03218 else
03219 ast_log(LOG_WARNING, "Unable to unregister command: '%s'!\n",fullcmd);
03220 return unregistered;
03221 }
03222
03223 int AST_OPTIONAL_API_NAME(ast_agi_register_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
03224 {
03225 unsigned int i, x = 0;
03226
03227 for (i = 0; i < len; i++) {
03228 if (ast_agi_register(mod, cmd + i) == 1) {
03229 x++;
03230 continue;
03231 }
03232
03233
03234
03235
03236 for (; x > 0; x--) {
03237
03238
03239
03240
03241
03242
03243
03244
03245 (void) ast_agi_unregister(mod, cmd + x - 1);
03246 }
03247 return -1;
03248 }
03249
03250 return 0;
03251 }
03252
03253 int AST_OPTIONAL_API_NAME(ast_agi_unregister_multiple)(struct ast_module *mod, struct agi_command *cmd, unsigned int len)
03254 {
03255 unsigned int i;
03256 int res = 0;
03257
03258 for (i = 0; i < len; i++) {
03259
03260
03261
03262
03263 res |= ast_agi_unregister(mod, cmd + i);
03264 }
03265
03266 return res;
03267 }
03268
03269 static agi_command *find_command(const char * const cmds[], int exact)
03270 {
03271 int y, match;
03272 struct agi_command *e;
03273
03274 AST_RWLIST_RDLOCK(&agi_commands);
03275 AST_RWLIST_TRAVERSE(&agi_commands, e, list) {
03276 if (!e->cmda[0])
03277 break;
03278
03279 match = 1;
03280 for (y = 0; match && cmds[y]; y++) {
03281
03282
03283
03284 if (!e->cmda[y] && !exact)
03285 break;
03286
03287 if (!e->cmda[y]) {
03288 AST_RWLIST_UNLOCK(&agi_commands);
03289 return NULL;
03290 }
03291 if (strcasecmp(e->cmda[y], cmds[y]))
03292 match = 0;
03293 }
03294
03295
03296 if ((exact > -1) && e->cmda[y])
03297 match = 0;
03298 if (match) {
03299 AST_RWLIST_UNLOCK(&agi_commands);
03300 return e;
03301 }
03302 }
03303 AST_RWLIST_UNLOCK(&agi_commands);
03304 return NULL;
03305 }
03306
03307 static int parse_args(char *s, int *max, const char *argv[])
03308 {
03309 int x = 0, quoted = 0, escaped = 0, whitespace = 1;
03310 char *cur;
03311
03312 cur = s;
03313 while(*s) {
03314 switch(*s) {
03315 case '"':
03316
03317 if (escaped)
03318 goto normal;
03319 else
03320 quoted = !quoted;
03321 if (quoted && whitespace) {
03322
03323 argv[x++] = cur;
03324 whitespace=0;
03325 }
03326 escaped = 0;
03327 break;
03328 case ' ':
03329 case '\t':
03330 if (!quoted && !escaped) {
03331
03332
03333 whitespace = 1;
03334 *(cur++) = '\0';
03335 } else
03336
03337 goto normal;
03338 break;
03339 case '\\':
03340
03341 if (escaped) {
03342 goto normal;
03343 } else {
03344 escaped=1;
03345 }
03346 break;
03347 default:
03348 normal:
03349 if (whitespace) {
03350 if (x >= MAX_ARGS -1) {
03351 ast_log(LOG_WARNING, "Too many arguments, truncating\n");
03352 break;
03353 }
03354
03355 argv[x++] = cur;
03356 whitespace=0;
03357 }
03358 *(cur++) = *s;
03359 escaped=0;
03360 }
03361 s++;
03362 }
03363
03364 *(cur++) = '\0';
03365 argv[x] = NULL;
03366 *max = x;
03367 return 0;
03368 }
03369
03370 static enum agi_result agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf, int dead)
03371 {
03372 const char *argv[MAX_ARGS];
03373 int argc = MAX_ARGS;
03374 int res;
03375 agi_command *c;
03376 const char *ami_res;
03377 char *ami_cmd = ast_strdupa(buf);
03378 int command_id = ast_random();
03379 int resultcode;
03380
03381 manager_event(EVENT_FLAG_AGI, "AGIExec",
03382 "SubEvent: Start\r\n"
03383 "Channel: %s\r\n"
03384 "CommandId: %d\r\n"
03385 "Command: %s\r\n", chan->name, command_id, ami_cmd);
03386 parse_args(buf, &argc, argv);
03387 c = find_command(argv, 0);
03388 if (c && (!dead || (dead && c->dead))) {
03389
03390
03391 if (c->mod != ast_module_info->self)
03392 ast_module_ref(c->mod);
03393
03394
03395 if (chan->cdr && !ast_check_hangup(chan) && strcasecmp(argv[0], "EXEC"))
03396 ast_cdr_setapp(chan->cdr, "AGI", buf);
03397
03398 res = c->handler(chan, agi, argc, argv);
03399 if (c->mod != ast_module_info->self)
03400 ast_module_unref(c->mod);
03401 switch (res) {
03402 case RESULT_SHOWUSAGE:
03403 ami_res = "Usage";
03404 resultcode = 520;
03405 break;
03406 case RESULT_FAILURE:
03407 ami_res = "Failure";
03408 resultcode = -1;
03409 break;
03410 case ASYNC_AGI_BREAK:
03411 case RESULT_SUCCESS:
03412 ami_res = "Success";
03413 resultcode = 200;
03414 break;
03415 default:
03416 ami_res = "Unknown Result";
03417 resultcode = 200;
03418 break;
03419 }
03420 manager_event(EVENT_FLAG_AGI, "AGIExec",
03421 "SubEvent: End\r\n"
03422 "Channel: %s\r\n"
03423 "CommandId: %d\r\n"
03424 "Command: %s\r\n"
03425 "ResultCode: %d\r\n"
03426 "Result: %s\r\n", chan->name, command_id, ami_cmd, resultcode, ami_res);
03427 switch (res) {
03428 case RESULT_SHOWUSAGE:
03429 if (ast_strlen_zero(c->usage)) {
03430 ast_agi_send(agi->fd, chan, "520 Invalid command syntax. Proper usage not available.\n");
03431 } else {
03432 ast_agi_send(agi->fd, chan, "520-Invalid command syntax. Proper usage follows:\n");
03433 ast_agi_send(agi->fd, chan, "%s", c->usage);
03434 ast_agi_send(agi->fd, chan, "520 End of proper usage.\n");
03435 }
03436 break;
03437 case ASYNC_AGI_BREAK:
03438 return AGI_RESULT_SUCCESS_ASYNC;
03439 case RESULT_FAILURE:
03440
03441 return AGI_RESULT_FAILURE;
03442 default:
03443 break;
03444 }
03445 } else if (c) {
03446 ast_agi_send(agi->fd, chan, "511 Command Not Permitted on a dead channel\n");
03447 manager_event(EVENT_FLAG_AGI, "AGIExec",
03448 "SubEvent: End\r\n"
03449 "Channel: %s\r\n"
03450 "CommandId: %d\r\n"
03451 "Command: %s\r\n"
03452 "ResultCode: 511\r\n"
03453 "Result: Command not permitted on a dead channel\r\n", chan->name, command_id, ami_cmd);
03454 } else {
03455 ast_agi_send(agi->fd, chan, "510 Invalid or unknown command\n");
03456 manager_event(EVENT_FLAG_AGI, "AGIExec",
03457 "SubEvent: End\r\n"
03458 "Channel: %s\r\n"
03459 "CommandId: %d\r\n"
03460 "Command: %s\r\n"
03461 "ResultCode: 510\r\n"
03462 "Result: Invalid or unknown command\r\n", chan->name, command_id, ami_cmd);
03463 }
03464 return AGI_RESULT_SUCCESS;
03465 }
03466 static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead, int argc, char *argv[])
03467 {
03468 struct ast_channel *c;
03469 int outfd;
03470 int ms;
03471 int needhup = 0;
03472 enum agi_result returnstatus = AGI_RESULT_SUCCESS;
03473 struct ast_frame *f;
03474 char buf[AGI_BUF_LEN];
03475 char *res = NULL;
03476 FILE *readf;
03477
03478
03479 int retry = AGI_NANDFS_RETRY;
03480 int send_sighup;
03481 const char *sighup_str;
03482 char *tmpdata, *var;
03483 struct ast_variable_list *cur;
03484
03485 ast_channel_lock(chan);
03486 sighup_str = pbx_builtin_getvar_helper(chan, "AGISIGHUP");
03487 send_sighup = ast_strlen_zero(sighup_str) || !ast_false(sighup_str);
03488 ast_channel_unlock(chan);
03489
03490 if (!(readf = fdopen(agi->ctrl, "r"))) {
03491 ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
03492 if (send_sighup && pid > -1)
03493 kill(pid, SIGHUP);
03494 close(agi->ctrl);
03495 return AGI_RESULT_FAILURE;
03496 }
03497
03498 setlinebuf(readf);
03499 setup_env(chan, request, agi->fd, (agi->audio > -1), argc, argv);
03500 for (;;) {
03501 if (needhup) {
03502 needhup = 0;
03503 dead = 1;
03504 if (send_sighup) {
03505 if (pid > -1) {
03506 kill(pid, SIGHUP);
03507 } else if (agi->fast) {
03508 ast_agi_send(agi->fd, chan, "HANGUP\n");
03509 }
03510 }
03511 }
03512 ms = -1;
03513 if (dead) {
03514 c = ast_waitfor_nandfds(&chan, 0, &agi->ctrl, 1, NULL, &outfd, &ms);
03515 } else if (!ast_check_hangup(chan)) {
03516 c = ast_waitfor_nandfds(&chan, 1, &agi->ctrl, 1, NULL, &outfd, &ms);
03517 } else {
03518
03519
03520
03521
03522 c = chan;
03523 }
03524 if (c) {
03525 retry = AGI_NANDFS_RETRY;
03526
03527 f = ast_read(c);
03528 if (!f) {
03529 ast_debug(1, "%s hungup\n", chan->name);
03530 needhup = 1;
03531 if (!returnstatus) {
03532 returnstatus = AGI_RESULT_HANGUP;
03533 }
03534 } else {
03535
03536 if ((agi->audio > -1) && (f->frametype == AST_FRAME_VOICE)) {
03537
03538 if (write(agi->audio, f->data.ptr, f->datalen) < 0) {
03539 }
03540 }
03541 ast_frfree(f);
03542 }
03543 } else if (outfd > -1) {
03544 size_t len = sizeof(buf);
03545 size_t buflen = 0;
03546 enum agi_result cmd_status;
03547
03548 retry = AGI_NANDFS_RETRY;
03549 buf[0] = '\0';
03550
03551 while (len > 1) {
03552 res = fgets(buf + buflen, len, readf);
03553 if (feof(readf))
03554 break;
03555 if (ferror(readf) && ((errno != EINTR) && (errno != EAGAIN)))
03556 break;
03557 if (res != NULL && !agi->fast)
03558 break;
03559 buflen = strlen(buf);
03560 if (buflen && buf[buflen - 1] == '\n')
03561 break;
03562 len = sizeof(buf) - buflen;
03563 if (agidebug)
03564 ast_verbose("AGI Rx << temp buffer %s - errno %s\nNo \\n received, checking again.\n", buf, strerror(errno));
03565 }
03566
03567 if (!buf[0]) {
03568
03569 if (VERBOSITY_ATLEAST(3)) {
03570 tmpdata = ast_strdupa(request);
03571 char findstr[128];
03572 AST_LIST_TRAVERSE(&agimaskvars, cur, list) {
03573 ast_copy_string(findstr, cur->variable, sizeof(findstr));
03574 strncat(findstr, "=", sizeof(findstr));
03575 var = strstr(tmpdata, findstr);
03576 if (var)
03577 mask_string(var, agimaskvarini, agimaskvarend, 1);
03578 }
03579 ast_verb(3, "<%s>AGI Script %s completed, returning %d\n", chan->name, tmpdata, returnstatus);
03580 }
03581 if (pid > 0)
03582 waitpid(pid, status, 0);
03583
03584 pid = -1;
03585 break;
03586 }
03587
03588
03589 if (*buf && strncasecmp(buf, "failure", 7) == 0) {
03590 returnstatus = AGI_RESULT_FAILURE;
03591 break;
03592 }
03593
03594
03595 buflen = strlen(buf);
03596 if (buflen && buf[buflen - 1] == '\n') {
03597 buf[buflen - 1] = '\0';
03598 }
03599
03600 if (agidebug)
03601 ast_verbose("<%s>AGI Rx << %s\n", chan->name, buf);
03602 cmd_status = agi_handle_command(chan, agi, buf, dead);
03603 switch (cmd_status) {
03604 case AGI_RESULT_FAILURE:
03605 if (dead || !ast_check_hangup(chan)) {
03606
03607 returnstatus = AGI_RESULT_FAILURE;
03608 }
03609 break;
03610 default:
03611 break;
03612 }
03613 } else {
03614 if (--retry <= 0) {
03615 ast_log(LOG_WARNING, "No channel, no fd?\n");
03616 returnstatus = AGI_RESULT_FAILURE;
03617 break;
03618 }
03619 }
03620 }
03621 if (agi->speech) {
03622 ast_speech_destroy(agi->speech);
03623 }
03624
03625 if (send_sighup) {
03626 if (pid > -1) {
03627 if (kill(pid, SIGHUP)) {
03628 ast_log(LOG_WARNING, "unable to send SIGHUP to AGI process %d: %s\n", pid, strerror(errno));
03629 } else {
03630 usleep(1);
03631 }
03632 waitpid(pid, status, WNOHANG);
03633 } else if (agi->fast) {
03634 ast_agi_send(agi->fd, chan, "HANGUP\n");
03635 }
03636 }
03637 fclose(readf);
03638 return returnstatus;
03639 }
03640
03641 static char *handle_cli_agi_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03642 {
03643 struct agi_command *command;
03644 char fullcmd[MAX_CMD_LEN];
03645 int error = 0;
03646
03647 switch (cmd) {
03648 case CLI_INIT:
03649 e->command = "agi show commands [topic]";
03650 e->usage =
03651 "Usage: agi show commands [topic] <topic>\n"
03652 " When called with a topic as an argument, displays usage\n"
03653 " information on the given command. If called without a\n"
03654 " topic, it provides a list of AGI commands.\n";
03655 return NULL;
03656 case CLI_GENERATE:
03657 return NULL;
03658 }
03659 if (a->argc < e->args - 1 || (a->argc >= e->args && strcasecmp(a->argv[e->args - 1], "topic")))
03660 return CLI_SHOWUSAGE;
03661 if (a->argc > e->args - 1) {
03662 command = find_command(a->argv + e->args, 1);
03663 if (command) {
03664 char *synopsis = NULL, *description = NULL, *syntax = NULL, *seealso = NULL;
03665 char info[30 + MAX_CMD_LEN];
03666 char infotitle[30 + MAX_CMD_LEN + AST_TERM_MAX_ESCAPE_CHARS];
03667 char syntitle[11 + AST_TERM_MAX_ESCAPE_CHARS];
03668 char desctitle[15 + AST_TERM_MAX_ESCAPE_CHARS];
03669 char deadtitle[13 + AST_TERM_MAX_ESCAPE_CHARS];
03670 char deadcontent[3 + AST_TERM_MAX_ESCAPE_CHARS];
03671 char seealsotitle[12 + AST_TERM_MAX_ESCAPE_CHARS];
03672 char stxtitle[10 + AST_TERM_MAX_ESCAPE_CHARS];
03673 size_t synlen, desclen, seealsolen, stxlen;
03674
03675 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, sizeof(syntitle));
03676 term_color(desctitle, "[Description]\n", COLOR_MAGENTA, 0, sizeof(desctitle));
03677 term_color(deadtitle, "[Runs Dead]\n", COLOR_MAGENTA, 0, sizeof(deadtitle));
03678 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, sizeof(seealsotitle));
03679 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, sizeof(stxtitle));
03680 term_color(deadcontent, command->dead ? "Yes" : "No", COLOR_CYAN, 0, sizeof(deadcontent));
03681
03682 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03683 snprintf(info, sizeof(info), "\n -= Info about agi '%s' =- ", fullcmd);
03684 term_color(infotitle, info, COLOR_CYAN, 0, sizeof(infotitle));
03685 #ifdef AST_XML_DOCS
03686 if (command->docsrc == AST_XML_DOC) {
03687 synopsis = ast_xmldoc_printable(S_OR(command->summary, "Not available"), 1);
03688 description = ast_xmldoc_printable(S_OR(command->usage, "Not available"), 1);
03689 seealso = ast_xmldoc_printable(S_OR(command->seealso, "Not available"), 1);
03690 if (!seealso || !description || !synopsis) {
03691 error = 1;
03692 goto return_cleanup;
03693 }
03694 } else
03695 #endif
03696 {
03697 synlen = strlen(S_OR(command->summary, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03698 synopsis = ast_malloc(synlen);
03699
03700 desclen = strlen(S_OR(command->usage, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03701 description = ast_malloc(desclen);
03702
03703 seealsolen = strlen(S_OR(command->seealso, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03704 seealso = ast_malloc(seealsolen);
03705
03706 if (!synopsis || !description || !seealso) {
03707 error = 1;
03708 goto return_cleanup;
03709 }
03710 term_color(synopsis, S_OR(command->summary, "Not available"), COLOR_CYAN, 0, synlen);
03711 term_color(description, S_OR(command->usage, "Not available"), COLOR_CYAN, 0, desclen);
03712 term_color(seealso, S_OR(command->seealso, "Not available"), COLOR_CYAN, 0, seealsolen);
03713 }
03714
03715 stxlen = strlen(S_OR(command->syntax, "Not available")) + AST_TERM_MAX_ESCAPE_CHARS;
03716 syntax = ast_malloc(stxlen);
03717 if (!syntax) {
03718 error = 1;
03719 goto return_cleanup;
03720 }
03721 term_color(syntax, S_OR(command->syntax, "Not available"), COLOR_CYAN, 0, stxlen);
03722
03723 ast_cli(a->fd, "%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n", infotitle, stxtitle, syntax,
03724 desctitle, description, syntitle, synopsis, deadtitle, deadcontent,
03725 seealsotitle, seealso);
03726 return_cleanup:
03727 ast_free(synopsis);
03728 ast_free(description);
03729 ast_free(syntax);
03730 ast_free(seealso);
03731 } else {
03732 if (find_command(a->argv + e->args, -1)) {
03733 return help_workhorse(a->fd, a->argv + e->args);
03734 } else {
03735 ast_join(fullcmd, sizeof(fullcmd), a->argv + e->args);
03736 ast_cli(a->fd, "No such command '%s'.\n", fullcmd);
03737 }
03738 }
03739 } else {
03740 return help_workhorse(a->fd, NULL);
03741 }
03742 return (error ? CLI_FAILURE : CLI_SUCCESS);
03743 }
03744
03745
03746
03747
03748 static void write_html_escaped(FILE *htmlfile, char *str)
03749 {
03750 char *cur = str;
03751
03752 while(*cur) {
03753 switch (*cur) {
03754 case '<':
03755 fprintf(htmlfile, "%s", "<");
03756 break;
03757 case '>':
03758 fprintf(htmlfile, "%s", ">");
03759 break;
03760 case '&':
03761 fprintf(htmlfile, "%s", "&");
03762 break;
03763 case '"':
03764 fprintf(htmlfile, "%s", """);
03765 break;
03766 default:
03767 fprintf(htmlfile, "%c", *cur);
03768 break;
03769 }
03770 cur++;
03771 }
03772
03773 return;
03774 }
03775
03776 static int write_htmldump(const char *filename)
03777 {
03778 struct agi_command *command;
03779 char fullcmd[MAX_CMD_LEN];
03780 FILE *htmlfile;
03781
03782 if (!(htmlfile = fopen(filename, "wt")))
03783 return -1;
03784
03785 fprintf(htmlfile, "<HTML>\n<HEAD>\n<TITLE>AGI Commands</TITLE>\n</HEAD>\n");
03786 fprintf(htmlfile, "<BODY>\n<CENTER><B><H1>AGI Commands</H1></B></CENTER>\n\n");
03787 fprintf(htmlfile, "<TABLE BORDER=\"0\" CELLSPACING=\"10\">\n");
03788
03789 AST_RWLIST_RDLOCK(&agi_commands);
03790 AST_RWLIST_TRAVERSE(&agi_commands, command, list) {
03791 char *tempstr, *stringp;
03792
03793 if (!command->cmda[0])
03794 break;
03795
03796 if ((command->cmda[0])[0] == '_')
03797 continue;
03798 ast_join(fullcmd, sizeof(fullcmd), command->cmda);
03799
03800 fprintf(htmlfile, "<TR><TD><TABLE BORDER=\"1\" CELLPADDING=\"5\" WIDTH=\"100%%\">\n");
03801 fprintf(htmlfile, "<TR><TH ALIGN=\"CENTER\"><B>%s - %s</B></TH></TR>\n", fullcmd, command->summary);
03802 #ifdef AST_XML_DOCS
03803 stringp = ast_xmldoc_printable(command->usage, 0);
03804 #else
03805 stringp = ast_strdup(command->usage);
03806 #endif
03807 tempstr = strsep(&stringp, "\n");
03808
03809 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">");
03810 write_html_escaped(htmlfile, tempstr);
03811 fprintf(htmlfile, "</TD></TR>\n");
03812 fprintf(htmlfile, "<TR><TD ALIGN=\"CENTER\">\n");
03813
03814 while ((tempstr = strsep(&stringp, "\n")) != NULL) {
03815 write_html_escaped(htmlfile, tempstr);
03816 fprintf(htmlfile, "<BR>\n");
03817 }
03818 fprintf(htmlfile, "</TD></TR>\n");
03819 fprintf(htmlfile, "</TABLE></TD></TR>\n\n");
03820 ast_free(stringp);
03821 }
03822 AST_RWLIST_UNLOCK(&agi_commands);
03823 fprintf(htmlfile, "</TABLE>\n</BODY>\n</HTML>\n");
03824 fclose(htmlfile);
03825 return 0;
03826 }
03827
03828 static char *handle_cli_agi_dump_html(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03829 {
03830 switch (cmd) {
03831 case CLI_INIT:
03832 e->command = "agi dump html";
03833 e->usage =
03834 "Usage: agi dump html <filename>\n"
03835 " Dumps the AGI command list in HTML format to the given\n"
03836 " file.\n";
03837 return NULL;
03838 case CLI_GENERATE:
03839 return NULL;
03840 }
03841 if (a->argc != e->args + 1)
03842 return CLI_SHOWUSAGE;
03843
03844 if (write_htmldump(a->argv[e->args]) < 0) {
03845 ast_cli(a->fd, "Could not create file '%s'\n", a->argv[e->args]);
03846 return CLI_SHOWUSAGE;
03847 }
03848 ast_cli(a->fd, "AGI HTML commands dumped to: %s\n", a->argv[e->args]);
03849 return CLI_SUCCESS;
03850 }
03851
03852 static int agi_exec_full(struct ast_channel *chan, const char *data, int enhanced, int dead)
03853 {
03854 enum agi_result res;
03855 char *buf;
03856 int fds[2], efd = -1, pid = -1;
03857 AST_DECLARE_APP_ARGS(args,
03858 AST_APP_ARG(arg)[MAX_ARGS];
03859 );
03860 AGI agi;
03861
03862 if (ast_strlen_zero(data)) {
03863 ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
03864 return -1;
03865 }
03866 if (dead)
03867 ast_debug(3, "Hungup channel detected, running agi in dead mode.\n");
03868 memset(&agi, 0, sizeof(agi));
03869 buf = ast_strdupa(data);
03870 AST_STANDARD_APP_ARGS(args, buf);
03871 args.argv[args.argc] = NULL;
03872 #if 0
03873
03874 if (chan->_state != AST_STATE_UP) {
03875 if (ast_answer(chan))
03876 return -1;
03877 }
03878 #endif
03879 res = launch_script(chan, args.argv[0], args.argv, fds, enhanced ? &efd : NULL, &pid);
03880
03881
03882 if (res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) {
03883 int status = 0;
03884 agi.fd = fds[1];
03885 agi.ctrl = fds[0];
03886 agi.audio = efd;
03887 agi.fast = (res == AGI_RESULT_SUCCESS_FAST) ? 1 : 0;
03888 res = run_agi(chan, args.argv[0], &agi, pid, &status, dead, args.argc, args.argv);
03889
03890 if ((res == AGI_RESULT_SUCCESS || res == AGI_RESULT_SUCCESS_FAST) && status)
03891 res = AGI_RESULT_FAILURE;
03892 if (fds[1] != fds[0])
03893 close(fds[1]);
03894 if (efd > -1)
03895 close(efd);
03896 }
03897 ast_safe_fork_cleanup();
03898
03899 switch (res) {
03900 case AGI_RESULT_SUCCESS:
03901 case AGI_RESULT_SUCCESS_FAST:
03902 case AGI_RESULT_SUCCESS_ASYNC:
03903 pbx_builtin_setvar_helper(chan, "AGISTATUS", "SUCCESS");
03904 break;
03905 case AGI_RESULT_FAILURE:
03906 pbx_builtin_setvar_helper(chan, "AGISTATUS", "FAILURE");
03907 break;
03908 case AGI_RESULT_NOTFOUND:
03909 pbx_builtin_setvar_helper(chan, "AGISTATUS", "NOTFOUND");
03910 break;
03911 case AGI_RESULT_HANGUP:
03912 pbx_builtin_setvar_helper(chan, "AGISTATUS", "HANGUP");
03913 return -1;
03914 }
03915
03916 return 0;
03917 }
03918
03919 static int agi_exec(struct ast_channel *chan, const char *data)
03920 {
03921 if (!ast_check_hangup(chan))
03922 return agi_exec_full(chan, data, 0, 0);
03923 else
03924 return agi_exec_full(chan, data, 0, 1);
03925 }
03926
03927 static int eagi_exec(struct ast_channel *chan, const char *data)
03928 {
03929 int readformat, res;
03930
03931 if (ast_check_hangup(chan)) {
03932 ast_log(LOG_ERROR, "EAGI cannot be run on a dead/hungup channel, please use AGI.\n");
03933 return 0;
03934 }
03935 readformat = chan->readformat;
03936 if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
03937 ast_log(LOG_WARNING, "Unable to set channel '%s' to linear mode\n", chan->name);
03938 return -1;
03939 }
03940 res = agi_exec_full(chan, data, 1, 0);
03941 if (!res) {
03942 if (ast_set_read_format(chan, readformat)) {
03943 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(readformat));
03944 }
03945 }
03946 return res;
03947 }
03948
03949 static int deadagi_exec(struct ast_channel *chan, const char *data)
03950 {
03951 ast_log(LOG_WARNING, "DeadAGI has been deprecated, please use AGI in all cases!\n");
03952 return agi_exec(chan, data);
03953 }
03954
03955 static struct ast_cli_entry cli_agi[] = {
03956 AST_CLI_DEFINE(handle_cli_agi_add_cmd, "Add AGI command to a channel in Async AGI"),
03957 AST_CLI_DEFINE(handle_cli_agi_debug, "Enable/Disable AGI debugging"),
03958 AST_CLI_DEFINE(handle_cli_agi_show, "List AGI commands or specific help"),
03959 AST_CLI_DEFINE(handle_cli_agi_dump_html, "Dumps a list of AGI commands in HTML format")
03960 };
03961
03962 #ifdef TEST_FRAMEWORK
03963 AST_TEST_DEFINE(test_agi_null_docs)
03964 {
03965 int res = AST_TEST_PASS;
03966 struct agi_command noop_command =
03967 { { "testnoop", NULL }, handle_noop, NULL, NULL, 0 };
03968
03969 switch (cmd) {
03970 case TEST_INIT:
03971 info->name = "null_agi_docs";
03972 info->category = "/res/agi/";
03973 info->summary = "AGI command with no documentation";
03974 info->description = "Test whether an AGI command with no documentation will crash Asterisk";
03975 return AST_TEST_NOT_RUN;
03976 case TEST_EXECUTE:
03977 break;
03978 }
03979
03980 if (ast_agi_register(ast_module_info->self, &noop_command) == 0) {
03981 ast_test_status_update(test, "Unable to register testnoop command, because res_agi is not loaded.\n");
03982 return AST_TEST_NOT_RUN;
03983 }
03984
03985 #ifndef HAVE_NULLSAFE_PRINTF
03986
03987 if (noop_command.usage == NULL) {
03988 ast_test_status_update(test, "AGI testnoop usage was not updated properly.\n");
03989 res = AST_TEST_FAIL;
03990 }
03991 if (noop_command.syntax == NULL) {
03992 ast_test_status_update(test, "AGI testnoop syntax was not updated properly.\n");
03993 res = AST_TEST_FAIL;
03994 }
03995 #endif
03996
03997 ast_agi_unregister(ast_module_info->self, &noop_command);
03998 return res;
03999 }
04000 #endif
04001
04002 static int unload_module(void)
04003 {
04004 ast_cli_unregister_multiple(cli_agi, ARRAY_LEN(cli_agi));
04005
04006
04007
04008 (void) ast_agi_unregister_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
04009 ast_unregister_application(eapp);
04010 ast_unregister_application(deadapp);
04011 ast_manager_unregister("AGI");
04012 AST_TEST_UNREGISTER(test_agi_null_docs);
04013 return ast_unregister_application(app);
04014 }
04015
04016 static int load_module(void)
04017 {
04018 ast_cli_register_multiple(cli_agi, ARRAY_LEN(cli_agi));
04019
04020
04021
04022 (void) ast_agi_register_multiple(ast_module_info->self, commands, ARRAY_LEN(commands));
04023 ast_register_application_xml(deadapp, deadagi_exec);
04024 ast_register_application_xml(eapp, eagi_exec);
04025 ast_manager_register_xml("AGI", EVENT_FLAG_AGI, action_add_agi_cmd);
04026 AST_TEST_REGISTER(test_agi_null_docs);
04027 return ast_register_application_xml(app, agi_exec);
04028 }
04029
04030 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Asterisk Gateway Interface (AGI)",
04031 .load = load_module,
04032 .unload = unload_module,
04033 .load_pri = AST_MODPRI_APP_DEPEND,
04034 );