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