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