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