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