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