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