aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trunk/.cleancount1
-rw-r--r--trunk/BUGS22
-rw-r--r--trunk/CHANGES496
-rw-r--r--trunk/COPYING341
-rw-r--r--trunk/CREDITS244
-rw-r--r--trunk/LICENSE69
-rw-r--r--trunk/Makefile834
-rw-r--r--trunk/Makefile.moddir_rules166
-rw-r--r--trunk/Makefile.rules98
-rw-r--r--trunk/README262
-rw-r--r--trunk/UPGRADE.txt163
-rw-r--r--trunk/acinclude.m41106
-rw-r--r--trunk/agi/DialAnMp3.agi82
-rw-r--r--trunk/agi/Makefile52
-rw-r--r--trunk/agi/agi-test.agi79
-rw-r--r--trunk/agi/eagi-sphinx-test.c231
-rw-r--r--trunk/agi/eagi-test.c165
-rw-r--r--trunk/agi/fastagi-test94
-rwxr-xr-xtrunk/agi/jukebox.agi488
-rw-r--r--trunk/agi/numeralize44
-rw-r--r--trunk/apps/Makefile41
-rw-r--r--trunk/apps/app_adsiprog.c1581
-rw-r--r--trunk/apps/app_alarmreceiver.c813
-rw-r--r--trunk/apps/app_amd.c418
-rw-r--r--trunk/apps/app_authenticate.c212
-rw-r--r--trunk/apps/app_cdr.c63
-rw-r--r--trunk/apps/app_chanisavail.c157
-rw-r--r--trunk/apps/app_channelredirect.c93
-rw-r--r--trunk/apps/app_chanspy.c730
-rw-r--r--trunk/apps/app_controlplayback.c168
-rw-r--r--trunk/apps/app_db.c139
-rw-r--r--trunk/apps/app_dial.c2047
-rw-r--r--trunk/apps/app_dictate.c338
-rw-r--r--trunk/apps/app_directed_pickup.c172
-rw-r--r--trunk/apps/app_directory.c842
-rw-r--r--trunk/apps/app_disa.c367
-rw-r--r--trunk/apps/app_dumpchan.c160
-rw-r--r--trunk/apps/app_echo.c86
-rw-r--r--trunk/apps/app_exec.c221
-rw-r--r--trunk/apps/app_externalivr.c575
-rw-r--r--trunk/apps/app_festival.c523
-rw-r--r--trunk/apps/app_flash.c112
-rw-r--r--trunk/apps/app_followme.c1059
-rw-r--r--trunk/apps/app_forkcdr.c99
-rw-r--r--trunk/apps/app_getcpeid.c130
-rw-r--r--trunk/apps/app_ices.c205
-rw-r--r--trunk/apps/app_image.c80
-rw-r--r--trunk/apps/app_ivrdemo.c115
-rw-r--r--trunk/apps/app_jack.c971
-rw-r--r--trunk/apps/app_macro.c527
-rw-r--r--trunk/apps/app_meetme.c5592
-rw-r--r--trunk/apps/app_milliwatt.c134
-rw-r--r--trunk/apps/app_minivm.c3109
-rw-r--r--trunk/apps/app_mixmonitor.c424
-rw-r--r--trunk/apps/app_morsecode.c161
-rw-r--r--trunk/apps/app_mp3.c235
-rw-r--r--trunk/apps/app_nbscat.c218
-rw-r--r--trunk/apps/app_osplookup.c2041
-rw-r--r--trunk/apps/app_page.c193
-rw-r--r--trunk/apps/app_parkandannounce.c183
-rw-r--r--trunk/apps/app_pickupchan.c174
-rw-r--r--trunk/apps/app_playback.c524
-rw-r--r--trunk/apps/app_privacy.c173
-rw-r--r--trunk/apps/app_queue.c6153
-rw-r--r--trunk/apps/app_read.c231
-rw-r--r--trunk/apps/app_readexten.c258
-rw-r--r--trunk/apps/app_readfile.c107
-rw-r--r--trunk/apps/app_record.c365
-rw-r--r--trunk/apps/app_rpt.c7482
-rw-r--r--trunk/apps/app_sayunixtime.c112
-rw-r--r--trunk/apps/app_senddtmf.c127
-rw-r--r--trunk/apps/app_sendtext.c100
-rw-r--r--trunk/apps/app_setcallerid.c93
-rw-r--r--trunk/apps/app_skel.c125
-rw-r--r--trunk/apps/app_sms.c1932
-rw-r--r--trunk/apps/app_softhangup.c120
-rw-r--r--trunk/apps/app_speech_utils.c796
-rw-r--r--trunk/apps/app_stack.c416
-rw-r--r--trunk/apps/app_system.c129
-rw-r--r--trunk/apps/app_talkdetect.c211
-rw-r--r--trunk/apps/app_test.c467
-rw-r--r--trunk/apps/app_transfer.c125
-rw-r--r--trunk/apps/app_url.c149
-rw-r--r--trunk/apps/app_userevent.c89
-rw-r--r--trunk/apps/app_verbose.c158
-rw-r--r--trunk/apps/app_voicemail.c9831
-rw-r--r--trunk/apps/app_waitforring.c117
-rw-r--r--trunk/apps/app_waitforsilence.c189
-rw-r--r--trunk/apps/app_waituntil.c93
-rw-r--r--trunk/apps/app_while.c307
-rw-r--r--trunk/apps/app_zapateller.c113
-rw-r--r--trunk/apps/app_zapbarge.c299
-rw-r--r--trunk/apps/app_zapras.c238
-rw-r--r--trunk/apps/app_zapscan.c363
-rw-r--r--trunk/apps/enter.h287
-rw-r--r--trunk/apps/leave.h207
-rw-r--r--trunk/apps/rpt_flow.pdfbin0 -> 51935 bytes
-rwxr-xr-xtrunk/bootstrap.sh48
-rw-r--r--trunk/build_tools/cflags.xml62
-rw-r--r--trunk/build_tools/embed_modules.xml26
-rw-r--r--trunk/build_tools/get_makeopts3
-rw-r--r--trunk/build_tools/get_moduleinfo3
-rwxr-xr-xtrunk/build_tools/make_build_h20
-rwxr-xr-xtrunk/build_tools/make_buildopts_h37
-rwxr-xr-xtrunk/build_tools/make_defaults_h28
-rwxr-xr-xtrunk/build_tools/make_linker_eo_script27
-rwxr-xr-xtrunk/build_tools/make_sample_voicemail25
-rwxr-xr-xtrunk/build_tools/make_version66
-rwxr-xr-xtrunk/build_tools/make_version_c33
-rw-r--r--trunk/build_tools/menuselect-deps.in47
-rwxr-xr-xtrunk/build_tools/mkpkgconfig50
-rwxr-xr-xtrunk/build_tools/prep_tarball13
-rwxr-xr-xtrunk/build_tools/strip_nonapi29
-rw-r--r--trunk/cdr/Makefile20
-rw-r--r--trunk/cdr/cdr_adaptive_odbc.c674
-rw-r--r--trunk/cdr/cdr_csv.c346
-rw-r--r--trunk/cdr/cdr_custom.c169
-rw-r--r--trunk/cdr/cdr_manager.c204
-rw-r--r--trunk/cdr/cdr_odbc.c264
-rw-r--r--trunk/cdr/cdr_pgsql.c335
-rw-r--r--trunk/cdr/cdr_radius.c260
-rw-r--r--trunk/cdr/cdr_sqlite.c214
-rw-r--r--trunk/cdr/cdr_sqlite3_custom.c357
-rw-r--r--trunk/cdr/cdr_tds.c531
-rw-r--r--trunk/channels/DialTone.h257
-rw-r--r--trunk/channels/Makefile105
-rw-r--r--trunk/channels/chan_agent.c2399
-rw-r--r--trunk/channels/chan_alsa.c925
-rw-r--r--trunk/channels/chan_console.c1103
-rw-r--r--trunk/channels/chan_features.c570
-rw-r--r--trunk/channels/chan_gtalk.c1956
-rw-r--r--trunk/channels/chan_h323.c3353
-rw-r--r--trunk/channels/chan_iax2.c11726
-rw-r--r--trunk/channels/chan_jingle.c1862
-rw-r--r--trunk/channels/chan_local.c761
-rw-r--r--trunk/channels/chan_mgcp.c4398
-rw-r--r--trunk/channels/chan_misdn.c5747
-rw-r--r--trunk/channels/chan_nbs.c292
-rw-r--r--trunk/channels/chan_oss.c1470
-rw-r--r--trunk/channels/chan_phone.c1450
-rw-r--r--trunk/channels/chan_sip.c21227
-rw-r--r--trunk/channels/chan_skinny.c6066
-rw-r--r--trunk/channels/chan_unistim.c5668
-rw-r--r--trunk/channels/chan_usbradio.c2494
-rw-r--r--trunk/channels/chan_vpb.cc2899
-rw-r--r--trunk/channels/chan_zap.c14253
-rw-r--r--trunk/channels/console_board.c329
-rw-r--r--trunk/channels/console_gui.c1036
-rw-r--r--trunk/channels/console_video.c1035
-rw-r--r--trunk/channels/console_video.h127
-rw-r--r--trunk/channels/h323/ChangeLog43
-rw-r--r--trunk/channels/h323/INSTALL.openh32318
-rw-r--r--trunk/channels/h323/Makefile.in48
-rw-r--r--trunk/channels/h323/README144
-rw-r--r--trunk/channels/h323/TODO9
-rw-r--r--trunk/channels/h323/ast_h323.cxx2637
-rw-r--r--trunk/channels/h323/ast_h323.h189
-rw-r--r--trunk/channels/h323/caps_h323.cxx383
-rw-r--r--trunk/channels/h323/caps_h323.h172
-rw-r--r--trunk/channels/h323/chan_h323.h269
-rw-r--r--trunk/channels/h323/cisco-h225.asn74
-rw-r--r--trunk/channels/h323/cisco-h225.cxx853
-rw-r--r--trunk/channels/h323/cisco-h225.h299
-rw-r--r--trunk/channels/h323/compat_h323.cxx138
-rw-r--r--trunk/channels/h323/compat_h323.h94
-rw-r--r--trunk/channels/h323/noexport.map5
-rw-r--r--trunk/channels/iax2-parser.c1080
-rw-r--r--trunk/channels/iax2-parser.h163
-rw-r--r--trunk/channels/iax2-provision.c538
-rw-r--r--trunk/channels/iax2-provision.h53
-rw-r--r--trunk/channels/iax2.h277
-rw-r--r--trunk/channels/misdn/Makefile17
-rw-r--r--trunk/channels/misdn/chan_misdn_config.h160
-rw-r--r--trunk/channels/misdn/ie.c1422
-rw-r--r--trunk/channels/misdn/isdn_lib.c4582
-rw-r--r--trunk/channels/misdn/isdn_lib.h488
-rw-r--r--trunk/channels/misdn/isdn_lib_intern.h124
-rw-r--r--trunk/channels/misdn/isdn_msg_parser.c1353
-rw-r--r--trunk/channels/misdn/portinfo.c202
-rw-r--r--trunk/channels/misdn_config.c1158
-rw-r--r--trunk/channels/vcodecs.c1253
-rw-r--r--trunk/channels/vgrabbers.c346
-rwxr-xr-xtrunk/channels/xpmr/sinetabx.h290
-rwxr-xr-xtrunk/channels/xpmr/xpmr.c2256
-rwxr-xr-xtrunk/channels/xpmr/xpmr.h543
-rwxr-xr-xtrunk/channels/xpmr/xpmr_coef.h951
-rw-r--r--trunk/codecs/Makefile58
-rw-r--r--trunk/codecs/adpcm_slin_ex.h25
-rw-r--r--trunk/codecs/codec_a_mu.c159
-rw-r--r--trunk/codecs/codec_adpcm.c400
-rw-r--r--trunk/codecs/codec_alaw.c184
-rw-r--r--trunk/codecs/codec_g722.c301
-rw-r--r--trunk/codecs/codec_g726.c960
-rw-r--r--trunk/codecs/codec_gsm.c286
-rw-r--r--trunk/codecs/codec_ilbc.c235
-rw-r--r--trunk/codecs/codec_lpc10.c311
-rw-r--r--trunk/codecs/codec_resample.c237
-rw-r--r--trunk/codecs/codec_speex.c503
-rw-r--r--trunk/codecs/codec_ulaw.c195
-rw-r--r--trunk/codecs/codec_zap.c488
-rw-r--r--trunk/codecs/g722/Makefile18
-rw-r--r--trunk/codecs/g722/g722.h148
-rw-r--r--trunk/codecs/g722/g722_decode.c398
-rw-r--r--trunk/codecs/g722/g722_encode.c400
-rw-r--r--trunk/codecs/g722_slin_ex.h25
-rw-r--r--trunk/codecs/g726_slin_ex.h25
-rw-r--r--trunk/codecs/gsm/COPYRIGHT16
-rw-r--r--trunk/codecs/gsm/Makefile543
-rw-r--r--trunk/codecs/gsm/README37
-rw-r--r--trunk/codecs/gsm/inc/config.h51
-rw-r--r--trunk/codecs/gsm/inc/gsm.h71
-rw-r--r--trunk/codecs/gsm/inc/private.h312
-rw-r--r--trunk/codecs/gsm/inc/proto.h65
-rw-r--r--trunk/codecs/gsm/inc/unproto.h23
-rw-r--r--trunk/codecs/gsm/libgsm.vcproj253
-rw-r--r--trunk/codecs/gsm/src/add.c235
-rw-r--r--trunk/codecs/gsm/src/code.c97
-rw-r--r--trunk/codecs/gsm/src/debug.c76
-rw-r--r--trunk/codecs/gsm/src/decode.c62
-rw-r--r--trunk/codecs/gsm/src/gsm_create.c45
-rw-r--r--trunk/codecs/gsm/src/gsm_decode.c361
-rw-r--r--trunk/codecs/gsm/src/gsm_destroy.c26
-rw-r--r--trunk/codecs/gsm/src/gsm_encode.c451
-rw-r--r--trunk/codecs/gsm/src/gsm_explode.c417
-rw-r--r--trunk/codecs/gsm/src/gsm_implode.c515
-rw-r--r--trunk/codecs/gsm/src/gsm_option.c69
-rw-r--r--trunk/codecs/gsm/src/gsm_print.c167
-rw-r--r--trunk/codecs/gsm/src/k6opt.h84
-rw-r--r--trunk/codecs/gsm/src/k6opt.s739
-rw-r--r--trunk/codecs/gsm/src/long_term.c955
-rw-r--r--trunk/codecs/gsm/src/lpc.c372
-rw-r--r--trunk/codecs/gsm/src/preprocess.c127
-rw-r--r--trunk/codecs/gsm/src/rpe.c490
-rw-r--r--trunk/codecs/gsm/src/short_term.c448
-rw-r--r--trunk/codecs/gsm/src/table.c63
-rw-r--r--trunk/codecs/gsm_slin_ex.h16
-rw-r--r--trunk/codecs/ilbc/FrameClassify.c110
-rw-r--r--trunk/codecs/ilbc/FrameClassify.h26
-rw-r--r--trunk/codecs/ilbc/LPCdecode.c152
-rw-r--r--trunk/codecs/ilbc/LPCdecode.h44
-rw-r--r--trunk/codecs/ilbc/LPCencode.c228
-rw-r--r--trunk/codecs/ilbc/LPCencode.h29
-rw-r--r--trunk/codecs/ilbc/Makefile21
-rw-r--r--trunk/codecs/ilbc/StateConstructW.c76
-rw-r--r--trunk/codecs/ilbc/StateConstructW.h27
-rw-r--r--trunk/codecs/ilbc/StateSearchW.c194
-rw-r--r--trunk/codecs/ilbc/StateSearchW.h48
-rw-r--r--trunk/codecs/ilbc/anaFilter.c71
-rw-r--r--trunk/codecs/ilbc/anaFilter.h26
-rw-r--r--trunk/codecs/ilbc/constants.c729
-rw-r--r--trunk/codecs/ilbc/constants.h74
-rw-r--r--trunk/codecs/ilbc/createCB.c216
-rw-r--r--trunk/codecs/ilbc/createCB.h56
-rw-r--r--trunk/codecs/ilbc/doCPLC.c259
-rw-r--r--trunk/codecs/ilbc/doCPLC.h32
-rw-r--r--trunk/codecs/ilbc/enhancer.c665
-rw-r--r--trunk/codecs/ilbc/enhancer.h33
-rw-r--r--trunk/codecs/ilbc/filter.c168
-rw-r--r--trunk/codecs/ilbc/filter.h73
-rw-r--r--trunk/codecs/ilbc/gainquant.c107
-rw-r--r--trunk/codecs/ilbc/gainquant.h31
-rw-r--r--trunk/codecs/ilbc/getCBvec.c181
-rw-r--r--trunk/codecs/ilbc/getCBvec.h28
-rw-r--r--trunk/codecs/ilbc/helpfun.c308
-rw-r--r--trunk/codecs/ilbc/helpfun.h101
-rw-r--r--trunk/codecs/ilbc/hpInput.c60
-rw-r--r--trunk/codecs/ilbc/hpInput.h27
-rw-r--r--trunk/codecs/ilbc/hpOutput.c59
-rw-r--r--trunk/codecs/ilbc/hpOutput.h25
-rw-r--r--trunk/codecs/ilbc/iCBConstruct.c108
-rw-r--r--trunk/codecs/ilbc/iCBConstruct.h38
-rw-r--r--trunk/codecs/ilbc/iCBSearch.c480
-rw-r--r--trunk/codecs/ilbc/iCBSearch.h35
-rw-r--r--trunk/codecs/ilbc/iLBC_decode.c619
-rw-r--r--trunk/codecs/ilbc/iLBC_decode.h40
-rw-r--r--trunk/codecs/ilbc/iLBC_define.h200
-rw-r--r--trunk/codecs/ilbc/iLBC_encode.c514
-rw-r--r--trunk/codecs/ilbc/iLBC_encode.h37
-rw-r--r--trunk/codecs/ilbc/libilbc.vcproj353
-rw-r--r--trunk/codecs/ilbc/lsf.c264
-rw-r--r--trunk/codecs/ilbc/lsf.h30
-rw-r--r--trunk/codecs/ilbc/packing.c175
-rw-r--r--trunk/codecs/ilbc/packing.h67
-rw-r--r--trunk/codecs/ilbc/syntFilter.c108
-rw-r--r--trunk/codecs/ilbc/syntFilter.h27
-rw-r--r--trunk/codecs/ilbc_slin_ex.h17
-rw-r--r--trunk/codecs/log2comp.h74
-rw-r--r--trunk/codecs/lpc10/Makefile78
-rw-r--r--trunk/codecs/lpc10/README89
-rw-r--r--trunk/codecs/lpc10/analys.c649
-rw-r--r--trunk/codecs/lpc10/bsynz.c447
-rw-r--r--trunk/codecs/lpc10/chanwr.c232
-rw-r--r--trunk/codecs/lpc10/dcbias.c107
-rw-r--r--trunk/codecs/lpc10/decode.c625
-rw-r--r--trunk/codecs/lpc10/deemp.c154
-rw-r--r--trunk/codecs/lpc10/difmag.c133
-rw-r--r--trunk/codecs/lpc10/dyptrk.c405
-rw-r--r--trunk/codecs/lpc10/encode.c373
-rw-r--r--trunk/codecs/lpc10/energy.c103
-rw-r--r--trunk/codecs/lpc10/f2c.h325
-rw-r--r--trunk/codecs/lpc10/f2clib.c85
-rw-r--r--trunk/codecs/lpc10/ham84.c126
-rw-r--r--trunk/codecs/lpc10/hp100.c169
-rw-r--r--trunk/codecs/lpc10/invert.c193
-rw-r--r--trunk/codecs/lpc10/irc2pc.c151
-rw-r--r--trunk/codecs/lpc10/ivfilt.c136
-rw-r--r--trunk/codecs/lpc10/liblpc10.vcproj305
-rw-r--r--trunk/codecs/lpc10/lpc10.h256
-rw-r--r--trunk/codecs/lpc10/lpcdec.c297
-rw-r--r--trunk/codecs/lpc10/lpcenc.c181
-rw-r--r--trunk/codecs/lpc10/lpcini.c446
-rw-r--r--trunk/codecs/lpc10/lpfilt.c125
-rw-r--r--trunk/codecs/lpc10/median.c89
-rw-r--r--trunk/codecs/lpc10/mload.c163
-rw-r--r--trunk/codecs/lpc10/onset.c324
-rw-r--r--trunk/codecs/lpc10/pitsyn.c583
-rw-r--r--trunk/codecs/lpc10/placea.c242
-rw-r--r--trunk/codecs/lpc10/placev.c275
-rw-r--r--trunk/codecs/lpc10/preemp.c144
-rw-r--r--trunk/codecs/lpc10/prepro.c116
-rw-r--r--trunk/codecs/lpc10/random.c125
-rw-r--r--trunk/codecs/lpc10/rcchk.c119
-rw-r--r--trunk/codecs/lpc10/synths.c425
-rw-r--r--trunk/codecs/lpc10/tbdm.c188
-rw-r--r--trunk/codecs/lpc10/voicin.c786
-rw-r--r--trunk/codecs/lpc10/vparms.c255
-rw-r--r--trunk/codecs/lpc10_slin_ex.h13
-rw-r--r--trunk/codecs/slin_adpcm_ex.h25
-rw-r--r--trunk/codecs/slin_g722_ex.h25
-rw-r--r--trunk/codecs/slin_g726_ex.h25
-rw-r--r--trunk/codecs/slin_gsm_ex.h28
-rw-r--r--trunk/codecs/slin_ilbc_ex.h28
-rw-r--r--trunk/codecs/slin_lpc10_ex.h21
-rw-r--r--trunk/codecs/slin_resample_ex.h43
-rw-r--r--trunk/codecs/slin_speex_ex.h262
-rw-r--r--trunk/codecs/slin_ulaw_ex.h25
-rw-r--r--trunk/codecs/speex_slin_ex.h16
-rw-r--r--trunk/codecs/ulaw_slin_ex.h25
-rwxr-xr-xtrunk/config.guess1495
-rwxr-xr-xtrunk/config.sub1609
-rw-r--r--trunk/configs/adsi.conf.sample8
-rw-r--r--trunk/configs/adtranvofr.conf.sample39
-rw-r--r--trunk/configs/agents.conf.sample105
-rw-r--r--trunk/configs/alarmreceiver.conf.sample80
-rw-r--r--trunk/configs/alsa.conf.sample62
-rw-r--r--trunk/configs/amd.conf.sample18
-rw-r--r--trunk/configs/asterisk.adsi159
-rw-r--r--trunk/configs/cdr.conf.sample148
-rw-r--r--trunk/configs/cdr_adaptive_odbc.conf.sample40
-rw-r--r--trunk/configs/cdr_custom.conf.sample10
-rw-r--r--trunk/configs/cdr_manager.conf.sample15
-rw-r--r--trunk/configs/cdr_odbc.conf.sample12
-rw-r--r--trunk/configs/cdr_pgsql.conf.sample9
-rw-r--r--trunk/configs/cdr_sqlite3_custom.conf.sample7
-rw-r--r--trunk/configs/cdr_tds.conf.sample11
-rw-r--r--trunk/configs/codecs.conf.sample65
-rw-r--r--trunk/configs/console.conf.sample68
-rw-r--r--trunk/configs/dnsmgr.conf.sample5
-rw-r--r--trunk/configs/dundi.conf.sample261
-rw-r--r--trunk/configs/enum.conf.sample22
-rw-r--r--trunk/configs/extconfig.conf.sample63
-rw-r--r--trunk/configs/extensions.ael.sample448
-rw-r--r--trunk/configs/extensions.conf.sample614
-rw-r--r--trunk/configs/extensions.lua.sample208
-rw-r--r--trunk/configs/extensions_minivm.conf.sample159
-rw-r--r--trunk/configs/features.conf.sample124
-rw-r--r--trunk/configs/festival.conf.sample35
-rw-r--r--trunk/configs/followme.conf.sample86
-rw-r--r--trunk/configs/func_odbc.conf.sample77
-rw-r--r--trunk/configs/gtalk.conf.sample19
-rw-r--r--trunk/configs/h323.conf.sample207
-rw-r--r--trunk/configs/http.conf.sample71
-rw-r--r--trunk/configs/iax.conf.sample434
-rw-r--r--trunk/configs/iaxprov.conf.sample81
-rw-r--r--trunk/configs/indications.conf.sample733
-rw-r--r--trunk/configs/jabber.conf.sample21
-rw-r--r--trunk/configs/jingle.conf.sample19
-rw-r--r--trunk/configs/logger.conf.sample96
-rw-r--r--trunk/configs/manager.conf.sample97
-rw-r--r--trunk/configs/meetme.conf.sample45
-rw-r--r--trunk/configs/mgcp.conf.sample110
-rw-r--r--trunk/configs/minivm.conf.sample218
-rw-r--r--trunk/configs/misdn.conf.sample455
-rw-r--r--trunk/configs/modules.conf.sample39
-rw-r--r--trunk/configs/musiconhold.conf.sample79
-rw-r--r--trunk/configs/muted.conf.sample39
-rw-r--r--trunk/configs/osp.conf.sample90
-rw-r--r--trunk/configs/oss.conf.sample138
-rw-r--r--trunk/configs/phone.conf.sample51
-rw-r--r--trunk/configs/phoneprov.conf.sample60
-rw-r--r--trunk/configs/queuerules.conf.sample20
-rw-r--r--trunk/configs/queues.conf.sample403
-rw-r--r--trunk/configs/res_config_sqlite.conf11
-rw-r--r--trunk/configs/res_odbc.conf.sample48
-rw-r--r--trunk/configs/res_pgsql.conf.sample14
-rw-r--r--trunk/configs/res_snmp.conf.sample10
-rw-r--r--trunk/configs/rpt.conf.sample193
-rw-r--r--trunk/configs/rtp.conf.sample22
-rw-r--r--trunk/configs/say.conf.sample200
-rw-r--r--trunk/configs/sip.conf.sample896
-rw-r--r--trunk/configs/sip_notify.conf.sample22
-rw-r--r--trunk/configs/skinny.conf.sample120
-rw-r--r--trunk/configs/sla.conf.sample140
-rw-r--r--trunk/configs/smdi.conf.sample43
-rw-r--r--trunk/configs/telcordia-1.adsi83
-rw-r--r--trunk/configs/udptl.conf.sample30
-rw-r--r--trunk/configs/unistim.conf.sample76
-rw-r--r--trunk/configs/usbradio.conf.sample54
-rw-r--r--trunk/configs/users.conf.sample79
-rw-r--r--trunk/configs/voicemail.conf.sample307
-rw-r--r--trunk/configs/vpb.conf.sample108
-rw-r--r--trunk/configs/zapata.conf.sample909
-rwxr-xr-xtrunk/configure50171
-rw-r--r--trunk/configure.ac1208
-rw-r--r--trunk/contrib/README.festival47
-rw-r--r--trunk/contrib/asterisk-doxygen-header10
-rw-r--r--trunk/contrib/asterisk-ices.xml93
-rw-r--r--trunk/contrib/asterisk-ng-doxygen1274
-rw-r--r--trunk/contrib/dictionary.digium31
-rw-r--r--trunk/contrib/festival-1.4.1-diff76
-rw-r--r--trunk/contrib/festival-1.4.2.diff75
-rw-r--r--trunk/contrib/festival-1.4.3.diff93
-rw-r--r--trunk/contrib/festival-1.95.diff107
-rw-r--r--trunk/contrib/firmware/iax/iaxy.binbin0 -> 39402 bytes
-rw-r--r--trunk/contrib/i18n.testsuite.conf136
-rwxr-xr-xtrunk/contrib/init.d/rc.debian.asterisk85
-rwxr-xr-xtrunk/contrib/init.d/rc.gentoo.asterisk18
-rwxr-xr-xtrunk/contrib/init.d/rc.mandrake.asterisk185
-rwxr-xr-xtrunk/contrib/init.d/rc.mandrake.zaptel108
-rwxr-xr-xtrunk/contrib/init.d/rc.redhat.asterisk136
-rwxr-xr-xtrunk/contrib/init.d/rc.slackware.asterisk43
-rwxr-xr-xtrunk/contrib/init.d/rc.suse.asterisk127
-rw-r--r--trunk/contrib/scripts/README.messages-expire20
-rw-r--r--trunk/contrib/scripts/agents.php73
-rw-r--r--trunk/contrib/scripts/ast_grab_core70
-rw-r--r--trunk/contrib/scripts/astgenkey61
-rw-r--r--trunk/contrib/scripts/astgenkey.8129
-rw-r--r--trunk/contrib/scripts/autosupport163
-rw-r--r--trunk/contrib/scripts/autosupport.841
-rw-r--r--trunk/contrib/scripts/iax-friends.sql15
-rw-r--r--trunk/contrib/scripts/loadtest.tcl148
-rw-r--r--trunk/contrib/scripts/lookup.agi90
-rw-r--r--trunk/contrib/scripts/managerproxy.pl242
-rw-r--r--trunk/contrib/scripts/meetme.sql12
-rw-r--r--trunk/contrib/scripts/messages-expire.pl96
-rw-r--r--trunk/contrib/scripts/postgres_cdr.sql33
-rw-r--r--trunk/contrib/scripts/qview.pl100
-rw-r--r--trunk/contrib/scripts/realtime_pgsql.sql141
-rw-r--r--trunk/contrib/scripts/retrieve_extensions_from_mysql.pl113
-rw-r--r--trunk/contrib/scripts/retrieve_extensions_from_sql.pl158
-rw-r--r--trunk/contrib/scripts/retrieve_sip_conf_from_mysql.pl93
-rw-r--r--trunk/contrib/scripts/safe_asterisk184
-rw-r--r--trunk/contrib/scripts/safe_asterisk.869
-rw-r--r--trunk/contrib/scripts/safe_asterisk_restart110
-rw-r--r--trunk/contrib/scripts/sip-friends.sql14
-rw-r--r--trunk/contrib/scripts/vmail.cgi1099
-rw-r--r--trunk/contrib/scripts/vmdb.sql66
-rw-r--r--trunk/contrib/thirdparty/spexxilbcfix_xlite.regbin0 -> 452 bytes
-rw-r--r--trunk/contrib/thirdparty/spexxilbcfix_xpro.regbin0 -> 450 bytes
-rw-r--r--trunk/contrib/utils/README.rawplayer37
-rw-r--r--trunk/contrib/utils/eagi_proxy.c419
-rw-r--r--trunk/contrib/utils/rawplayer.c46
-rw-r--r--trunk/contrib/utils/zones2indications.c153
-rw-r--r--trunk/contrib/valgrind-RedHat-8.0.supp41
-rw-r--r--trunk/doc/CODING-GUIDELINES684
-rw-r--r--trunk/doc/India-CID.txt75
-rw-r--r--trunk/doc/PEERING503
-rw-r--r--trunk/doc/asterisk-mib.txt769
-rw-r--r--trunk/doc/asterisk.8199
-rw-r--r--trunk/doc/asterisk.sgml373
-rw-r--r--trunk/doc/backtrace.txt191
-rw-r--r--trunk/doc/callfiles.txt139
-rw-r--r--trunk/doc/datastores.txt63
-rw-r--r--trunk/doc/digium-mib.txt17
-rw-r--r--trunk/doc/externalivr.txt117
-rw-r--r--trunk/doc/jabber.txt15
-rw-r--r--trunk/doc/jingle.txt10
-rw-r--r--trunk/doc/macroexclusive.txt78
-rw-r--r--trunk/doc/manager_1_1.txt286
-rw-r--r--trunk/doc/modules.txt25
-rw-r--r--trunk/doc/osp.txt747
-rw-r--r--trunk/doc/queue.txt39
-rw-r--r--trunk/doc/res_config_sqlite.txt124
-rw-r--r--trunk/doc/rtp-packetization.txt75
-rw-r--r--trunk/doc/siptls.txt94
-rw-r--r--trunk/doc/smdi.txt25
-rw-r--r--trunk/doc/sms.txt147
-rw-r--r--trunk/doc/snmp.txt39
-rw-r--r--trunk/doc/speechrec.txt295
-rw-r--r--trunk/doc/ss7.txt113
-rw-r--r--trunk/doc/tex/Makefile44
-rw-r--r--trunk/doc/tex/README.txt24
-rw-r--r--trunk/doc/tex/ael.tex1305
-rw-r--r--trunk/doc/tex/ajam.tex97
-rw-r--r--trunk/doc/tex/app-sms.tex518
-rw-r--r--trunk/doc/tex/asterisk-conf.tex141
-rw-r--r--trunk/doc/tex/asterisk.tex162
-rw-r--r--trunk/doc/tex/backtrace.tex217
-rw-r--r--trunk/doc/tex/billing.tex86
-rw-r--r--trunk/doc/tex/cdrdriver.tex458
-rw-r--r--trunk/doc/tex/chaniax.tex84
-rw-r--r--trunk/doc/tex/channelvariables.tex974
-rw-r--r--trunk/doc/tex/cliprompt.tex29
-rw-r--r--trunk/doc/tex/configuration.tex225
-rw-r--r--trunk/doc/tex/dundi.tex41
-rw-r--r--trunk/doc/tex/enum.tex355
-rw-r--r--trunk/doc/tex/extensions.tex82
-rw-r--r--trunk/doc/tex/freetds.tex16
-rw-r--r--trunk/doc/tex/hardware.tex100
-rw-r--r--trunk/doc/tex/ices.tex7
-rw-r--r--trunk/doc/tex/imapstorage.tex196
-rw-r--r--trunk/doc/tex/jitterbuffer.tex98
-rw-r--r--trunk/doc/tex/localchannel.tex80
-rw-r--r--trunk/doc/tex/manager.tex258
-rw-r--r--trunk/doc/tex/misdn.tex272
-rw-r--r--trunk/doc/tex/mp3.tex11
-rw-r--r--trunk/doc/tex/odbcstorage.tex31
-rw-r--r--trunk/doc/tex/phoneprov.tex307
-rw-r--r--trunk/doc/tex/privacy.tex354
-rw-r--r--trunk/doc/tex/qos.tex135
-rw-r--r--trunk/doc/tex/queuelog.tex118
-rw-r--r--trunk/doc/tex/queues-with-callback-members.tex551
-rw-r--r--trunk/doc/tex/realtime.tex127
-rw-r--r--trunk/doc/tex/security.tex80
-rw-r--r--trunk/doc/tex/sla.tex387
-rw-r--r--trunk/doc/unistim.txt127
-rw-r--r--trunk/doc/valgrind.txt19
-rw-r--r--trunk/doc/video.txt46
-rw-r--r--trunk/doc/voicemail_odbc_postgresql.txt427
-rw-r--r--trunk/formats/Makefile20
-rw-r--r--trunk/formats/format_g723.c152
-rw-r--r--trunk/formats/format_g726.c261
-rw-r--r--trunk/formats/format_g729.c148
-rw-r--r--trunk/formats/format_gsm.c170
-rw-r--r--trunk/formats/format_h263.c186
-rw-r--r--trunk/formats/format_h264.c175
-rw-r--r--trunk/formats/format_ilbc.c146
-rw-r--r--trunk/formats/format_jpeg.c115
-rw-r--r--trunk/formats/format_ogg_vorbis.c552
-rw-r--r--trunk/formats/format_pcm.c485
-rw-r--r--trunk/formats/format_sln.c130
-rw-r--r--trunk/formats/format_sln16.c138
-rw-r--r--trunk/formats/format_vox.c135
-rw-r--r--trunk/formats/format_wav.c491
-rw-r--r--trunk/formats/format_wav_gsm.c559
-rw-r--r--trunk/formats/msgsm.h689
-rw-r--r--trunk/funcs/Makefile20
-rw-r--r--trunk/funcs/func_base64.c87
-rw-r--r--trunk/funcs/func_blacklist.c74
-rw-r--r--trunk/funcs/func_callerid.c233
-rw-r--r--trunk/funcs/func_cdr.c162
-rw-r--r--trunk/funcs/func_channel.c206
-rw-r--r--trunk/funcs/func_curl.c204
-rw-r--r--trunk/funcs/func_cut.c300
-rw-r--r--trunk/funcs/func_db.c225
-rw-r--r--trunk/funcs/func_devstate.c255
-rw-r--r--trunk/funcs/func_dialgroup.c220
-rw-r--r--trunk/funcs/func_dialplan.c106
-rw-r--r--trunk/funcs/func_enum.c391
-rw-r--r--trunk/funcs/func_env.c215
-rw-r--r--trunk/funcs/func_extstate.c133
-rw-r--r--trunk/funcs/func_global.c82
-rw-r--r--trunk/funcs/func_groupcount.c231
-rw-r--r--trunk/funcs/func_iconv.c125
-rw-r--r--trunk/funcs/func_lock.c350
-rw-r--r--trunk/funcs/func_logic.c242
-rw-r--r--trunk/funcs/func_math.c333
-rw-r--r--trunk/funcs/func_md5.c67
-rw-r--r--trunk/funcs/func_module.c68
-rw-r--r--trunk/funcs/func_odbc.c900
-rw-r--r--trunk/funcs/func_rand.c93
-rw-r--r--trunk/funcs/func_realtime.c154
-rw-r--r--trunk/funcs/func_sha1.c76
-rw-r--r--trunk/funcs/func_shell.c92
-rw-r--r--trunk/funcs/func_strings.c886
-rw-r--r--trunk/funcs/func_sysinfo.c116
-rw-r--r--trunk/funcs/func_timeout.c184
-rw-r--r--trunk/funcs/func_uri.c96
-rw-r--r--trunk/funcs/func_version.c101
-rw-r--r--trunk/funcs/func_vmcount.c93
-rw-r--r--trunk/funcs/func_volume.c160
-rw-r--r--trunk/images/animlogo.gifbin0 -> 63968 bytes
-rw-r--r--trunk/images/asterisk-intro.jpgbin0 -> 6143 bytes
-rw-r--r--trunk/images/font.pngbin0 -> 1549 bytes
-rw-r--r--trunk/images/kpad2.jpgbin0 -> 10374 bytes
-rw-r--r--trunk/images/play.gifbin0 -> 341 bytes
-rw-r--r--trunk/include/asterisk.h184
-rw-r--r--trunk/include/asterisk/_private.h53
-rw-r--r--trunk/include/asterisk/abstract_jb.h220
-rw-r--r--trunk/include/asterisk/acl.h84
-rw-r--r--trunk/include/asterisk/adsi.h353
-rw-r--r--trunk/include/asterisk/ael_structs.h123
-rw-r--r--trunk/include/asterisk/aes.h67
-rw-r--r--trunk/include/asterisk/aes_internal.h170
-rw-r--r--trunk/include/asterisk/agi.h66
-rw-r--r--trunk/include/asterisk/alaw.h86
-rw-r--r--trunk/include/asterisk/app.h463
-rw-r--r--trunk/include/asterisk/ast_expr.h40
-rw-r--r--trunk/include/asterisk/astdb.h58
-rw-r--r--trunk/include/asterisk/astmm.h82
-rw-r--r--trunk/include/asterisk/astobj.h819
-rw-r--r--trunk/include/asterisk/astobj2.h568
-rw-r--r--trunk/include/asterisk/astosp.h31
-rw-r--r--trunk/include/asterisk/audiohook.h210
-rw-r--r--trunk/include/asterisk/autoconfig.h.in1205
-rw-r--r--trunk/include/asterisk/callerid.h345
-rw-r--r--trunk/include/asterisk/causes.h149
-rw-r--r--trunk/include/asterisk/cdr.h337
-rw-r--r--trunk/include/asterisk/channel.h1577
-rw-r--r--trunk/include/asterisk/chanvars.h42
-rw-r--r--trunk/include/asterisk/cli.h285
-rw-r--r--trunk/include/asterisk/compat.h184
-rw-r--r--trunk/include/asterisk/compiler.h56
-rw-r--r--trunk/include/asterisk/config.h406
-rw-r--r--trunk/include/asterisk/crypto.h126
-rw-r--r--trunk/include/asterisk/devicestate.h203
-rw-r--r--trunk/include/asterisk/dial.h168
-rw-r--r--trunk/include/asterisk/dlfcn-compat.h88
-rw-r--r--trunk/include/asterisk/dns.h39
-rw-r--r--trunk/include/asterisk/dnsmgr.h62
-rw-r--r--trunk/include/asterisk/doxyref.h563
-rw-r--r--trunk/include/asterisk/dsp.h111
-rw-r--r--trunk/include/asterisk/dundi.h231
-rw-r--r--trunk/include/asterisk/endian.h69
-rw-r--r--trunk/include/asterisk/enum.h90
-rw-r--r--trunk/include/asterisk/event.h482
-rw-r--r--trunk/include/asterisk/event_defs.h143
-rw-r--r--trunk/include/asterisk/extconf.h248
-rw-r--r--trunk/include/asterisk/features.h112
-rw-r--r--trunk/include/asterisk/file.h322
-rw-r--r--trunk/include/asterisk/frame.h603
-rw-r--r--trunk/include/asterisk/fskmodem.h81
-rw-r--r--trunk/include/asterisk/global_datastores.h36
-rw-r--r--trunk/include/asterisk/hashtab.h324
-rw-r--r--trunk/include/asterisk/http.h93
-rw-r--r--trunk/include/asterisk/image.h90
-rw-r--r--trunk/include/asterisk/indications.h89
-rw-r--r--trunk/include/asterisk/inline_api.h66
-rw-r--r--trunk/include/asterisk/io.h150
-rw-r--r--trunk/include/asterisk/jabber.h201
-rw-r--r--trunk/include/asterisk/jingle.h61
l---------trunk/include/asterisk/libresample.h1
-rw-r--r--trunk/include/asterisk/linkedlists.h775
-rw-r--r--trunk/include/asterisk/localtime.h48
-rw-r--r--trunk/include/asterisk/lock.h1205
-rw-r--r--trunk/include/asterisk/logger.h178
-rw-r--r--trunk/include/asterisk/manager.h211
-rw-r--r--trunk/include/asterisk/md5.h38
-rw-r--r--trunk/include/asterisk/mod_format.h144
-rw-r--r--trunk/include/asterisk/module.h421
-rw-r--r--trunk/include/asterisk/monitor.h71
-rw-r--r--trunk/include/asterisk/musiconhold.h59
-rw-r--r--trunk/include/asterisk/netsock.h70
-rw-r--r--trunk/include/asterisk/network.h98
-rw-r--r--trunk/include/asterisk/options.h137
-rw-r--r--trunk/include/asterisk/paths.h39
-rw-r--r--trunk/include/asterisk/pbx.h978
-rw-r--r--trunk/include/asterisk/plc.h153
-rw-r--r--trunk/include/asterisk/poll-compat.h111
-rw-r--r--trunk/include/asterisk/privacy.h46
-rw-r--r--trunk/include/asterisk/pval.h273
-rw-r--r--trunk/include/asterisk/res_odbc.h122
-rw-r--r--trunk/include/asterisk/rtp.h293
-rw-r--r--trunk/include/asterisk/say.h170
-rw-r--r--trunk/include/asterisk/sched.h176
-rw-r--r--trunk/include/asterisk/sha1.h73
-rw-r--r--trunk/include/asterisk/slinfactory.h65
-rw-r--r--trunk/include/asterisk/smdi.h127
-rw-r--r--trunk/include/asterisk/speech.h156
-rw-r--r--trunk/include/asterisk/srv.h45
-rw-r--r--trunk/include/asterisk/stringfields.h307
-rw-r--r--trunk/include/asterisk/strings.h691
-rw-r--r--trunk/include/asterisk/tcptls.h166
-rw-r--r--trunk/include/asterisk/tdd.h82
-rw-r--r--trunk/include/asterisk/term.h85
-rw-r--r--trunk/include/asterisk/threadstorage.h212
-rw-r--r--trunk/include/asterisk/time.h178
-rw-r--r--trunk/include/asterisk/transcap.h46
-rw-r--r--trunk/include/asterisk/translate.h273
-rw-r--r--trunk/include/asterisk/udptl.h127
-rw-r--r--trunk/include/asterisk/ulaw.h87
-rw-r--r--trunk/include/asterisk/unaligned.h102
-rw-r--r--trunk/include/asterisk/utils.h657
-rw-r--r--trunk/include/asterisk/version.h44
-rw-r--r--trunk/include/asterisk/zapata.h48
-rw-r--r--trunk/include/jitterbuf.h174
-rw-r--r--trunk/include/solaris-compat/compat.h46
-rw-r--r--trunk/include/solaris-compat/sys/cdefs.h10
-rw-r--r--trunk/include/solaris-compat/sys/queue.h540
-rwxr-xr-xtrunk/install-sh269
-rw-r--r--trunk/keys/freeworlddialup.pub6
-rw-r--r--trunk/keys/iaxtel.pub6
-rw-r--r--trunk/main/Makefile174
-rw-r--r--trunk/main/abstract_jb.c774
-rw-r--r--trunk/main/acl.c357
-rw-r--r--trunk/main/adsistub.c77
-rw-r--r--trunk/main/aescrypt.c321
-rw-r--r--trunk/main/aeskey.c473
-rw-r--r--trunk/main/aesopt.h1029
-rw-r--r--trunk/main/aestab.c236
-rw-r--r--trunk/main/alaw.c210
-rw-r--r--trunk/main/app.c1739
-rw-r--r--trunk/main/ast_expr2.c3448
-rw-r--r--trunk/main/ast_expr2.fl444
-rw-r--r--trunk/main/ast_expr2.h115
-rw-r--r--trunk/main/ast_expr2.y1619
-rw-r--r--trunk/main/ast_expr2f.c2515
-rw-r--r--trunk/main/asterisk.c3267
-rw-r--r--trunk/main/astmm.c479
-rw-r--r--trunk/main/astobj2.c732
-rw-r--r--trunk/main/audiohook.c693
-rw-r--r--trunk/main/autoservice.c252
-rw-r--r--trunk/main/buildinfo.c33
-rw-r--r--trunk/main/callerid.c1115
-rw-r--r--trunk/main/cdr.c1456
-rw-r--r--trunk/main/channel.c4843
-rw-r--r--trunk/main/chanvars.c82
-rw-r--r--trunk/main/cli.c1918
-rw-r--r--trunk/main/config.c2281
-rw-r--r--trunk/main/cryptostub.c67
-rw-r--r--trunk/main/cygload.c39
-rw-r--r--trunk/main/db.c671
-rw-r--r--trunk/main/db1-ast/Makefile72
-rw-r--r--trunk/main/db1-ast/btree/bt_close.c182
-rw-r--r--trunk/main/db1-ast/btree/bt_conv.c221
-rw-r--r--trunk/main/db1-ast/btree/bt_debug.c329
-rw-r--r--trunk/main/db1-ast/btree/bt_delete.c657
-rw-r--r--trunk/main/db1-ast/btree/bt_get.c105
-rw-r--r--trunk/main/db1-ast/btree/bt_open.c458
-rw-r--r--trunk/main/db1-ast/btree/bt_overflow.c228
-rw-r--r--trunk/main/db1-ast/btree/bt_page.c100
-rw-r--r--trunk/main/db1-ast/btree/bt_put.c321
-rw-r--r--trunk/main/db1-ast/btree/bt_search.c213
-rw-r--r--trunk/main/db1-ast/btree/bt_seq.c460
-rw-r--r--trunk/main/db1-ast/btree/bt_split.c829
-rw-r--r--trunk/main/db1-ast/btree/bt_utils.c260
-rw-r--r--trunk/main/db1-ast/btree/btree.h391
-rw-r--r--trunk/main/db1-ast/btree/extern.h70
-rw-r--r--trunk/main/db1-ast/db/db.c103
-rw-r--r--trunk/main/db1-ast/hash/README72
-rw-r--r--trunk/main/db1-ast/hash/extern.h65
-rw-r--r--trunk/main/db1-ast/hash/hash.c999
-rw-r--r--trunk/main/db1-ast/hash/hash.h293
-rw-r--r--trunk/main/db1-ast/hash/hash_bigkey.c668
-rw-r--r--trunk/main/db1-ast/hash/hash_buf.c355
-rw-r--r--trunk/main/db1-ast/hash/hash_func.c225
-rw-r--r--trunk/main/db1-ast/hash/hash_log2.c56
-rw-r--r--trunk/main/db1-ast/hash/hash_page.c944
-rw-r--r--trunk/main/db1-ast/hash/hsearch.c107
-rw-r--r--trunk/main/db1-ast/hash/ndbm.c235
-rw-r--r--trunk/main/db1-ast/hash/page.h92
-rw-r--r--trunk/main/db1-ast/hash/search.h51
-rw-r--r--trunk/main/db1-ast/include/circ-queue.h131
-rw-r--r--trunk/main/db1-ast/include/compat.h49
-rw-r--r--trunk/main/db1-ast/include/db.h250
-rw-r--r--trunk/main/db1-ast/include/mpool.h115
-rw-r--r--trunk/main/db1-ast/include/ndbm.h79
-rw-r--r--trunk/main/db1-ast/libdb.map11
-rw-r--r--trunk/main/db1-ast/mpool/README7
-rw-r--r--trunk/main/db1-ast/mpool/mpool.c498
-rw-r--r--trunk/main/db1-ast/recno/extern.h54
-rw-r--r--trunk/main/db1-ast/recno/rec_close.c183
-rw-r--r--trunk/main/db1-ast/recno/rec_delete.c197
-rw-r--r--trunk/main/db1-ast/recno/rec_get.c311
-rw-r--r--trunk/main/db1-ast/recno/rec_open.c241
-rw-r--r--trunk/main/db1-ast/recno/rec_put.c280
-rw-r--r--trunk/main/db1-ast/recno/rec_search.c126
-rw-r--r--trunk/main/db1-ast/recno/rec_seq.c131
-rw-r--r--trunk/main/db1-ast/recno/rec_utils.c122
-rw-r--r--trunk/main/db1-ast/recno/recno.h39
-rw-r--r--trunk/main/devicestate.c553
-rw-r--r--trunk/main/dial.c1014
-rw-r--r--trunk/main/dlfcn.c1309
-rw-r--r--trunk/main/dns.c299
-rw-r--r--trunk/main/dnsmgr.c425
-rw-r--r--trunk/main/dsp.c1349
-rw-r--r--trunk/main/ecdisa.h15
-rw-r--r--trunk/main/editline/CHANGES42
-rw-r--r--trunk/main/editline/INSTALL64
-rw-r--r--trunk/main/editline/Makefile.in234
-rw-r--r--trunk/main/editline/PLATFORMS13
-rw-r--r--trunk/main/editline/README11
-rw-r--r--trunk/main/editline/TEST/test.c268
-rw-r--r--trunk/main/editline/chared.c695
-rw-r--r--trunk/main/editline/chared.h159
-rw-r--r--trunk/main/editline/common.c951
-rwxr-xr-xtrunk/main/editline/config.guess1449
-rw-r--r--trunk/main/editline/config.h.in21
-rwxr-xr-xtrunk/main/editline/config.sub1412
-rwxr-xr-xtrunk/main/editline/configure2309
-rw-r--r--trunk/main/editline/configure.in274
-rw-r--r--trunk/main/editline/editline.3646
-rw-r--r--trunk/main/editline/editrc.5491
-rw-r--r--trunk/main/editline/el.c509
-rw-r--r--trunk/main/editline/el.h145
-rw-r--r--trunk/main/editline/emacs.c488
-rw-r--r--trunk/main/editline/hist.c197
-rw-r--r--trunk/main/editline/hist.h80
-rw-r--r--trunk/main/editline/histedit.h197
-rw-r--r--trunk/main/editline/history.c875
-rwxr-xr-xtrunk/main/editline/install-sh250
-rw-r--r--trunk/main/editline/key.c687
-rw-r--r--trunk/main/editline/key.h79
-rw-r--r--trunk/main/editline/makelist254
-rw-r--r--trunk/main/editline/map.c1418
-rw-r--r--trunk/main/editline/map.h79
-rw-r--r--trunk/main/editline/np/fgetln.c88
-rw-r--r--trunk/main/editline/np/strlcat.c75
-rw-r--r--trunk/main/editline/np/strlcpy.c75
-rw-r--r--trunk/main/editline/np/unvis.c322
-rw-r--r--trunk/main/editline/np/vis.c347
-rw-r--r--trunk/main/editline/np/vis.h96
-rw-r--r--trunk/main/editline/parse.c259
-rw-r--r--trunk/main/editline/parse.h52
-rw-r--r--trunk/main/editline/prompt.c174
-rw-r--r--trunk/main/editline/prompt.h62
-rw-r--r--trunk/main/editline/read.c555
-rw-r--r--trunk/main/editline/read.h55
-rw-r--r--trunk/main/editline/readline.c1665
-rw-r--r--trunk/main/editline/readline/readline.h118
-rw-r--r--trunk/main/editline/refresh.c1104
-rw-r--r--trunk/main/editline/refresh.h63
-rw-r--r--trunk/main/editline/search.c649
-rw-r--r--trunk/main/editline/search.h70
-rw-r--r--trunk/main/editline/sig.c198
-rw-r--r--trunk/main/editline/sig.h72
-rw-r--r--trunk/main/editline/sys.h123
-rw-r--r--trunk/main/editline/term.c1587
-rw-r--r--trunk/main/editline/term.h124
-rw-r--r--trunk/main/editline/tokenizer.c397
-rw-r--r--trunk/main/editline/tokenizer.h54
-rw-r--r--trunk/main/editline/tty.c1182
-rw-r--r--trunk/main/editline/tty.h484
-rw-r--r--trunk/main/editline/vi.c941
-rw-r--r--trunk/main/enum.c655
-rw-r--r--trunk/main/event.c822
-rw-r--r--trunk/main/file.c1245
-rw-r--r--trunk/main/fixedjitterbuf.c347
-rw-r--r--trunk/main/fixedjitterbuf.h93
-rw-r--r--trunk/main/frame.c1513
-rw-r--r--trunk/main/fskmodem.c360
-rw-r--r--trunk/main/global_datastores.c83
-rw-r--r--trunk/main/hashtab.c805
-rw-r--r--trunk/main/http.c1118
-rw-r--r--trunk/main/image.c208
-rw-r--r--trunk/main/indications.c598
-rw-r--r--trunk/main/io.c381
-rw-r--r--trunk/main/jitterbuf.c844
-rw-r--r--trunk/main/libresample/LICENSE.txt463
-rw-r--r--trunk/main/libresample/Makefile.asterisk11
-rw-r--r--trunk/main/libresample/Makefile.in52
-rw-r--r--trunk/main/libresample/README.txt84
-rwxr-xr-xtrunk/main/libresample/config.guess1432
-rwxr-xr-xtrunk/main/libresample/config.sub1537
-rwxr-xr-xtrunk/main/libresample/configure4552
-rw-r--r--trunk/main/libresample/configure.in68
-rw-r--r--trunk/main/libresample/include/libresample.h120
-rwxr-xr-xtrunk/main/libresample/install-sh251
-rw-r--r--trunk/main/libresample/src/configtemplate.h7
-rw-r--r--trunk/main/libresample/src/filterkit.c215
-rw-r--r--trunk/main/libresample/src/filterkit.h28
-rw-r--r--trunk/main/libresample/src/resample.c347
-rw-r--r--trunk/main/libresample/src/resample_defs.h88
-rw-r--r--trunk/main/libresample/src/resamplesubs.c123
-rw-r--r--trunk/main/libresample/tests/compareresample.c183
-rw-r--r--trunk/main/libresample/tests/resample-sndfile.c213
-rw-r--r--trunk/main/libresample/tests/testresample.c182
-rw-r--r--trunk/main/libresample/win/libresample.dsp116
-rw-r--r--trunk/main/libresample/win/libresample.vcproj192
-rw-r--r--trunk/main/loader.c1006
-rw-r--r--trunk/main/logger.c1203
-rw-r--r--trunk/main/manager.c3768
-rw-r--r--trunk/main/md5.c265
-rw-r--r--trunk/main/minimime/Make.conf7
-rw-r--r--trunk/main/minimime/Makefile67
-rw-r--r--trunk/main/minimime/mimeparser.h76
-rw-r--r--trunk/main/minimime/mimeparser.l484
-rw-r--r--trunk/main/minimime/mimeparser.tab.c2339
-rw-r--r--trunk/main/minimime/mimeparser.tab.h112
-rw-r--r--trunk/main/minimime/mimeparser.y748
-rw-r--r--trunk/main/minimime/mimeparser.yy.c2627
-rw-r--r--trunk/main/minimime/minimime.c244
-rw-r--r--trunk/main/minimime/mm.h367
-rw-r--r--trunk/main/minimime/mm_base64.c210
-rw-r--r--trunk/main/minimime/mm_codecs.c250
-rw-r--r--trunk/main/minimime/mm_contenttype.c759
-rw-r--r--trunk/main/minimime/mm_context.c614
-rw-r--r--trunk/main/minimime/mm_envelope.c271
-rw-r--r--trunk/main/minimime/mm_error.c123
-rw-r--r--trunk/main/minimime/mm_header.c213
-rw-r--r--trunk/main/minimime/mm_init.c65
-rw-r--r--trunk/main/minimime/mm_internal.h65
-rw-r--r--trunk/main/minimime/mm_mem.c170
-rw-r--r--trunk/main/minimime/mm_mem.h32
-rw-r--r--trunk/main/minimime/mm_mimepart.c659
-rw-r--r--trunk/main/minimime/mm_mimeutil.c137
-rw-r--r--trunk/main/minimime/mm_param.c225
-rw-r--r--trunk/main/minimime/mm_parse.c168
-rw-r--r--trunk/main/minimime/mm_queue.h508
-rw-r--r--trunk/main/minimime/mm_util.c412
-rw-r--r--trunk/main/minimime/mm_util.h50
-rw-r--r--trunk/main/minimime/mm_warnings.c99
-rw-r--r--trunk/main/minimime/strlcat.c70
-rw-r--r--trunk/main/minimime/strlcpy.c66
-rw-r--r--trunk/main/minimime/sys/mm_queue.h503
-rwxr-xr-xtrunk/main/minimime/test.sh54
-rw-r--r--trunk/main/minimime/tests/Makefile18
-rw-r--r--trunk/main/minimime/tests/create.c105
-rw-r--r--trunk/main/minimime/tests/messages/test1.txt50
-rw-r--r--trunk/main/minimime/tests/messages/test2.txt50
-rw-r--r--trunk/main/minimime/tests/messages/test3.txt12
-rw-r--r--trunk/main/minimime/tests/messages/test4.txt168
-rw-r--r--trunk/main/minimime/tests/messages/test5.txt44
-rw-r--r--trunk/main/minimime/tests/messages/test6.txt12
-rw-r--r--trunk/main/minimime/tests/messages/test7.txt64
-rw-r--r--trunk/main/minimime/tests/parse.c230
-rw-r--r--trunk/main/netsock.c208
-rw-r--r--trunk/main/pbx.c7800
-rw-r--r--trunk/main/plc.c248
-rw-r--r--trunk/main/poll.c306
-rw-r--r--trunk/main/privacy.c112
-rw-r--r--trunk/main/rtp.c4093
-rw-r--r--trunk/main/say.c7461
-rw-r--r--trunk/main/sched.c406
-rw-r--r--trunk/main/sha1.c337
-rw-r--r--trunk/main/slinfactory.c165
-rw-r--r--trunk/main/srv.c238
-rw-r--r--trunk/main/stdtime/Makefile29
-rw-r--r--trunk/main/stdtime/localtime.c1820
-rw-r--r--trunk/main/stdtime/private.h358
-rw-r--r--trunk/main/stdtime/test.c21
-rw-r--r--trunk/main/stdtime/tzfile.h184
-rw-r--r--trunk/main/strcompat.c463
-rw-r--r--trunk/main/tcptls.c452
-rw-r--r--trunk/main/tdd.c338
-rw-r--r--trunk/main/term.c297
-rw-r--r--trunk/main/threadstorage.c239
-rw-r--r--trunk/main/translate.c904
-rw-r--r--trunk/main/udptl.c1273
-rw-r--r--trunk/main/ulaw.c246
-rw-r--r--trunk/main/utils.c1557
-rw-r--r--trunk/makeopts.in227
-rwxr-xr-xtrunk/missing198
-rwxr-xr-xtrunk/mkinstalldirs40
-rw-r--r--trunk/pbx/Makefile32
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest10/extensions.ael131
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest12/extensions.ael13
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/extensions.ael7
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/qq.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t1/a.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t1/b.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t1/c.ael13
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t2/d.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t2/e.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t2/f.ael9
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/g.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/h.ael6
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/i.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-ntest22/t3/j.ael6
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-ntest9/extensions.ael12
-rw-r--r--trunk/pbx/ael/ael-test/ael-test1/extensions.ael163
-rw-r--r--trunk/pbx/ael/ael-test/ael-test11/extensions.ael57
-rw-r--r--trunk/pbx/ael/ael-test/ael-test14/extensions.ael20
-rw-r--r--trunk/pbx/ael/ael-test/ael-test15/extensions.ael17
-rw-r--r--trunk/pbx/ael/ael-test/ael-test16/extensions.ael4
-rw-r--r--trunk/pbx/ael/ael-test/ael-test18/extensions.ael40
-rw-r--r--trunk/pbx/ael/ael-test/ael-test19/extensions.ael377
-rw-r--r--trunk/pbx/ael/ael-test/ael-test2/apptest.ael2146
-rw-r--r--trunk/pbx/ael/ael-test/ael-test2/extensions.ael8
-rw-r--r--trunk/pbx/ael/ael-test/ael-test20/extensions.ael8
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-test3/extensions.ael3184
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include1.ael23
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include2.ael24
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include3.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include4.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-test3/include5.ael21
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-test3/telemarket_torture.ael2812
-rw-r--r--trunk/pbx/ael/ael-test/ael-test4/apptest.ael2146
-rw-r--r--trunk/pbx/ael/ael-test/ael-test4/extensions.ael8
-rw-r--r--trunk/pbx/ael/ael-test/ael-test5/extensions.ael838
-rw-r--r--trunk/pbx/ael/ael-test/ael-test6/extensions.ael833
-rw-r--r--trunk/pbx/ael/ael-test/ael-test7/extensions.ael460
-rw-r--r--trunk/pbx/ael/ael-test/ael-test8/extensions.ael27
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-vtest13/extensions.ael3183
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include1.ael23
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include2.ael24
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include3.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include4.ael22
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest13/include5.ael21
-rwxr-xr-xtrunk/pbx/ael/ael-test/ael-vtest13/telemarket_torture.ael2812
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest17/extensions.ael116
-rw-r--r--trunk/pbx/ael/ael-test/ael-vtest21/extensions.ael14
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest10171
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest1230
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest2254
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-ntest923
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test118
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1113
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1411
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1512
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1612
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1811
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test1918
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test228
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test2011
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test399
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test428
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test514
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test624
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test719
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-test811
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-vtest133030
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-vtest1769
-rw-r--r--trunk/pbx/ael/ael-test/ref.ael-vtest219
-rwxr-xr-xtrunk/pbx/ael/ael-test/runtests56
-rwxr-xr-xtrunk/pbx/ael/ael-test/setref7
-rw-r--r--trunk/pbx/dundi-parser.c846
-rw-r--r--trunk/pbx/dundi-parser.h88
-rw-r--r--trunk/pbx/pbx_ael.c313
-rw-r--r--trunk/pbx/pbx_config.c1668
-rw-r--r--trunk/pbx/pbx_dundi.c4847
-rw-r--r--trunk/pbx/pbx_gtkconsole.c502
-rw-r--r--trunk/pbx/pbx_loopback.c176
-rw-r--r--trunk/pbx/pbx_lua.c1354
-rw-r--r--trunk/pbx/pbx_realtime.c251
-rw-r--r--trunk/pbx/pbx_spool.c509
-rw-r--r--trunk/phoneprov/000000000000-directory.xml6
-rw-r--r--trunk/phoneprov/000000000000-phone.cfg1
-rw-r--r--trunk/phoneprov/000000000000.cfg2
-rw-r--r--trunk/phoneprov/polycom.xml37
-rw-r--r--trunk/redhat/asterisk.spec137
-rw-r--r--trunk/redhat/rpmmacros3
-rw-r--r--trunk/redhat/rpmrc3
-rw-r--r--trunk/res/Makefile53
-rw-r--r--trunk/res/ael/ael.flex694
-rw-r--r--trunk/res/ael/ael.tab.c3413
-rw-r--r--trunk/res/ael/ael.tab.h154
-rw-r--r--trunk/res/ael/ael.y823
-rw-r--r--trunk/res/ael/ael_lex.c3127
-rw-r--r--trunk/res/ael/pval.c5435
-rw-r--r--trunk/res/res_adsi.c1120
-rw-r--r--trunk/res/res_ael_share.c54
-rw-r--r--trunk/res/res_agi.c2992
-rw-r--r--trunk/res/res_clioriginate.c191
-rw-r--r--trunk/res/res_config_curl.c503
-rw-r--r--trunk/res/res_config_odbc.c739
-rw-r--r--trunk/res/res_config_pgsql.c1008
-rw-r--r--trunk/res/res_config_sqlite.c1534
-rw-r--r--trunk/res/res_convert.c160
-rw-r--r--trunk/res/res_crypto.c624
-rw-r--r--trunk/res/res_features.c3444
-rw-r--r--trunk/res/res_indications.c419
-rw-r--r--trunk/res/res_jabber.c3015
-rw-r--r--trunk/res/res_limit.c216
-rw-r--r--trunk/res/res_monitor.c765
-rw-r--r--trunk/res/res_musiconhold.c1566
-rw-r--r--trunk/res/res_odbc.c778
-rw-r--r--trunk/res/res_phoneprov.c1033
-rw-r--r--trunk/res/res_realtime.c129
-rw-r--r--trunk/res/res_smdi.c746
-rw-r--r--trunk/res/res_snmp.c121
-rw-r--r--trunk/res/res_speech.c344
-rw-r--r--trunk/res/snmp/agent.c842
-rw-r--r--trunk/res/snmp/agent.h40
-rw-r--r--trunk/sample.call80
-rw-r--r--trunk/sounds/Makefile157
-rw-r--r--trunk/sounds/sounds.xml68
-rw-r--r--trunk/static-http/ajamdemo.html219
-rw-r--r--trunk/static-http/astman.css34
-rw-r--r--trunk/static-http/astman.js262
-rw-r--r--trunk/static-http/prototype.js1781
-rw-r--r--trunk/tests/Makefile20
-rw-r--r--trunk/tests/test_skel.c54
-rw-r--r--trunk/utils/Makefile177
-rw-r--r--trunk/utils/ael_main.c584
-rw-r--r--trunk/utils/astcanary.c84
-rw-r--r--trunk/utils/astman.1102
-rw-r--r--trunk/utils/astman.c752
-rwxr-xr-xtrunk/utils/build-extensions-conf.lua81
-rw-r--r--trunk/utils/check_expr.c459
-rw-r--r--trunk/utils/clicompat.c16
-rw-r--r--trunk/utils/conf2ael.c692
-rw-r--r--trunk/utils/expr2.testinput126
-rw-r--r--trunk/utils/extconf.c6211
-rw-r--r--trunk/utils/frame.c1034
-rw-r--r--trunk/utils/frame.h300
-rw-r--r--trunk/utils/hashtest.c364
-rw-r--r--trunk/utils/hashtest2.c376
-rw-r--r--trunk/utils/muted.c698
-rw-r--r--trunk/utils/smsq.c771
-rw-r--r--trunk/utils/stereorize.c159
-rw-r--r--trunk/utils/streamplayer.c121
1092 files changed, 554646 insertions, 0 deletions
diff --git a/trunk/.cleancount b/trunk/.cleancount
new file mode 100644
index 000000000..bb95160cb
--- /dev/null
+++ b/trunk/.cleancount
@@ -0,0 +1 @@
+33
diff --git a/trunk/BUGS b/trunk/BUGS
new file mode 100644
index 000000000..96b55e655
--- /dev/null
+++ b/trunk/BUGS
@@ -0,0 +1,22 @@
+Asterisk Bug Tracking Information
+=================================
+
+To learn about and report Asterisk bugs, please visit
+the official Asterisk Bug Tracker at:
+
+ http://bugs.digium.com
+
+For more information on using the bug tracker, or to
+learn how you can contribute by acting as a bug marshal
+please see:
+
+ http://www.asterisk.org/developers/bug-guidelines
+
+If you would like to submit a feature request, please
+resist the temptation to post it to the bug tracker.
+Feature requests should be posted to the asterisk-dev
+mailing list, located at:
+
+ http://lists.digium.com
+
+Thank you!
diff --git a/trunk/CHANGES b/trunk/CHANGES
new file mode 100644
index 000000000..00757c4b1
--- /dev/null
+++ b/trunk/CHANGES
@@ -0,0 +1,496 @@
+------------------------------------------------------------------------------
+--- Functionality changes since Asterisk 1.4-beta was branched ----------------
+-------------------------------------------------------------------------------
+
+AMI - The manager (TCP/TLS/HTTP)
+--------------------------------
+ * Manager has undergone a lot of changes, all of them documented
+ in doc/manager_1_1.txt
+ * Manager version has changed to 1.1
+ * Added a new action 'CoreShowChannels' to list currently defined channels
+ and some information about them.
+ * Added a new action 'SIPshowregistry' to list SIP registrations.
+ * Added TLS support for the manager interface and HTTP server
+ * Added the URI redirect option for the built-in HTTP server
+ * The output of CallerID in Manager events is now more consistent.
+ CallerIDNum is used for number and CallerIDName for name.
+ * Enable https support for builtin web server.
+ See configs/http.conf.sample for details.
+ * Added a new action, GetConfigJSON, which can return the contents of an
+ Asterisk configuration file in JSON format. This is intended to help
+ improve the performance of AJAX applications using the manager interface
+ over HTTP.
+ * SIP and IAX manager events now use "ChannelType" in all cases where we
+ indicate channel driver. Previously, we used a mixture of "Channel"
+ and "ChannelDriver" headers.
+ * Added a "Bridge" action which allows you to bridge any two channels that
+ are currently active on the system.
+ * Added a "ListAllVoicemailUsers" action that allows you to get a list of all
+ the voicemail users setup.
+ * Added 'DBDel' and 'DBDelTree' manager commands.
+ * cdr_manager now reports events via the "cdr" level, separating it from
+ the very verbose "call" level.
+ * Manager users are now stored in memory. If you change the manager account
+ list (delete or add accounts) you need to reload manager.
+ * Added Masquerade manager event for when a masquerade happens between
+ two channels.
+ * Added "manager reload" command for the CLI
+ * Lots of commands that only provided information are now allowed under the
+ Reporting privilege, instead of only under Call or System.
+ * The IAX* commands now require either System or Reporting privilege, to
+ mirror the privileges of the SIP* commands.
+
+Dialplan functions
+------------------
+ * Added the DEVICE_STATE() dialplan function which allows retrieving any device
+ state in the dialplan, as well as creating custom device states that are
+ controllable from the dialplan.
+ * Extend CALLERID() function with "pres" and "ton" parameters to
+ fetch string representation of calling number presentation indicator
+ and numeric representation of type of calling number value.
+ * MailboxExists converted to dialplan function
+ * A new option to Dial() for telling IP phones not to count the call
+ as "missed" when dial times out and cancels.
+ * Added LOCK(), TRYLOCK(), and UNLOCK(), which provide a single level dialplan
+ mutex. No deadlocks are possible, as LOCK() only allows a single lock to be
+ held for any given channel. Also, locks are automatically freed when a
+ channel is hung up.
+ * Added HINT() dialplan function that allows retrieving hint information.
+ Hints are mappings between extensions and devices for the sake of
+ determining the state of an extension. This function can retrieve the list
+ of devices or the name associated with a hint.
+ * Added EXTENSION_STATE() dialplan function which allows retrieving the state
+ of any extension.
+ * Added SYSINFO() dialplan function which allows retrieval of system information
+ * Added a new dialplan function, DIALPLAN_EXISTS(), which allows you to check for
+ the existence of a dialplan target.
+ * Added two new dialplan functions, TOUPPER and TOLOWER, which convert a string to
+ upper and lower case, respectively.
+
+CLI Changes
+-----------
+ * New CLI command "core show hint" (usage: core show hint <exten>)
+ * New CLI command "core show settings"
+ * Added 'core show channels count' CLI command.
+ * Added the ability to set the core debug and verbose values on a per-file basis.
+ * Added 'queue pause member' and 'queue unpause member' CLI commands
+ * Ability to set process limits ("ulimit") without restarting Asterisk
+ * Enhanced "agi debug" to print the channel name as a prefix to the debug
+ output to make debugging on busy systems much easier.
+ * New CLI commands "dialplan set extenpatternmatching true/false"
+ * New CLI command: "core set chanvar" to set a channel variable from the CLI.
+ * Added an easy way to execute Asterisk CLI commands at startup. Any commands
+ listed in the startup_commands file in the Asterisk configuration directory
+ will get executed.
+
+SIP changes
+-----------
+ * Improved NAT and STUN support.
+ chan_sip now can use port numbers in bindaddr, externip and externhost
+ options, as well as contact a STUN server to detect its external address
+ for the SIP socket. See sip.conf.sample, 'NAT' section.
+ * The default SIP useragent= identifier now includes the Asterisk version
+ * A new option, match_auth_username in sip.conf changes the matching of incoming requests.
+ If set, and the incoming request carries authentication info,
+ the username to match in the users list is taken from the Digest header
+ rather than from the From: field. This feature is considered experimental.
+ * The "musiconhold" and "musicclass" settings in sip.conf are now removed,
+ since they where replaced by "mohsuggest" and "mohinterpret" in version 1.4
+ * The "localmask" setting was removed in version 1.2 and the reminder about it
+ being removed is now also removed.
+ * A new option "busylevel" for setting a level of calls where asterisk reports
+ a device as busy, to separate it from call-limit. This value is also added
+ to the SIP_PEER dialplan function.
+ * A new realtime family called "sipregs" is now supported to store SIP registration
+ data. If this family is defined, "sippeers" will be used for configuration and
+ "sipregs" for registrations. If it's not defined, "sippeers" will be used for
+ registration data, as before.
+ * The SIPPEER function have new options for port address, call and pickup groups
+ * Added support for T.140 realtime text in SIP/RTP
+ * The "checkmwi" option has been removed from sip.conf, as it is no longer
+ required due to the restructuring of how MWI is handled. See the descriptions
+ in this file of the "pollmailboxes" and "pollfreq" options to voicemail.conf
+ for more information.
+ * Added rtpdest option to CHANNEL() dialplan function.
+ * Added SIPREFERRINGCONTEXT and SIPREFERREDBYHDR variables which are set when a transfer takes place.
+ * SIP now adds a header to the CANCEL if the call was answered by another phone
+ in the same dial command, or if the new c option in dial() is used.
+ * The new default is that 100 Trying is not sent on REGISTER attempts as the RFC specifically
+ states it is not needed. For phones, however, that do require it the "registertrying" option
+ has been added so it can be enabled.
+ * A new option called "callcounter" (global/peer/user level) enables call counters needed
+ for better status reports needed for queues and SIP subscriptions. (Call-Limit was previously
+ used to enable this functionality).
+ * New settings for timer T1 and timer B on a global level or per device. This makes it
+ possible to force timeout faster on non-responsive SIP servers. These settings are
+ considered advanced, so don't use them unless you have a problem.
+ * Added a dial string option to be able to set the To: header in an INVITE to any
+ SIP uri.
+ * Added a new global and per-peer option, qualifyfreq, which allows you to configure
+ the qualify frequency.
+ * Added SIP Session Timers support (RFC 4028). This prevents stuck SIP sessions that
+ were not properly torn down due to network or endpoint failures during an established
+ SIP session.
+ * Added TCP and TLS support for SIP. See doc/siptls.txt and configs/sip.conf.sample for
+ more information on how it is used.
+
+IAX2 changes
+------------
+ * Added the trunkmaxsize configuration option to chan_iax2.
+ * Added the srvlookup option to iax.conf
+ * Added support for OSP. The token is set and retrieved through the CHANNEL()
+ dialplan function.
+
+XMPP Google Talk/Jingle changes
+-------------------------------
+ * Added the bindaddr option to gtalk.conf.
+
+Skinny changes
+-------------
+ * Added skinny show device, skinny show line, and skinny show settings CLI commands.
+ * Proper codec support in chan_skinny.
+ * Added settings for IP and Ethernet QoS requests
+
+MGCP changes
+------------
+ * Added separate settings for media QoS in mgcp.conf
+
+Console Channel Driver changes
+-------------------
+ * Added experimental support for video send & receive to chan_oss.
+ This requires SDL and ffmpeg/avcodec, plus Video4Linux or X11 to act as
+ a video source.
+
+Phone channel changes (chan_phone)
+----------------------------------
+ * Added G729 passthrough support to chan_phone for Sigma Designs boards.
+
+H.323 channel Changes
+---------------------
+ * H323 remote hold notification support added (by NOTIFY message
+ and/or H.450 supplementary service)
+
+Local channel changes
+---------------------
+ * The device state functionality in the Local channel driver has been updated
+ to indicate INUSE or NOT_INUSE when a Local channel is being used as opposed
+ to just UNKNOWN if the extension exists.
+ * Added jitterbuffer support for chan_local. This allows you to use the
+ generic jitterbuffer on incoming calls going to Asterisk applications.
+ For example, this would allow you to use a jitterbuffer for an incoming
+ SIP call to Voicemail by putting a Local channel in the middle. This
+ feature is enabled by using the 'j' option in the Dial string to the Local
+ channel in conjunction with the existing 'n' option for local channels.
+
+Zaptel channel driver (chan_zap) Changes
+----------------------------------------
+ * SS7 support in chan_zap (via libss7 library)
+ * In India, some carriers transmit CID via dtmf. Some code has been added
+ that will handle some situations. The cidstart=polarity_IN choice has been added for
+ those carriers that transmit CID via dtmf after a polarity change.
+ * CID matching information is now shown when doing 'dialplan show'.
+ * Added zap show version CLI command to chan_zap.
+ * Added setvar support to zapata.conf channel entries.
+ * Added two new options: mwimonitor and mwimonitornotify. These options allow
+ you to enable MWI monitoring on FXO lines. When the MWI state changes,
+ the script specified in the mwimonitornotify option is executed. An internal
+ event indicating the new state of the mailbox is also generated, so that
+ the normal MWI facilities in Asterisk work as usual.
+ * Added signalling type 'auto', which attempts to use the same signalling type
+ for a channel as configured in Zaptel. This is primarily designed for analog
+ ports, but will also work for digital ports that are configured for FXS or FXO
+ signalling types. This mode is also the default now, so if your zapata.conf
+ does not specify signalling for a channel (which is unlikely as the sample
+ configuration file has always recommended specifying it for every channel) then
+ the 'auto' mode will be used for that channel if possible.
+ * Added a 'zap set dnd' command to allow CLI control of the Do-Not-Disturb
+ state for a channel; also ensured that the DNDState Manager event is
+ emitted no matter how the DND state is set or cleared.
+
+New Channel Drivers
+-------------------
+ * Added a new channel driver, chan_unistim. See doc/unistim.txt and
+ configs/unistim.conf.sample for details. This new channel driver allows
+ you to use Nortel i2002, i2004, and i2050 phones with Asterisk.
+ * Added a new channel driver, chan_console, which uses portaudio as a cross
+ platform audio interface. It was written as a channel driver that would
+ work with Mac CoreAudio, but portaudio supports a number of other audio
+ interfaces, as well. Note that this channel driver requires v19 or higher
+ of portaudio; older versions have a different API.
+
+DUNDi changes
+-------------
+ * Added the ability to specify arguments to the Dial application when using
+ the DUNDi switch in the dialplan.
+ * Added the ability to set weights for responses dynamically. This can be
+ done using a global variable or a dialplan function. Using the SHELL()
+ function would allow you to have an external script set the weight for
+ each response.
+ * Added two new dialplan functions, DUNDIQUERY and DUNDIRESULT. These
+ functions will allow you to initiate a DUNDi query from the dialplan,
+ find out how many results there are, and access each one.
+
+ENUM changes
+------------
+ * Added two new dialplan functions, ENUMQUERY and ENUMRESULT. These
+ functions will allow you to initiate an ENUM lookup from the dialplan,
+ and Asterisk will cache the results. ENUMRESULT can be used to access
+ the results without doing multiple DNS queries.
+
+Voicemail Changes
+-----------------
+ * Added the ability to customize which sound files are used for some of the
+ prompts within the Voicemail application by changing them in voicemail.conf
+ * Added the ability for the "voicemail show users" CLI command to show users
+ configured by the dynamic realtime configuration method.
+ * MWI (Message Waiting Indication) handling has been significantly
+ restructured internally to Asterisk. It is now totally event based
+ instead of polling based. The voicemail application will notify other
+ modules that have subscribed to MWI events when something in the mailbox
+ changes.
+ This also means that if any other entity outside of Asterisk is changing
+ the contents of mailboxes, then the voicemail application still needs to
+ poll for changes. Examples of situations that would require this option
+ are web interfaces to voicemail or an email client in the case of using
+ IMAP storage. So, two new options have been added to voicemail.conf
+ to account for this: "pollmailboxes" and "pollfreq". See the sample
+ configuration file for details.
+ * Added "tw" language support
+ * Added support for storage of greetings using an IMAP server
+ * Added ability to customize forward, reverse, stop, and pause keys for message playback
+ * SMDI is now enabled in voicemail using the smdienable option.
+ * A "lockmode" option has been added to asterisk.conf to configure the file
+ locking method used for voicemail, and potentially other things in the
+ future. The default is the old behavior, lockfile. However, there is a
+ new method, "flock", that uses a different method for situations where the
+ lockfile will not work, such as on SMB/CIFS mounts.
+ * Added the ability to backup deleted messages, to ease recovery in the case
+ that a user accidentally deletes a message, and discovers that they need it.
+
+Queue changes
+-------------
+ * Added the general option 'shared_lastcall' so that member's wrapuptime may be
+ used across multiple queues.
+ * Added QUEUE_VARIABLES function to set queue variables added setqueuevar and
+ setqueueentryvar options for each queue, see queues.conf.sample for details.
+ * Added keepstats option to queues.conf which will keep queue
+ statistics during a reload.
+ * setinterfacevar option in queues.conf also now sets a variable
+ called MEMBERNAME which contains the member's name.
+ * Added 'Strategy' field to manager event QueueParams which represents
+ the queue strategy in use.
+ * Added option to run macro when a queue member is connected to a caller,
+ see queues.conf.sample for details.
+ * app_queue now has a 'loose' option which is almost exactly like 'strict' except it
+ does not count paused queue members as unavailable.
+ * Added min-announce-frequency option to queues.conf which allows you to control the
+ minimum amount of time between queue announcements for use when the caller's queue
+ position changes frequently.
+ * Added additional information to EXITWITHTIMEOUT and EXITWITHKEY events in the
+ queue log.
+ * Added ability for non-realtime queues to have realtime members
+ * Added the "linear" strategy to queues.
+ * Added the "wrandom" strategy to queues.
+ * Added new channel variable QUEUE_MIN_PENALTY
+ * QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY may be adjusted in mid-call by defining
+ rules in queuerules.conf. See configs/queuerules.conf.sample for details
+ * Added a new parameter for member definition, called state_interface. This may be
+ used so that a member may be called via one interface but have a different interface's
+ device state reported.
+
+MeetMe Changes
+--------------
+ * The 'o' option to provide an optimization has been removed and its functionality
+ has been enabled by default.
+ * When a conference is created, the UNIQUEID of the channel that caused it to be
+ created is stored. Then, every channel that joins the conference will have the
+ MEETMEUNIQUEID channel variable set with this ID. This can be used to relate
+ callers that come and go from long standing conferences.
+ * Added a new application, MeetMeChannelAdmin, which is similar to MeetMeAdmin,
+ except it does operations on a channel by name, instead of number in a conference.
+ This is a very useful feature in combination with the 'X' option to ChanSpy.
+ * Added 'C' option to Meetme which causes a caller to continue in the dialplan
+ when kicked out.
+ * Added new RealTime functionality to provide support for scheduled conferencing.
+ This includes optional messages to the caller if they attempt to join before
+ the schedule start time, or to allow the caller to join the conference early.
+ Also included is optional support for limiting the number of callers per
+ RealTime conference.
+ * Added the S() and L() options to the MeetMe application. These are pretty
+ much identical to the S() and L() options to Dial(). They let you set
+ timeouts for the conference, as well as have warning sounds played to
+ let the caller know how much time is left, and when it is running out.
+ * Added the ability to do "meetme concise" with the "meetme" CLI command.
+ This extends the concise capabilities of this CLI command to include
+ listing all conferences, instead of an addition to the other sub commands
+ for the "meetme" command.
+ * Added the ability to specify the music on hold class used to play into the
+ conference when there is only one member and the M option is used.
+
+Other Dialplan Application Changes
+----------------------------------
+ * Argument support for Gosub application
+ * From the to-do lists: straighten out the app timeout args:
+ Wait() app now really does 0.3 seconds- was truncating arg to an int.
+ WaitExten() same as Wait().
+ Congestion() - Now takes floating pt. argument.
+ Busy() - now takes floating pt. argument.
+ Read() - timeout now can be floating pt.
+ WaitForRing() now takes floating pt timeout arg.
+ SpeechBackground() -- clarified in the docstrings that the timeout is an integer seconds.
+ * Added 's' option to Page application.
+ * Added 'E' and 'V' commands to ExternalIVR.
+ * Added 'o' and 'X' options to Chanspy.
+ * Added a new dialplan application, Bridge, which allows you to bridge the
+ calling channel to any other active channel on the system.
+ * Added the ability to specify a music on hold class to play instead of ringing
+ for the SLATrunk application.
+ * The Read application no longer exits the dialplan on error. Instead, it sets
+ READSTATUS to ERROR, which you can catch and handle separately.
+ * Added 'm' option to Directory, which lists out names, 8 at a time, instead
+ of asking for verification of each name, one at a time.
+ * Privacy() no longer uses privacy.conf, as all options are specifyable as
+ direct options to the app.
+ * AMD() has a new "maximum word length" option. "show application AMD" from the CLI
+ for more details
+
+Music On Hold Changes
+---------------------
+ * A new option, "digit", has been added for music on hold classes in
+ musiconhold.conf. If this is set for a music on hold class, a caller
+ listening to music on hold can press this digit to switch to listening
+ to this music on hold class.
+ * Support for realtime music on hold has been added.
+ * In conjunction with the realtime music on hold, a general section has
+ been added to musiconhold.conf, its sole variable is cachertclasses. If this
+ is set, then music on hold classes found in realtime will be cached in memory.
+
+AEL Changes
+-----------
+ * AEL upgraded to use the Gosub with Arguments instead
+ of Macro application, to hopefully reduce the problems
+ seen with the artificially low stack ceiling that
+ Macro bumps into. Macros can only call other Macros
+ to a depth of 7. Tests run using gosub, show depths
+ limited only by virtual memory. A small test demonstrated
+ recursive call depths of 100,000 without problems.
+ -- in addition to this, all apps that allowed a macro
+ to be called, as in Dial, queues, etc, are now allowing
+ a gosub call in similar fashion.
+ * AEL now generates LOCAL(argname) declarations when it
+ Set()'s the each arg name to the value of ${ARG1}, ${ARG2),
+ etc. That makes the arguments local in scope. The user
+ can define their own local variables in macros, now,
+ by saying "local myvar=someval;" or using Set() in this
+ fashion: Set(LOCAL(myvar)=someval); ("local" is now
+ an AEL keyword).
+ * utils/conf2ael introduced. Will convert an extensions.conf
+ file into extensions.ael. Very crude and unfinished, but
+ will be improved as time goes by. Should be useful for a
+ first pass at conversion.
+ * aelparse will now read extensions.conf to see if a referenced
+ macro or context is there before issueing a warning.
+
+Call Features (res_features) Changes
+------------------------------------
+ * Added the parkedcalltransfers option to features.conf
+ * The built-in method for doing attended transfers has been updated to
+ include some new options that allow you to have the transferee sent
+ back to the person that did the transfer if the transfer is not successful.
+ See the options "atxferdropcall", "atxferloopdelay", and "atxfercallbackretries"
+ in features.conf.sample.
+ * Added support for configuring named groups of custom call features in
+ features.conf. This means that features can be written a single time, and
+ then mapped into groups of features for different key mappings or easier
+ access control.
+ * Updated the ParkedCall application to allow you to not specify a parking
+ extension. If you don't specify a parking space to pick up, it will grab
+ the first one available.
+
+Language Support Changes
+------------------------
+ * Brazilian Portuguese (pt-BR) in VM, and say.c was added
+ * Added support for the Hungarian language for saying numbers, dates, and times.
+
+AGI Changes
+-----------
+ * Added SPEECH commands for speech recognition. A complete listing can be found
+ using agi show.
+
+Logger changes
+--------------
+ * Added rotatestrategy option to logger.conf, along with two new options:
+ "timestamp" which will use the time to name the logger files instead of
+ sequence number; and "rotate", which rotates the names of the logfiles,
+ similar to the way syslog rotates files.
+ * Added exec_after_rotate option to logger.conf, which allows a system
+ command to be run after rotation. This is primarily useful with
+ rotatestrategry=rotate, to allow a limit on the number of logfiles kept
+ and to ensure that the oldest log file gets deleted.
+ * Added realtime support for the queue log
+
+Miscellaneous New Modules
+-------------------------
+ * Added a new CDR module, cdr_sqlite3_custom.
+ * Added a new realtime configuration module, res_config_sqlite
+ * Added a new codec translation module, codec_resample, which re-samples
+ signed linear audio between 8 kHz and 16 kHz to help support wideband
+ codecs.
+ * Added a new module, res_phoneprov, which allows auto-provisioning of phones
+ based on configuration templates that use Asterisk dialplan function and
+ variable substitution. It should be possible to create phone profiles and
+ templates that work for the majority of phones provisioned over http. It
+ is currently only intended to provision a single user account per phone.
+ An example profile and set of templates for Polycom phones is provided.
+ NOTE: Polycom firmware is not included, but should be placed in
+ AST_DATA_DIR/phoneprov/configs to match up with the included templates.
+ * Added a new module, app_jack, which provides interfaces to JACK, the Jack
+ Audio Connection Kit (http://www.jackaudio.org/). Two interfaces are
+ provided; there is a JACK() application, and a JACK_HOOK() function. Both
+ interfaces create an input and output JACK port. The application makes
+ these ports the endpoint of the call. The audio coming from the channel
+ goes out the output port and whatever comes back in on the input port is
+ what gets sent to the channel. The JACK_HOOK() function turns on a JACK
+ audiohook on the channel. This lets you run the audio coming from a
+ channel through JACK, and whatever comes back in is what gets forwarded
+ on as the channel's audio. This is very useful for building custom
+ vocoders or doing recording or analysis of the channel's audio in another
+ application.
+ * Added a new module, res_config_curl, which permits using a HTTP POST url
+ to retrieve, create, update, and delete realtime information from a remote
+ web server. Note that this module requires func_curl.so to be loaded for
+ backend functionality.
+
+Miscellaneous
+-------------
+ * Ability to use libcap to set high ToS bits when non-root
+ on Linux. If configure is unable to find libcap then you
+ can use --with-cap to specify the path.
+ * Added maxfiles option to options section of asterisk.conf which allows you to specify
+ what Asterisk should set as the maximum number of open files when it loads.
+ * Added the jittertargetextra configuration option.
+ * The cdr_manager module has a [mappings] feature, like cdr_custom,
+ to add fields to the manager event from the CDR variables.
+ * Added support for setting the CoS for VLAN traffic (802.1p). See the sample
+ configuration files for the IP channel drivers. The new option is "cos".
+ This information is also documented in doc/qos.tex, or the IP Quality of Service
+ section of asterisk.pdf.
+ * When originating a call using AMI or pbx_spool that fails the reason for failure
+ will now be available in the failed extension using the REASON dialplan variable.
+ * Added support for reading the TOUCH_MONITOR_PREFIX channel variable.
+ It allows you to configure a prefix for auto-monitor recordings.
+ * Added support for writing and running your dialplan in lua. See
+ configs/extensions.lua.sample for examples of how to do this.
+ * A new extension pattern matching algorithm, based on a trie, is introduced
+ here, that could noticeably speed up mid-sized to large dialplans.
+ It is NOT used by default, as duplicating the behaviour of the old pattern
+ matcher is still under development. A config file option, in extensions.conf,
+ in the [general] section, called "extenpatternmatchingnew", is by default
+ set to false; setting that to true will force the use of the new algorithm.
+ Also, the cli commands "dialplan set extenpatternmatchingnew true/false" can
+ be used to switch the algorithms at run time.
+ * A new option when starting a remote asterisk (rasterisk, asterisk -r) for
+ specifying which socket to use to connect to the running Asterisk daemon
+ (-s)
+ * Added logging to 'make update' command. See update.log
+
diff --git a/trunk/COPYING b/trunk/COPYING
new file mode 100644
index 000000000..aa2ebac66
--- /dev/null
+++ b/trunk/COPYING
@@ -0,0 +1,341 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/trunk/CREDITS b/trunk/CREDITS
new file mode 100644
index 000000000..a7a432d69
--- /dev/null
+++ b/trunk/CREDITS
@@ -0,0 +1,244 @@
+
+=== DEVELOPMENT SUPPORT ===
+We'd like to thank the following companies for helping fund development of
+Asterisk:
+
+Pilosoft, Inc. - for supporting ADSI development in Asterisk
+
+Asterlink, Inc. - for supporting broad Asterisk development
+
+GFS - for supporting ALSA development
+
+Telesthetic - for supporting SIP development
+
+Christos Ricudis - for substantial code contributions
+
+nic.at - ENUM support in Asterisk
+
+Paul Bagyenda, Digital Solutions - for initial Voicetronix driver development
+
+John Todd, TalkPlus, Inc. and JR Richardson, Ntegrated Solutions. - for funding
+ the development of SIP Session Timers support.
+
+=== WISHLIST CONTRIBUTERS ===
+Jeremy McNamara - SpeeX support
+Nick Seraphin - RDNIS support
+Gary - Phonejack ADSI (in progress)
+Wasim - Hangup detect
+
+=== HARDWARE DONORS ===
+* Thanks to QuickNet Technologies for their donation of an Internet
+PhoneJack and Linejack card to the project. (http://www.quicknet.net)
+
+* Thanks to VoipSupply for their donation of Sipura ATAs to the project for
+T.38 testing. (http://www.voipsupply.com)
+
+* Thanks to Grandstream for their donation of ATAs to the project for
+T.38 testing. (http://www.grandstream.com)
+
+=== MISCELLANEOUS PATCHES ===
+Jim Dixon - Zapata Telephony and app_rpt
+ http://www.zapatatelephony.org/app_rpt.html
+
+Russell Bryant - Asterisk release manager and countless enhancements and bug
+ fixes.
+ russell(AT)digium.com
+
+Anthony Minessale II - Countless big and small fixes, and relentless forward
+ push. ChanSpy, ForkCDR, ControlPlayback, While/EndWhile, DumpChan, Dictate,
+ MacroIf, ExecIf, ExecIfTime, RetryDial, MixMonitor applications; many
+ realtime concepts and implementation pieces, including res_config_odbc;
+ format_slin; cdr_custom; several features in Dial including L(), G() and
+ enhancements to M() and D(); several CDR enhancements including CDR
+ variables; attended transfer; one touch record; native MOH; manager
+ eventmask; command line '-t' flag to allow recording/voicemail on nfs
+ shares; #exec command and multiline comments in config files; setvar in iax
+ and sip configs.
+ anthmct(AT)yahoo.com http://www.asterlink.com
+
+James Golovich - Innumerable contributions, including SIP TCP and TLS support.
+ You can find him and asterisk-perl at http://asterisk.gnuinter.net
+
+Andre Bierwirth - Extension hints and status
+
+Jean-Denis Girard - Various contributions from the South Pacific Islands
+ jd-girard(AT)esoft.pf http://www.esoft.pf
+
+William Jordan / Vonage - MySQL enhancements to Voicemail
+ wjordan(AT)vonage.com
+
+Jac Kersing - Various fixes
+
+Steven Critchfield - Seek and Trunc functions for playback and recording
+ critch(AT)basesys.com
+
+Jefferson Noxon - app_lookupcidname, app_db, and various other contributions
+
+Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
+
+Ross Finlayson - Dynamic RTP payload support
+
+Mahmut Fettahlioglu - Audio recording, music-on-hold changes, alaw file
+ format, and various fixes. Can be contacted at mahmut(AT)oa.com.au
+
+James Dennis - Cisco SIP compatibility patches to work with SIP service
+ providers. Can be contacted at asterisk(AT)jdennis.net
+
+Tilghman Lesher - ast_localtime(); ast_say_date_with_format();
+ GotoIfTime, SayUnixTime, HasNewVoicemail applications;
+ CUT, SORT, EVAL, CURL, FIELDQTY, STRFTIME, some QUEUE* functions;
+ func_odbc, cdr_adaptive_odbc, and other innumerable bug fixes.
+ tilghman(AT)digium.com http://asterisk.drunkcoder.com/
+
+Jayson Vantuyl - Manager protocol changes, various other bugs.
+ jvantuyl(AT)computingedge.net
+
+Thorsten Lockert - OpenBSD, FreeBSD ports, making MacOS X port run on 10.3,
+ dialplan include verification, route lookup on OpenBSD, SNMP agent
+ support (res_snmp), various other bugs. tholo(AT)sigmasoft.com
+
+Josh Roberson - chan_zap reload support, Advanced Voicemail Features, & other
+ misc. patches. - josh(AT)asteriasgi.com, http://www.asteriasgi.com
+
+William Waites - syslog support, SIP NAT traversal for SIP-UA. ww(AT)styx.org
+
+Rich Murphey - Porting to FreeBSD, NetBSD, OpenBSD, and Darwin.
+ rich(AT)whiteoaklabs.com http://whiteoaklabs.com
+
+Simon Lockhart - Porting to Solaris (based on work of Logan ???)
+ simon(AT)slimey.org
+
+Olle E. Johansson - SIP RFC compliance, documentation and testing, testing,
+ testing; MiniVM - the small voicemail system, many documentation
+ updates/corrections, and many bug fixes.
+ oej(AT)edvina.net, http://edvina.net
+
+Steve Kann - new jitter buffer for IAX2
+ stevek(AT)stevek.com
+
+Constantine Filin - major contributions to the Asterisk Realtime Architecture
+
+Steve Murphy - privacy support, $[ ] parser upgrade, AEL2 parser upgrade.
+ murf(AT)digium.com
+
+Claude Patry - bug fixes, feature enhancements, and bug marshalling
+ cpatry(AT)gmail.com
+
+Miroslav Nachev, miro(AT)space-comm.com COSMOS Software Enterprises, Ltd.
+ - for Variable for No Answer Timeout for Attended Transfer
+
+Slav Klenov & Vanheuverzwijn Joachim - development of the generic jitterbuffer
+ Securax Ltd. info(AT)securax.be
+
+Roy Sigurd Karlsbakk - providing funding for generic jitterbuffer development
+ roy(AT)karlsbakk.net, Briiz Telecom AS
+
+Voop AS, Nuvio Inc, Inotel S.A and Foniris Telecom A/S - funding for rewrite
+ of SIP transfers
+
+Philippe Sultan - RADIUS CDR module, many fixes to res_jabber and gtalk/jingle
+ channel drivers.
+ INRIA, http://www.inria.fr/
+
+John Martin, Aupix - Improved video support in the SIP channel
+ T.140 text support in RTP/SIP
+
+Steve Underwood - Provided T.38 pass through support.
+
+George Konstantoulakis - Support for Greek in voicemail added by InAccess
+ Networks (work funded by HOL, www.hol.gr) gkon(AT)inaccessnetworks.com
+
+Daniel Nylander - Support for Swedish and Norwegian languages in voicemail.
+ http://www.danielnylander.se/
+
+Stojan Sljivic - An option for maximum number of messsages per mailbox in
+ voicemail. Also an issue with voicemail synchronization has been fixed.
+ GDS Partners www.gdspartners.com . stojan.sljivic(AT)gdspartners.com
+
+Bartosz Supczinski - Support for Polish added by DIR (www.dir.pl)
+ Bartosz.Supczinski(AT)dir.pl
+
+James Rothenberger - Support for IMAP storage integration added by
+ OneBizTone LLC Work funded by University of Pennsylvania jar(AT)onebiztone.com
+
+Paul Cadach - Bringing chan_h323 up to date, bug fixes, and more!
+
+Voop AS - Financial support for a lot of work with the SIP driver and the IAX
+ trunk MTU patch
+
+Cedric Hans - Development of chan_unistim
+ cedric.hans(AT)mlkj.net
+
+Sergio Fadda - console_video: video support for chan_oss and chan_alsa
+
+Marta Carbone - console_video and the astobj2 framework
+
+Luigi Rizzo - astobj2, console_video, windows build, chan_oss cleanup,
+ and a bunch of infrastructure work (loader, new_cli, ...)
+
+Brett Bryant - digit option for musiconhold selection, ENUMQUERY and ENUMRESULT functions,
+ feature group configuration for features.conf, per-file CLI debug and verbose settings,
+ TCP and TLS support for SIP, and various bug fixes.
+ brettbryant(AT)gmail.com
+
+=== OTHER CONTRIBUTIONS ===
+John Todd - Monkey sounds and associated teletorture prompt
+Michael Jerris - bug marshaling
+Leif Madsen, Jared Smith and Jim van Meggelen - the Asterisk book
+ available under a Creative Commons License at http://www.asteriskdocs.org
+Brian M. Clapper - poll.c emulation
+ This product includes software developed by Brian M. Clapper <bmc(AT)clapper.org>
+
+=== HOLD MUSIC ===
+Music provided by www.freeplaymusic.com
+
+=== OTHER SOURCE CODE IN ASTERISK ===
+Asterisk uses libedit, the lightweight readline replacement from NetBSD.
+The cdr_radius module uses libradiusclient-ng, which is also from NetBSD.
+They are BSD-licensed and require the following statement:
+
+ This product includes software developed by the NetBSD
+ Foundation, Inc. and its contributors.
+
+Digium did not implement the codecs in Asterisk. Here is the copyright on the
+GSM source:
+
+Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
+Technische Universitaet Berlin
+
+Any use of this software is permitted provided that this notice is not
+removed and that neither the authors nor the Technische Universitaet Berlin
+are deemed to have made any representations as to the suitability of this
+software for any purpose nor are held responsible for any defects of
+this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+
+As a matter of courtesy, the authors request to be informed about uses
+this software has found, about bugs in this software, and about any
+improvements that may be of general interest.
+
+Berlin, 28.11.1994
+Jutta Degener
+Carsten Bormann
+
+And the copyright on the ADPCM source:
+
+Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/trunk/LICENSE b/trunk/LICENSE
new file mode 100644
index 000000000..39e0bb8ae
--- /dev/null
+++ b/trunk/LICENSE
@@ -0,0 +1,69 @@
+Asterisk is distributed under the GNU General Public License version 2
+and is also available under alternative licenses negotiated directly
+with Digium, Inc. If you obtained Asterisk under the GPL, then the GPL
+applies to all loadable Asterisk modules used on your system as well,
+except as defined below. The GPL (version 2) is included in this
+source tree in the file COPYING.
+
+This package also includes various components that are not part of
+Asterisk itself; these components are in the 'contrib' directory
+and its subdirectories. Most of these components are also
+distributed under the GPL version 2 as well, except for the following:
+
+contrib/firmware/iax/iaxy.bin:
+ This file is Copyright (C) Digium, Inc. and is licensed for
+ use with Digium IAXy hardware devices only. It can be
+ distributed freely as long as the distribution is in the
+ original form present in this package (not reformatted or
+ modified).
+
+Digium, Inc. (formerly Linux Support Services) holds copyright
+and/or sufficient licenses to all components of the Asterisk
+package, and therefore can grant, at its sole discretion, the ability
+for companies, individuals, or organizations to create proprietary or
+Open Source (even if not GPL) modules which may be dynamically linked at
+runtime with the portions of Asterisk which fall under our
+copyright/license umbrella, or are distributed under more flexible
+licenses than GPL.
+
+If you wish to use our code in other GPL programs, don't worry --
+there is no requirement that you provide the same exception in your
+GPL'd products (although if you've written a module for Asterisk we
+would strongly encourage you to make the same exception that we do).
+
+Specific permission is also granted to link Asterisk with OpenSSL and
+OpenH323 and distribute the resulting binary files.
+
+In addition, Asterisk implements two management/control protocols: the
+Asterisk Manager Interface (AMI) and the Asterisk Gateway Interface
+(AGI). It is our belief that applications using these protocols to
+manage or control an Asterisk instance do not have to be licensed
+under the GPL or a compatible license, as we believe these protocols
+do not create a 'derivative work' as referred to in the GPL. However,
+should any court or other judiciary body find that these protocols do
+fall under the terms of the GPL, then we hereby grant you a license to
+use these protocols in combination with Asterisk in external
+applications licensed under any license you wish.
+
+The 'Asterisk' name and logos are trademarks owned by Digium, Inc.,
+and use of them is subject to our trademark licensing policies. If you
+wish to use these trademarks for purposes other than simple
+redistribution of Asterisk source code obtained from Digium, you
+should contact our licensing department to determine the necessary
+steps you must take. For more information on this policy, please read:
+
+http://www.digium.com/en/company/profile/trademarkpolicy.php
+
+If you have any questions regarding our licensing policy, please
+contact us:
+
++1.877.344.4861 (via telephone in the USA)
++1.256.428.6000 (via telephone outside the USA)
++1.256.864.0464 (via FAX inside or outside the USA)
+IAX2/misery.digium.com/6000 (via IAX2)
+licensing@digium.com (via email)
+
+Digium, Inc.
+445 Jan Davis Drive
+Huntsville, AL 35806
+USA
diff --git a/trunk/Makefile b/trunk/Makefile
new file mode 100644
index 000000000..5b8951809
--- /dev/null
+++ b/trunk/Makefile
@@ -0,0 +1,834 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Top level Makefile
+#
+# Copyright (C) 1999-2006, Digium, Inc.
+#
+# Mark Spencer <markster@digium.com>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+# All Makefiles use the following variables:
+#
+# ASTCFLAGS - compiler options
+# ASTLDFLAGS - linker flags (not libraries)
+# LIBS - additional libraries, at top-level for all links,
+# on a single object just for that object
+# SOLINK - linker flags used only for creating shared objects (.so files),
+# used for all .so links
+#
+# Initial values for ASTCFLAGS and ASTLDFLAGS can be specified in the
+# environment when running make, as follows:
+#
+# $ ASTCFLAGS="-Werror" make ...
+#
+# note that this is different from
+#
+# $ make ASTCFLAGS="-Werror" ...
+#
+# If you need to pass compiler/linker flags as 'make' variables, please use
+#
+# $ make COPTS="..." LDOPTS="..." ...
+#
+#
+# You can add the path of local module subdirs from the command line with
+# make LOCAL_MOD_SUBDIRS= ....
+
+export ASTTOPDIR # Top level dir, used in subdirs' Makefiles
+export ASTERISKVERSION
+export ASTERISKVERSIONNUM
+
+#--- values used for default paths
+
+# DESTDIR is the staging (or final) directory where files are copied
+# during the install process. Define it before 'export', otherwise
+# export will set it to the empty string making ?= fail.
+# WARNING: do not put spaces or comments after the value.
+DESTDIR?=$(INSTALL_PATH)
+export DESTDIR
+
+export INSTALL_PATH # Additional prefix for the following paths
+export ASTETCDIR # Path for config files
+export ASTVARRUNDIR
+export MODULES_DIR
+export ASTSPOOLDIR
+export ASTVARLIBDIR
+export ASTDATADIR
+export ASTLOGDIR
+export ASTLIBDIR
+export ASTMANDIR
+export ASTHEADERDIR
+export ASTBINDIR
+export ASTSBINDIR
+export AGI_DIR
+export ASTCONFPATH
+
+export OSARCH # Operating system
+export PROC # Processor type
+
+export NOISY_BUILD # Used in Makefile.rules
+export MENUSELECT_CFLAGS # Options selected in menuselect.
+export AST_DEVMODE # Set to "yes" for additional compiler
+ # and runtime checks
+
+export SOLINK # linker flags for shared objects
+export STATIC_BUILD # Additional cflags, set to -static
+ # for static builds. Probably
+ # should go directly to ASTLDFLAGS
+
+#--- paths to various commands
+export CC
+export CXX
+export AR
+export RANLIB
+export HOST_CC
+export INSTALL
+export STRIP
+export DOWNLOAD
+export AWK
+export GREP
+export ID
+
+# even though we could use '-include makeopts' here, use a wildcard
+# lookup anyway, so that make won't try to build makeopts if it doesn't
+# exist (other rules will force it to be built if needed)
+ifneq ($(wildcard makeopts),)
+ include makeopts
+endif
+
+# Some build systems, such as the one in openwrt, like to pass custom target
+# CFLAGS and LDFLAGS in the COPTS and LDOPTS variables.
+ASTCFLAGS+=$(COPTS)
+ASTLDFLAGS+=$(LDOPTS)
+
+#Uncomment this to see all build commands instead of 'quiet' output
+#NOISY_BUILD=yes
+
+ASTTOPDIR:=$(CURDIR)
+
+# Overwite config files on "make samples"
+OVERWRITE=y
+
+# Include debug and macro symbols in the executables (-g) and profiling info (-pg)
+DEBUG=-g3
+
+
+# Define standard directories for various platforms
+# These apply if they are not redefined in asterisk.conf
+ifeq ($(OSARCH),SunOS)
+ ASTETCDIR=/var/etc/asterisk
+ ASTLIBDIR=/opt/asterisk/lib
+ ASTVARLIBDIR=/var/opt/asterisk
+ ASTDBDIR=$(ASTVARLIBDIR)
+ ASTKEYDIR=$(ASTVARLIBDIR)
+ ASTSPOOLDIR=/var/spool/asterisk
+ ASTLOGDIR=/var/log/asterisk
+ ASTHEADERDIR=/opt/asterisk/include
+ ASTBINDIR=/opt/asterisk/bin
+ ASTSBINDIR=/opt/asterisk/sbin
+ ASTVARRUNDIR=/var/run/asterisk
+ ASTMANDIR=/opt/asterisk/man
+else
+ ASTETCDIR=$(sysconfdir)/asterisk
+ ASTLIBDIR=$(libdir)/asterisk
+ ASTHEADERDIR=$(includedir)/asterisk
+ ASTBINDIR=$(bindir)
+ ASTSBINDIR=$(sbindir)
+ ASTSPOOLDIR=$(localstatedir)/spool/asterisk
+ ASTLOGDIR=$(localstatedir)/log/asterisk
+ ASTVARRUNDIR=$(localstatedir)/run
+ ASTMANDIR=$(mandir)
+ifneq ($(findstring BSD,$(OSARCH)),)
+ ASTVARLIBDIR=$(prefix)/share/asterisk
+ ASTVARRUNDIR=$(localstatedir)/run/asterisk
+ ASTDBDIR=$(localstatedir)/db/asterisk
+else
+ ASTVARLIBDIR=$(localstatedir)/lib/asterisk
+ ASTDBDIR=$(ASTVARLIBDIR)
+endif
+ ASTKEYDIR=$(ASTVARLIBDIR)
+endif
+ifeq ($(ASTDATADIR),)
+ ASTDATADIR:=$(ASTVARLIBDIR)
+endif
+
+# Asterisk.conf is located in ASTETCDIR or by using the -C flag
+# when starting Asterisk
+ASTCONFPATH=$(ASTETCDIR)/asterisk.conf
+MODULES_DIR=$(ASTLIBDIR)/modules
+AGI_DIR=$(ASTDATADIR)/agi-bin
+
+# If you use Apache, you may determine by a grep 'DocumentRoot' of your httpd.conf file
+HTTP_DOCSDIR=/var/www/html
+# Determine by a grep 'ScriptAlias' of your Apache httpd.conf file
+HTTP_CGIDIR=/var/www/cgi-bin
+
+# Uncomment this to use the older DSP routines
+#ASTCFLAGS+=-DOLD_DSP_ROUTINES
+
+# If the file .asterisk.makeopts is present in your home directory, you can
+# include all of your favorite menuselect options so that every time you download
+# a new version of Asterisk, you don't have to run menuselect to set them.
+# The file /etc/asterisk.makeopts will also be included but can be overridden
+# by the file in your home directory.
+
+GLOBAL_MAKEOPTS=$(wildcard /etc/asterisk.makeopts)
+USER_MAKEOPTS=$(wildcard ~/.asterisk.makeopts)
+
+MOD_SUBDIR_CFLAGS=-I$(ASTTOPDIR)/include
+OTHER_SUBDIR_CFLAGS=-I$(ASTTOPDIR)/include
+
+# Create OPTIONS variable, but probably we can assign directly to ASTCFLAGS
+OPTIONS=
+
+ifeq ($(OSARCH),linux-gnu)
+ ifeq ($(PROC),x86_64)
+ # You must have GCC 3.4 to use k8, otherwise use athlon
+ PROC=k8
+ #PROC=athlon
+ endif
+
+ ifeq ($(PROC),sparc64)
+ #The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only.
+ #This works for even old (2.96) versions of gcc and provides a small boost either way.
+ #A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesn't support it.
+ #So we go lowest common available by gcc and go a step down, still a step up from
+ #the default as we now have a better instruction set to work with. - Belgarath
+ PROC=ultrasparc
+ OPTIONS+=$(shell if $(CC) -mtune=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mtune=$(PROC)"; fi)
+ OPTIONS+=$(shell if $(CC) -mcpu=v8 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mcpu=v8"; fi)
+ OPTIONS+=-fomit-frame-pointer
+ endif
+
+ ifeq ($(PROC),arm)
+ # The Cirrus logic is the only heavily shipping arm processor with a real floating point unit
+ ifeq ($(SUB_PROC),maverick)
+ OPTIONS+=-fsigned-char -mcpu=ep9312
+ else
+ ifeq ($(SUB_PROC),xscale)
+ OPTIONS+=-fsigned-char -mcpu=xscale
+ else
+ OPTIONS+=-fsigned-char
+ endif
+ endif
+ endif
+endif
+
+ifeq ($(findstring -save-temps,$(ASTCFLAGS)),)
+ASTCFLAGS+=-pipe
+endif
+
+ASTCFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG)
+
+ASTCFLAGS+=-include $(ASTTOPDIR)/include/asterisk/autoconfig.h
+
+ifeq ($(AST_DEVMODE),yes)
+ ASTCFLAGS+=-Werror -Wunused -Wundef $(AST_DECLARATION_AFTER_STATEMENT)
+endif
+
+ifneq ($(findstring BSD,$(OSARCH)),)
+ ASTCFLAGS+=-I/usr/local/include
+ ASTLDFLAGS+=-L/usr/local/lib
+endif
+
+ifneq ($(PROC),ultrasparc)
+ ASTCFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
+endif
+
+ifeq ($(PROC),ppc)
+ ASTCFLAGS+=-fsigned-char
+endif
+
+ifeq ($(OSARCH),FreeBSD)
+ # -V is understood by BSD Make, not by GNU make.
+ BSDVERSION=$(shell make -V OSVERSION -f /usr/share/mk/bsd.port.subdir.mk)
+ ASTCFLAGS+=$(shell if test $(BSDVERSION) -lt 500016 ; then echo "-D_THREAD_SAFE"; fi)
+endif
+
+ifeq ($(OSARCH),NetBSD)
+ ASTCFLAGS+=-pthread -I/usr/pkg/include
+endif
+
+ifeq ($(OSARCH),OpenBSD)
+ ASTCFLAGS+=-pthread
+endif
+
+ifeq ($(OSARCH),SunOS)
+ ASTCFLAGS+=-Wcast-align -DSOLARIS -I../include/solaris-compat -I/opt/ssl/include -I/usr/local/ssl/include -D_XPG4_2
+endif
+
+ASTERISKVERSION:=$(shell GREP=$(GREP) AWK=$(AWK) build_tools/make_version .)
+
+ifneq ($(wildcard .version),)
+ ASTERISKVERSIONNUM:=$(shell $(AWK) -F. '{printf "%01d%02d%02d", $$1, $$2, $$3}' .version)
+ RPMVERSION:=$(shell sed 's/[-\/:]/_/g' .version)
+else
+ RPMVERSION=unknown
+endif
+
+ifneq ($(wildcard .svn),)
+ ASTERISKVERSIONNUM:=999999
+endif
+
+# XXX MALLOC_DEBUG is probably unused, Makefile.moddir_rules adds the
+# value directly to ASTCFLAGS
+ASTCFLAGS+=$(MALLOC_DEBUG)$(OPTIONS)
+
+MOD_SUBDIRS:=channels pbx apps codecs formats cdr funcs tests main res $(LOCAL_MOD_SUBDIRS)
+OTHER_SUBDIRS:=utils agi
+SUBDIRS:=$(OTHER_SUBDIRS) $(MOD_SUBDIRS)
+SUBDIRS_INSTALL:=$(SUBDIRS:%=%-install)
+SUBDIRS_CLEAN:=$(SUBDIRS:%=%-clean)
+SUBDIRS_DIST_CLEAN:=$(SUBDIRS:%=%-dist-clean)
+SUBDIRS_UNINSTALL:=$(SUBDIRS:%=%-uninstall)
+MOD_SUBDIRS_EMBED_LDSCRIPT:=$(MOD_SUBDIRS:%=%-embed-ldscript)
+MOD_SUBDIRS_EMBED_LDFLAGS:=$(MOD_SUBDIRS:%=%-embed-ldflags)
+MOD_SUBDIRS_EMBED_LIBS:=$(MOD_SUBDIRS:%=%-embed-libs)
+MOD_SUBDIRS_MENUSELECT_TREE:=$(MOD_SUBDIRS:%=%-menuselect-tree)
+
+ifneq ($(findstring darwin,$(OSARCH)),)
+ ASTCFLAGS+=-D__Darwin__
+ SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace
+else
+# These are used for all but Darwin
+ SOLINK=-shared -Xlinker -x
+ ifneq ($(findstring BSD,$(OSARCH)),)
+ LDFLAGS+=-L/usr/local/lib
+ endif
+endif
+
+ifeq ($(OSARCH),SunOS)
+ SOLINK=-shared -fpic -L/usr/local/ssl/lib
+endif
+
+# comment to print directories during submakes
+#PRINT_DIR=yes
+
+SILENTMAKE:=$(MAKE) --quiet --no-print-directory
+ifneq ($(PRINT_DIR)$(NOISY_BUILD),)
+SUBMAKE:=$(MAKE) --quiet
+else
+SUBMAKE:=$(MAKE) --quiet --no-print-directory
+endif
+
+# This is used when generating the doxygen documentation
+ifneq ($(DOT),:)
+ HAVEDOT=yes
+else
+ HAVEDOT=no
+endif
+
+# $(MAKE) is printed in several places, and we want it to be a
+# fixed size string. Define a variable whose name has also the
+# same size, so we can easily align text.
+ifeq ($(MAKE), gmake)
+ mK="gmake"
+else
+ mK=" make"
+endif
+
+all: _all
+ @echo " +--------- Asterisk Build Complete ---------+"
+ @echo " + Asterisk has successfully been built, and +"
+ @echo " + can be installed by running: +"
+ @echo " + +"
+ @echo " + $(mK) install +"
+ @echo " +-------------------------------------------+"
+
+_all: cleantest makeopts $(SUBDIRS)
+
+makeopts: configure
+ @echo "****"
+ @echo "**** The configure script must be executed before running '$(MAKE)'."
+ @echo "**** Please run \"./configure\"."
+ @echo "****"
+ @exit 1
+
+menuselect.makeopts: menuselect/menuselect menuselect-tree
+ menuselect/menuselect --check-deps $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts
+
+$(MOD_SUBDIRS_EMBED_LDSCRIPT):
+ @echo "EMBED_LDSCRIPTS+="`$(SILENTMAKE) -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
+
+$(MOD_SUBDIRS_EMBED_LDFLAGS):
+ @echo "EMBED_LDFLAGS+="`$(SILENTMAKE) -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules
+
+$(MOD_SUBDIRS_EMBED_LIBS):
+ @echo "EMBED_LIBS+="`$(SILENTMAKE) -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules
+
+$(MOD_SUBDIRS_MENUSELECT_TREE):
+ @$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) moduleinfo
+ @$(SUBMAKE) -C $(@:-menuselect-tree=) SUBDIR=$(@:-menuselect-tree=) makeopts
+
+makeopts.embed_rules: menuselect.makeopts
+ @echo "Generating embedded module rules ..."
+ @rm -f $@
+ @$(MAKE) $(PRINT_DIR) $(MOD_SUBDIRS_EMBED_LDSCRIPT)
+ @$(MAKE) $(PRINT_DIR) $(MOD_SUBDIRS_EMBED_LDFLAGS)
+ @$(MAKE) $(PRINT_DIR) $(MOD_SUBDIRS_EMBED_LIBS)
+
+$(SUBDIRS): main/version.c include/asterisk/build.h include/asterisk/buildopts.h defaults.h makeopts.embed_rules
+
+ifeq ($(findstring $(OSARCH), mingw32 cygwin ),)
+ # Non-windows:
+ # ensure that all module subdirectories are processed before 'main' during
+ # a parallel build, since if there are modules selected to be embedded the
+ # directories containing them must be completed before the main Asterisk
+ # binary can be built
+main: $(filter-out main,$(MOD_SUBDIRS))
+else
+ # Windows: we need to build main (i.e. the asterisk dll) first,
+ # followed by res, followed by the other directories, because
+ # dll symbols must be resolved during linking and not at runtime.
+D1:= $(filter-out main,$(MOD_SUBDIRS))
+D1:= $(filter-out res,$(D1))
+
+$(D1): res
+res: main
+endif
+
+$(MOD_SUBDIRS):
+ @ASTCFLAGS="$(MOD_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" $(MAKE) $(PRINT_DIR) --no-builtin-rules -C $@ SUBDIR=$@ all
+
+$(OTHER_SUBDIRS):
+ @ASTCFLAGS="$(OTHER_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" $(MAKE) $(PRINT_DIR) --no-builtin-rules -C $@ SUBDIR=$@ all
+
+defaults.h: makeopts
+ @build_tools/make_defaults_h > $@.tmp
+ @cmp -s $@.tmp $@ || mv $@.tmp $@
+ @rm -f $@.tmp
+
+main/version.c:
+ @build_tools/make_version_c > $@.tmp
+ @cmp -s $@.tmp $@ || mv $@.tmp $@
+ @rm -f $@.tmp
+
+include/asterisk/buildopts.h: menuselect.makeopts
+ @build_tools/make_buildopts_h > $@.tmp
+ @cmp -s $@.tmp $@ || mv $@.tmp $@
+ @rm -f $@.tmp
+
+include/asterisk/build.h:
+ @build_tools/make_build_h > $@.tmp
+ @cmp -s $@.tmp $@ || mv $@.tmp $@
+ @rm -f $@.tmp
+
+$(SUBDIRS_CLEAN):
+ @$(MAKE) $(PRINT_DIR) -C $(@:-clean=) clean
+
+$(SUBDIRS_DIST_CLEAN):
+ @$(MAKE) $(PRINT_DIR) -C $(@:-dist-clean=) dist-clean
+
+clean: $(SUBDIRS_CLEAN)
+ rm -f defaults.h
+ rm -f include/asterisk/build.h
+ rm -f main/version.c
+ @$(MAKE) -C menuselect clean
+ cp -f .cleancount .lastclean
+
+dist-clean: distclean
+
+distclean: $(SUBDIRS_DIST_CLEAN) clean
+ @$(MAKE) -C menuselect dist-clean
+ @$(MAKE) -C sounds dist-clean
+ rm -f menuselect.makeopts makeopts menuselect-tree menuselect.makedeps
+ rm -f makeopts.embed_rules
+ rm -f config.log config.status
+ rm -rf autom4te.cache
+ rm -f include/asterisk/autoconfig.h
+ rm -f include/asterisk/buildopts.h
+ rm -rf doc/api
+ rm -f build_tools/menuselect-deps
+
+datafiles: _all
+ if [ x`$(ID) -un` = xroot ]; then CFLAGS="$(ASTCFLAGS)" sh build_tools/mkpkgconfig $(DESTDIR)/usr/lib/pkgconfig; fi
+# Should static HTTP be installed during make samples or even with its own target ala
+# webvoicemail? There are portions here that *could* be customized but might also be
+# improved a lot. I'll put it here for now.
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/phoneprov
+ for x in phoneprov/*; do \
+ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/phoneprov ; \
+ done
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/static-http
+ for x in static-http/*; do \
+ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/static-http ; \
+ done
+ if [ -d doc/tex/asterisk ] ; then \
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/static-http/docs ; \
+ for n in doc/tex/asterisk/* ; do \
+ $(INSTALL) -m 644 $$n $(DESTDIR)$(ASTDATADIR)/static-http/docs ; \
+ done \
+ fi
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/images
+ for x in images/*.jpg; do \
+ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/images ; \
+ done
+ mkdir -p $(DESTDIR)$(AGI_DIR)
+ $(MAKE) -C sounds install
+
+update:
+ @if [ -d .svn ]; then \
+ echo "Updating from Subversion..." ; \
+ fromrev="`svn info | $(AWK) '/Revision: / {print $$2}'`"; \
+ svn update | tee update.out; \
+ torev="`svn info | $(AWK) '/Revision: / {print $$2}'`"; \
+ echo "`date` Updated from revision $${fromrev} to $${torev}." >> update.log; \
+ rm -f .version; \
+ if [ `grep -c ^C update.out` -gt 0 ]; then \
+ echo ; echo "The following files have conflicts:" ; \
+ grep ^C update.out | cut -b4- ; \
+ fi ; \
+ rm -f update.out; \
+ else \
+ echo "Not under version control"; \
+ fi
+
+NEWHEADERS=$(notdir $(wildcard include/asterisk/*.h))
+OLDHEADERS=$(filter-out $(NEWHEADERS),$(notdir $(wildcard $(DESTDIR)$(ASTHEADERDIR)/*.h)))
+
+bininstall: _all
+ mkdir -p $(DESTDIR)$(MODULES_DIR)
+ mkdir -p $(DESTDIR)$(ASTSBINDIR)
+ mkdir -p $(DESTDIR)$(ASTETCDIR)
+ mkdir -p $(DESTDIR)$(ASTBINDIR)
+ mkdir -p $(DESTDIR)$(ASTVARRUNDIR)
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/dictate
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/system
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/tmp
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/meetme
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/monitor
+ $(INSTALL) -m 755 main/asterisk $(DESTDIR)$(ASTSBINDIR)/
+ $(LN) -sf asterisk $(DESTDIR)$(ASTSBINDIR)/rasterisk
+ $(INSTALL) -m 755 contrib/scripts/astgenkey $(DESTDIR)$(ASTSBINDIR)/
+ $(INSTALL) -m 755 contrib/scripts/autosupport $(DESTDIR)$(ASTSBINDIR)/
+ if [ ! -f $(DESTDIR)$(ASTSBINDIR)/safe_asterisk ]; then \
+ cat contrib/scripts/safe_asterisk | sed 's|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)$(ASTSBINDIR)/safe_asterisk ;\
+ chmod 755 $(DESTDIR)$(ASTSBINDIR)/safe_asterisk;\
+ fi
+ $(INSTALL) -d $(DESTDIR)$(ASTHEADERDIR)
+ $(INSTALL) -m 644 include/asterisk.h $(DESTDIR)$(includedir)
+ $(INSTALL) -m 644 include/asterisk/*.h $(DESTDIR)$(ASTHEADERDIR)
+ if [ -n "$(OLDHEADERS)" ]; then \
+ rm -f $(addprefix $(DESTDIR)$(ASTHEADERDIR)/,$(OLDHEADERS)) ;\
+ fi
+ mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-csv
+ mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-custom
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/keys
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware
+ mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware/iax
+ mkdir -p $(DESTDIR)$(ASTMANDIR)/man8
+ $(INSTALL) -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTDATADIR)/keys
+ $(INSTALL) -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTDATADIR)/keys
+ $(INSTALL) -m 644 doc/asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8
+ $(INSTALL) -m 644 contrib/scripts/astgenkey.8 $(DESTDIR)$(ASTMANDIR)/man8
+ $(INSTALL) -m 644 contrib/scripts/autosupport.8 $(DESTDIR)$(ASTMANDIR)/man8
+ $(INSTALL) -m 644 contrib/scripts/safe_asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8
+ if [ -f contrib/firmware/iax/iaxy.bin ] ; then \
+ $(INSTALL) -m 644 contrib/firmware/iax/iaxy.bin $(DESTDIR)$(ASTDATADIR)/firmware/iax/iaxy.bin; \
+ fi
+
+$(SUBDIRS_INSTALL):
+ @DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" $(MAKE) --quiet $(PRINT_DIR) -C $(@:-install=) install
+
+NEWMODS:=$(foreach d,$(MOD_SUBDIRS),$(notdir $(wildcard $(d)/*.so)))
+OLDMODS=$(filter-out $(NEWMODS),$(notdir $(wildcard $(DESTDIR)$(MODULES_DIR)/*.so)))
+
+oldmodcheck:
+ @if [ -n "$(OLDMODS)" ]; then \
+ echo " WARNING WARNING WARNING" ;\
+ echo "" ;\
+ echo " Your Asterisk modules directory, located at" ;\
+ echo " $(DESTDIR)$(MODULES_DIR)" ;\
+ echo " contains modules that were not installed by this " ;\
+ echo " version of Asterisk. Please ensure that these" ;\
+ echo " modules are compatible with this version before" ;\
+ echo " attempting to run Asterisk." ;\
+ echo "" ;\
+ for f in $(OLDMODS); do \
+ echo " $$f" ;\
+ done ;\
+ echo "" ;\
+ echo " WARNING WARNING WARNING" ;\
+ fi
+
+install: datafiles bininstall $(SUBDIRS_INSTALL)
+ @if [ -x /usr/sbin/asterisk-post-install ]; then \
+ /usr/sbin/asterisk-post-install $(DESTDIR) . ; \
+ fi
+ @echo " +---- Asterisk Installation Complete -------+"
+ @echo " + +"
+ @echo " + YOU MUST READ THE SECURITY DOCUMENT +"
+ @echo " + +"
+ @echo " + Asterisk has successfully been installed. +"
+ @echo " + If you would like to install the sample +"
+ @echo " + configuration files (overwriting any +"
+ @echo " + existing config files), run: +"
+ @echo " + +"
+ @echo " + $(mK) samples +"
+ @echo " + +"
+ @echo " +----------------- or ---------------------+"
+ @echo " + +"
+ @echo " + You can go ahead and install the asterisk +"
+ @echo " + program documentation now or later run: +"
+ @echo " + +"
+ @echo " + $(mK) progdocs +"
+ @echo " + +"
+ @echo " + **Note** This requires that you have +"
+ @echo " + doxygen installed on your local system +"
+ @echo " +-------------------------------------------+"
+ @$(MAKE) -s oldmodcheck
+
+upgrade: bininstall
+
+# XXX why *.adsi is installed first ?
+adsi:
+ @echo Installing adsi config files...
+ @mkdir -p $(DESTDIR)$(ASTETCDIR)
+ @for x in configs/*.adsi; do \
+ dst="$(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x`" ; \
+ if [ -f $${dst} ] ; then \
+ echo "Overwriting $$x" ; \
+ else \
+ echo "Installing $$x" ; \
+ fi ; \
+ $(INSTALL) -m 644 $$x $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x` ; \
+ done
+
+samples: adsi
+ @echo Installing other config files...
+ @mkdir -p $(DESTDIR)$(ASTETCDIR)
+ @for x in configs/*.sample; do \
+ dst="$(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample`" ; \
+ if [ -f $${dst} ]; then \
+ if [ "$(OVERWRITE)" = "y" ]; then \
+ if cmp -s $${dst} $$x ; then \
+ echo "Config file $$x is unchanged"; \
+ continue; \
+ fi ; \
+ mv -f $${dst} $${dst}.old ; \
+ else \
+ echo "Skipping config file $$x"; \
+ continue; \
+ fi ;\
+ fi ; \
+ echo "Installing file $$x"; \
+ $(INSTALL) -m 644 $$x $${dst} ;\
+ done
+ @if [ "$(OVERWRITE)" = "y" ] || [ ! -f $(DESTDIR)$(ASTCONFPATH) ]; then \
+ echo "Creating asterisk.conf"; \
+ ( \
+ echo "[directories](!) ; remove the (!) to enable this" ; \
+ echo "astetcdir => $(ASTETCDIR)" ; \
+ echo "astmoddir => $(MODULES_DIR)" ; \
+ echo "astvarlibdir => $(ASTVARLIBDIR)" ; \
+ echo "astdbdir => $(ASTDBDIR)" ; \
+ echo "astkeydir => $(ASTKEYDIR)" ; \
+ echo "astdatadir => $(ASTDATADIR)" ; \
+ echo "astagidir => $(AGI_DIR)" ; \
+ echo "astspooldir => $(ASTSPOOLDIR)" ; \
+ echo "astrundir => $(ASTVARRUNDIR)" ; \
+ echo "astlogdir => $(ASTLOGDIR)" ; \
+ echo "" ; \
+ echo ";[options]" ; \
+ echo ";verbose = 3" ; \
+ echo ";debug = 3" ; \
+ echo ";alwaysfork = yes ; same as -F at startup" ; \
+ echo ";nofork = yes ; same as -f at startup" ; \
+ echo ";quiet = yes ; same as -q at startup" ; \
+ echo ";timestamp = yes ; same as -T at startup" ; \
+ echo ";execincludes = yes ; support #exec in config files" ; \
+ echo ";console = yes ; Run as console (same as -c at startup)" ; \
+ echo ";highpriority = yes ; Run realtime priority (same as -p at startup)" ; \
+ echo ";initcrypto = yes ; Initialize crypto keys (same as -i at startup)" ; \
+ echo ";nocolor = yes ; Disable console colors" ; \
+ echo ";dontwarn = yes ; Disable some warnings" ; \
+ echo ";dumpcore = yes ; Dump core on crash (same as -g at startup)" ; \
+ echo ";languageprefix = yes ; Use the new sound prefix path syntax" ; \
+ echo ";internal_timing = yes" ; \
+ echo ";systemname = my_system_name ; prefix uniqueid with a system name for global uniqueness issues" ; \
+ echo ";autosystemname = yes ; automatically set systemname to hostname - uses 'localhost' on failure, or systemname if set" ; \
+ echo ";maxcalls = 10 ; Maximum amount of calls allowed" ; \
+ echo ";maxload = 0.9 ; Asterisk stops accepting new calls if the load average exceed this limit" ; \
+ echo ";maxfiles = 1000 ; Maximum amount of openfiles" ; \
+ echo ";minmemfree = 1 ; in MBs, Asterisk stops accepting new calls if the amount of free memory falls below this watermark" ; \
+ echo ";cache_record_files = yes ; Cache recorded sound files to another directory during recording" ; \
+ echo ";record_cache_dir = /tmp ; Specify cache directory (used in cnjunction with cache_record_files)" ; \
+ echo ";transmit_silence_during_record = yes ; Transmit SLINEAR silence while a channel is being recorded" ; \
+ echo ";transcode_via_sln = yes ; Build transcode paths via SLINEAR, instead of directly" ; \
+ echo ";runuser = asterisk ; The user to run as" ; \
+ echo ";rungroup = asterisk ; The group to run as" ; \
+ echo "" ; \
+ echo "; Changing the following lines may compromise your security." ; \
+ echo ";[files]" ; \
+ echo ";astctlpermissions = 0660" ; \
+ echo ";astctlowner = root" ; \
+ echo ";astctlgroup = apache" ; \
+ echo ";astctl = asterisk.ctl" ; \
+ ) > $(DESTDIR)$(ASTCONFPATH) ; \
+ else \
+ echo "Skipping asterisk.conf creation"; \
+ fi
+ mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/INBOX
+ build_tools/make_sample_voicemail $(DESTDIR)/$(ASTDATADIR) $(DESTDIR)/$(ASTSPOOLDIR)
+
+webvmail:
+ @[ -d $(DESTDIR)$(HTTP_DOCSDIR)/ ] || ( printf "http docs directory not found.\nUpdate assignment of variable HTTP_DOCSDIR in Makefile!\n" && exit 1 )
+ @[ -d $(DESTDIR)$(HTTP_CGIDIR) ] || ( printf "cgi-bin directory not found.\nUpdate assignment of variable HTTP_CGIDIR in Makefile!\n" && exit 1 )
+ $(INSTALL) -m 4755 -o root -g root contrib/scripts/vmail.cgi $(DESTDIR)$(HTTP_CGIDIR)/vmail.cgi
+ mkdir -p $(DESTDIR)$(HTTP_DOCSDIR)/_asterisk
+ for x in images/*.gif; do \
+ $(INSTALL) -m 644 $$x $(DESTDIR)$(HTTP_DOCSDIR)/_asterisk/; \
+ done
+ @echo " +--------- Asterisk Web Voicemail ----------+"
+ @echo " + +"
+ @echo " + Asterisk Web Voicemail is installed in +"
+ @echo " + your cgi-bin directory: +"
+ @echo " + $(DESTDIR)$(HTTP_CGIDIR)"
+ @echo " + IT USES A SETUID ROOT PERL SCRIPT, SO +"
+ @echo " + IF YOU DON'T LIKE THAT, UNINSTALL IT! +"
+ @echo " + +"
+ @echo " + Other static items have been stored in: +"
+ @echo " + $(DESTDIR)$(HTTP_DOCSDIR)"
+ @echo " + +"
+ @echo " + If these paths do not match your httpd +"
+ @echo " + installation, correct the definitions +"
+ @echo " + in your Makefile of HTTP_CGIDIR and +"
+ @echo " + HTTP_DOCSDIR +"
+ @echo " + +"
+ @echo " +-------------------------------------------+"
+
+spec:
+ sed "s/^Version:.*/Version: $(RPMVERSION)/g" redhat/asterisk.spec > asterisk.spec ; \
+
+rpm: __rpm
+
+__rpm: main/version.c include/asterisk/buildopts.h spec
+ rm -rf /tmp/asterisk ; \
+ mkdir -p /tmp/asterisk/redhat/RPMS/i386 ; \
+ $(MAKE) DESTDIR=/tmp/asterisk install ; \
+ $(MAKE) DESTDIR=/tmp/asterisk samples ; \
+ mkdir -p /tmp/asterisk/etc/rc.d/init.d ; \
+ cp -f contrib/init.d/rc.redhat.asterisk /tmp/asterisk/etc/rc.d/init.d/asterisk ; \
+ rpmbuild --rcfile /usr/lib/rpm/rpmrc:redhat/rpmrc -bb asterisk.spec
+
+progdocs:
+ (cat contrib/asterisk-ng-doxygen; echo "HAVE_DOT=$(HAVEDOT)"; \
+ echo "PROJECT_NUMBER=$(ASTERISKVERSION)") | doxygen -
+
+config:
+ @if [ "${OSARCH}" = "linux-gnu" ]; then \
+ if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \
+ $(INSTALL) -m 755 contrib/init.d/rc.redhat.asterisk $(DESTDIR)/etc/rc.d/init.d/asterisk; \
+ if [ -z "$(DESTDIR)" ]; then /sbin/chkconfig --add asterisk; fi; \
+ elif [ -f /etc/debian_version ]; then \
+ $(INSTALL) -m 755 contrib/init.d/rc.debian.asterisk $(DESTDIR)/etc/init.d/asterisk; \
+ if [ -z "$(DESTDIR)" ]; then /usr/sbin/update-rc.d asterisk start 50 2 3 4 5 . stop 91 2 3 4 5 .; fi; \
+ elif [ -f /etc/gentoo-release ]; then \
+ $(INSTALL) -m 755 contrib/init.d/rc.gentoo.asterisk $(DESTDIR)/etc/init.d/asterisk; \
+ if [ -z "$(DESTDIR)" ]; then /sbin/rc-update add asterisk default; fi; \
+ elif [ -f /etc/mandrake-release -o -f /etc/mandriva-release ]; then \
+ $(INSTALL) -m 755 contrib/init.d/rc.mandrake.asterisk $(DESTDIR)/etc/rc.d/init.d/asterisk; \
+ if [ -z "$(DESTDIR)" ]; then /sbin/chkconfig --add asterisk; fi; \
+ elif [ -f /etc/SuSE-release -o -f /etc/novell-release ]; then \
+ $(INSTALL) -m 755 contrib/init.d/rc.suse.asterisk $(DESTDIR)/etc/init.d/asterisk; \
+ if [ -z "$(DESTDIR)" ]; then /sbin/chkconfig --add asterisk; fi; \
+ elif [ -f /etc/slackware-version ]; then \
+ echo "Slackware is not currently supported, although an init script does exist for it." \
+ else \
+ echo "We could not install init scripts for your distribution."; \
+ fi \
+ else \
+ echo "We could not install init scripts for your operating system."; \
+ fi
+
+sounds:
+ $(MAKE) -C sounds all
+
+# If the cleancount has been changed, force a make clean.
+# .cleancount is the global clean count, and .lastclean is the
+# last clean count we had
+
+cleantest:
+ @cmp -s .cleancount .lastclean || $(MAKE) clean
+
+$(SUBDIRS_UNINSTALL):
+ @$(MAKE) $(PRINT_DIR) -C $(@:-uninstall=) uninstall
+
+_uninstall: $(SUBDIRS_UNINSTALL)
+ rm -f $(DESTDIR)$(MODULES_DIR)/*
+ rm -f $(DESTDIR)$(ASTSBINDIR)/*asterisk*
+ rm -f $(DESTDIR)$(ASTSBINDIR)/astgenkey
+ rm -f $(DESTDIR)$(ASTSBINDIR)/autosupport
+ rm -rf $(DESTDIR)$(ASTHEADERDIR)
+ rm -rf $(DESTDIR)$(ASTDATADIR)/firmware
+ rm -f $(DESTDIR)$(ASTMANDIR)/man8/asterisk.8
+ rm -f $(DESTDIR)$(ASTMANDIR)/man8/astgenkey.8
+ rm -f $(DESTDIR)$(ASTMANDIR)/man8/autosupport.8
+ rm -f $(DESTDIR)$(ASTMANDIR)/man8/safe_asterisk.8
+ $(MAKE) -C sounds uninstall
+
+uninstall: _uninstall
+ @echo " +--------- Asterisk Uninstall Complete -----+"
+ @echo " + Asterisk binaries, sounds, man pages, +"
+ @echo " + headers, modules, and firmware builds, +"
+ @echo " + have all been uninstalled. +"
+ @echo " + +"
+ @echo " + To remove ALL traces of Asterisk, +"
+ @echo " + including configuration, spool +"
+ @echo " + directories, and logs, run the following +"
+ @echo " + command: +"
+ @echo " + +"
+ @echo " + $(mK) uninstall-all +"
+ @echo " +-------------------------------------------+"
+
+uninstall-all: _uninstall
+ rm -rf $(DESTDIR)$(ASTLIBDIR)
+ rm -rf $(DESTDIR)$(ASTVARLIBDIR)
+ rm -rf $(DESTDIR)$(ASTDATADIR)
+ rm -rf $(DESTDIR)$(ASTSPOOLDIR)
+ rm -rf $(DESTDIR)$(ASTETCDIR)
+ rm -rf $(DESTDIR)$(ASTLOGDIR)
+
+menuconfig: menuselect
+
+gmenuconfig: gmenuselect
+
+menuselect: menuselect/menuselect menuselect-tree
+ -@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
+
+gmenuselect: menuselect/gmenuselect menuselect-tree
+ -@menuselect/gmenuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
+
+# options for make in menuselect/
+MAKE_MENUSELECT=CC="$(HOST_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" CFLAGS="" $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
+
+menuselect/menuselect: menuselect/makeopts
+ $(MAKE_MENUSELECT)
+
+menuselect/gmenuselect: menuselect/makeopts
+ $(MAKE_MENUSELECT) gmenuselect
+
+menuselect/makeopts:
+ $(MAKE_MENUSELECT) makeopts
+
+menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml sounds/sounds.xml build_tools/embed_modules.xml configure
+ @echo "Generating input for menuselect ..."
+ @echo "<?xml version=\"1.0\"?>" > $@
+ @echo >> $@
+ @echo "<menu name=\"Asterisk Module and Build Option Selection\">" >> $@
+ @for dir in $(sort $(filter-out main,$(MOD_SUBDIRS))); do $(SUBMAKE) -C $${dir} SUBDIR=$${dir} moduleinfo >> $@; done
+ @for dir in $(sort $(filter-out main,$(MOD_SUBDIRS))); do $(SUBMAKE) -C $${dir} SUBDIR=$${dir} makeopts >> $@; done
+ @cat build_tools/cflags.xml >> $@
+ @cat build_tools/embed_modules.xml >> $@
+ @cat sounds/sounds.xml >> $@
+ @echo "</menu>" >> $@
+
+pdf: asterisk.pdf
+asterisk.pdf:
+ $(MAKE) -C doc/tex asterisk.pdf
+
+.PHONY: menuselect main sounds clean dist-clean distclean all prereqs cleantest uninstall _uninstall uninstall-all pdf dont-optimize $(SUBDIRS_INSTALL) $(SUBDIRS_DIST_CLEAN) $(SUBDIRS_CLEAN) $(SUBDIRS_UNINSTALL) $(SUBDIRS) $(MOD_SUBDIRS_EMBED_LDSCRIPT) $(MOD_SUBDIRS_EMBED_LDFLAGS) $(MOD_SUBDIRS_EMBED_LIBS) main/version.c
diff --git a/trunk/Makefile.moddir_rules b/trunk/Makefile.moddir_rules
new file mode 100644
index 000000000..9258e8d63
--- /dev/null
+++ b/trunk/Makefile.moddir_rules
@@ -0,0 +1,166 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Makefile rules for subdirectories containing modules
+#
+# Copyright (C) 2006, Digium, Inc.
+#
+# Kevin P. Fleming <kpfleming@digium.com>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+# Makefile rules for building modules.
+
+# In most cases, we set target-specific variables for certain targets
+# (remember that they apply recursively to prerequisites).
+# Also note that we can only set one variable per rule, so we have to
+# repeat the left hand side to set multiple variables.
+
+ifneq ($(findstring MALLOC_DEBUG,$(MENUSELECT_CFLAGS)),)
+ ifeq ($(findstring astmm.h,$(ASTCFLAGS)),)
+ ASTCFLAGS+=-include $(ASTTOPDIR)/include/asterisk/astmm.h
+ endif
+endif
+
+ifeq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
+ ASTCFLAGS+=${GC_CFLAGS}
+endif
+
+ifneq ($(findstring STATIC_BUILD,$(MENUSELECT_CFLAGS)),)
+ STATIC_BUILD=-static
+endif
+
+include $(ASTTOPDIR)/Makefile.rules
+
+# If MODULE_PREFIX is defined, use it to run the standard functions to set
+# C_MODS, CC_MODS, LOADABLE_MODS and EMBEDDED_MODS.
+# Each word of MODULE_PREFIX is a prefix for filenames that we consider
+# valid C or CC modules (eg. app, func ...). Note that the underscore
+# is added here, and does not need to be in MODULE_PREFIX
+#
+# Use MODULE_EXCLUDE to specify additional modules to exclude.
+
+ifneq ($(MODULE_PREFIX),)
+ ALL_C_MODS:=
+ ALL_C_MODS+=$(foreach p,$(MODULE_PREFIX),$(patsubst %.c,%,$(wildcard $(p)_*.c)))
+ ALL_CC_MODS:=
+ ALL_CC_MODS+=$(foreach p,$(MODULE_PREFIX),$(patsubst %.cc,%,$(wildcard $(p)_*.cc)))
+
+ C_MODS:=$(filter-out $(MENUSELECT_$(MENUSELECT_CATEGORY)),$(ALL_C_MODS))
+ CC_MODS:=$(filter-out $(MENUSELECT_$(MENUSELECT_CATEGORY)),$(ALL_CC_MODS))
+
+ # and store in the list of embedded or loadable modules
+ ifneq ($(findstring $(MENUSELECT_CATEGORY),$(MENUSELECT_EMBED)),)
+ EMBEDDED_MODS:=$(C_MODS) $(CC_MODS)
+ else
+ LOADABLE_MODS:=$(C_MODS) $(CC_MODS)
+ endif
+endif
+
+# Both C++ and C++ sources need their module name in AST_MODULE
+# We also pass whatever _INCLUDE list is generated by menuselect
+# (they are stored in file 'makeopts')
+
+$(addsuffix .oo,$(CC_MODS)) $(addsuffix .o,$(C_MODS)): \
+ ASTCFLAGS+= -DAST_MODULE=\"$*\" $(MENUSELECT_OPTS_$*:%=-D%) $(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_INCLUDE))
+
+ifeq ($(findstring $(OSARCH), mingw32 cygwin ),)
+ # don't define -fPIC on mingw32 and cygwin, it is the default
+ $(LOADABLE_MODS:%=%.so): ASTCFLAGS+=-fPIC
+endif
+
+# For loadable modules, pass _LIB and _LDFLAGS from menuselect.
+$(LOADABLE_MODS:%=%.so): LIBS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LIB))
+$(LOADABLE_MODS:%=%.so): ASTLDFLAGS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LDFLAGS))
+
+$(EMBEDDED_MODS:%=%.o): ASTCFLAGS+=-DEMBEDDED_MODULE=$*
+
+$(addsuffix .so,$(filter $(LOADABLE_MODS),$(C_MODS))): %.so: %.o
+$(addsuffix .so,$(filter $(LOADABLE_MODS),$(CC_MODS))): %.so: %.oo
+
+modules.link: $(addsuffix .eo,$(filter $(EMBEDDED_MODS),$(C_MODS)))
+
+.PHONY: clean uninstall _all moduleinfo makeopts
+
+ifneq ($(LOADABLE_MODS),)
+_all: $(LOADABLE_MODS:%=%.so)
+ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
+ # linker options and extra libraries for cygwin
+ SOLINK=-Wl,--out-implib=lib$@.a -shared
+ LIBS+=-L$(ASTTOPDIR)/main -lasterisk -L$(ASTTOPDIR)/res $($@_LIBS)
+ # additional libraries in res/
+endif
+endif
+
+ifneq ($(EMBEDDED_MODS),)
+_all: modules.link
+__embed_ldscript:
+ @echo "../$(SUBDIR)/modules.link"
+__embed_ldflags:
+ @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(C_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LDFLAGS))"
+ @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(CC_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LDFLAGS))"
+__embed_libs:
+ @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(C_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LIB))"
+ @echo "$(foreach mod,$(filter $(EMBEDDED_MODS),$(CC_MODS)),$(foreach dep,$(MENUSELECT_DEPENDS_$(mod)),$(dep)_LIB))"
+else
+__embed_ldscript:
+__embed_ldflags:
+__embed_libs:
+endif
+
+modules.link:
+ @rm -f $@
+ @for file in $(patsubst %,$(SUBDIR)/%,$(filter %.eo,$^)); do echo "INPUT (../$${file})" >> $@; done
+ @for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.eo,$^)); do echo "INPUT (../$${file})" >> $@; done
+
+clean::
+ rm -f *.so *.o *.oo *.eo
+ rm -f .*.o.d .*.oo.d
+ rm -f *.s *.i
+ rm -f modules.link
+
+install:: all
+ @echo "Installing modules from `basename $(CURDIR)`..."
+ @for x in $(LOADABLE_MODS:%=%.so); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done
+
+uninstall::
+
+dist-clean::
+ rm -f .*.moduleinfo .moduleinfo
+ rm -f .*.makeopts .makeopts
+
+.%.moduleinfo: %.c
+ @echo "<member name=\"$*\" displayname=\"$(shell $(GREP) -e AST_MODULE_INFO $< | head -n 1 | cut -d '"' -f 2)\" remove_on_change=\"$(SUBDIR)/$*.o $(SUBDIR)/$*.so\">" > $@
+ $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $< >> $@
+ echo "</member>" >> $@
+
+.%.moduleinfo: %.cc
+ @echo "<member name=\"$*\" displayname=\"$(shell $(GREP) -e AST_MODULE_INFO $< | head -n 1 | cut -d '"' -f 2)\" remove_on_change=\"$(SUBDIR)/$*.oo $(SUBDIR)/$*.so\">" > $@
+ $(AWK) -f $(ASTTOPDIR)/build_tools/get_moduleinfo $< >> $@
+ echo "</member>" >> $@
+
+.moduleinfo:: $(addsuffix .moduleinfo,$(addprefix .,$(ALL_C_MODS) $(ALL_CC_MODS)))
+ @echo "<category name=\"MENUSELECT_$(MENUSELECT_CATEGORY)\" displayname=\"$(MENUSELECT_DESCRIPTION)\" remove_on_change=\"$(SUBDIR)/modules.link\">" > $@
+ @cat $^ >> $@
+ @echo "</category>" >> $@
+
+moduleinfo: .moduleinfo
+ @cat $<
+
+.%.makeopts: %.c
+ @$(AWK) -f $(ASTTOPDIR)/build_tools/get_makeopts $< > $@
+
+.%.makeopts: %.cc
+ @$(AWK) -f $(ASTTOPDIR)/build_tools/get_makeopts $< > $@
+
+.makeopts:: $(addsuffix .makeopts,$(addprefix .,$(ALL_C_MODS) $(ALL_CC_MODS)))
+ @cat $^ > $@
+
+makeopts: .makeopts
+ @cat $<
+
+ifneq ($(wildcard .*.d),)
+ include .*.d
+endif
diff --git a/trunk/Makefile.rules b/trunk/Makefile.rules
new file mode 100644
index 000000000..ca21dcc04
--- /dev/null
+++ b/trunk/Makefile.rules
@@ -0,0 +1,98 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Makefile rules
+#
+# Copyright (C) 2006, Digium, Inc.
+#
+# Kevin P. Fleming <kpfleming@digium.com>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+# Rules for various build phases.
+# Each command is preceded by a short comment on what to do.
+# Prefixing one or the other with @\# or @ or nothing makes the desired
+# behaviour. ECHO_PREFIX prefixes the comment, CMD_PREFIX prefixes the command.
+
+-include $(ASTTOPDIR)/makeopts
+
+.PHONY: dist-clean
+
+# extra cflags to build dependencies. Recursively expanded.
+MAKE_DEPS= -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
+
+ifeq ($(NOISY_BUILD),)
+ ECHO_PREFIX=@
+ CMD_PREFIX=@
+else
+ ECHO_PREFIX=@\#
+ CMD_PREFIX=
+endif
+
+ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),)
+ # More GSM codec optimization
+ # Uncomment to enable MMXTM optimizations for x86 architecture CPU's
+ # which support MMX instructions. This should be newer pentiums,
+ # ppro's, etc, as well as the AMD K6 and K7.
+ #K6OPT=-DK6OPT
+
+ OPTIMIZE?=-O6
+ ASTCFLAGS+=$(OPTIMIZE)
+endif
+
+# build rules for various targets
+%.o: %.c
+ $(ECHO_PREFIX) echo " [CC] $< -> $@"
+ $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) $(MAKE_DEPS)
+
+%.o: %.i
+ $(ECHO_PREFIX) echo " [CCi] $< -> $@"
+ $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) $(MAKE_DEPS)
+
+%.i: %.c
+ $(ECHO_PREFIX) echo " [CPP] $< -> $@"
+ $(CMD_PREFIX) $(CC) -o $@ -E $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) $(MAKE_DEPS)
+
+%.o: %.s
+ $(ECHO_PREFIX) echo " [AS] $< -> $@"
+ $(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) $(MAKE_DEPS)
+
+%.oo: %.cc
+ $(ECHO_PREFIX) echo " [CXX] $< -> $@"
+ $(CMD_PREFIX) $(CXX) -o $@ -c $< $(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations,$(ASTCFLAGS)) $(MAKE_DEPS)
+
+%.c: %.y
+ $(ECHO_PREFIX) echo " [BISON] $< -> $@"
+ $(CMD_PREFIX) bison -o $@ -d --name-prefix=ast_yy $<
+
+%.c: %.fl
+ $(ECHO_PREFIX) echo " [FLEX] $< -> $@"
+ $(CMD_PREFIX) flex -o $@ --full $<
+
+%.so: %.o
+ $(ECHO_PREFIX) echo " [LD] $^ -> $@"
+ $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $^ $(PTHREAD_LIBS) $(LIBS)
+
+%.so: %.oo
+ $(ECHO_PREFIX) echo " [LDXX] $^ -> $@"
+ $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $^ $(PTHREAD_LIBS) $(LIBS)
+
+%.eo: %.o
+ $(ECHO_PREFIX) echo " [EMBED] $< -> $@"
+ $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld
+ $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $<
+ $(CMD_PREFIX) rm -f .$@.ld
+
+%.eo: %.oo
+ $(ECHO_PREFIX) echo " [EMBED] $< -> $@"
+ $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/make_linker_eo_script $* > .$@.ld
+ $(CMD_PREFIX) $(LD) -r -T .$@.ld -o $@ $<
+ $(CMD_PREFIX) rm -f .$@.ld
+
+%: %.o
+ $(ECHO_PREFIX) echo " [LD] $^ -> $@"
+ $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $^ $(PTHREAD_LIBS) $(LIBS)
+
+dist-clean::
diff --git a/trunk/README b/trunk/README
new file mode 100644
index 000000000..176bfca44
--- /dev/null
+++ b/trunk/README
@@ -0,0 +1,262 @@
+The Asterisk(R) Open Source PBX
+by Mark Spencer <markster@digium.com>
+and the Asterisk.org developer community
+
+Copyright (C) 2001-2006 Digium, Inc.
+and other copyright holders.
+================================================================
+
+* SECURITY
+ It is imperative that you read and fully understand the contents of
+the security information file (doc/security.txt) before you attempt
+to configure and run an Asterisk server.
+
+* WHAT IS ASTERISK ?
+ Asterisk is an Open Source PBX and telephony toolkit. It is, in a
+sense, middleware between Internet and telephony channels on the bottom,
+and Internet and telephony applications at the top. For more information
+on the project itself, please visit the Asterisk home page at:
+
+ http://www.asterisk.org
+
+In addition you'll find lots of information compiled by the Asterisk
+community on this Wiki:
+
+ http://www.voip-info.org/wiki-Asterisk
+
+There is a book on Asterisk published by O'Reilly under the
+Creative Commons License. It is available in book stores as well
+as in a downloadable version on the http://www.asteriskdocs.org
+web site.
+
+* SUPPORTED OPERATING SYSTEMS
+
+== Linux ==
+ The Asterisk Open Source PBX is developed and tested primarily on the
+GNU/Linux operating system, and is supported on every major GNU/Linux
+distribution.
+
+== Others ==
+ Asterisk has also been 'ported' and reportedly runs properly on other
+operating systems as well, including Sun Solaris, Apple's Mac OS X, and
+the BSD variants.
+
+* GETTING STARTED
+
+ First, be sure you've got supported hardware (but note that you don't need
+ANY special hardware, not even a soundcard) to install and run Asterisk.
+
+ Supported telephony hardware includes:
+
+ * All Wildcard (tm) products from Digium (www.digium.com)
+ * QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net)
+ * any full duplex sound card supported by ALSA or OSS
+ * any ISDN card supported by mISDN on Linux (BRI)
+ * The Xorcom AstriBank channel bank
+ * VoiceTronix OpenLine products
+
+The are several drivers for ISDN BRI cards available from third party sources.
+Check the voip-info.org wiki for more information on chan_capi and
+zaphfc.
+
+* UPGRADING FROM AN EARLIER VERSION
+
+ If you are updating from a previous version of Asterisk, make sure you
+read the UPGRADE.txt file in the source directory. There are some files
+and configuration options that you will have to change, even though we
+made every effort possible to maintain backwards compatibility.
+
+ In order to discover new features to use, please check the configuration
+examples in the /configs directory of the source code distribution.
+To discover the major new features of Asterisk 1.2, please visit
+http://edvina.net/asterisk1-2/
+
+* NEW INSTALLATIONS
+
+ Ensure that your system contains a compatible compiler and development
+libraries. Asterisk requires either the GNU Compiler Collection (GCC) version
+3.0 or higher, or a compiler that supports the C99 specification and some of
+the gcc language extensions. In addition, your system needs to have the C
+library headers available, and the headers and libraries for OpenSSL,
+ncurses and zlib.
+On many distributions, these files are installed by packages with names like
+'glibc-devel', 'ncurses-devel', 'openssl-devel' and 'zlib-devel' or similar.
+
+ So let's proceed:
+
+1) Read this README file.
+
+ There are more documents than this one in the doc/ directory.
+You may also want to check the configuration files that contain
+examples and reference guides. They are all in the configs/
+directory.
+
+2) Run "./configure"
+
+ Execute the configure script to guess values for system-dependent
+variables used during compilation.
+
+3) Run "make menuselect" [optional]
+
+ This is needed if you want to select the modules that will be
+compiled and to check modules dependencies.
+
+4) Run "make"
+
+ Assuming the build completes successfully:
+
+5) Run "make install"
+
+ Each time you update or checkout from the repository, you are strongly
+encouraged to ensure all previous object files are removed to avoid internal
+inconsistency in Asterisk. Normally, this is automatically done with
+the presence of the file .cleancount, which increments each time a 'make clean'
+is required, and the file .lastclean, which contains the last .cleancount used.
+
+ If this is your first time working with Asterisk, you may wish to install
+the sample PBX, with demonstration extensions, etc. If so, run:
+
+6) "make samples"
+
+ Doing so will overwrite any existing config files you have.
+
+ Finally, you can launch Asterisk in the foreground mode (not a daemon)
+with:
+
+# asterisk -vvvc
+
+ You'll see a bunch of verbose messages fly by your screen as Asterisk
+initializes (that's the "very very verbose" mode). When it's ready, if
+you specified the "c" then you'll get a command line console, that looks
+like this:
+
+*CLI>
+
+ You can type "help" at any time to get help with the system. For help
+with a specific command, type "help <command>". To start the PBX using
+your sound card, you can type "dial" to dial the PBX. Then you can use
+"answer", "hangup", and "dial" to simulate the actions of a telephone.
+Remember that if you don't have a full duplex sound card (and Asterisk
+will tell you somewhere in its verbose messages if you do/don't) then it
+won't work right (not yet).
+
+ "man asterisk" at the Unix/Linux command prompt will give you detailed
+information on how to start and stop Asterisk, as well as all the command
+line options for starting Asterisk.
+
+ Feel free to look over the configuration files in /etc/asterisk, where
+you'll find a lot of information about what you can do with Asterisk.
+
+* ABOUT CONFIGURATION FILES
+
+ All Asterisk configuration files share a common format. Comments are
+delimited by ';' (since '#' of course, being a DTMF digit, may occur in
+many places). A configuration file is divided into sections whose names
+appear in []'s. Each section typically contains two types of statements,
+those of the form 'variable = value', and those of the form 'object =>
+parameters'. Internally the use of '=' and '=>' is exactly the same, so
+they're used only to help make the configuration file easier to
+understand, and do not affect how it is actually parsed.
+
+ Entries of the form 'variable=value' set the value of some parameter in
+asterisk. For example, in zapata.conf, one might specify:
+
+ switchtype=national
+
+in order to indicate to Asterisk that the switch they are connecting to is
+of the type "national". In general, the parameter will apply to
+instantiations which occur below its specification. For example, if the
+configuration file read:
+
+ switchtype = national
+ channel => 1-4
+ channel => 10-12
+ switchtype = dms100
+ channel => 25-47
+
+the "national" switchtype would be applied to channels one through
+four and channels 10 through 12, whereas the "dms100" switchtype would
+apply to channels 25 through 47.
+
+ The "object => parameters" instantiates an object with the given
+parameters. For example, the line "channel => 25-47" creates objects for
+the channels 25 through 47 of the card, obtaining the settings
+from the variables specified above.
+
+* SPECIAL NOTE ON TIME
+
+ Those using SIP phones should be aware that Asterisk is sensitive to
+large jumps in time. Manually changing the system time using date(1)
+(or other similar commands) may cause SIP registrations and other
+internal processes to fail. If your system cannot keep accurate time
+by itself use NTP (http://www.ntp.org/) to keep the system clock
+synchronized to "real time". NTP is designed to keep the system clock
+synchronized by speeding up or slowing down the system clock until it
+is synchronized to "real time" rather than by jumping the time and
+causing discontinuities. Most Linux distributions include precompiled
+versions of NTP. Beware of some time synchronization methods that get
+the correct real time periodically and then manually set the system
+clock.
+
+ Apparent time changes due to daylight savings time are just that,
+apparent. The use of daylight savings time in a Linux system is
+purely a user interface issue and does not affect the operation of the
+Linux kernel or Asterisk. The system clock on Linux kernels operates
+on UTC. UTC does not use daylight savings time.
+
+ Also note that this issue is separate from the clocking of TDM
+channels, and is known to at least affect SIP registrations.
+
+* FILE DESCRIPTORS
+
+ Depending on the size of your system and your configuration,
+Asterisk can consume a large number of file descriptors. In UNIX,
+file descriptors are used for more than just files on disk. File
+descriptors are also used for handling network communication
+(e.g. SIP, IAX2, or H.323 calls) and hardware access (e.g. analog and
+digital trunk hardware). Asterisk accesses many on-disk files for
+everything from configuration information to voicemail storage.
+
+ Most systems limit the number of file descriptors that Asterisk can
+have open at one time. This can limit the number of simultaneous
+calls that your system can handle. For example, if the limit is set
+at 1024 (a common default value) Asterisk can handle approxiately 150
+SIP calls simultaneously. To change the number of file descriptors
+follow the instructions for your system below:
+
+== PAM-based Linux System ==
+
+ If your system uses PAM (Pluggable Authentication Modules) edit
+/etc/security/limits.conf. Add these lines to the bottom of the file:
+
+root soft nofile 4096
+root hard nofile 8196
+asterisk soft nofile 4096
+asterisk hard nofile 8196
+
+(adjust the numbers to taste). You may need to reboot the system for
+these changes to take effect.
+
+== Generic UNIX System ==
+
+ If there are no instructions specifically adapted to your system
+above you can try adding the command "ulimit -n 8192" to the script
+that starts Asterisk.
+
+* MORE INFORMATION
+
+ See the doc directory for more documentation on various features. Again,
+please read all the configuration samples that include documentation on
+the configuration options.
+
+ Finally, you may wish to visit the web site and join the mailing list if
+you're interested in getting more information.
+
+ http://www.asterisk.org/support
+
+ Welcome to the growing worldwide community of Asterisk users!
+
+Mark Spencer
+
+----
+Asterisk is a trademark belonging to Digium, inc
diff --git a/trunk/UPGRADE.txt b/trunk/UPGRADE.txt
new file mode 100644
index 000000000..dcde18981
--- /dev/null
+++ b/trunk/UPGRADE.txt
@@ -0,0 +1,163 @@
+Information for Upgrading From Previous Asterisk Releases
+=========================================================
+
+AEL:
+
+* Macros are now implemented underneath with the Gosub() application.
+ Heaven Help You if you wrote code depending on any aspect of this!
+ Previous to 1.6, macros were implemented with the Macro() app, which
+ provided a nice feature of auto-returning. The compiler will do its
+ best to insert a Return() app call at the end of your macro if you did
+ not include it, but really, you should make sure that all execution
+ paths within your macros end in "return;".
+
+* The conf2ael program is 'introduced' in this release; it is in a rather
+ crude state, but deemed useful for making a first pass at converting
+ extensions.conf code into AEL. More intelligence will come with time.
+
+Core:
+
+* The 'languageprefix' option in asterisk.conf is now deprecated, and
+ the default sound file layout for non-English sounds is the 'new
+ style' layout introduced in Asterisk 1.4 (and used by the automatic
+ sound file installer in the Makefile).
+
+* The ast_expr2 stuff has been modified to handle floating-point numbers.
+ Numbers of the format D.D are now acceptable input for the expr parser,
+ Where D is a string of base-10 digits. All math is now done in "long double",
+ if it is available on your compiler/architecture. This was half-way between
+ a bug-fix (because the MATH func returns fp by default), and an enhancement.
+ Also, for those counting on, or needing, integer operations, a series of
+ 'functions' were also added to the expr language, to allow several styles
+ of rounding/truncation, along with a set of common floating point operations,
+ like sin, cos, tan, log, pow, etc. The ability to call external functions
+ like CDR(), etc. was also added, without having to use the ${...} notation.
+
+* The delimiter passed to applications has been changed to the comma (','), as
+ that is what people are used to using within extensions.conf. If you are
+ using realtime extensions, you will need to translate your existing dialplan
+ to use this separator. To use a literal comma, you need merely to escape it
+ with a backslash ('\'). Another possible side effect is that you may need to
+ remove the obscene level of backslashing that was necessary for the dialplan
+ to work correctly in 1.4 and previous versions. This should make writing
+ dialplans less painful in the future, albeit with the pain of a one-time
+ conversion.
+
+* The logger.conf option 'rotatetimestamp' has been deprecated in favor of
+ 'rotatestrategy'. This new option supports a 'rotate' strategy that more
+ closely mimics the system logger in terms of file rotation.
+
+* The concise versions of various CLI commands are now deprecated. We recommend
+ using the manager interface (AMI) for application integration with Asterisk.
+
+Voicemail:
+
+* The voicemail configuration values 'maxmessage' and 'minmessage' have
+ been changed to 'maxsecs' and 'minsecs' to clarify their purpose and
+ to make them more distinguishable from 'maxmsgs', which sets folder
+ size. The old variables will continue to work in this version, albeit
+ with a deprecation warning.
+* If you use any interface for modifying voicemail aside from the built in
+ dialplan applications, then the option "pollmailboxes" *must* be set in
+ voicemail.conf for message waiting indication (MWI) to work properly. This
+ is because Voicemail notification is now event based instead of polling
+ based. The channel drivers are no longer responsible for constantly manually
+ checking mailboxes for changes so that they can send MWI information to users.
+ Examples of situations that would require this option are web interfaces to
+ voicemail or an email client in the case of using IMAP storage.
+
+Applications:
+
+* ChanIsAvail() now has a 't' option, which allows the specified device
+ to be queried for state without consulting the channel drivers. This
+ performs mostly a 'ChanExists' sort of function.
+* SetCallerPres() has been replaced with the CALLERPRES() dialplan function
+ and is now deprecated.
+* DISA()'s fifth argument is now an options argument. If you have previously
+ used 'NOANSWER' in this argument, you'll need to convert that to the new
+ option 'n'.
+* Macro() is now deprecated. If you need subroutines, you should use the
+ Gosub()/Return() applications. To replace MacroExclusive(), we have
+ introduced dialplan functions LOCK(), TRYLOCK(), and UNLOCK(). You may use
+ these functions in any location where you desire to ensure that only one
+ channel is executing that path at any one time.
+* Read() now sets a READSTATUS variable on exit. It does NOT automatically
+ return -1 (and hangup) anymore on error. If you want to hangup on error,
+ you need to do so explicitly in your dialplan.
+* Privacy() no longer uses privacy.conf, so any options must be specified
+ directly in the application arguments.
+
+Dialplan Functions:
+
+* QUEUE_MEMBER_COUNT() has been deprecated in favor of the QUEUE_MEMBER() function. For
+ more information, issue a "show function QUEUE_MEMBER" from the CLI.
+
+CDR:
+
+* The cdr_sqlite module has been marked as deprecated in favor of
+ cdr_sqlite3_custom. It will potentially be removed from the tree
+ after Asterisk 1.6 is released.
+
+* The cdr_odbc module now uses res_odbc to manage its connections. The
+ username and password parameters in cdr_odbc.conf, therefore, are no
+ longer used. The dsn parameter now points to an entry in res_odbc.conf.
+
+Formats:
+
+* format_wav: The GAIN preprocessor definition and source code that used it
+ is removed. This change was made in response to user complaints of
+ choppiness or the clipping of loud signal peaks. To increase the volume
+ of voicemail messages, use the 'volgain' option in voicemail.conf
+
+Channel Drivers:
+
+* SIP: a small upgrade to support the "Record" button on the SNOM360,
+ which sends a sip INFO message with a "Record: on" or "Record: off"
+ header. If Asterisk is set up (via features.conf) to accept "One Touch Monitor"
+ requests (by default, via '*1'), then the user-configured dialpad sequence
+ is generated, and recording can be started and stopped via this button. The
+ file names and formats are all controlled via the normal mechanisms. If the
+ user has not configured the automon feature, the normal "415 Unsupported media type"
+ is returned, and nothing is done.
+* SIP: The "call-limit" option is marked as deprecated. It still works in this version of
+ Asterisk, but will be removed in the following version. Please use the groupcount functions
+ in the dialplan to enforce call limits. The "limitonpeer" configuration option is
+ now renamed to "counteronpeer".
+* SIP: The "username" option is now renamed to "defaultuser" to match "defaultip".
+ These are used only before registration to call a peer with the uri
+ sip:defaultuser@defaultip
+ The "username" setting still work, but is deprecated and will not work in
+ the next version of Asterisk.
+
+* chan_local.c: the comma delimiter inside the channel name has been changed to a
+ semicolon, in order to make the Local channel driver compatible with the comma
+ delimiter change in applications.
+* H323: The "tos" setting has changed name to "tos_audio" and "cos" to "cos_audio"
+ to be compatible with settings in sip.conf. The "tos" and "cos" configuration
+ is deprecated and will stop working in the next release of Asterisk.
+
+* Console: A new console channel driver, chan_console, has been added to Asterisk.
+ This new module can not be loaded at the same time as chan_alsa or chan_oss. The
+ default modules.conf only loads one of them (chan_oss by default). So, unless you
+ have modified your modules.conf to not use the autoload option, then you will need
+ to modify modules.conf to add another "noload" line to ensure that only one of
+ these three modules gets loaded.
+
+Configuration:
+
+* pbx_dundi.c: tos parameter changed to use new values. Old values like lowdelay,
+ lowcost and other is not acceptable now. Look into qos.tex for description of
+ this parameter.
+
+Manager:
+
+* Manager has been upgraded to version 1.1 with a lot of changes.
+ Please check doc/manager_1_1.txt for information
+
+* The IAXpeers command output has been changed to more closely resemble the
+ output of the SIPpeers command.
+
+* cdr_manager now reports at the "cdr" level, not at "call" You may need to
+ change your manager.conf to add the level to existing AMI users, if they
+ want to see the CDR events generated.
+
diff --git a/trunk/acinclude.m4 b/trunk/acinclude.m4
new file mode 100644
index 000000000..9b84af614
--- /dev/null
+++ b/trunk/acinclude.m4
@@ -0,0 +1,1106 @@
+# Various support functions for configure.ac in asterisk
+#
+
+# Helper function to check for gcc attributes.
+# AST_GCC_ATTRIBUTE([attribute name])
+
+AC_DEFUN([AST_GCC_ATTRIBUTE],
+[
+AC_MSG_CHECKING(for compiler 'attribute $1' support)
+AC_COMPILE_IFELSE(
+ AC_LANG_PROGRAM([static int __attribute__(($1)) test(void) {}],
+ []),
+ AC_MSG_RESULT(yes)
+ AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
+ AC_MSG_RESULT(no))
+])
+
+# Helper function to setup variables for a package.
+# $1 -> the package name. Used in configure.ac and also as a prefix
+# for the variables ($1_DIR, $1_INCLUDE, $1_LIB) in makeopts
+# $3 -> option name, used in --with-$3 or --without-$3 when calling configure.
+# $2 and $4 are just text describing the package (short and long form)
+
+# AST_EXT_LIB_SETUP([package], [short description], [configure option name], [long description])
+
+AC_DEFUN([AST_EXT_LIB_SETUP],
+[
+ $1_DESCRIP="$2"
+ $1_OPTION="$3"
+ AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH $4]),
+ [
+ case ${withval} in
+ n|no)
+ USE_$1=no
+ ;;
+ y|ye|yes)
+ ac_mandatory_list="${ac_mandatory_list} $1"
+ ;;
+ *)
+ $1_DIR="${withval}"
+ ac_mandatory_list="${ac_mandatory_list} $1"
+ ;;
+ esac
+ ])
+ PBX_$1=0
+ AC_SUBST([$1_LIB])
+ AC_SUBST([$1_INCLUDE])
+ AC_SUBST([$1_DIR])
+ AC_SUBST([PBX_$1])
+])
+
+# Check whether any of the mandatory modules are not present, and
+# print error messages in case. The mandatory list is built using
+# --with-* arguments when invoking configure.
+
+AC_DEFUN([AST_CHECK_MANDATORY],
+[
+ AC_MSG_CHECKING([for mandatory modules: ${ac_mandatory_list}])
+ err=0;
+ for i in ${ac_mandatory_list}; do
+ eval "a=\${PBX_$i}"
+ if test "x${a}" = "x1" ; then continue; fi
+ if test ${err} = "0" ; then AC_MSG_RESULT(fail) ; fi
+ AC_MSG_RESULT()
+ eval "a=\${${i}_OPTION}"
+ AC_MSG_NOTICE([***])
+ AC_MSG_NOTICE([*** The $i installation appears to be missing or broken.])
+ AC_MSG_NOTICE([*** Either correct the installation, or run configure])
+ AC_MSG_NOTICE([*** including --without-${a}.])
+ err=1
+ done
+ if test $err = 1 ; then exit 1; fi
+ AC_MSG_RESULT(ok)
+])
+
+# The next three functions check for the availability of a given package.
+# AST_C_DEFINE_CHECK looks for the presence of a #define in a header file,
+# AST_C_COMPILE_CHECK can be used for testing for various items in header files,
+# AST_EXT_LIB_CHECK looks for a symbol in a given library, or at least
+# for the presence of a header file.
+# AST_EXT_TOOL_CHECK looks for a symbol in using $1-config to determine CFLAGS and LIBS
+#
+# They are only run if PBX_$1 != 1 (where $1 is the package),
+# so you can call them multiple times and stop at the first matching one.
+# On success, they both set PBX_$1 = 1, set $1_INCLUDE and $1_LIB as applicable,
+# and also #define HAVE_$1 1 and #define HAVE_$1_VERSION ${last_argument}
+# in autoconfig.h so you can tell which test succeeded.
+# They should be called after AST_EXT_LIB_SETUP($1, ...)
+
+# Check if a given macro is defined in a certain header.
+
+# AST_C_DEFINE_CHECK([package], [macro name], [header file], [version])
+AC_DEFUN([AST_C_DEFINE_CHECK],
+[
+ if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+ AC_MSG_CHECKING([for $2 in $3])
+ saved_cppflags="${CPPFLAGS}"
+ if test "x${$1_DIR}" != "x"; then
+ $1_INCLUDE="-I${$1_DIR}/include"
+ fi
+ CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+ AC_COMPILE_IFELSE(
+ [ AC_LANG_PROGRAM( [#include <$3>],
+ [#if defined($2)
+ int foo = 0;
+ #else
+ int foo = bar;
+ #endif
+ 0
+ ])],
+ [ AC_MSG_RESULT(yes)
+ PBX_$1=1
+ AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+ AC_DEFINE([HAVE_$1_VERSION], $4, [Define $1 headers version])
+ ],
+ [ AC_MSG_RESULT(no) ]
+ )
+ CPPFLAGS="${saved_cppflags}"
+ fi
+])
+
+
+# Check if a given expression will compile using a certain header.
+
+# AST_C_COMPILE_CHECK([package], [expression], [header file], [version])
+AC_DEFUN([AST_C_COMPILE_CHECK],
+[
+ if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+ AC_MSG_CHECKING([if "$2" compiles using $3])
+ saved_cppflags="${CPPFLAGS}"
+ if test "x${$1_DIR}" != "x"; then
+ $1_INCLUDE="-I${$1_DIR}/include"
+ fi
+ CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+ AC_COMPILE_IFELSE(
+ [ AC_LANG_PROGRAM( [#include <$3>],
+ [ $2; ]
+ )],
+ [ AC_MSG_RESULT(yes)
+ PBX_$1=1
+ AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+ AC_DEFINE([HAVE_$1_VERSION], $4, [Define $1 headers version])
+ ],
+ [ AC_MSG_RESULT(no) ]
+ )
+ CPPFLAGS="${saved_cppflags}"
+ fi
+])
+
+
+# Check for existence of a given package ($1), either looking up a function
+# in a library, or, if no function is supplied, only check for the
+# existence of the header files.
+
+# AST_EXT_LIB_CHECK([package], [library], [function], [header],
+# [extra libs], [extra cflags], [version])
+AC_DEFUN([AST_EXT_LIB_CHECK],
+[
+if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+ pbxlibdir=""
+ # if --with-$1=DIR has been specified, use it.
+ if test "x${$1_DIR}" != "x"; then
+ if test -d ${$1_DIR}/lib; then
+ pbxlibdir="-L${$1_DIR}/lib"
+ else
+ pbxlibdir="-L${$1_DIR}"
+ fi
+ fi
+ pbxfuncname="$3"
+ if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers
+ AST_$1_FOUND=yes
+ else
+ AC_CHECK_LIB([$2], [${pbxfuncname}], [AST_$1_FOUND=yes], [AST_$1_FOUND=no], ${pbxlibdir} $5)
+ fi
+
+ # now check for the header.
+ if test "${AST_$1_FOUND}" = "yes"; then
+ $1_LIB="${pbxlibdir} -l$2 $5"
+ # if --with-$1=DIR has been specified, use it.
+ if test "x${$1_DIR}" != "x"; then
+ $1_INCLUDE="-I${$1_DIR}/include"
+ fi
+ $1_INCLUDE="${$1_INCLUDE} $6"
+ if test "x$4" = "x" ; then # no header, assume found
+ $1_HEADER_FOUND="1"
+ else # check for the header
+ saved_cppflags="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE} $6"
+ AC_CHECK_HEADER([$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
+ CPPFLAGS="${saved_cppflags}"
+ fi
+ if test "x${$1_HEADER_FOUND}" = "x0" ; then
+ $1_LIB=""
+ $1_INCLUDE=""
+ else
+ if test "x${pbxfuncname}" = "x" ; then # only checking headers -> no library
+ $1_LIB=""
+ fi
+ PBX_$1=1
+ # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED
+ AC_DEFINE_UNQUOTED([HAVE_$1], 1, [Define this to indicate the ${$1_DESCRIP} library])
+ AC_DEFINE_UNQUOTED([HAVE_$1_VERSION], [$7], [Define to indicate the ${$1_DESCRIP} library version])
+ fi
+ fi
+fi
+])
+
+
+# Check for a package using $2-config. Similar to AST_EXT_LIB_CHECK,
+# but use $2-config to determine cflags and libraries to use.
+# $3 and $4 can be used to replace --cflags and --libs in the request
+
+# AST_EXT_TOOL_CHECK([package], [tool name], [--cflags], [--libs], [includes], [expression])
+AC_DEFUN([AST_EXT_TOOL_CHECK],
+[
+ if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+ PBX_$1=0
+ AC_CHECK_TOOL(CONFIG_$1, $2-config, No)
+ if test ! "x${CONFIG_$1}" = xNo; then
+ if test x"$3" = x ; then A=--cflags ; else A="$3" ; fi
+ $1_INCLUDE=$(${CONFIG_$1} $A)
+ if test x"$4" = x ; then A=--libs ; else A="$4" ; fi
+ $1_LIB=$(${CONFIG_$1} $A)
+ if test x"$5" != x ; then
+ saved_cppflags="${CPPFLAGS}"
+ if test "x${$1_DIR}" != "x"; then
+ $1_INCLUDE="-I${$1_DIR}/include"
+ fi
+ CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+ AC_COMPILE_IFELSE(
+ [ AC_LANG_PROGRAM( [ $5 ],
+ [ $6; ]
+ )],
+ [ PBX_$1=1
+ AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+ ],
+ []
+ )
+ CPPFLAGS="${saved_cppflags}"
+ else
+ PBX_$1=1
+ AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 libraries.])
+ fi
+ fi
+ fi
+])
+
+AC_DEFUN(
+[AST_CHECK_GNU_MAKE], [AC_CACHE_CHECK(for GNU make, GNU_MAKE,
+ GNU_MAKE='Not Found' ;
+ GNU_MAKE_VERSION_MAJOR=0 ;
+ GNU_MAKE_VERSION_MINOR=0 ;
+ for a in make gmake gnumake ; do
+ if test -z "$a" ; then continue ; fi ;
+ if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
+ GNU_MAKE=$a ;
+ GNU_MAKE_VERSION_MAJOR=`$GNU_MAKE --version | grep "GNU Make" | cut -f3 -d' ' | cut -f1 -d'.'`
+ GNU_MAKE_VERSION_MINOR=`$GNU_MAKE --version | grep "GNU Make" | cut -f2 -d'.' | cut -c1-2`
+ break;
+ fi
+ done ;
+) ;
+if test "x$GNU_MAKE" = "xNot Found" ; then
+ AC_MSG_ERROR( *** Please install GNU make. It is required to build Asterisk!)
+ exit 1
+fi
+AC_SUBST([GNU_MAKE])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB], [
+PWLIB_INCDIR=
+PWLIB_LIBDIR=
+AC_LANG_PUSH([C++])
+if test "${PWLIBDIR:-unset}" != "unset" ; then
+ AC_CHECK_HEADER(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
+fi
+if test "${HAS_PWLIB:-unset}" = "unset" ; then
+ if test "${OPENH323DIR:-unset}" != "unset"; then
+ AC_CHECK_HEADER(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
+ fi
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ PWLIBDIR="${OPENH323DIR}/../pwlib"
+ else
+ AC_CHECK_HEADER(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ PWLIBDIR="${HOME}/pwlib"
+ else
+ AC_CHECK_HEADER(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
+ if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
+ fi
+ PWLIB_INCDIR="/usr/local/include"
+ PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
+ if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+ if test "x$LIB64" != "x"; then
+ PWLIB_LIBDIR="/usr/local/lib64"
+ else
+ PWLIB_LIBDIR="/usr/local/lib"
+ fi
+ fi
+ PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
+ PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
+ else
+ AC_CHECK_HEADER(/usr/include/ptlib.h, HAS_PWLIB=1, )
+ if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
+ PWLIB_INCDIR="/usr/include"
+ PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
+ if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+ if test "x$LIB64" != "x"; then
+ PWLIB_LIBDIR="/usr/lib64"
+ else
+ PWLIB_LIBDIR="/usr/lib"
+ fi
+ fi
+ PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
+ PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
+ fi
+ fi
+ fi
+ fi
+fi
+
+#if test "${HAS_PWLIB:-unset}" = "unset" ; then
+# echo "Cannot find pwlib - please install or set PWLIBDIR and try again"
+# exit
+#fi
+
+if test "${HAS_PWLIB:-unset}" != "unset" ; then
+ if test "${PWLIBDIR:-unset}" = "unset" ; then
+ if test "${PTLIB_CONFIG:-unset}" != "unset" ; then
+ PWLIBDIR=`$PTLIB_CONFIG --prefix`
+ else
+ echo "Cannot find ptlib-config - please install and try again"
+ exit
+ fi
+ fi
+
+ if test "x$PWLIBDIR" = "x/usr" -o "x$PWLIBDIR" = "x/usr/"; then
+ PWLIBDIR="/usr/share/pwlib"
+ PWLIB_INCDIR="/usr/include"
+ if test "x$LIB64" != "x"; then
+ PWLIB_LIBDIR="/usr/lib64"
+ else
+ PWLIB_LIBDIR="/usr/lib"
+ fi
+ fi
+ if test "x$PWLIBDIR" = "x/usr/local" -o "x$PWLIBDIR" = "x/usr/"; then
+ PWLIBDIR="/usr/local/share/pwlib"
+ PWLIB_INCDIR="/usr/local/include"
+ if test "x$LIB64" != "x"; then
+ PWLIB_LIBDIR="/usr/local/lib64"
+ else
+ PWLIB_LIBDIR="/usr/local/lib"
+ fi
+ fi
+
+ if test "${PWLIB_INCDIR:-unset}" = "unset"; then
+ PWLIB_INCDIR="${PWLIBDIR}/include"
+ fi
+ if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+ PWLIB_LIBDIR="${PWLIBDIR}/lib"
+ fi
+
+ AC_SUBST([PWLIBDIR])
+ AC_SUBST([PWLIB_INCDIR])
+ AC_SUBST([PWLIB_LIBDIR])
+fi
+ AC_LANG_POP([C++])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_PLATFORM], [
+PWLIB_OSTYPE=
+case "$host_os" in
+ linux*) PWLIB_OSTYPE=linux ;
+ ;;
+ freebsd* ) PWLIB_OSTYPE=FreeBSD ;
+ ;;
+ openbsd* ) PWLIB_OSTYPE=OpenBSD ;
+ ENDLDLIBS="-lossaudio" ;
+ ;;
+ netbsd* ) PWLIB_OSTYPE=NetBSD ;
+ ENDLDLIBS="-lossaudio" ;
+ ;;
+ solaris* | sunos* ) PWLIB_OSTYPE=solaris ;
+ ;;
+ darwin* ) PWLIB_OSTYPE=Darwin ;
+ ;;
+ beos*) PWLIB_OSTYPE=beos ;
+ STDCCFLAGS="$STDCCFLAGS -D__BEOS__"
+ ;;
+ cygwin*) PWLIB_OSTYPE=cygwin ;
+ ;;
+ mingw*) PWLIB_OSTYPE=mingw ;
+ STDCCFLAGS="$STDCCFLAGS -mms-bitfields" ;
+ ENDLDLIBS="-lwinmm -lwsock32 -lsnmpapi -lmpr -lcomdlg32 -lgdi32 -lavicap32" ;
+ ;;
+ * ) PWLIB_OSTYPE="$host_os" ;
+ AC_MSG_WARN("OS $PWLIB_OSTYPE not recognized - proceed with caution!") ;
+ ;;
+esac
+
+PWLIB_MACHTYPE=
+case "$host_cpu" in
+ x86 | i686 | i586 | i486 | i386 ) PWLIB_MACHTYPE=x86
+ ;;
+
+ x86_64) PWLIB_MACHTYPE=x86_64 ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ alpha | alphaev56 | alphaev6 | alphaev67 | alphaev7) PWLIB_MACHTYPE=alpha ;
+ P_64BIT=1 ;
+ ;;
+
+ sparc ) PWLIB_MACHTYPE=sparc ;
+ ;;
+
+ powerpc ) PWLIB_MACHTYPE=ppc ;
+ ;;
+
+ ppc ) PWLIB_MACHTYPE=ppc ;
+ ;;
+
+ powerpc64 ) PWLIB_MACHTYPE=ppc64 ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ ppc64 ) PWLIB_MACHTYPE=ppc64 ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ ia64) PWLIB_MACHTYPE=ia64 ;
+ P_64BIT=1 ;
+ ;;
+
+ s390x) PWLIB_MACHTYPE=s390x ;
+ P_64BIT=1 ;
+ LIB64=1 ;
+ ;;
+
+ s390) PWLIB_MACHTYPE=s390 ;
+ ;;
+
+ * ) PWLIB_MACHTYPE="$host_cpu";
+ AC_MSG_WARN("CPU $PWLIB_MACHTYPE not recognized - proceed with caution!") ;;
+esac
+
+PWLIB_PLATFORM="${PWLIB_OSTYPE}_${PWLIB_MACHTYPE}"
+
+AC_SUBST([PWLIB_PLATFORM])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323], [
+OPENH323_INCDIR=
+OPENH323_LIBDIR=
+AC_LANG_PUSH([C++])
+if test "${OPENH323DIR:-unset}" != "unset" ; then
+ AC_CHECK_HEADER(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
+fi
+if test "${HAS_OPENH323:-unset}" = "unset" ; then
+ AC_CHECK_HEADER(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="${PWLIBDIR}/../openh323"
+ saved_cppflags="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} -I${PWLIB_INCDIR}/openh323 -I${PWLIB_INCDIR}"
+ AC_CHECK_HEADER(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}", [#include <ptlib.h>])
+ CPPFLAGS="${saved_cppflags}"
+ else
+ saved_cppflags="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} -I${HOME}/openh323/include -I${PWLIB_INCDIR}"
+ AC_CHECK_HEADER(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
+ CPPFLAGS="${saved_cppflags}"
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="${HOME}/openh323"
+ else
+ saved_cppflags="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} -I/usr/local/include/openh323 -I${PWLIB_INCDIR}"
+ AC_CHECK_HEADER(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
+ CPPFLAGS="${saved_cppflags}"
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="/usr/local/share/openh323"
+ OPENH323_INCDIR="/usr/local/include/openh323"
+ if test "x$LIB64" != "x"; then
+ OPENH323_LIBDIR="/usr/local/lib64"
+ else
+ OPENH323_LIBDIR="/usr/local/lib"
+ fi
+ else
+ saved_cppflags="${CPPFLAGS}"
+ CPPFLAGS="${CPPFLAGS} -I/usr/include/openh323 -I${PWLIB_INCDIR}"
+ AC_CHECK_HEADER(/usr/include/openh323/h323.h, HAS_OPENH323=1, , [#include <ptlib.h>])
+ CPPFLAGS="${saved_cppflags}"
+ if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ OPENH323DIR="/usr/share/openh323"
+ OPENH323_INCDIR="/usr/include/openh323"
+ if test "x$LIB64" != "x"; then
+ OPENH323_LIBDIR="/usr/lib64"
+ else
+ OPENH323_LIBDIR="/usr/lib"
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+
+if test "${HAS_OPENH323:-unset}" != "unset" ; then
+ if test "${OPENH323_INCDIR:-unset}" = "unset"; then
+ OPENH323_INCDIR="${OPENH323DIR}/include"
+ fi
+ if test "${OPENH323_LIBDIR:-unset}" = "unset"; then
+ OPENH323_LIBDIR="${OPENH323DIR}/lib"
+ fi
+
+ OPENH323_LIBDIR="`cd ${OPENH323_LIBDIR}; pwd`"
+ OPENH323_INCDIR="`cd ${OPENH323_INCDIR}; pwd`"
+ OPENH323DIR="`cd ${OPENH323DIR}; pwd`"
+
+ AC_SUBST([OPENH323DIR])
+ AC_SUBST([OPENH323_INCDIR])
+ AC_SUBST([OPENH323_LIBDIR])
+fi
+ AC_LANG_POP([C++])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_VERSION], [
+ if test "${HAS_$2:-unset}" != "unset"; then
+ $2_VERSION=`grep "$2_VERSION" ${$2_INCDIR}/$3 | cut -f2 -d ' ' | sed -e 's/"//g'`
+ $2_MAJOR_VERSION=`echo ${$2_VERSION} | cut -f1 -d.`
+ $2_MINOR_VERSION=`echo ${$2_VERSION} | cut -f2 -d.`
+ $2_BUILD_NUMBER=`echo ${$2_VERSION} | cut -f3 -d.`
+ let $2_VER=${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}
+ let $2_REQ=$4*10000+$5*100+$6
+
+ AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)
+ if test ${$2_VER} -lt ${$2_REQ}; then
+ AC_MSG_RESULT(no)
+ unset HAS_$2
+ else
+ AC_MSG_RESULT(yes)
+ fi
+ fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_BUILD], [
+ if test "${HAS_$2:-unset}" != "unset"; then
+ AC_MSG_CHECKING($1 installation validity)
+
+ saved_cppflags="${CPPFLAGS}"
+ saved_libs="${LIBS}"
+ if test "${$2_LIB:-unset}" != "unset"; then
+ LIBS="${LIBS} ${$2_LIB} $7"
+ else
+ LIBS="${LIBS} -L${$2_LIBDIR} -l${PLATFORM_$2} $7"
+ fi
+ CPPFLAGS="${CPPFLAGS} -I${$2_INCDIR} $6"
+
+ AC_LANG_PUSH([C++])
+
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([$4],[$5])],
+ [ AC_MSG_RESULT(yes)
+ ac_cv_lib_$2="yes"
+ ],
+ [ AC_MSG_RESULT(no)
+ ac_cv_lib_$2="no"
+ ]
+ )
+
+ AC_LANG_POP([C++])
+
+ LIBS="${saved_libs}"
+ CPPFLAGS="${saved_cppflags}"
+
+ if test "${ac_cv_lib_$2}" = "yes"; then
+ if test "${$2_LIB:-undef}" = "undef"; then
+ if test "${$2_LIBDIR}" != "" -a "${$2_LIBDIR}" != "/usr/lib"; then
+ $2_LIB="-L${$2_LIBDIR} -l${PLATFORM_$2}"
+ else
+ $2_LIB="-l${PLATFORM_$2}"
+ fi
+ fi
+ if test "${$2_INCDIR}" != "" -a "${$2_INCDIR}" != "/usr/include"; then
+ $2_INCLUDE="-I${$2_INCDIR}"
+ fi
+ PBX_$2=1
+ AC_DEFINE([HAVE_$2], 1, [$3])
+ fi
+ fi
+])
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_BUILD], [
+ if test "${HAS_OPENH323:-unset}" != "unset"; then
+ AC_MSG_CHECKING(OpenH323 build option)
+ OPENH323_SUFFIX=
+ prefixes="h323_${PWLIB_PLATFORM}_ h323_ openh323"
+ for pfx in $prefixes; do
+ files=`ls -l ${OPENH323_LIBDIR}/lib${pfx}*.so* 2>/dev/null`
+ libfile=
+ if test -n "$files"; then
+ for f in $files; do
+ if test -f $f -a ! -L $f; then
+ libfile=`basename $f`
+ break;
+ fi
+ done
+ fi
+ if test -n "$libfile"; then
+ OPENH323_PREFIX=$pfx
+ break;
+ fi
+ done
+ if test "${libfile:-unset}" != "unset"; then
+ OPENH323_SUFFIX=`eval "echo ${libfile} | sed -e 's/lib${OPENH323_PREFIX}\(@<:@^.@:>@*\)\..*/\1/'"`
+ fi
+ case "${OPENH323_SUFFIX}" in
+ n)
+ OPENH323_BUILD="notrace";;
+ r)
+ OPENH323_BUILD="opt";;
+ d)
+ OPENH323_BUILD="debug";;
+ *)
+ if test "${OPENH323_PREFIX:-undef}" = "openh323"; then
+ notrace=`eval "grep NOTRACE ${OPENH323DIR}/openh323u.mak | grep = | sed -e 's/@<:@A-Z0-9_@:>@*@<:@ @:>@*=@<:@ @:>@*//'"`
+ if test "x$notrace" = "x"; then
+ notrace="0"
+ fi
+ if test "$notrace" -ne 0; then
+ OPENH323_BUILD="notrace"
+ else
+ OPENH323_BUILD="opt"
+ fi
+ OPENH323_LIB="-l${OPENH323_PREFIX}"
+ else
+ OPENH323_BUILD="notrace"
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT(${OPENH323_BUILD})
+
+ AC_SUBST([OPENH323_SUFFIX])
+ AC_SUBST([OPENH323_BUILD])
+ fi
+])
+
+
+# AST_FUNC_FORK
+# -------------
+AN_FUNCTION([fork], [AST_FUNC_FORK])
+AN_FUNCTION([vfork], [AST_FUNC_FORK])
+AC_DEFUN([AST_FUNC_FORK],
+[AC_REQUIRE([AC_TYPE_PID_T])dnl
+AC_CHECK_HEADERS(vfork.h)
+AC_CHECK_FUNCS(fork vfork)
+if test "x$ac_cv_func_fork" = xyes; then
+ _AST_FUNC_FORK
+else
+ ac_cv_func_fork_works=$ac_cv_func_fork
+fi
+if test "x$ac_cv_func_fork_works" = xcross; then
+ case $host in
+ *-*-amigaos* | *-*-msdosdjgpp* | *-*-uclinux* | *-*-linux-uclibc* )
+ # Override, as these systems have only a dummy fork() stub
+ ac_cv_func_fork_works=no
+ ;;
+ *)
+ ac_cv_func_fork_works=yes
+ ;;
+ esac
+ AC_MSG_WARN([result $ac_cv_func_fork_works guessed because of cross compilation])
+fi
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+if test "x$ac_cv_func_vfork" = xyes; then
+ _AC_FUNC_VFORK
+fi;
+if test "x$ac_cv_func_fork_works" = xcross; then
+ ac_cv_func_vfork_works=$ac_cv_func_vfork
+ AC_MSG_WARN([result $ac_cv_func_vfork_works guessed because of cross compilation])
+fi
+
+if test "x$ac_cv_func_vfork_works" = xyes; then
+ AC_DEFINE(HAVE_WORKING_VFORK, 1, [Define to 1 if `vfork' works.])
+else
+ AC_DEFINE(vfork, fork, [Define as `fork' if `vfork' does not work.])
+fi
+if test "x$ac_cv_func_fork_works" = xyes; then
+ AC_DEFINE(HAVE_WORKING_FORK, 1, [Define to 1 if `fork' works.])
+fi
+])# AST_FUNC_FORK
+
+
+# _AST_FUNC_FORK
+# -------------
+AC_DEFUN([_AST_FUNC_FORK],
+ [AC_CACHE_CHECK(for working fork, ac_cv_func_fork_works,
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+ [
+ /* By Ruediger Kuhlmann. */
+ return fork () < 0;
+ ])],
+ [ac_cv_func_fork_works=yes],
+ [ac_cv_func_fork_works=no],
+ [ac_cv_func_fork_works=cross])])]
+)# _AST_FUNC_FORK
+
+# AST_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AST_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+ [AC_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])
+AC_REQUIRE([AST_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
+ while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AST_PROG_LD_GNU
+])# AST_PROG_LD
+
+
+# AST_PROG_LD_GNU
+# --------------
+AC_DEFUN([AST_PROG_LD_GNU],
+[AC_REQUIRE([AST_PROG_EGREP])dnl
+AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# AST_PROG_LD_GNU
+
+# AST_PROG_EGREP
+# -------------
+m4_ifndef([AST_PROG_EGREP], [AC_DEFUN([AST_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+ [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+ then ac_cv_prog_egrep='grep -E'
+ else ac_cv_prog_egrep='egrep'
+ fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])]) # AST_PROG_EGREP
+
+# AST_PROG_SED
+# -----------
+# Check for a fully functional sed program that truncates
+# as few characters as possible. Prefer GNU sed if found.
+AC_DEFUN([AST_PROG_SED],
+[AC_CACHE_CHECK([for a sed that does not truncate output], ac_cv_path_SED,
+ [dnl ac_script should not contain more than 99 commands (for HP-UX sed),
+ dnl but more than about 7000 bytes, to catch a limit in Solaris 8 /usr/ucb/sed.
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" | sed 99q >conftest.sed
+ $as_unset ac_script || ac_script=
+ _AC_PATH_PROG_FEATURE_CHECK(SED, [sed gsed],
+ [_AC_FEATURE_CHECK_LENGTH([ac_path_SED], [ac_cv_path_SED],
+ ["$ac_path_SED" -f conftest.sed])])])
+ SED="$ac_cv_path_SED"
+ AC_SUBST([SED])dnl
+ rm -f conftest.sed
+])# AST_PROG_SED
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl LIBS="$PTHREAD_LIBS $LIBS"
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+
+AC_DEFUN([ACX_PTHREAD],
+[
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+ else
+ PTHREAD_CC=$CC
+ fi
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/trunk/agi/DialAnMp3.agi b/trunk/agi/DialAnMp3.agi
new file mode 100644
index 000000000..59a54265e
--- /dev/null
+++ b/trunk/agi/DialAnMp3.agi
@@ -0,0 +1,82 @@
+#!/usr/bin/perl
+#
+# Simple AGI application to play mp3's selected by a user both using
+# xmms and over the phone itself.
+#
+$|=1;
+while(<STDIN>) {
+ chomp;
+ last unless length($_);
+ if (/^agi_(\w+)\:\s+(.*)$/) {
+ $AGI{$1} = $2;
+ }
+}
+
+print STDERR "AGI Environment Dump:\n";
+foreach $i (sort keys %AGI) {
+ print STDERR " -- $i = $AGI{$i}\n";
+}
+
+dbmopen(%DIGITS, "/var/lib/asterisk/mp3list", 0644) || die("Unable to open mp3list");;
+
+sub checkresult {
+ my ($res) = @_;
+ my $retval;
+ $tests++;
+ chomp $res;
+ if ($res =~ /^200/) {
+ $res =~ /result=(-?[\w\*\#]+)/;
+ return $1;
+ } else {
+ return -1;
+ }
+}
+
+#print STDERR "1. Playing beep...\n";
+#print "STREAM FILE beep \"\"\n";
+#$result = <STDIN>;
+#checkresult($result);
+
+print STDERR "2. Getting song name...\n";
+print "GET DATA demo-enterkeywords\n";
+$result = <STDIN>;
+$digitstr = checkresult($result);
+if ($digitstr < 0) {
+ exit(1);
+}
+$digitstr =~ s/\*/ /g;
+
+print STDERR "Resulting songname is $digitstr\n";
+@searchwords = split (/\s+/, $digitstr);
+print STDERR "Searchwords: " . join(':', @searchwords) . "\n";
+
+foreach $key (sort keys %DIGITS) {
+ @words = split(/\s+/, $DIGITS{$key});
+ $match = 1;
+ foreach $search (@searchwords) {
+ $match = 0 unless grep(/$search/, @words);
+ }
+ if ($match > 0) {
+ print STDERR "File $key matches\n";
+ # Play a beep
+ print "STREAM FILE beep \"\"\n";
+ system("xmms", $key);
+ $result = <STDIN>;
+ if (&checkresult($result) < 0) {
+ exit 0;
+ }
+ print "EXEC MP3Player \"$key\"\n";
+# print "WAIT FOR DIGIT 60000\n";
+ $result = <STDIN>;
+ if (&checkresult($result) < 0) {
+ exit 0;
+ }
+ print STDERR "Got here...\n";
+ }
+}
+
+print STDERR "4. Testing 'saynumber' of $digitstr...\n";
+print "STREAM FILE demo-nomatch\"\"\n";
+$result = <STDIN>;
+checkresult($result);
+
diff --git a/trunk/agi/Makefile b/trunk/agi/Makefile
new file mode 100644
index 000000000..0cb6f3f02
--- /dev/null
+++ b/trunk/agi/Makefile
@@ -0,0 +1,52 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Makefile for AGI-related stuff
+#
+# Copyright (C) 1999-2006, Digium
+#
+# Mark Spencer <markster@digium.com>
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+.PHONY: clean all uninstall
+
+AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi
+
+ifeq ($(OSARCH),SunOS)
+ LIBS+=-lsocket -lnsl
+endif
+
+ifeq ($(OSARCH),mingw32)
+ AGIS:=
+endif
+
+include $(ASTTOPDIR)/Makefile.rules
+
+all: $(AGIS)
+
+strcompat.c: ../main/strcompat.c
+ @cp $< $@
+
+eagi-test: eagi-test.o strcompat.o
+
+eagi-sphinx-test: eagi-sphinx-test.o
+
+install: all
+ mkdir -p $(DESTDIR)$(AGI_DIR)
+ for x in $(AGIS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(AGI_DIR) ; done
+
+uninstall:
+ for x in $(AGIS); do rm -f $(DESTDIR)$(AGI_DIR)/$$x ; done
+
+clean:
+ rm -f *.so *.o look eagi-test eagi-sphinx-test
+ rm -f .*.o.d .*.oo.d
+ rm -f *.s *.i
+ rm -f strcompat.c
+
+ifneq ($(wildcard .*.d),)
+ include .*.d
+endif
diff --git a/trunk/agi/agi-test.agi b/trunk/agi/agi-test.agi
new file mode 100644
index 000000000..4fc36eda8
--- /dev/null
+++ b/trunk/agi/agi-test.agi
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+use strict;
+
+$|=1;
+
+# Setup some variables
+my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
+
+while(<STDIN>) {
+ chomp;
+ last unless length($_);
+ if (/^agi_(\w+)\:\s+(.*)$/) {
+ $AGI{$1} = $2;
+ }
+}
+
+print STDERR "AGI Environment Dump:\n";
+foreach my $i (sort keys %AGI) {
+ print STDERR " -- $i = $AGI{$i}\n";
+}
+
+sub checkresult {
+ my ($res) = @_;
+ my $retval;
+ $tests++;
+ chomp $res;
+ if ($res =~ /^200/) {
+ $res =~ /result=(-?\d+)/;
+ if (!length($1)) {
+ print STDERR "FAIL ($res)\n";
+ $fail++;
+ } else {
+ print STDERR "PASS ($1)\n";
+ $pass++;
+ }
+ } else {
+ print STDERR "FAIL (unexpected result '$res')\n";
+ $fail++;
+ }
+}
+
+print STDERR "1. Testing 'sendfile'...";
+print "STREAM FILE beep \"\"\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "2. Testing 'sendtext'...";
+print "SEND TEXT \"hello world\"\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "3. Testing 'sendimage'...";
+print "SEND IMAGE asterisk-image\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "4. Testing 'saynumber'...";
+print "SAY NUMBER 192837465 \"\"\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "5. Testing 'waitdtmf'...";
+print "WAIT FOR DIGIT 1000\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "6. Testing 'record'...";
+print "RECORD FILE testagi gsm 1234 3000\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "6a. Testing 'record' playback...";
+print "STREAM FILE testagi \"\"\n";
+my $result = <STDIN>;
+&checkresult($result);
+
+print STDERR "================== Complete ======================\n";
+print STDERR "$tests tests completed, $pass passed, $fail failed\n";
+print STDERR "==================================================\n";
diff --git a/trunk/agi/eagi-sphinx-test.c b/trunk/agi/eagi-sphinx-test.c
new file mode 100644
index 000000000..d2898763c
--- /dev/null
+++ b/trunk/agi/eagi-sphinx-test.c
@@ -0,0 +1,231 @@
+/*
+ * Extended AGI test application
+ *
+ * This code is released into public domain
+ * without any warranty of any kind.
+ *
+ */
+
+/*! \file
+ * Extended AGI test application
+ *
+ * This code is released into public domain
+ * without any warranty of any kind.
+ *
+ * \ingroup agi
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "asterisk.h"
+
+#include "asterisk/compat.h"
+
+#define AUDIO_FILENO (STDERR_FILENO + 1)
+
+#define SPHINX_HOST "192.168.1.108"
+#define SPHINX_PORT 3460
+
+static int sphinx_sock = -1;
+
+static int connect_sphinx(void)
+{
+ struct hostent *hp;
+ struct sockaddr_in sin;
+ int res;
+ hp = gethostbyname(SPHINX_HOST);
+ if (!hp) {
+ fprintf(stderr, "Unable to resolve '%s'\n", SPHINX_HOST);
+ return -1;
+ }
+ sphinx_sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sphinx_sock < 0) {
+ fprintf(stderr, "Unable to allocate socket: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(SPHINX_PORT);
+ memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+ if (connect(sphinx_sock, (struct sockaddr *)&sin, sizeof(sin))) {
+ fprintf(stderr, "Unable to connect on socket: %s\n", strerror(errno));
+ close(sphinx_sock);
+ sphinx_sock = -1;
+ return -1;
+ }
+ res = fcntl(sphinx_sock, F_GETFL);
+ if ((res < 0) || (fcntl(sphinx_sock, F_SETFL, res | O_NONBLOCK) < 0)) {
+ fprintf(stderr, "Unable to set flags on socket: %s\n", strerror(errno));
+ close(sphinx_sock);
+ sphinx_sock = -1;
+ return -1;
+ }
+ return 0;
+}
+
+static int read_environment(void)
+{
+ char buf[256];
+ char *val;
+ /* Read environment */
+ for(;;) {
+ fgets(buf, sizeof(buf), stdin);
+ if (feof(stdin))
+ return -1;
+ buf[strlen(buf) - 1] = '\0';
+ /* Check for end of environment */
+ if (!strlen(buf))
+ return 0;
+ val = strchr(buf, ':');
+ if (!val) {
+ fprintf(stderr, "Invalid environment: '%s'\n", buf);
+ return -1;
+ }
+ *val = '\0';
+ val++;
+ val++;
+ /* Skip space */
+ fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
+
+ /* Load into normal environment */
+ setenv(buf, val, 1);
+
+ }
+ /* Never reached */
+ return 0;
+}
+
+static char *wait_result(void)
+{
+ fd_set fds;
+ int res;
+ int max;
+ static char astresp[256];
+ static char sphinxresp[256];
+ char audiobuf[4096];
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ FD_SET(AUDIO_FILENO, &fds);
+ max = AUDIO_FILENO;
+ if (sphinx_sock > -1) {
+ FD_SET(sphinx_sock, &fds);
+ if (sphinx_sock > max)
+ max = sphinx_sock;
+ }
+ /* Wait for *some* sort of I/O */
+ res = select(max + 1, &fds, NULL, NULL, NULL);
+ if (res < 0) {
+ fprintf(stderr, "Error in select: %s\n", strerror(errno));
+ return NULL;
+ }
+ if (FD_ISSET(STDIN_FILENO, &fds)) {
+ fgets(astresp, sizeof(astresp), stdin);
+ if (feof(stdin)) {
+ fprintf(stderr, "Got hungup on apparently\n");
+ return NULL;
+ }
+ astresp[strlen(astresp) - 1] = '\0';
+ fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
+ return astresp;
+ }
+ if (FD_ISSET(AUDIO_FILENO, &fds)) {
+ res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
+ if (res > 0) {
+ if (sphinx_sock > -1)
+ write(sphinx_sock, audiobuf, res);
+ }
+ }
+ if ((sphinx_sock > -1) && FD_ISSET(sphinx_sock, &fds)) {
+ res = read(sphinx_sock, sphinxresp, sizeof(sphinxresp));
+ if (res > 0) {
+ fprintf(stderr, "Oooh, Sphinx found a token: '%s'\n", sphinxresp);
+ return sphinxresp;
+ } else if (res == 0) {
+ fprintf(stderr, "Hrm, lost sphinx, guess we're on our own\n");
+ close(sphinx_sock);
+ sphinx_sock = -1;
+ }
+ }
+ }
+
+}
+
+static char *run_command(char *command)
+{
+ fprintf(stdout, "%s\n", command);
+ return wait_result();
+}
+
+static int run_script(void)
+{
+ char *res;
+ res = run_command("STREAM FILE demo-enterkeywords 0123456789*#");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "1. Result is '%s'\n", res);
+ res = run_command("STREAM FILE demo-nomatch 0123456789*#");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "2. Result is '%s'\n", res);
+ res = run_command("SAY NUMBER 23452345 0123456789*#");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "3. Result is '%s'\n", res);
+ res = run_command("GET DATA demo-enterkeywords");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "4. Result is '%s'\n", res);
+ res = run_command("STREAM FILE auth-thankyou \"\"");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "5. Result is '%s'\n", res);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char *tmp;
+ int ver = 0;
+ int subver = 0;
+ /* Setup stdin/stdout for line buffering */
+ setlinebuf(stdin);
+ setlinebuf(stdout);
+ if (read_environment()) {
+ fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
+ exit(1);
+ }
+ connect_sphinx();
+ tmp = getenv("agi_enhanced");
+ if (tmp) {
+ if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
+ ver = 0;
+ }
+ if (ver < 1) {
+ fprintf(stderr, "No enhanced AGI services available. Use EAGI, not AGI\n");
+ exit(1);
+ }
+ if (run_script())
+ return -1;
+ exit(0);
+}
diff --git a/trunk/agi/eagi-test.c b/trunk/agi/eagi-test.c
new file mode 100644
index 000000000..704fd7b22
--- /dev/null
+++ b/trunk/agi/eagi-test.c
@@ -0,0 +1,165 @@
+/*
+ * Extended AGI test application
+ *
+ * This code is released into the public domain
+ * with no warranty of any kind
+ */
+
+#include "asterisk.h"
+
+#define AUDIO_FILENO (STDERR_FILENO + 1)
+
+/*! \file
+ * Extended AGI test application
+ *
+ * This code is released into the public domain
+ * with no warranty of any kind
+ *
+ * \ingroup agi
+ */
+
+static int read_environment(void)
+{
+ char buf[256];
+ char *val;
+ /* Read environment */
+ for(;;) {
+ fgets(buf, sizeof(buf), stdin);
+ if (feof(stdin))
+ return -1;
+ buf[strlen(buf) - 1] = '\0';
+ /* Check for end of environment */
+ if (!strlen(buf))
+ return 0;
+ val = strchr(buf, ':');
+ if (!val) {
+ fprintf(stderr, "Invalid environment: '%s'\n", buf);
+ return -1;
+ }
+ *val = '\0';
+ val++;
+ val++;
+ /* Skip space */
+ fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
+
+ /* Load into normal environment */
+ setenv(buf, val, 1);
+
+ }
+ /* Never reached */
+ return 0;
+}
+
+static char *wait_result(void)
+{
+ fd_set fds;
+ int res;
+ int bytes = 0;
+ static char astresp[256];
+ char audiobuf[4096];
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds);
+ FD_SET(AUDIO_FILENO, &fds);
+ /* Wait for *some* sort of I/O */
+ res = select(AUDIO_FILENO + 1, &fds, NULL, NULL, NULL);
+ if (res < 0) {
+ fprintf(stderr, "Error in select: %s\n", strerror(errno));
+ return NULL;
+ }
+ if (FD_ISSET(STDIN_FILENO, &fds)) {
+ fgets(astresp, sizeof(astresp), stdin);
+ if (feof(stdin)) {
+ fprintf(stderr, "Got hungup on apparently\n");
+ return NULL;
+ }
+ astresp[strlen(astresp) - 1] = '\0';
+ fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
+ return astresp;
+ }
+ if (FD_ISSET(AUDIO_FILENO, &fds)) {
+ res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
+ if (res > 0) {
+ /* XXX Process the audio with sphinx here XXX */
+#if 0
+ fprintf(stderr, "Got %d/%d bytes of audio\n", res, bytes);
+#endif
+ bytes += res;
+ /* Prentend we detected some audio after 3 seconds */
+ if (bytes > 16000 * 3) {
+ return "Sample Message";
+ bytes = 0;
+ }
+ }
+ }
+ }
+
+}
+
+static char *run_command(char *command)
+{
+ fprintf(stdout, "%s\n", command);
+ return wait_result();
+}
+
+static int run_script(void)
+{
+ char *res;
+ res = run_command("STREAM FILE demo-enterkeywords 0123456789*#");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "1. Result is '%s'\n", res);
+ res = run_command("STREAM FILE demo-nomatch 0123456789*#");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "2. Result is '%s'\n", res);
+ res = run_command("SAY NUMBER 23452345 0123456789*#");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "3. Result is '%s'\n", res);
+ res = run_command("GET DATA demo-enterkeywords");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "4. Result is '%s'\n", res);
+ res = run_command("STREAM FILE auth-thankyou \"\"");
+ if (!res) {
+ fprintf(stderr, "Failed to execute command\n");
+ return -1;
+ }
+ fprintf(stderr, "5. Result is '%s'\n", res);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char *tmp;
+ int ver = 0;
+ int subver = 0;
+ /* Setup stdin/stdout for line buffering */
+ setlinebuf(stdin);
+ setlinebuf(stdout);
+ if (read_environment()) {
+ fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
+ exit(1);
+ }
+ tmp = getenv("agi_enhanced");
+ if (tmp) {
+ if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
+ ver = 0;
+ }
+ if (ver < 1) {
+ fprintf(stderr, "No enhanced AGI services available. Use EAGI, not AGI\n");
+ exit(1);
+ }
+ if (run_script())
+ return -1;
+ exit(0);
+}
diff --git a/trunk/agi/fastagi-test b/trunk/agi/fastagi-test
new file mode 100644
index 000000000..d3f13cf6b
--- /dev/null
+++ b/trunk/agi/fastagi-test
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+use strict;
+use Socket;
+use Carp;
+use IO::Handle;
+
+my $port = 4573;
+
+$|=1;
+
+# Setup some variables
+my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
+
+sub checkresult {
+ my ($res) = @_;
+ my $retval;
+ $tests++;
+ chomp $res;
+ if ($res =~ /^200/) {
+ $res =~ /result=(-?\d+)/;
+ if (!length($1)) {
+ print STDERR "FAIL ($res)\n";
+ $fail++;
+ } else {
+ print STDERR "PASS ($1)\n";
+ $pass++;
+ }
+ } else {
+ print STDERR "FAIL (unexpected result '$res')\n";
+ $fail++;
+ }
+}
+
+socket(SERVER, PF_INET, SOCK_STREAM, 0);
+setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));
+bind(SERVER, sockaddr_in($port, INADDR_ANY)) || die("can't bind\n");
+listen(SERVER, SOMAXCONN);
+
+for(;;) {
+ my $raddr = accept(CLIENT, SERVER);
+ my ($s, $p) = sockaddr_in($raddr);
+ CLIENT->autoflush(1);
+ while(<CLIENT>) {
+ chomp;
+ last unless length($_);
+ if (/^agi_(\w+)\:\s+(.*)$/) {
+ $AGI{$1} = $2;
+ }
+ }
+ print STDERR "AGI Environment Dump from $s:$p --\n";
+ foreach my $i (sort keys %AGI) {
+ print STDERR " -- $i = $AGI{$i}\n";
+ }
+
+ print STDERR "1. Testing 'sendfile'...";
+ print CLIENT "STREAM FILE beep \"\"\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+
+ print STDERR "2. Testing 'sendtext'...";
+ print CLIENT "SEND TEXT \"hello world\"\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+
+ print STDERR "3. Testing 'sendimage'...";
+ print CLIENT "SEND IMAGE asterisk-image\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+
+ print STDERR "4. Testing 'saynumber'...";
+ print CLIENT "SAY NUMBER 192837465 \"\"\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+
+ print STDERR "5. Testing 'waitdtmf'...";
+ print CLIENT "WAIT FOR DIGIT 1000\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+
+ print STDERR "6. Testing 'record'...";
+ print CLIENT "RECORD FILE testagi gsm 1234 3000\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+
+ print STDERR "6a. Testing 'record' playback...";
+ print CLIENT "STREAM FILE testagi \"\"\n";
+ my $result = <CLIENT>;
+ &checkresult($result);
+ close(CLIENT);
+ print STDERR "================== Complete ======================\n";
+ print STDERR "$tests tests completed, $pass passed, $fail failed\n";
+ print STDERR "==================================================\n";
+}
+
diff --git a/trunk/agi/jukebox.agi b/trunk/agi/jukebox.agi
new file mode 100755
index 000000000..7bd9c10f9
--- /dev/null
+++ b/trunk/agi/jukebox.agi
@@ -0,0 +1,488 @@
+#!/usr/bin/perl
+#
+# Jukebox 0.2
+#
+# A music manager for Asterisk.
+#
+# Copyright (C) 2005-2006, Justin Tunney
+#
+# Justin Tunney <jesuscyborg@gmail.com>
+#
+# This program is free software, distributed under the terms of the
+# GNU General Public License v2.
+#
+# Keep it open source pigs
+#
+# --------------------------------------------------------------------
+#
+# Uses festival to list off all your MP3 music files over a channel in
+# a hierarchical fashion. Put this file in your agi-bin folder which
+# is located at: /var/lib/asterisk/agi-bin Be sure to chmod +x it!
+#
+# Invocation Example:
+# exten => 68742,1,Answer()
+# exten => 68742,2,agi,jukebox.agi|/home/justin/Music
+# exten => 68742,3,Hangup()
+#
+# exten => 68742,1,Answer()
+# exten => 68742,2,agi,jukebox.agi|/home/justin/Music|pm
+# exten => 68742,3,Hangup()
+#
+# Options:
+# p - Precache text2wave outputs for every possible filename.
+# It is much better to set this option because if a caller
+# presses a key during a cache operation, it will be ignored.
+# m - Go back to menu after playing song
+# g - Do not play the greeting message
+#
+# Usage Instructions:
+# - Press '*' to go up a directory. If you are in the root music
+# folder you will be exitted from the script.
+# - If you have a really long list of files, you can filter the list
+# at any time by pressing '#' and spelling out a few letters you
+# expect the files to start with. For example, if you wanted to
+# know what extension 'Requiem For A Dream' was, you'd type:
+# '#737'. Note, phone keypads don't include Q and Z. Q is 7 and
+# Z is 9.
+#
+# Notes:
+# - This AGI script uses the MP3Player command which uses the
+# mpg123 Program. Grab yourself a copy of this program by
+# going to http://www.mpg123.de/cgi-bin/sitexplorer.cgi?/mpg123/
+# Be sure to download mpg123-0.59r.tar.gz because it is known to
+# work with Asterisk and hopefully isn't the release with that
+# awful security problem. If you're using Fedora Core 3 with
+# Alsa like me, make linux-alsa isn't going to work. Do make
+# linux-devel and you're peachy keen.
+#
+# - You won't get nifty STDERR debug messages if you're using a
+# remote asterisk shell.
+#
+# - For some reason, caching certain files will generate the
+# error: 'using default diphone ax-ax for y-pau'. Example:
+# # echo "Depeche Mode - CUW - 05 - The Meaning of Love" | text2wave -o /var/jukeboxcache/jukeboxcache/Depeche_Mode/Depeche_Mode_-_CUW_-_05_-_The_Meaning_of_Love.mp3.ul -otype ulaw -
+# The temporary work around is to just touch these files.
+#
+# - The background app doesn't like to get more than 2031 chars
+# of input.
+#
+
+use strict;
+
+$|=1;
+
+# Setup some variables
+my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
+my @masterCacheList = ();
+my $maxNumber = 10;
+
+while (<STDIN>) {
+ chomp;
+ last unless length($_);
+ if (/^agi_(\w+)\:\s+(.*)$/) {
+ $AGI{$1} = $2;
+ }
+}
+
+# setup options
+my $SHOWGREET = 1;
+my $PRECACHE = 0;
+my $MENUAFTERSONG = 0;
+
+$PRECACHE = 1 if $ARGV[1] =~ /p/;
+$MENUAFTERSONG = 1 if $ARGV[1] =~ /m/;
+$SHOWGREET = 0 if $ARGV[1] =~ /g/;
+
+# setup folders
+my $MUSIC = $ARGV[0];
+$MUSIC = &rmts($MUSIC);
+my $FESTIVALCACHE = "/var/jukeboxcache";
+if (! -e $FESTIVALCACHE) {
+ `mkdir -p -m0776 $FESTIVALCACHE`;
+}
+
+# make sure we have some essential files
+if (! -e "$FESTIVALCACHE/jukebox_greet.ul") {
+ `echo "Welcome to the Asterisk Jukebox" | text2wave -o $FESTIVALCACHE/jukebox_greet.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_press.ul") {
+ `echo "Press" | text2wave -o $FESTIVALCACHE/jukebox_press.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_for.ul") {
+ `echo "For" | text2wave -o $FESTIVALCACHE/jukebox_for.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_toplay.ul") {
+ `echo "To play" | text2wave -o $FESTIVALCACHE/jukebox_toplay.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_nonefound.ul") {
+ `echo "There were no music files found in this folder" | text2wave -o $FESTIVALCACHE/jukebox_nonefound.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_percent.ul") {
+ `echo "Percent" | text2wave -o $FESTIVALCACHE/jukebox_percent.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_generate.ul") {
+ `echo "Please wait while Astrisk Jukebox cashes the files of your music collection" | text2wave -o $FESTIVALCACHE/jukebox_generate.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_invalid.ul") {
+ `echo "You have entered an invalid selection" | text2wave -o $FESTIVALCACHE/jukebox_invalid.ul -otype ulaw -`;
+}
+if (! -e "$FESTIVALCACHE/jukebox_thankyou.ul") {
+ `echo "Thank you for using Astrisk Jukebox, Goodbye" | text2wave -o $FESTIVALCACHE/jukebox_thankyou.ul -otype ulaw -`;
+}
+
+# greet the user
+if ($SHOWGREET) {
+ print "EXEC Playback \"$FESTIVALCACHE/jukebox_greet\"\n";
+ my $result = <STDIN>; &check_result($result);
+}
+
+# go through the directories
+music_dir_cache() if $PRECACHE;
+music_dir_menu('/');
+
+exit 0;
+
+##########################################################################
+
+sub music_dir_menu {
+ my $dir = shift;
+
+# generate a list of mp3's and directories and assign each one it's
+# own selection number. Then make sure that we've got a sound clip
+# for the file name
+ if (!opendir(THEDIR, rmts($MUSIC.$dir))) {
+ print STDERR "Failed to open music directory: $dir\n";
+ exit 1;
+ }
+ my @files = sort readdir THEDIR;
+ my $cnt = 1;
+ my @masterBgList = ();
+
+ foreach my $file (@files) {
+ chomp($file);
+ if ($file ne '.' && $file ne '..' && $file ne 'festivalcache') { # ignore special files
+ my $real_version = &rmts($MUSIC.$dir).'/'.$file;
+ my $cache_version = &rmts($FESTIVALCACHE.$dir).'/'.$file.'.ul';
+ my $cache_version2 = &rmts($FESTIVALCACHE.$dir).'/'.$file;
+ my $cache_version_esc = &clean_file($cache_version);
+ my $cache_version2_esc = &clean_file($cache_version2);
+
+ if (-d $real_version) {
+# 0:id 1:type 2:text2wav-file 3:for-filtering 4:the-directory 5:text2wav echo
+ push(@masterBgList, [$cnt++, 1, $cache_version2_esc, &remove_special_chars($file), $file, "for the $file folder"]);
+ } elsif ($real_version =~ /\.mp3$/) {
+# 0:id 1:type 2:text2wav-file 3:for-filtering 4:the-mp3
+ push(@masterBgList, [$cnt++, 2, $cache_version2_esc, &remove_special_chars($file), $real_version, "to play $file"]);
+ }
+ }
+ }
+ close(THEDIR);
+
+ my @filterList = @masterBgList;
+
+ if (@filterList == 0) {
+ print "EXEC Playback \"$FESTIVALCACHE/jukebox_nonefound\"\n";
+ my $result = <STDIN>; &check_result($result);
+ return 0;
+ }
+
+ for (;;) {
+MYCONTINUE:
+
+# play bg selections and figure out their selection
+ my $digit = '';
+ my $digitstr = '';
+ for (my $n=0; $n<@filterList; $n++) {
+ &cache_speech(&remove_file_extension($filterList[$n][5]), "$filterList[$n][2].ul") if ! -e "$filterList[$n][2].ul";
+ &cache_speech("Press $filterList[$n][0]", "$FESTIVALCACHE/jukebox_$filterList[$n][0].ul") if ! -e "$FESTIVALCACHE/jukebox_$filterList[$n][0].ul";
+ print "EXEC Background \"$filterList[$n][2]&$FESTIVALCACHE/jukebox_$filterList[$n][0]\"\n";
+ my $result = <STDIN>;
+ $digit = &check_result($result);
+ if ($digit > 0) {
+ $digitstr .= chr($digit);
+ last;
+ }
+ }
+ for (;;) {
+ print "WAIT FOR DIGIT 3000\n";
+ my $result = <STDIN>;
+ $digit = &check_result($result);
+ last if $digit <= 0;
+ $digitstr .= chr($digit);
+ }
+
+# see if it's a valid selection
+ print STDERR "Digits Entered: '$digitstr'\n";
+ exit 0 if $digitstr eq '';
+ my $found = 0;
+ goto EXITSUB if $digitstr =~ /\*/;
+
+# filter the list
+ if ($digitstr =~ /^\#\d+/) {
+ my $regexp = '';
+ for (my $n=1; $n<length($digitstr); $n++) {
+ my $d = substr($digitstr, $n, 1);
+ if ($d == 2) {
+ $regexp .= '[abc]';
+ } elsif ($d == 3) {
+ $regexp .= '[def]';
+ } elsif ($d == 4) {
+ $regexp .= '[ghi]';
+ } elsif ($d == 5) {
+ $regexp .= '[jkl]';
+ } elsif ($d == 6) {
+ $regexp .= '[mno]';
+ } elsif ($d == 7) {
+ $regexp .= '[pqrs]';
+ } elsif ($d == 8) {
+ $regexp .= '[tuv]';
+ } elsif ($d == 9) {
+ $regexp .= '[wxyz]';
+ }
+ }
+ @filterList = ();
+ for (my $n=1; $n<@masterBgList; $n++) {
+ push(@filterList, $masterBgList[$n]) if $masterBgList[$n][3] =~ /^$regexp/i;
+ }
+ goto MYCONTINUE;
+ }
+
+ for (my $n=0; $n<@masterBgList; $n++) {
+ if ($digitstr == $masterBgList[$n][0]) {
+ if ($masterBgList[$n][1] == 1) { # a folder
+ &music_dir_menu(rmts($dir).'/'.$masterBgList[$n][4]);
+ @filterList = @masterBgList;
+ goto MYCONTINUE;
+ } elsif ($masterBgList[$n][1] == 2) { # a file
+# because *'s scripting language is crunk and won't allow us to escape
+# funny filenames, we need to create a temporary symlink to the mp3
+# file
+ my $mp3 = &escape_file($masterBgList[$n][4]);
+ my $link = `mktemp`;
+ chomp($link);
+ $link .= '.mp3';
+ print STDERR "ln -s $mp3 $link\n";
+ my $cmdr = `ln -s $mp3 $link`;
+ chomp($cmdr);
+ print "Failed to create symlink to mp3: $cmdr\n" if $cmdr ne '';
+
+ print "EXEC MP3Player \"$link\"\n";
+ my $result = <STDIN>; &check_result($result);
+
+ `rm $link`;
+
+ if (!$MENUAFTERSONG) {
+ print "EXEC Playback \"$FESTIVALCACHE/jukebox_thankyou\"\n";
+ my $result = <STDIN>; &check_result($result);
+ exit 0;
+ } else {
+ goto MYCONTINUE;
+ }
+ }
+ }
+ }
+ print "EXEC Playback \"$FESTIVALCACHE/jukebox_invalid\"\n";
+ my $result = <STDIN>; &check_result($result);
+ }
+ EXITSUB:
+}
+
+sub cache_speech {
+ my $speech = shift;
+ my $file = shift;
+
+ my $theDir = extract_file_dir($file);
+ `mkdir -p -m0776 $theDir`;
+
+ print STDERR "echo \"$speech\" | text2wave -o $file -otype ulaw -\n";
+ my $cmdr = `echo "$speech" | text2wave -o $file -otype ulaw -`;
+ chomp($cmdr);
+ if ($cmdr =~ /using default diphone/) {
+# temporary bug work around....
+ `touch $file`;
+ } elsif ($cmdr ne '') {
+ print STDERR "Command Failed\n";
+ exit 1;
+ }
+}
+
+sub music_dir_cache {
+# generate list of text2speech files to generate
+ if (!music_dir_cache_genlist('/')) {
+ print STDERR "Horrible Dreadful Error: No Music Found in $MUSIC!";
+ exit 1;
+ }
+
+# add to list how many 'number' files we have to generate. We can't
+# use the SayNumber app in Asterisk because we want to chain all
+# talking in one Background command. We also want a consistent
+# voice...
+ for (my $n=1; $n<=$maxNumber; $n++) {
+ push(@masterCacheList, [3, "Press $n", "$FESTIVALCACHE/jukebox_$n.ul"]) if ! -e "$FESTIVALCACHE/jukebox_$n.ul";
+ }
+
+# now generate all these darn text2speech files
+ if (@masterCacheList > 5) {
+ print "EXEC Playback \"$FESTIVALCACHE/jukebox_generate\"\n";
+ my $result = <STDIN>; &check_result($result);
+ }
+ my $theTime = time();
+ for (my $n=0; $n < @masterCacheList; $n++) {
+ my $cmdr = '';
+ if ($masterCacheList[$n][0] == 1) { # directory
+ &cache_speech("for folder $masterCacheList[$n][1]", $masterCacheList[$n][2]);
+ } elsif ($masterCacheList[$n][0] == 2) { # file
+ &cache_speech("to play $masterCacheList[$n][1]", $masterCacheList[$n][2]);
+ } elsif ($masterCacheList[$n][0] == 3) { # number
+ &cache_speech($masterCacheList[$n][1], $masterCacheList[$n][2]);
+ }
+ if (time() >= $theTime + 30) {
+ my $percent = int($n / @masterCacheList * 100);
+ print "SAY NUMBER $percent \"\"\n";
+ my $result = <STDIN>; &check_result($result);
+ print "EXEC Playback \"$FESTIVALCACHE/jukebox_percent\"\n";
+ my $result = <STDIN>; &check_result($result);
+ $theTime = time();
+ }
+ }
+}
+
+# this function will fill the @masterCacheList of all the files that
+# need to have text2speeced ulaw files of their names generated
+sub music_dir_cache_genlist {
+ my $dir = shift;
+ if (!opendir(THEDIR, rmts($MUSIC.$dir))) {
+ print STDERR "Failed to open music directory: $dir\n";
+ exit 1;
+ }
+ my @files = sort readdir THEDIR;
+ my $foundFiles = 0;
+ my $tmpMaxNum = 0;
+ foreach my $file (@files) {
+ chomp;
+ if ($file ne '.' && $file ne '..' && $file ne 'festivalcache') { # ignore special files
+ my $real_version = &rmts($MUSIC.$dir).'/'.$file;
+ my $cache_version = &rmts($FESTIVALCACHE.$dir).'/'.$file.'.ul';
+ my $cache_version2 = &rmts($FESTIVALCACHE.$dir).'/'.$file;
+ my $cache_version_esc = &clean_file($cache_version);
+ my $cache_version2_esc = &clean_file($cache_version2);
+
+ if (-d $real_version) {
+ if (music_dir_cache_genlist(rmts($dir).'/'.$file)) {
+ $tmpMaxNum++;
+ $maxNumber = $tmpMaxNum if $tmpMaxNum > $maxNumber;
+ push(@masterCacheList, [1, $file, $cache_version_esc]) if ! -e $cache_version_esc;
+ $foundFiles = 1;
+ }
+ } elsif ($real_version =~ /\.mp3$/) {
+ $tmpMaxNum++;
+ $maxNumber = $tmpMaxNum if $tmpMaxNum > $maxNumber;
+ push(@masterCacheList, [2, &remove_file_extension($file), $cache_version_esc]) if ! -e $cache_version_esc;
+ $foundFiles = 1;
+ }
+ }
+ }
+ close(THEDIR);
+ return $foundFiles;
+}
+
+sub rmts { # remove trailing slash
+ my $hog = shift;
+ $hog =~ s/\/$//;
+ return $hog;
+}
+
+sub extract_file_name {
+ my $hog = shift;
+ $hog =~ /\/?([^\/]+)$/;
+ return $1;
+}
+
+sub extract_file_dir {
+ my $hog = shift;
+ return $hog if ! ($hog =~ /\//);
+ $hog =~ /(.*)\/[^\/]*$/;
+ return $1;
+}
+
+sub remove_file_extension {
+ my $hog = shift;
+ return $hog if ! ($hog =~ /\./);
+ $hog =~ /(.*)\.[^.]*$/;
+ return $1;
+}
+
+sub clean_file {
+ my $hog = shift;
+ $hog =~ s/\\/_/g;
+ $hog =~ s/ /_/g;
+ $hog =~ s/\t/_/g;
+ $hog =~ s/\'/_/g;
+ $hog =~ s/\"/_/g;
+ $hog =~ s/\(/_/g;
+ $hog =~ s/\)/_/g;
+ $hog =~ s/&/_/g;
+ $hog =~ s/\[/_/g;
+ $hog =~ s/\]/_/g;
+ $hog =~ s/\$/_/g;
+ $hog =~ s/\|/_/g;
+ $hog =~ s/\^/_/g;
+ return $hog;
+}
+
+sub remove_special_chars {
+ my $hog = shift;
+ $hog =~ s/\\//g;
+ $hog =~ s/ //g;
+ $hog =~ s/\t//g;
+ $hog =~ s/\'//g;
+ $hog =~ s/\"//g;
+ $hog =~ s/\(//g;
+ $hog =~ s/\)//g;
+ $hog =~ s/&//g;
+ $hog =~ s/\[//g;
+ $hog =~ s/\]//g;
+ $hog =~ s/\$//g;
+ $hog =~ s/\|//g;
+ $hog =~ s/\^//g;
+ return $hog;
+}
+
+sub escape_file {
+ my $hog = shift;
+ $hog =~ s/\\/\\\\/g;
+ $hog =~ s/ /\\ /g;
+ $hog =~ s/\t/\\\t/g;
+ $hog =~ s/\'/\\\'/g;
+ $hog =~ s/\"/\\\"/g;
+ $hog =~ s/\(/\\\(/g;
+ $hog =~ s/\)/\\\)/g;
+ $hog =~ s/&/\\&/g;
+ $hog =~ s/\[/\\\[/g;
+ $hog =~ s/\]/\\\]/g;
+ $hog =~ s/\$/\\\$/g;
+ $hog =~ s/\|/\\\|/g;
+ $hog =~ s/\^/\\\^/g;
+ return $hog;
+}
+
+sub check_result {
+ my ($res) = @_;
+ my $retval;
+ $tests++;
+ chomp $res;
+ if ($res =~ /^200/) {
+ $res =~ /result=(-?\d+)/;
+ if (!length($1)) {
+ print STDERR "FAIL ($res)\n";
+ $fail++;
+ exit 1;
+ } else {
+ print STDERR "PASS ($1)\n";
+ return $1;
+ }
+ } else {
+ print STDERR "FAIL (unexpected result '$res')\n";
+ exit 1;
+ }
+}
diff --git a/trunk/agi/numeralize b/trunk/agi/numeralize
new file mode 100644
index 000000000..5ca51913d
--- /dev/null
+++ b/trunk/agi/numeralize
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+#
+# Build a database linking filenames to their numerical representations
+# using a keypad for the DialAnMp3 application
+#
+
+$mp3dir="/usr/media/mpeg3";
+
+dbmopen(%DIGITS, "/var/lib/asterisk/mp3list", 0644) || die("Unable to open mp3list");;
+sub process_dir {
+ my ($dir) = @_;
+ my $file;
+ my $digits;
+ my @entries;
+ opendir(DIR, $dir);
+ @entries = readdir(DIR);
+ closedir(DIR);
+ foreach $_ (@entries) {
+ if (!/^\./) {
+ $file = "$dir/$_";
+ if (-d "$file") {
+ process_dir("$file");
+ } else {
+ $digits = $_;
+ $digits =~ s/[^ \w]+//g;
+ $digits =~ s/\_/ /g;
+ $digits =~ tr/[a-z]/[A-Z]/;
+ $digits =~ tr/[A-C]/2/;
+ $digits =~ tr/[D-F]/3/;
+ $digits =~ tr/[G-I]/4/;
+ $digits =~ tr/[J-L]/5/;
+ $digits =~ tr/[M-O]/6/;
+ $digits =~ tr/[P-S]/7/;
+ $digits =~ tr/[T-V]/8/;
+ $digits =~ tr/[W-Z]/9/;
+ $digits =~ s/\s+/ /;
+ print "File: $file, digits: $digits\n";
+ $DIGITS{$file} = $digits;
+ }
+ }
+ }
+}
+
+process_dir($mp3dir);
diff --git a/trunk/apps/Makefile b/trunk/apps/Makefile
new file mode 100644
index 000000000..22b8f6d7a
--- /dev/null
+++ b/trunk/apps/Makefile
@@ -0,0 +1,41 @@
+#
+# Asterisk -- A telephony toolkit for Linux.
+#
+# Makefile for PBX applications
+#
+# Copyright (C) 1999-2006, Digium, Inc.
+#
+# This program is free software, distributed under the terms of
+# the GNU General Public License
+#
+
+-include $(ASTTOPDIR)/menuselect.makeopts $(ASTTOPDIR)/menuselect.makedeps
+
+MODULE_PREFIX=app
+MENUSELECT_CATEGORY=APPS
+MENUSELECT_DESCRIPTION=Applications
+
+MENUSELECT_OPTS_app_directory:=$(MENUSELECT_OPTS_app_voicemail)
+ifneq ($(findstring ODBC_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
+ MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
+ MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
+endif
+ifneq ($(findstring IMAP_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
+ MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
+ MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
+endif
+
+ifeq (SunOS,$(shell uname))
+ MENUSELECT_DEPENDS_app_chanspy+=RT
+ RT_LIB=-lrt
+endif
+
+all: _all
+
+include $(ASTTOPDIR)/Makefile.moddir_rules
+
+ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
+ LIBS+= -lres_features.so -lres_ael_share.so -lres_monitor.so -lres_speech.so
+ LIBS+= -lres_smdi.so
+endif
+
diff --git a/trunk/apps/app_adsiprog.c b/trunk/apps/app_adsiprog.c
new file mode 100644
index 000000000..1b09ce7b5
--- /dev/null
+++ b/trunk/apps/app_adsiprog.c
@@ -0,0 +1,1581 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Program Asterisk ADSI Scripts into phone
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+ * \ingroup applications
+ */
+
+/*** MODULEINFO
+ <depend>res_adsi</depend>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <netinet/in.h>
+#include <ctype.h>
+
+#include "asterisk/paths.h" /* use ast_config_AST_CONFIG_DIR */
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/adsi.h"
+#include "asterisk/utils.h"
+#include "asterisk/lock.h"
+
+static char *app = "ADSIProg";
+
+static char *synopsis = "Load Asterisk ADSI Scripts into phone";
+
+/* #define DUMP_MESSAGES */
+
+static char *descrip =
+" ADSIProg(script): This application programs an ADSI Phone with the given\n"
+"script. If nothing is specified, the default script (asterisk.adsi) is used.\n";
+
+struct adsi_event {
+ int id;
+ char *name;
+};
+
+static struct adsi_event events[] = {
+ { 1, "CALLERID" },
+ { 2, "VMWI" },
+ { 3, "NEARANSWER" },
+ { 4, "FARANSWER" },
+ { 5, "ENDOFRING" },
+ { 6, "IDLE" },
+ { 7, "OFFHOOK" },
+ { 8, "CIDCW" },
+ { 9, "BUSY" },
+ { 10, "FARRING" },
+ { 11, "DIALTONE" },
+ { 12, "RECALL" },
+ { 13, "MESSAGE" },
+ { 14, "REORDER" },
+ { 15, "DISTINCTIVERING" },
+ { 16, "RING" },
+ { 17, "REMINDERRING" },
+ { 18, "SPECIALRING" },
+ { 19, "CODEDRING" },
+ { 20, "TIMER" },
+ { 21, "INUSE" },
+ { 22, "EVENT22" },
+ { 23, "EVENT23" },
+ { 24, "CPEID" },
+};
+
+static struct adsi_event justify[] = {
+ { 0, "CENTER" },
+ { 1, "RIGHT" },
+ { 2, "LEFT" },
+ { 3, "INDENT" },
+};
+
+#define STATE_NORMAL 0
+#define STATE_INKEY 1
+#define STATE_INSUB 2
+#define STATE_INIF 3
+
+#define MAX_RET_CODE 20
+#define MAX_SUB_LEN 255
+#define MAX_MAIN_LEN 1600
+
+#define ARG_STRING (1 << 0)
+#define ARG_NUMBER (1 << 1)
+
+struct adsi_soft_key {
+ char vname[40]; /* Which "variable" is associated with it */
+ int retstrlen; /* Length of return string */
+ int initlen; /* initial length */
+ int id;
+ int defined;
+ char retstr[80]; /* Return string data */
+};
+
+struct adsi_subscript {
+ char vname[40];
+ int id;
+ int defined;
+ int datalen;
+ int inscount;
+ int ifinscount;
+ char *ifdata;
+ char data[2048];
+};
+
+struct adsi_state {
+ char vname[40];
+ int id;
+};
+
+struct adsi_flag {
+ char vname[40];
+ int id;
+};
+
+struct adsi_display {
+ char vname[40];
+ int id;
+ char data[70];
+ int datalen;
+};
+
+struct adsi_script {
+ int state;
+ int numkeys;
+ int numsubs;
+ int numstates;
+ int numdisplays;
+ int numflags;
+ struct adsi_soft_key *key;
+ struct adsi_subscript *sub;
+ /* Pre-defined displays */
+ struct adsi_display displays[63];
+ /* ADSI States 1 (initial) - 254 */
+ struct adsi_state states[256];
+ /* Keys 2-63 */
+ struct adsi_soft_key keys[62];
+ /* Subscripts 0 (main) to 127 */
+ struct adsi_subscript subs[128];
+ /* Flags 1-7 */
+ struct adsi_flag flags[7];
+
+ /* Stuff from adsi script */
+ unsigned char sec[5];
+ char desc[19];
+ unsigned char fdn[5];
+ int ver;
+};
+
+
+static int process_token(void *out, char *src, int maxlen, int argtype)
+{
+ if ((strlen(src) > 1) && src[0] == '\"') {
+ /* This is a quoted string */
+ if (!(argtype & ARG_STRING))
+ return -1;
+ src++;
+ /* Don't take more than what's there */
+ if (maxlen > strlen(src) - 1)
+ maxlen = strlen(src) - 1;
+ memcpy(out, src, maxlen);
+ ((char *)out)[maxlen] = '\0';
+ } else if (!ast_strlen_zero(src) && (src[0] == '\\')) {
+ if (!(argtype & ARG_NUMBER))
+ return -1;
+ /* Octal value */
+ if (sscanf(src, "%o", (int *)out) != 1)
+ return -1;
+ if (argtype & ARG_STRING) {
+ /* Convert */
+ *((unsigned int *)out) = htonl(*((unsigned int *)out));
+ }
+ } else if ((strlen(src) > 2) && (src[0] == '0') && (tolower(src[1]) == 'x')) {
+ if (!(argtype & ARG_NUMBER))
+ return -1;
+ /* Hex value */
+ if (sscanf(src + 2, "%x", (unsigned int *)out) != 1)
+ return -1;
+ if (argtype & ARG_STRING) {
+ /* Convert */
+ *((unsigned int *)out) = htonl(*((unsigned int *)out));
+ }
+ } else if ((!ast_strlen_zero(src) && isdigit(src[0]))) {
+ if (!(argtype & ARG_NUMBER))
+ return -1;
+ /* Hex value */
+ if (sscanf(src, "%d", (int *)out) != 1)
+ return -1;
+ if (argtype & ARG_STRING) {
+ /* Convert */
+ *((unsigned int *)out) = htonl(*((unsigned int *)out));
+ }
+ } else
+ return -1;
+ return 0;
+}
+
+static char *get_token(char **buf, char *script, int lineno)
+{
+ char *tmp = *buf, *keyword;
+ int quoted = 0;
+
+ /* Advance past any white space */
+ while(*tmp && (*tmp < 33))
+ tmp++;
+ if (!*tmp)
+ return NULL;
+ keyword = tmp;
+ while(*tmp && ((*tmp > 32) || quoted)) {
+ if (*tmp == '\"') {
+ quoted = !quoted;
+ }
+ tmp++;
+ }
+ if (quoted) {
+ ast_log(LOG_WARNING, "Mismatched quotes at line %d of %s\n", lineno, script);
+ return NULL;
+ }
+ *tmp = '\0';
+ tmp++;
+ while(*tmp && (*tmp < 33))
+ tmp++;
+ /* Note where we left off */
+ *buf = tmp;
+ return keyword;
+}
+
+static char *validdtmf = "123456789*0#ABCD";
+
+static int send_dtmf(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char dtmfstr[80], *a;
+ int bytes = 0;
+
+ if (!(a = get_token(&args, script, lineno))) {
+ ast_log(LOG_WARNING, "Expecting something to send for SENDDTMF at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(dtmfstr, a, sizeof(dtmfstr) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid token for SENDDTMF at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ a = dtmfstr;
+
+ while(*a) {
+ if (strchr(validdtmf, *a)) {
+ *buf = *a;
+ buf++;
+ bytes++;
+ } else
+ ast_log(LOG_WARNING, "'%c' is not a valid DTMF tone at line %d of %s\n", *a, lineno, script);
+ a++;
+ }
+
+ return bytes;
+}
+
+static int goto_line(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *page = get_token(&args, script, lineno);
+ char *gline = get_token(&args, script, lineno);
+ int line;
+ unsigned char cmd;
+
+ if (!page || !gline) {
+ ast_log(LOG_WARNING, "Expecting page and line number for GOTOLINE at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (!strcasecmp(page, "INFO")) {
+ cmd = 0;
+ } else if (!strcasecmp(page, "COMM")) {
+ cmd = 0x80;
+ } else {
+ ast_log(LOG_WARNING, "Expecting either 'INFO' or 'COMM' page, got got '%s' at line %d of %s\n", page, lineno, script);
+ return 0;
+ }
+
+ if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
+ return 0;
+ }
+
+ cmd |= line;
+ buf[0] = 0x8b;
+ buf[1] = cmd;
+
+ return 2;
+}
+
+static int goto_line_rel(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *dir = get_token(&args, script, lineno);
+ char *gline = get_token(&args, script, lineno);
+ int line;
+ unsigned char cmd;
+
+ if (!dir || !gline) {
+ ast_log(LOG_WARNING, "Expecting direction and number of lines for GOTOLINEREL at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (!strcasecmp(dir, "UP")) {
+ cmd = 0;
+ } else if (!strcasecmp(dir, "DOWN")) {
+ cmd = 0x20;
+ } else {
+ ast_log(LOG_WARNING, "Expecting either 'UP' or 'DOWN' direction, got '%s' at line %d of %s\n", dir, lineno, script);
+ return 0;
+ }
+
+ if (process_token(&line, gline, sizeof(line), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid line number '%s' at line %d of %s\n", gline, lineno, script);
+ return 0;
+ }
+
+ cmd |= line;
+ buf[0] = 0x8c;
+ buf[1] = cmd;
+
+ return 2;
+}
+
+static int send_delay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *gtime = get_token(&args, script, lineno);
+ int ms;
+
+ if (!gtime) {
+ ast_log(LOG_WARNING, "Expecting number of milliseconds to wait at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(&ms, gtime, sizeof(ms), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid delay milliseconds '%s' at line %d of %s\n", gtime, lineno, script);
+ return 0;
+ }
+
+ buf[0] = 0x90;
+
+ if (id == 11)
+ buf[1] = ms / 100;
+ else
+ buf[1] = ms / 10;
+
+ return 2;
+}
+
+static int set_state(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *gstate = get_token(&args, script, lineno);
+ int state;
+
+ if (!gstate) {
+ ast_log(LOG_WARNING, "Expecting state number at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(&state, gstate, sizeof(state), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid state number '%s' at line %d of %s\n", gstate, lineno, script);
+ return 0;
+ }
+
+ buf[0] = id;
+ buf[1] = state;
+
+ return 2;
+}
+
+static int cleartimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+
+ if (tok)
+ ast_log(LOG_WARNING, "Clearing timer requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
+
+ buf[0] = id;
+
+ /* For some reason the clear code is different slightly */
+ if (id == 7)
+ buf[1] = 0x10;
+ else
+ buf[1] = 0x00;
+
+ return 2;
+}
+
+static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
+{
+ int x;
+
+ for (x = 0; x < state->numflags; x++) {
+ if (!strcasecmp(state->flags[x].vname, name))
+ return &state->flags[x];
+ }
+
+ /* Return now if we're not allowed to create */
+ if (!create)
+ return NULL;
+
+ if (state->numflags > 6) {
+ ast_log(LOG_WARNING, "No more flag space at line %d of %s\n", lineno, script);
+ return NULL;
+ }
+
+ ast_copy_string(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname));
+ state->flags[state->numflags].id = state->numflags + 1;
+ state->numflags++;
+
+ return &state->flags[state->numflags-1];
+}
+
+static int setflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+ char sname[80];
+ struct adsi_flag *flag;
+
+ if (!tok) {
+ ast_log(LOG_WARNING, "Setting flag requires a flag number at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+
+ if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
+ ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
+ return 0;
+ }
+
+ buf[0] = id;
+ buf[1] = ((flag->id & 0x7) << 4) | 1;
+
+ return 2;
+}
+
+static int clearflag(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+ struct adsi_flag *flag;
+ char sname[80];
+
+ if (!tok) {
+ ast_log(LOG_WARNING, "Clearing flag requires a flag number at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(sname, tok, sizeof(sname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid flag '%s' at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+
+ if (!(flag = getflagbyname(state, sname, script, lineno, 0))) {
+ ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", sname, lineno, script);
+ return 0;
+ }
+
+ buf[0] = id;
+ buf[1] = ((flag->id & 0x7) << 4);
+
+ return 2;
+}
+
+static int starttimer(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+ int secs;
+
+ if (!tok) {
+ ast_log(LOG_WARNING, "Missing number of seconds at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(&secs, tok, sizeof(secs), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+
+ buf[0] = id;
+ buf[1] = 0x1;
+ buf[2] = secs;
+
+ return 3;
+}
+
+static int geteventbyname(char *name)
+{
+ int x;
+
+ for (x = 0; x < sizeof(events) / sizeof(events[0]); x++) {
+ if (!strcasecmp(events[x].name, name))
+ return events[x].id;
+ }
+
+ return 0;
+}
+
+static int getjustifybyname(char *name)
+{
+ int x;
+
+ for (x = 0; x <sizeof(justify) / sizeof(justify[0]); x++) {
+ if (!strcasecmp(justify[x].name, name))
+ return justify[x].id;
+ }
+
+ return -1;
+}
+
+static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name, char *script, int lineno)
+{
+ int x;
+
+ for (x = 0; x < state->numkeys; x++) {
+ if (!strcasecmp(state->keys[x].vname, name))
+ return &state->keys[x];
+ }
+
+ if (state->numkeys > 61) {
+ ast_log(LOG_WARNING, "No more key space at line %d of %s\n", lineno, script);
+ return NULL;
+ }
+
+ ast_copy_string(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname));
+ state->keys[state->numkeys].id = state->numkeys + 2;
+ state->numkeys++;
+
+ return &state->keys[state->numkeys-1];
+}
+
+static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name, char *script, int lineno)
+{
+ int x;
+
+ for (x = 0; x < state->numsubs; x++) {
+ if (!strcasecmp(state->subs[x].vname, name))
+ return &state->subs[x];
+ }
+
+ if (state->numsubs > 127) {
+ ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, script);
+ return NULL;
+ }
+
+ ast_copy_string(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname));
+ state->subs[state->numsubs].id = state->numsubs;
+ state->numsubs++;
+
+ return &state->subs[state->numsubs-1];
+}
+
+static struct adsi_state *getstatebyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
+{
+ int x;
+
+ for (x = 0; x <state->numstates; x++) {
+ if (!strcasecmp(state->states[x].vname, name))
+ return &state->states[x];
+ }
+
+ /* Return now if we're not allowed to create */
+ if (!create)
+ return NULL;
+
+ if (state->numstates > 253) {
+ ast_log(LOG_WARNING, "No more state space at line %d of %s\n", lineno, script);
+ return NULL;
+ }
+
+ ast_copy_string(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname));
+ state->states[state->numstates].id = state->numstates + 1;
+ state->numstates++;
+
+ return &state->states[state->numstates-1];
+}
+
+static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *name, char *script, int lineno, int create)
+{
+ int x;
+
+ for (x = 0; x < state->numdisplays; x++) {
+ if (!strcasecmp(state->displays[x].vname, name))
+ return &state->displays[x];
+ }
+
+ /* Return now if we're not allowed to create */
+ if (!create)
+ return NULL;
+
+ if (state->numdisplays > 61) {
+ ast_log(LOG_WARNING, "No more display space at line %d of %s\n", lineno, script);
+ return NULL;
+ }
+
+ ast_copy_string(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname));
+ state->displays[state->numdisplays].id = state->numdisplays + 1;
+ state->numdisplays++;
+
+ return &state->displays[state->numdisplays-1];
+}
+
+static int showkeys(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok, newkey[80];
+ int bytes, x, flagid = 0;
+ unsigned char keyid[6];
+ struct adsi_soft_key *key;
+ struct adsi_flag *flag;
+
+ for (x = 0; x < 7; x++) {
+ /* Up to 6 key arguments */
+ if (!(tok = get_token(&args, script, lineno)))
+ break;
+ if (!strcasecmp(tok, "UNLESS")) {
+ /* Check for trailing UNLESS flag */
+ if (!(tok = get_token(&args, script, lineno))) {
+ ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
+ } else if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid flag name '%s' at line %d of %s\n", tok, lineno, script);
+ } else if (!(flag = getflagbyname(state, newkey, script, lineno, 0))) {
+ ast_log(LOG_WARNING, "Flag '%s' is undeclared at line %d of %s\n", newkey, lineno, script);
+ } else
+ flagid = flag->id;
+ if ((tok = get_token(&args, script, lineno)))
+ ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
+ break;
+ }
+ if (x > 5) {
+ ast_log(LOG_WARNING, "Only 6 keys can be defined, ignoring '%s' at line %d of %s\n", tok, lineno, script);
+ break;
+ }
+ if (process_token(newkey, tok, sizeof(newkey) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid token for key name: %s\n", tok);
+ continue;
+ }
+
+ if (!(key = getkeybyname(state, newkey, script, lineno)))
+ break;
+ keyid[x] = key->id;
+ }
+ buf[0] = id;
+ buf[1] = (flagid & 0x7) << 3 | (x & 0x7);
+ for (bytes = 0; bytes < x; bytes++) {
+ buf[bytes + 2] = keyid[bytes];
+ }
+ return 2 + x;
+}
+
+static int showdisplay(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok, dispname[80];
+ int line = 0, flag = 0, cmd = 3;
+ struct adsi_display *disp;
+
+ /* Get display */
+ if (!(tok = get_token(&args, script, lineno)) || process_token(dispname, tok, sizeof(dispname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid display name: %s at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
+ return 0;
+ }
+
+ if (!(disp = getdisplaybyname(state, dispname, script, lineno, 0))) {
+ ast_log(LOG_WARNING, "Display '%s' is undefined at line %d of %s\n", dispname, lineno, script);
+ return 0;
+ }
+
+ if (!(tok = get_token(&args, script, lineno)) || strcasecmp(tok, "AT")) {
+ ast_log(LOG_WARNING, "Missing token 'AT' at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ /* Get line number */
+ if (!(tok = get_token(&args, script, lineno)) || process_token(&line, tok, sizeof(line), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid line: '%s' at line %d of %s\n", tok ? tok : "<nothing>", lineno, script);
+ return 0;
+ }
+
+ if ((tok = get_token(&args, script, lineno)) && !strcasecmp(tok, "NOUPDATE")) {
+ cmd = 1;
+ tok = get_token(&args, script, lineno);
+ }
+
+ if (tok && !strcasecmp(tok, "UNLESS")) {
+ /* Check for trailing UNLESS flag */
+ if (!(tok = get_token(&args, script, lineno))) {
+ ast_log(LOG_WARNING, "Missing argument for UNLESS clause at line %d of %s\n", lineno, script);
+ } else if (process_token(&flag, tok, sizeof(flag), ARG_NUMBER)) {
+ ast_log(LOG_WARNING, "Invalid flag number '%s' at line %d of %s\n", tok, lineno, script);
+ }
+ if ((tok = get_token(&args, script, lineno)))
+ ast_log(LOG_WARNING, "Extra arguments after UNLESS clause: '%s' at line %d of %s\n", tok, lineno, script);
+ }
+
+ buf[0] = id;
+ buf[1] = (cmd << 6) | (disp->id & 0x3f);
+ buf[2] = ((line & 0x1f) << 3) | (flag & 0x7);
+
+ return 3;
+}
+
+static int cleardisplay(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+
+ if (tok)
+ ast_log(LOG_WARNING, "Clearing display requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
+
+ buf[0] = id;
+ buf[1] = 0x00;
+ return 2;
+}
+
+static int digitdirect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+
+ if (tok)
+ ast_log(LOG_WARNING, "Digitdirect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
+
+ buf[0] = id;
+ buf[1] = 0x7;
+ return 2;
+}
+
+static int clearcbone(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+
+ if (tok)
+ ast_log(LOG_WARNING, "CLEARCB1 requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
+
+ buf[0] = id;
+ buf[1] = 0;
+ return 2;
+}
+
+static int digitcollect(char *buf, char *name, int id, char *args, struct adsi_script *istate, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+
+ if (tok)
+ ast_log(LOG_WARNING, "Digitcollect requires no arguments ('%s') at line %d of %s\n", tok, lineno, script);
+
+ buf[0] = id;
+ buf[1] = 0xf;
+ return 2;
+}
+
+static int subscript(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+ char subscript[80];
+ struct adsi_subscript *sub;
+
+ if (!tok) {
+ ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if (process_token(subscript, tok, sizeof(subscript) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid number of seconds '%s' at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+
+ if (!(sub = getsubbyname(state, subscript, script, lineno)))
+ return 0;
+
+ buf[0] = 0x9d;
+ buf[1] = sub->id;
+
+ return 2;
+}
+
+static int onevent(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ char *tok = get_token(&args, script, lineno);
+ char subscript[80], sname[80];
+ int sawin = 0, event, snums[8], scnt = 0, x;
+ struct adsi_subscript *sub;
+
+ if (!tok) {
+ ast_log(LOG_WARNING, "Missing event for 'ONEVENT' at line %d of %s\n", lineno, script);
+ return 0;
+ }
+
+ if ((event = geteventbyname(tok)) < 1) {
+ ast_log(LOG_WARNING, "'%s' is not a valid event name, at line %d of %s\n", args, lineno, script);
+ return 0;
+ }
+
+ tok = get_token(&args, script, lineno);
+ while ((!sawin && !strcasecmp(tok, "IN")) ||
+ (sawin && !strcasecmp(tok, "OR"))) {
+ sawin = 1;
+ if (scnt > 7) {
+ ast_log(LOG_WARNING, "No more than 8 states may be specified for inclusion at line %d of %s\n", lineno, script);
+ return 0;
+ }
+ /* Process 'in' things */
+ tok = get_token(&args, script, lineno);
+ if (process_token(sname, tok, sizeof(sname), ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid state name at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+ if ((snums[scnt] = getstatebyname(state, sname, script, lineno, 0) < 0)) {
+ ast_log(LOG_WARNING, "State '%s' not declared at line %d of %s\n", sname, lineno, script);
+ return 0;
+ }
+ scnt++;
+ if (!(tok = get_token(&args, script, lineno)))
+ break;
+ }
+ if (!tok || strcasecmp(tok, "GOTO")) {
+ if (!tok)
+ tok = "<nothing>";
+ if (sawin)
+ ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'OR' at line %d of %s\n", tok, lineno, script);
+ else
+ ast_log(LOG_WARNING, "Got '%s' while looking for 'GOTO' or 'IN' at line %d of %s\n", tok, lineno, script);
+ }
+ if (!(tok = get_token(&args, script, lineno))) {
+ ast_log(LOG_WARNING, "Missing subscript to call at line %d of %s\n", lineno, script);
+ return 0;
+ }
+ if (process_token(subscript, tok, sizeof(subscript) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Invalid subscript '%s' at line %d of %s\n", tok, lineno, script);
+ return 0;
+ }
+ if (!(sub = getsubbyname(state, subscript, script, lineno)))
+ return 0;
+ buf[0] = 8;
+ buf[1] = event;
+ buf[2] = sub->id | 0x80;
+ for (x = 0; x < scnt; x++)
+ buf[3 + x] = snums[x];
+ return 3 + scnt;
+}
+
+struct adsi_key_cmd {
+ char *name;
+ int id;
+ int (*add_args)(char *buf, char *name, int id, char *args, struct adsi_script *state, char *script, int lineno);
+};
+
+static struct adsi_key_cmd kcmds[] = {
+ { "SENDDTMF", 0, send_dtmf },
+ /* Encoded DTMF would go here */
+ { "ONHOOK", 0x81 },
+ { "OFFHOOK", 0x82 },
+ { "FLASH", 0x83 },
+ { "WAITDIALTONE", 0x84 },
+ /* Send line number */
+ { "BLANK", 0x86 },
+ { "SENDCHARS", 0x87 },
+ { "CLEARCHARS", 0x88 },
+ { "BACKSPACE", 0x89 },
+ /* Tab column */
+ { "GOTOLINE", 0x8b, goto_line },
+ { "GOTOLINEREL", 0x8c, goto_line_rel },
+ { "PAGEUP", 0x8d },
+ { "PAGEDOWN", 0x8e },
+ /* Extended DTMF */
+ { "DELAY", 0x90, send_delay },
+ { "DIALPULSEONE", 0x91 },
+ { "DATAMODE", 0x92 },
+ { "VOICEMODE", 0x93 },
+ /* Display call buffer 'n' */
+ /* Clear call buffer 'n' */
+ { "CLEARCB1", 0x95, clearcbone },
+ { "DIGITCOLLECT", 0x96, digitcollect },
+ { "DIGITDIRECT", 0x96, digitdirect },
+ { "CLEAR", 0x97 },
+ { "SHOWDISPLAY", 0x98, showdisplay },
+ { "CLEARDISPLAY", 0x98, cleardisplay },
+ { "SHOWKEYS", 0x99, showkeys },
+ { "SETSTATE", 0x9a, set_state },
+ { "TIMERSTART", 0x9b, starttimer },
+ { "TIMERCLEAR", 0x9b, cleartimer },
+ { "SETFLAG", 0x9c, setflag },
+ { "CLEARFLAG", 0x9c, clearflag },
+ { "GOTO", 0x9d, subscript },
+ { "EVENT22", 0x9e },
+ { "EVENT23", 0x9f },
+ { "EXIT", 0xa0 },
+};
+
+static struct adsi_key_cmd opcmds[] = {
+
+ /* 1 - Branch on event -- handled specially */
+ { "SHOWKEYS", 2, showkeys },
+ /* Display Control */
+ { "SHOWDISPLAY", 3, showdisplay },
+ { "CLEARDISPLAY", 3, cleardisplay },
+ { "CLEAR", 5 },
+ { "SETSTATE", 6, set_state },
+ { "TIMERSTART", 7, starttimer },
+ { "TIMERCLEAR", 7, cleartimer },
+ { "ONEVENT", 8, onevent },
+ /* 9 - Subroutine label, treated specially */
+ { "SETFLAG", 10, setflag },
+ { "CLEARFLAG", 10, clearflag },
+ { "DELAY", 11, send_delay },
+ { "EXIT", 12 },
+};
+
+
+static int process_returncode(struct adsi_soft_key *key, char *code, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ int x, res;
+ char *unused;
+
+ for (x = 0; x < sizeof(kcmds) / sizeof(kcmds[0]); x++) {
+ if ((kcmds[x].id > -1) && !strcasecmp(kcmds[x].name, code)) {
+ if (kcmds[x].add_args) {
+ res = kcmds[x].add_args(key->retstr + key->retstrlen,
+ code, kcmds[x].id, args, state, script, lineno);
+ if ((key->retstrlen + res - key->initlen) <= MAX_RET_CODE)
+ key->retstrlen += res;
+ else
+ ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", kcmds[x].name, key->vname, lineno, script);
+ } else {
+ if ((unused = get_token(&args, script, lineno)))
+ ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", kcmds[x].name, lineno, script, unused);
+ if ((key->retstrlen + 1 - key->initlen) <= MAX_RET_CODE) {
+ key->retstr[key->retstrlen] = kcmds[x].id;
+ key->retstrlen++;
+ } else
+ ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", kcmds[x].name, key->vname, lineno, script);
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int process_opcode(struct adsi_subscript *sub, char *code, char *args, struct adsi_script *state, char *script, int lineno)
+{
+ int x, res, max = sub->id ? MAX_SUB_LEN : MAX_MAIN_LEN;
+ char *unused;
+
+ for (x = 0; x < sizeof(opcmds) / sizeof(opcmds[0]); x++) {
+ if ((opcmds[x].id > -1) && !strcasecmp(opcmds[x].name, code)) {
+ if (opcmds[x].add_args) {
+ res = opcmds[x].add_args(sub->data + sub->datalen,
+ code, opcmds[x].id, args, state, script, lineno);
+ if ((sub->datalen + res + 1) <= max)
+ sub->datalen += res;
+ else {
+ ast_log(LOG_WARNING, "No space for '%s' code in subscript '%s' at line %d of %s\n", opcmds[x].name, sub->vname, lineno, script);
+ return -1;
+ }
+ } else {
+ if ((unused = get_token(&args, script, lineno)))
+ ast_log(LOG_WARNING, "'%s' takes no arguments at line %d of %s (token is '%s')\n", opcmds[x].name, lineno, script, unused);
+ if ((sub->datalen + 2) <= max) {
+ sub->data[sub->datalen] = opcmds[x].id;
+ sub->datalen++;
+ } else {
+ ast_log(LOG_WARNING, "No space for '%s' code in key '%s' at line %d of %s\n", opcmds[x].name, sub->vname, lineno, script);
+ return -1;
+ }
+ }
+ /* Separate commands with 0xff */
+ sub->data[sub->datalen] = 0xff;
+ sub->datalen++;
+ sub->inscount++;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int adsi_process(struct adsi_script *state, char *buf, char *script, int lineno)
+{
+ char *keyword = get_token(&buf, script, lineno);
+ char *args, vname[256], tmp[80], tmp2[80];
+ int lrci, wi, event;
+ struct adsi_display *disp;
+ struct adsi_subscript *newsub;
+
+ if (!keyword)
+ return 0;
+
+ switch(state->state) {
+ case STATE_NORMAL:
+ if (!strcasecmp(keyword, "DESCRIPTION")) {
+ if ((args = get_token(&buf, script, lineno))) {
+ if (process_token(state->desc, args, sizeof(state->desc) - 1, ARG_STRING))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for DESCRIPTION at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for DESCRIPTION at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "VERSION")) {
+ if ((args = get_token(&buf, script, lineno))) {
+ if (process_token(&state->ver, args, sizeof(state->ver) - 1, ARG_NUMBER))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for VERSION at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for VERSION at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "SECURITY")) {
+ if ((args = get_token(&buf, script, lineno))) {
+ if (process_token(state->sec, args, sizeof(state->sec) - 1, ARG_STRING | ARG_NUMBER))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for SECURITY at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for SECURITY at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "FDN")) {
+ if ((args = get_token(&buf, script, lineno))) {
+ if (process_token(state->fdn, args, sizeof(state->fdn) - 1, ARG_STRING | ARG_NUMBER))
+ ast_log(LOG_WARNING, "'%s' is not a valid token for FDN at line %d of %s\n", args, lineno, script);
+ } else
+ ast_log(LOG_WARNING, "Missing argument for FDN at line %d of %s\n", lineno, script);
+ } else if (!strcasecmp(keyword, "KEY")) {
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "KEY definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (!(state->key = getkeybyname(state, vname, script, lineno))) {
+ ast_log(LOG_WARNING, "Out of key space at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (state->key->defined) {
+ ast_log(LOG_WARNING, "Cannot redefine key '%s' at line %d of %s\n", vname, lineno, script);
+ break;
+ }
+ if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "IS")) {
+ ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
+ break;
+ }
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "KEY definition missing short name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY short name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if ((args = get_token(&buf, script, lineno))) {
+ if (strcasecmp(args, "OR")) {
+ ast_log(LOG_WARNING, "Expecting 'OR' but got '%s' instead at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "KEY definition missing optional long name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp2, args, sizeof(tmp2) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY long name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ } else {
+ ast_copy_string(tmp2, tmp, sizeof(tmp2));
+ }
+ if (strlen(tmp2) > 18) {
+ ast_log(LOG_WARNING, "Truncating full name to 18 characters at line %d of %s\n", lineno, script);
+ tmp2[18] = '\0';
+ }
+ if (strlen(tmp) > 7) {
+ ast_log(LOG_WARNING, "Truncating short name to 7 bytes at line %d of %s\n", lineno, script);
+ tmp[7] = '\0';
+ }
+ /* Setup initial stuff */
+ state->key->retstr[0] = 128;
+ /* 1 has the length */
+ state->key->retstr[2] = state->key->id;
+ /* Put the Full name in */
+ memcpy(state->key->retstr + 3, tmp2, strlen(tmp2));
+ /* Update length */
+ state->key->retstrlen = strlen(tmp2) + 3;
+ /* Put trailing 0xff */
+ state->key->retstr[state->key->retstrlen++] = 0xff;
+ /* Put the short name */
+ memcpy(state->key->retstr + state->key->retstrlen, tmp, strlen(tmp));
+ /* Update length */
+ state->key->retstrlen += strlen(tmp);
+ /* Put trailing 0xff */
+ state->key->retstr[state->key->retstrlen++] = 0xff;
+ /* Record initial length */
+ state->key->initlen = state->key->retstrlen;
+ state->state = STATE_INKEY;
+ } else if (!strcasecmp(keyword, "SUB")) {
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (!(state->sub = getsubbyname(state, vname, script, lineno))) {
+ ast_log(LOG_WARNING, "Out of subroutine space at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (state->sub->defined) {
+ ast_log(LOG_WARNING, "Cannot redefine subroutine '%s' at line %d of %s\n", vname, lineno, script);
+ break;
+ }
+ /* Setup sub */
+ state->sub->data[0] = 130;
+ /* 1 is the length */
+ state->sub->data[2] = 0x0; /* Clear extensibility bit */
+ state->sub->datalen = 3;
+ if (state->sub->id) {
+ /* If this isn't the main subroutine, make a subroutine label for it */
+ state->sub->data[3] = 9;
+ state->sub->data[4] = state->sub->id;
+ /* 5 is length */
+ state->sub->data[6] = 0xff;
+ state->sub->datalen = 7;
+ }
+ if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "IS")) {
+ ast_log(LOG_WARNING, "Expecting 'IS', but got '%s' at line %d of %s\n", args ? args : "<nothing>", lineno, script);
+ break;
+ }
+ state->state = STATE_INSUB;
+ } else if (!strcasecmp(keyword, "STATE")) {
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "STATE definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a STATE name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (getstatebyname(state, vname, script, lineno, 0)) {
+ ast_log(LOG_WARNING, "State '%s' is already defined at line %d of %s\n", vname, lineno, script);
+ break;
+ }
+ getstatebyname(state, vname, script, lineno, 1);
+ } else if (!strcasecmp(keyword, "FLAG")) {
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "FLAG definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a FLAG name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (getflagbyname(state, vname, script, lineno, 0)) {
+ ast_log(LOG_WARNING, "Flag '%s' is already defined\n", vname);
+ break;
+ }
+ getflagbyname(state, vname, script, lineno, 1);
+ } else if (!strcasecmp(keyword, "DISPLAY")) {
+ lrci = 0;
+ wi = 0;
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "SUB definition missing name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(vname, args, sizeof(vname) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid token for a KEY name at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (getdisplaybyname(state, vname, script, lineno, 0)) {
+ ast_log(LOG_WARNING, "State '%s' is already defined\n", vname);
+ break;
+ }
+ if (!(disp = getdisplaybyname(state, vname, script, lineno, 1)))
+ break;
+ if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "IS")) {
+ ast_log(LOG_WARNING, "Missing 'IS' at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "Missing Column 1 text at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "Token '%s' is not valid column 1 text at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (strlen(tmp) > 20) {
+ ast_log(LOG_WARNING, "Truncating column one to 20 characters at line %d of %s\n", lineno, script);
+ tmp[20] = '\0';
+ }
+ memcpy(disp->data + 5, tmp, strlen(tmp));
+ disp->datalen = strlen(tmp) + 5;
+ disp->data[disp->datalen++] = 0xff;
+
+ args = get_token(&buf, script, lineno);
+ if (args && !process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ /* Got a column two */
+ if (strlen(tmp) > 20) {
+ ast_log(LOG_WARNING, "Truncating column two to 20 characters at line %d of %s\n", lineno, script);
+ tmp[20] = '\0';
+ }
+ memcpy(disp->data + disp->datalen, tmp, strlen(tmp));
+ disp->datalen += strlen(tmp);
+ args = get_token(&buf, script, lineno);
+ }
+ while(args) {
+ if (!strcasecmp(args, "JUSTIFY")) {
+ args = get_token(&buf, script, lineno);
+ if (!args) {
+ ast_log(LOG_WARNING, "Qualifier 'JUSTIFY' requires an argument at line %d of %s\n", lineno, script);
+ break;
+ }
+ lrci = getjustifybyname(args);
+ if (lrci < 0) {
+ ast_log(LOG_WARNING, "'%s' is not a valid justification at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ } else if (!strcasecmp(args, "WRAP")) {
+ wi = 0x80;
+ } else {
+ ast_log(LOG_WARNING, "'%s' is not a known qualifier at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ args = get_token(&buf, script, lineno);
+ }
+ if (args) {
+ /* Something bad happened */
+ break;
+ }
+ disp->data[0] = 129;
+ disp->data[1] = disp->datalen - 2;
+ disp->data[2] = ((lrci & 0x3) << 6) | disp->id;
+ disp->data[3] = wi;
+ disp->data[4] = 0xff;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in PROGRAM\n", keyword);
+ }
+ break;
+ case STATE_INKEY:
+ if (process_returncode(state->key, keyword, buf, state, script, lineno)) {
+ if (!strcasecmp(keyword, "ENDKEY")) {
+ /* Return to normal operation and increment current key */
+ state->state = STATE_NORMAL;
+ state->key->defined = 1;
+ state->key->retstr[1] = state->key->retstrlen - 2;
+ state->key = NULL;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SOFTKEY definition at line %d of %s\n", keyword, lineno, script);
+ }
+ }
+ break;
+ case STATE_INIF:
+ if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
+ if (!strcasecmp(keyword, "ENDIF")) {
+ /* Return to normal SUB operation and increment current key */
+ state->state = STATE_INSUB;
+ state->sub->defined = 1;
+ /* Store the proper number of instructions */
+ state->sub->ifdata[2] = state->sub->ifinscount;
+ } else if (!strcasecmp(keyword, "GOTO")) {
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "GOTO clause missing Subscript name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if (process_token(tmp, args, sizeof(tmp) - 1, ARG_STRING)) {
+ ast_log(LOG_WARNING, "'%s' is not a valid subscript name token at line %d of %s\n", args, lineno, script);
+ break;
+ }
+ if (!(newsub = getsubbyname(state, tmp, script, lineno)))
+ break;
+ /* Somehow you use GOTO to go to another place */
+ state->sub->data[state->sub->datalen++] = 0x8;
+ state->sub->data[state->sub->datalen++] = state->sub->ifdata[1];
+ state->sub->data[state->sub->datalen++] = newsub->id;
+ /* Terminate */
+ state->sub->data[state->sub->datalen++] = 0xff;
+ /* Increment counters */
+ state->sub->inscount++;
+ state->sub->ifinscount++;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in IF clause at line %d of %s\n", keyword, lineno, script);
+ }
+ } else
+ state->sub->ifinscount++;
+ break;
+ case STATE_INSUB:
+ if (process_opcode(state->sub, keyword, buf, state, script, lineno)) {
+ if (!strcasecmp(keyword, "ENDSUB")) {
+ /* Return to normal operation and increment current key */
+ state->state = STATE_NORMAL;
+ state->sub->defined = 1;
+ /* Store the proper length */
+ state->sub->data[1] = state->sub->datalen - 2;
+ if (state->sub->id) {
+ /* if this isn't main, store number of instructions, too */
+ state->sub->data[5] = state->sub->inscount;
+ }
+ state->sub = NULL;
+ } else if (!strcasecmp(keyword, "IFEVENT")) {
+ if (!(args = get_token(&buf, script, lineno))) {
+ ast_log(LOG_WARNING, "IFEVENT clause missing Event name at line %d of %s\n", lineno, script);
+ break;
+ }
+ if ((event = geteventbyname(args)) < 1) {
+ ast_log(LOG_WARNING, "'%s' is not a valid event\n", args);
+ break;
+ }
+ if (!(args = get_token(&buf, script, lineno)) || strcasecmp(args, "THEN")) {
+ ast_log(LOG_WARNING, "IFEVENT clause missing 'THEN' at line %d of %s\n", lineno, script);
+ break;
+ }
+ state->sub->ifinscount = 0;
+ state->sub->ifdata = state->sub->data +
+ state->sub->datalen;
+ /* Reserve header and insert op codes */
+ state->sub->ifdata[0] = 0x1;
+ state->sub->ifdata[1] = event;
+ /* 2 is for the number of instructions */
+ state->sub->ifdata[3] = 0xff;
+ state->sub->datalen += 4;
+ /* Update Subscript instruction count */
+ state->sub->inscount++;
+ state->state = STATE_INIF;
+ } else {
+ ast_log(LOG_WARNING, "Invalid or Unknown keyword '%s' in SUB definition at line %d of %s\n", keyword, lineno, script);
+ }
+ }
+ break;
+ default:
+ ast_log(LOG_WARNING, "Can't process keyword '%s' in weird state %d\n", keyword, state->state);
+ }
+ return 0;
+}
+
+static struct adsi_script *compile_script(char *script)
+{
+ FILE *f;
+ char fn[256], buf[256], *c;
+ int lineno = 0, x, err;
+ struct adsi_script *scr;
+
+ if (script[0] == '/')
+ ast_copy_string(fn, script, sizeof(fn));
+ else
+ snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, script);
+
+ if (!(f = fopen(fn, "r"))) {
+ ast_log(LOG_WARNING, "Can't open file '%s'\n", fn);
+ return NULL;
+ }
+
+ if (!(scr = ast_calloc(1, sizeof(*scr)))) {
+ fclose(f);
+ return NULL;
+ }
+
+ /* Create "main" as first subroutine */
+ getsubbyname(scr, "main", NULL, 0);
+ while(!feof(f)) {
+ fgets(buf, sizeof(buf), f);
+ if (!feof(f)) {
+ lineno++;
+ /* Trim off trailing return */
+ buf[strlen(buf) - 1] = '\0';
+ /* Strip comments */
+ if ((c = strchr(buf, ';')))
+ *c = '\0';
+ if (!ast_strlen_zero(buf))
+ adsi_process(scr, buf, script, lineno);
+ }
+ }
+ fclose(f);
+ /* Make sure we're in the main routine again */
+ switch(scr->state) {
+ case STATE_NORMAL:
+ break;
+ case STATE_INSUB:
+ ast_log(LOG_WARNING, "Missing ENDSUB at end of file %s\n", script);
+ ast_free(scr);
+ return NULL;
+ case STATE_INKEY:
+ ast_log(LOG_WARNING, "Missing ENDKEY at end of file %s\n", script);
+ ast_free(scr);
+ return NULL;
+ }
+ err = 0;
+
+ /* Resolve all keys and record their lengths */
+ for (x = 0; x < scr->numkeys; x++) {
+ if (!scr->keys[x].defined) {
+ ast_log(LOG_WARNING, "Key '%s' referenced but never defined in file %s\n", scr->keys[x].vname, fn);
+ err++;
+ }
+ }
+
+ /* Resolve all subs */
+ for (x = 0; x < scr->numsubs; x++) {
+ if (!scr->subs[x].defined) {
+ ast_log(LOG_WARNING, "Subscript '%s' referenced but never defined in file %s\n", scr->subs[x].vname, fn);
+ err++;
+ }
+ if (x == (scr->numsubs - 1)) {
+ /* Clear out extension bit on last message */
+ scr->subs[x].data[2] = 0x80;
+ }
+ }
+
+ if (err) {
+ ast_free(scr);
+ return NULL;
+ }
+ return scr;
+}
+
+#ifdef DUMP_MESSAGES
+static void dump_message(char *type, char *vname, unsigned char *buf, int buflen)
+{
+ int x;
+ printf("%s %s: [ ", type, vname);
+ for (x = 0; x < buflen; x++)
+ printf("%02x ", buf[x]);
+ printf("]\n");
+}
+#endif
+
+static int adsi_prog(struct ast_channel *chan, char *script)
+{
+ struct adsi_script *scr;
+ int x, bytes;
+ unsigned char buf[1024];
+
+ if (!(scr = compile_script(script)))
+ return -1;
+
+ /* Start an empty ADSI Session */
+ if (ast_adsi_load_session(chan, NULL, 0, 1) < 1)
+ return -1;
+
+ /* Now begin the download attempt */
+ if (ast_adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
+ /* User rejected us for some reason */
+ ast_verb(3, "User rejected download attempt\n");
+ ast_log(LOG_NOTICE, "User rejected download on channel %s\n", chan->name);
+ ast_free(scr);
+ return -1;
+ }
+
+ bytes = 0;
+ /* Start with key definitions */
+ for (x = 0; x < scr->numkeys; x++) {
+ if (bytes + scr->keys[x].retstrlen > 253) {
+ /* Send what we've collected so far */
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ bytes =0;
+ }
+ memcpy(buf + bytes, scr->keys[x].retstr, scr->keys[x].retstrlen);
+ bytes += scr->keys[x].retstrlen;
+#ifdef DUMP_MESSAGES
+ dump_message("Key", scr->keys[x].vname, scr->keys[x].retstr, scr->keys[x].retstrlen);
+#endif
+ }
+ if (bytes) {
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ }
+
+ bytes = 0;
+ /* Continue with the display messages */
+ for (x = 0; x < scr->numdisplays; x++) {
+ if (bytes + scr->displays[x].datalen > 253) {
+ /* Send what we've collected so far */
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ bytes =0;
+ }
+ memcpy(buf + bytes, scr->displays[x].data, scr->displays[x].datalen);
+ bytes += scr->displays[x].datalen;
+#ifdef DUMP_MESSAGES
+ dump_message("Display", scr->displays[x].vname, scr->displays[x].data, scr->displays[x].datalen);
+#endif
+ }
+ if (bytes) {
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ }
+
+ bytes = 0;
+ /* Send subroutines */
+ for (x = 0; x < scr->numsubs; x++) {
+ if (bytes + scr->subs[x].datalen > 253) {
+ /* Send what we've collected so far */
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ bytes =0;
+ }
+ memcpy(buf + bytes, scr->subs[x].data, scr->subs[x].datalen);
+ bytes += scr->subs[x].datalen;
+#ifdef DUMP_MESSAGES
+ dump_message("Sub", scr->subs[x].vname, scr->subs[x].data, scr->subs[x].datalen);
+#endif
+ }
+ if (bytes) {
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+ ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
+ return -1;
+ }
+ }
+
+
+ bytes = 0;
+ bytes += ast_adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
+ bytes += ast_adsi_set_line(buf, ADSI_INFO_PAGE, 1);
+ if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
+ return -1;
+ if (ast_adsi_end_download(chan)) {
+ /* Download failed for some reason */
+ ast_verb(3, "Download attempt failed\n");
+ ast_log(LOG_NOTICE, "Download failed on %s\n", chan->name);
+ ast_free(scr);
+ return -1;
+ }
+ ast_free(scr);
+ ast_adsi_unload_session(chan);
+ return 0;
+}
+
+static int adsi_exec(struct ast_channel *chan, void *data)
+{
+ int res = 0;
+
+ if (ast_strlen_zero(data))
+ data = "asterisk.adsi";
+
+ if (!ast_adsi_available(chan)) {
+ ast_verb(3, "ADSI Unavailable on CPE. Not bothering to try.\n");
+ } else {
+ ast_verb(3, "ADSI Available on CPE. Attempting Upload.\n");
+ res = adsi_prog(chan, data);
+ }
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+ if (ast_register_application(app, adsi_exec, synopsis, descrip))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk ADSI Programming Application");
diff --git a/trunk/apps/app_alarmreceiver.c b/trunk/apps/app_alarmreceiver.c
new file mode 100644
index 000000000..c4fa81109
--- /dev/null
+++ b/trunk/apps/app_alarmreceiver.c
@@ -0,0 +1,813 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2004 - 2005 Steve Rodgers
+ *
+ * Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ * \brief Central Station Alarm receiver for Ademco Contact ID
+ * \author Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
+ *
+ * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
+ *
+ * Use at your own risk. Please consult the GNU GPL license document included with Asterisk. *
+ *
+ * *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <math.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/translate.h"
+#include "asterisk/ulaw.h"
+#include "asterisk/app.h"
+#include "asterisk/dsp.h"
+#include "asterisk/config.h"
+#include "asterisk/localtime.h"
+#include "asterisk/callerid.h"
+#include "asterisk/astdb.h"
+#include "asterisk/utils.h"
+
+#define ALMRCV_CONFIG "alarmreceiver.conf"
+#define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
+
+struct event_node{
+ char data[17];
+ struct event_node *next;
+};
+
+typedef struct event_node event_node_t;
+
+static char *app = "AlarmReceiver";
+
+static char *synopsis = "Provide support for receiving alarm reports from a burglar or fire alarm panel";
+static char *descrip =
+" AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n"
+"Contact ID. This application should be called whenever there is an alarm\n"
+"panel calling in to dump its events. The application will handshake with the\n"
+"alarm panel, and receive events, validate them, handshake them, and store them\n"
+"until the panel hangs up. Once the panel hangs up, the application will run the\n"
+"system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n"
+"the events to the standard input of the application. The configuration file also\n"
+"contains settings for DTMF timing, and for the loudness of the acknowledgement\n"
+"tones.\n";
+
+/* Config Variables */
+
+static int fdtimeout = 2000;
+static int sdtimeout = 200;
+static int toneloudness = 4096;
+static int log_individual_events = 0;
+static char event_spool_dir[128] = {'\0'};
+static char event_app[128] = {'\0'};
+static char db_family[128] = {'\0'};
+static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
+
+/* Misc variables */
+
+static char event_file[14] = "/event-XXXXXX";
+
+/*
+* Attempt to access a database variable and increment it,
+* provided that the user defined db-family in alarmreceiver.conf
+* The alarmreceiver app will write statistics to a few variables
+* in this family if it is defined. If the new key doesn't exist in the
+* family, then create it and set its value to 1.
+*/
+
+static void database_increment( char *key )
+{
+ int res = 0;
+ unsigned v;
+ char value[16];
+
+
+ if (ast_strlen_zero(db_family))
+ return; /* If not defined, don't do anything */
+
+ res = ast_db_get(db_family, key, value, sizeof(value) - 1);
+
+ if(res){
+ ast_verb(4, "AlarmReceiver: Creating database entry %s and setting to 1\n", key);
+ /* Guess we have to create it */
+ res = ast_db_put(db_family, key, "1");
+ return;
+ }
+
+ sscanf(value, "%u", &v);
+ v++;
+
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: New value for %s: %u\n", key, v);
+
+ snprintf(value, sizeof(value), "%u", v);
+
+ res = ast_db_put(db_family, key, value);
+
+ if((res)&&(option_verbose >= 4))
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error\n");
+
+ return;
+}
+
+
+/*
+* Build a MuLaw data block for a single frequency tone
+*/
+
+static void make_tone_burst(unsigned char *data, float freq, float loudness, int len, int *x)
+{
+ int i;
+ float val;
+
+ for(i = 0; i < len; i++){
+ val = loudness * sin((freq * 2.0 * M_PI * (*x)++)/8000.0);
+ data[i] = AST_LIN2MU((int)val);
+ }
+
+ /* wrap back around from 8000 */
+
+ if (*x >= 8000) *x = 0;
+ return;
+}
+
+/*
+* Send a single tone burst for a specifed duration and frequency.
+* Returns 0 if successful
+*/
+
+static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn)
+{
+ int res = 0;
+ int i = 0;
+ int x = 0;
+ struct ast_frame *f, wf;
+
+ struct {
+ unsigned char offset[AST_FRIENDLY_OFFSET];
+ unsigned char buf[640];
+ } tone_block;
+
+ for(;;)
+ {
+
+ if (ast_waitfor(chan, -1) < 0){
+ res = -1;
+ break;
+ }
+
+ f = ast_read(chan);
+ if (!f){
+ res = -1;
+ break;
+ }
+
+ if (f->frametype == AST_FRAME_VOICE) {
+ wf.frametype = AST_FRAME_VOICE;
+ wf.subclass = AST_FORMAT_ULAW;
+ wf.offset = AST_FRIENDLY_OFFSET;
+ wf.mallocd = 0;
+ wf.data = tone_block.buf;
+ wf.datalen = f->datalen;
+ wf.samples = wf.datalen;
+
+ make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x);
+
+ i += wf.datalen / 8;
+ if (i > duration) {
+ ast_frfree(f);
+ break;
+ }
+ if (ast_write(chan, &wf)){
+ ast_verb(4, "AlarmReceiver: Failed to write frame on %s\n", chan->name);
+ ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",chan->name);
+ res = -1;
+ ast_frfree(f);
+ break;
+ }
+ }
+
+ ast_frfree(f);
+ }
+ return res;
+}
+
+/*
+* Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential
+* treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent
+* digits.
+*
+* Returns 0 if all digits successfully received.
+* Returns 1 if a digit time out occurred
+* Returns -1 if the caller hung up or there was a channel error.
+*
+*/
+
+static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto)
+{
+ int res = 0;
+ int i = 0;
+ int r;
+ struct ast_frame *f;
+ struct timeval lastdigittime;
+
+ lastdigittime = ast_tvnow();
+ for(;;){
+ /* if outa time, leave */
+ if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
+ ((i > 0) ? sdto : fdto)){
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
+
+ ast_debug(1,"AlarmReceiver: DTMF timeout on chan %s\n",chan->name);
+
+ res = 1;
+ break;
+ }
+
+ if ((r = ast_waitfor(chan, -1) < 0)) {
+ ast_debug(1, "Waitfor returned %d\n", r);
+ continue;
+ }
+
+ f = ast_read(chan);
+
+ if (f == NULL){
+ res = -1;
+ break;
+ }
+
+ /* If they hung up, leave */
+ if ((f->frametype == AST_FRAME_CONTROL) &&
+ (f->subclass == AST_CONTROL_HANGUP)){
+ ast_frfree(f);
+ res = -1;
+ break;
+ }
+
+ /* if not DTMF, just do it again */
+ if (f->frametype != AST_FRAME_DTMF){
+ ast_frfree(f);
+ continue;
+ }
+
+ digit_string[i++] = f->subclass; /* save digit */
+
+ ast_frfree(f);
+
+ /* If we have all the digits we expect, leave */
+ if(i >= length)
+ break;
+
+ lastdigittime = ast_tvnow();
+ }
+
+ digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
+ return res;
+
+}
+
+/*
+* Write the metadata to the log file
+*/
+
+static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan)
+{
+ int res = 0;
+ struct timeval t;
+ struct ast_tm now;
+ char *cl,*cn;
+ char workstring[80];
+ char timestamp[80];
+
+ /* Extract the caller ID location */
+ if (chan->cid.cid_num)
+ ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
+ workstring[sizeof(workstring) - 1] = '\0';
+
+ ast_callerid_parse(workstring, &cn, &cl);
+ if (cl)
+ ast_shrink_phone_number(cl);
+
+
+ /* Get the current time */
+
+ t = ast_tvnow();
+ ast_localtime(&t, &now, NULL);
+
+ /* Format the time */
+
+ ast_strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
+
+
+ res = fprintf(logfile, "\n\n[metadata]\n\n");
+
+ if(res >= 0)
+ res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
+
+ if(res >= 0)
+ res = fprintf(logfile, "CALLINGFROM=%s\n", (!cl) ? "<unknown>" : cl);
+
+ if(res >- 0)
+ res = fprintf(logfile, "CALLERNAME=%s\n", (!cn) ? "<unknown>" : cn);
+
+ if(res >= 0)
+ res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
+
+ if(res >= 0)
+ res = fprintf(logfile, "[events]\n\n");
+
+ if(res < 0){
+ if (option_verbose >= 3 )
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't write metadata\n");
+
+ ast_debug(1,"AlarmReceiver: can't write metadata\n");
+ }
+ else
+ res = 0;
+
+ return res;
+}
+
+/*
+* Write a single event to the log file
+*/
+
+static int write_event( FILE *logfile, event_node_t *event)
+{
+ int res = 0;
+
+ if( fprintf(logfile, "%s\n", event->data) < 0)
+ res = -1;
+
+ return res;
+}
+
+
+/*
+* If we are configured to log events, do so here.
+*
+*/
+
+static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
+{
+
+ int res = 0;
+ char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
+ int fd;
+ FILE *logfile;
+ event_node_t *elp = event;
+
+ if (!ast_strlen_zero(event_spool_dir)) {
+
+ /* Make a template */
+
+ ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
+ strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
+
+ /* Make the temporary file */
+
+ fd = mkstemp(workstring);
+
+ if(fd == -1) {
+ if (option_verbose >= 3)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't make temporary file\n");
+ ast_debug(1,"AlarmReceiver: can't make temporary file\n");
+ res = -1;
+ }
+
+ if(!res){
+ logfile = fdopen(fd, "w");
+ if(logfile){
+ /* Write the file */
+ res = write_metadata(logfile, signalling_type, chan);
+ if(!res)
+ while((!res) && (elp != NULL)){
+ res = write_event(logfile, elp);
+ elp = elp->next;
+ }
+ if(!res){
+ if(fflush(logfile) == EOF)
+ res = -1;
+ if(!res){
+ if(fclose(logfile) == EOF)
+ res = -1;
+ }
+ }
+ }
+ else
+ res = -1;
+ }
+ }
+
+ return res;
+}
+
+/*
+* This function implements the logic to receive the Ademco contact ID format.
+*
+* The function will return 0 when the caller hangs up, else a -1 if there was a problem.
+*/
+
+static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
+{
+ int i,j;
+ int res = 0;
+ int checksum;
+ char event[17];
+ event_node_t *enew, *elp;
+ int got_some_digits = 0;
+ int events_received = 0;
+ int ack_retries = 0;
+
+ static char digit_map[15] = "0123456789*#ABC";
+ static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
+
+ database_increment("calls-received");
+
+ /* Wait for first event */
+
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for first event from panel\n");
+
+ while(res >= 0){
+
+ if(got_some_digits == 0){
+
+ /* Send ACK tone sequence */
+
+
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
+
+
+ res = send_tone_burst(chan, 1400.0, 100, tldn);
+
+ if(!res)
+ res = ast_safe_sleep(chan, 100);
+
+ if(!res){
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
+
+ res = send_tone_burst(chan, 2300.0, 100, tldn);
+ }
+
+ }
+
+ if( res >= 0)
+ res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
+
+ if (res < 0){
+
+ if(events_received == 0)
+ /* Hangup with no events received should be logged in the DB */
+ database_increment("no-events-received");
+ else{
+ if(ack_retries){
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
+
+ database_increment("ack-retries");
+ }
+ }
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: App exiting...\n");
+ res = -1;
+ break;
+ }
+
+ if(res != 0){
+ /* Didn't get all of the digits */
+ if(option_verbose >= 2)
+ ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
+
+ if(!got_some_digits){
+ got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
+ ack_retries++;
+ }
+ continue;
+ }
+
+ got_some_digits = 1;
+
+ ast_verb(2, "AlarmReceiver: Received Event %s\n", event);
+ ast_debug(1, "AlarmReceiver: Received event: %s\n", event);
+
+ /* Calculate checksum */
+
+ for(j = 0, checksum = 0; j < 16; j++){
+ for(i = 0 ; i < sizeof(digit_map) ; i++){
+ if(digit_map[i] == event[j])
+ break;
+ }
+
+ if(i == 16)
+ break;
+
+ checksum += digit_weights[i];
+ }
+
+ if(i == 16){
+ ast_verb(2, "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
+ continue; /* Bad character */
+ }
+
+ /* Checksum is mod(15) of the total */
+
+ checksum = checksum % 15;
+
+ if (checksum) {
+ database_increment("checksum-errors");
+ ast_verb(2, "AlarmReceiver: Nonzero checksum\n");
+ ast_debug(1, "AlarmReceiver: Nonzero checksum\n");
+ continue;
+ }
+
+ /* Check the message type for correctness */
+
+ if(strncmp(event + 4, "18", 2)){
+ if(strncmp(event + 4, "98", 2)){
+ database_increment("format-errors");
+ ast_verb(2, "AlarmReceiver: Wrong message type\n");
+ ast_debug(1, "AlarmReceiver: Wrong message type\n");
+ continue;
+ }
+ }
+
+ events_received++;
+
+ /* Queue the Event */
+ if (!(enew = ast_calloc(1, sizeof(*enew)))) {
+ res = -1;
+ break;
+ }
+
+ enew->next = NULL;
+ ast_copy_string(enew->data, event, sizeof(enew->data));
+
+ /*
+ * Insert event onto end of list
+ */
+
+ if(*ehead == NULL){
+ *ehead = enew;
+ }
+ else{
+ for(elp = *ehead; elp->next != NULL; elp = elp->next)
+ ;
+
+ elp->next = enew;
+ }
+
+ if(res > 0)
+ res = 0;
+
+ /* Let the user have the option of logging the single event before sending the kissoff tone */
+
+ if((res == 0) && (log_individual_events))
+ res = log_events(chan, ADEMCO_CONTACT_ID, enew);
+
+ /* Wait 200 msec before sending kissoff */
+
+ if(res == 0)
+ res = ast_safe_sleep(chan, 200);
+
+ /* Send the kissoff tone */
+
+ if(res == 0)
+ res = send_tone_burst(chan, 1400.0, 900, tldn);
+ }
+
+
+ return res;
+}
+
+
+/*
+* This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
+* This function will always return 0.
+*/
+
+static int alarmreceiver_exec(struct ast_channel *chan, void *data)
+{
+ int res = 0;
+ event_node_t *elp, *efree;
+ char signalling_type[64] = "";
+
+ event_node_t *event_head = NULL;
+
+ /* Set write and read formats to ULAW */
+
+ ast_verb(4, "AlarmReceiver: Setting read and write formats to ULAW\n");
+
+ if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
+ ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
+ return -1;
+ }
+
+ if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
+ ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
+ return -1;
+ }
+
+ /* Set default values for this invocation of the application */
+
+ ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
+
+
+ /* Answer the channel if it is not already */
+
+ ast_verb(4, "AlarmReceiver: Answering channel\n");
+
+ if (chan->_state != AST_STATE_UP) {
+ if ((res = ast_answer(chan)))
+ return -1;
+ }
+
+ /* Wait for the connection to settle post-answer */
+
+ ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
+
+ res = ast_safe_sleep(chan, 1250);
+
+ /* Attempt to receive the events */
+
+ if(!res){
+
+ /* Determine the protocol to receive in advance */
+ /* Note: Ademco contact is the only one supported at this time */
+ /* Others may be added later */
+
+ if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
+ receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
+ else
+ res = -1;
+ }
+
+
+
+ /* Events queued by receiver, write them all out here if so configured */
+
+ if((!res) && (log_individual_events == 0)){
+ res = log_events(chan, signalling_type, event_head);
+
+ }
+
+ /*
+ * Do we exec a command line at the end?
+ */
+
+ if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
+ ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
+ ast_safe_system(event_app);
+ }
+
+ /*
+ * Free up the data allocated in our linked list
+ */
+
+ for(elp = event_head; (elp != NULL);){
+ efree = elp;
+ elp = elp->next;
+ ast_free(efree);
+ }
+
+ return 0;
+}
+
+/*
+* Load the configuration from the configuration file
+*/
+
+static int load_config(void)
+{
+ struct ast_config *cfg;
+ const char *p;
+ struct ast_flags config_flags = { 0 };
+
+ /* Read in the config file */
+
+ cfg = ast_config_load(ALMRCV_CONFIG, config_flags);
+
+ if(!cfg){
+
+ if(option_verbose >= 4)
+ ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
+ return 0;
+ }
+ else{
+
+
+ p = ast_variable_retrieve(cfg, "general", "eventcmd");
+
+ if(p){
+ ast_copy_string(event_app, p, sizeof(event_app));
+ event_app[sizeof(event_app) - 1] = '\0';
+ }
+
+ p = ast_variable_retrieve(cfg, "general", "loudness");
+ if(p){
+ toneloudness = atoi(p);
+ if(toneloudness < 100)
+ toneloudness = 100;
+ if(toneloudness > 8192)
+ toneloudness = 8192;
+ }
+ p = ast_variable_retrieve(cfg, "general", "fdtimeout");
+ if(p){
+ fdtimeout = atoi(p);
+ if(fdtimeout < 1000)
+ fdtimeout = 1000;
+ if(fdtimeout > 10000)
+ fdtimeout = 10000;
+ }
+
+ p = ast_variable_retrieve(cfg, "general", "sdtimeout");
+ if(p){
+ sdtimeout = atoi(p);
+ if(sdtimeout < 110)
+ sdtimeout = 110;
+ if(sdtimeout > 4000)
+ sdtimeout = 4000;
+
+ }
+
+ p = ast_variable_retrieve(cfg, "general", "logindividualevents");
+ if(p){
+ log_individual_events = ast_true(p);
+
+ }
+
+ p = ast_variable_retrieve(cfg, "general", "eventspooldir");
+
+ if(p){
+ ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
+ event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
+ }
+
+ p = ast_variable_retrieve(cfg, "general", "timestampformat");
+
+ if(p){
+ ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
+ time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
+ }
+
+ p = ast_variable_retrieve(cfg, "general", "db-family");
+
+ if(p){
+ ast_copy_string(db_family, p, sizeof(db_family));
+ db_family[sizeof(db_family) - 1] = '\0';
+ }
+ ast_config_destroy(cfg);
+ }
+ return 1;
+
+}
+
+/*
+* These functions are required to implement an Asterisk App.
+*/
+
+
+static int unload_module(void)
+{
+ return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+ if(load_config()) {
+ if (ast_register_application(app, alarmreceiver_exec, synopsis, descrip))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+ }
+ else
+ return AST_MODULE_LOAD_DECLINE;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");
diff --git a/trunk/apps/app_amd.c b/trunk/apps/app_amd.c
new file mode 100644
index 000000000..4e440d388
--- /dev/null
+++ b/trunk/apps/app_amd.c
@@ -0,0 +1,418 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2003 - 2006, Aheeva Technology.
+ *
+ * Claude Klimos (claude.klimos@aheeva.com)
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ *
+ * A license has been granted to Digium (via disclaimer) for the use of
+ * this code.
+ */
+
+/*! \file
+ *
+ * \brief Answering machine detection
+ *
+ * \author Claude Klimos (claude.klimos@aheeva.com)
+ */
+
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/channel.h"
+#include "asterisk/dsp.h"
+#include "asterisk/pbx.h"
+#include "asterisk/config.h"
+#include "asterisk/app.h"
+
+
+static char *app = "AMD";
+static char *synopsis = "Attempts to detect answering machines";
+static char *descrip =
+" AMD([initialSilence],[greeting],[afterGreetingSilence],[totalAnalysisTime]\n"
+" ,[minimumWordLength],[betweenWordsSilence],[maximumNumberOfWords]\n"
+" ,[silenceThreshold],[|maximumWordLength])\n"
+" This application attempts to detect answering machines at the beginning\n"
+" of outbound calls. Simply call this application after the call\n"
+" has been answered (outbound only, of course).\n"
+" When loaded, AMD reads amd.conf and uses the parameters specified as\n"
+" default values. Those default values get overwritten when calling AMD\n"
+" with parameters.\n"
+"- 'initialSilence' is the maximum silence duration before the greeting. If\n"
+" exceeded then MACHINE.\n"
+"- 'greeting' is the maximum length of a greeting. If exceeded then MACHINE.\n"
+"- 'afterGreetingSilence' is the silence after detecting a greeting.\n"
+" If exceeded then HUMAN.\n"
+"- 'totalAnalysisTime' is the maximum time allowed for the algorithm to decide\n"
+" on a HUMAN or MACHINE.\n"
+"- 'minimumWordLength'is the minimum duration of Voice to considered as a word.\n"
+"- 'betweenWordsSilence' is the minimum duration of silence after a word to \n"
+" consider the audio that follows as a new word.\n"
+"- 'maximumNumberOfWords'is the maximum number of words in the greeting. \n"
+" If exceeded then MACHINE.\n"
+"- 'silenceThreshold' is the silence threshold.\n"
+"- 'maximumWordLength' is the maximum duration of a word to accept. If exceeded then MACHINE\n"
+"This application sets the following channel variables upon completion:\n"
+" AMDSTATUS - This is the status of the answering machine detection.\n"
+" Possible values are:\n"
+" MACHINE | HUMAN | NOTSURE | HANGUP\n"
+" AMDCAUSE - Indicates the cause that led to the conclusion.\n"
+" Possible values are:\n"
+" TOOLONG-<%d total_time>\n"
+" INITIALSILENCE-<%d silenceDuration>-<%d initialSilence>\n"
+" HUMAN-<%d silenceDuration>-<%d afterGreetingSilence>\n"
+" MAXWORDS-<%d wordsCount>-<%d maximumNumberOfWords>\n"
+" LONGGREETING-<%d voiceDuration>-<%d greeting>\n"
+" MAXWORDLENGTH-<%d consecutiveVoiceDuration>\n";
+
+#define STATE_IN_WORD 1
+#define STATE_IN_SILENCE 2
+
+/* Some default values for the algorithm parameters. These defaults will be overwritten from amd.conf */
+static int dfltInitialSilence = 2500;
+static int dfltGreeting = 1500;
+static int dfltAfterGreetingSilence = 800;
+static int dfltTotalAnalysisTime = 5000;
+static int dfltMinimumWordLength = 100;
+static int dfltBetweenWordsSilence = 50;
+static int dfltMaximumNumberOfWords = 3;
+static int dfltSilenceThreshold = 256;
+static int dfltMaximumWordLength = 5000; /* Setting this to a large default so it is not used unless specify it in the configs or command line */
+
+static void isAnsweringMachine(struct ast_channel *chan, void *data)
+{
+ int res = 0;
+ struct ast_frame *f = NULL;
+ struct ast_dsp *silenceDetector = NULL;
+ int dspsilence = 0, readFormat, framelength;
+ int inInitialSilence = 1;
+ int inGreeting = 0;
+ int voiceDuration = 0;
+ int silenceDuration = 0;
+ int iTotalTime = 0;
+ int iWordsCount = 0;
+ int currentState = STATE_IN_SILENCE;
+ int previousState = STATE_IN_SILENCE;
+ int consecutiveVoiceDuration = 0;
+ char amdCause[256] = "", amdStatus[256] = "";
+ char *parse = ast_strdupa(data);
+
+ /* Lets set the initial values of the variables that will control the algorithm.
+ The initial values are the default ones. If they are passed as arguments
+ when invoking the application, then the default values will be overwritten
+ by the ones passed as parameters. */
+ int initialSilence = dfltInitialSilence;
+ int greeting = dfltGreeting;
+ int afterGreetingSilence = dfltAfterGreetingSilence;
+ int totalAnalysisTime = dfltTotalAnalysisTime;
+ int minimumWordLength = dfltMinimumWordLength;
+ int betweenWordsSilence = dfltBetweenWordsSilence;
+ int maximumNumberOfWords = dfltMaximumNumberOfWords;
+ int silenceThreshold = dfltSilenceThreshold;
+ int maximumWordLength = dfltMaximumWordLength;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(argInitialSilence);
+ AST_APP_ARG(argGreeting);
+ AST_APP_ARG(argAfterGreetingSilence);
+ AST_APP_ARG(argTotalAnalysisTime);
+ AST_APP_ARG(argMinimumWordLength);
+ AST_APP_ARG(argBetweenWordsSilence);
+ AST_APP_ARG(argMaximumNumberOfWords);
+ AST_APP_ARG(argSilenceThreshold);
+ AST_APP_ARG(argMaximumWordLength);
+ );
+
+ ast_verb(3, "AMD: %s %s %s (Fmt: %d)\n", chan->name ,chan->cid.cid_ani, chan->cid.cid_rdnis, chan->readformat);
+
+ /* Lets parse the arguments. */
+ if (!ast_strlen_zero(parse)) {
+ /* Some arguments have been passed. Lets parse them and overwrite the defaults. */
+ AST_STANDARD_APP_ARGS(args, parse);
+ if (!ast_strlen_zero(args.argInitialSilence))
+ initialSilence = atoi(args.argInitialSilence);
+ if (!ast_strlen_zero(args.argGreeting))
+ greeting = atoi(args.argGreeting);
+ if (!ast_strlen_zero(args.argAfterGreetingSilence))
+ afterGreetingSilence = atoi(args.argAfterGreetingSilence);
+ if (!ast_strlen_zero(args.argTotalAnalysisTime))
+ totalAnalysisTime = atoi(args.argTotalAnalysisTime);
+ if (!ast_strlen_zero(args.argMinimumWordLength))
+ minimumWordLength = atoi(args.argMinimumWordLength);
+ if (!ast_strlen_zero(args.argBetweenWordsSilence))
+ betweenWordsSilence = atoi(args.argBetweenWordsSilence);
+ if (!ast_strlen_zero(args.argMaximumNumberOfWords))
+ maximumNumberOfWords = atoi(args.argMaximumNumberOfWords);
+ if (!ast_strlen_zero(args.argSilenceThreshold))
+ silenceThreshold = atoi(args.argSilenceThreshold);
+ if (!ast_strlen_zero(args.argMaximumWordLength))
+ maximumWordLength = atoi(args.argMaximumWordLength);
+ } else {
+ ast_debug(1, "AMD using the default parameters.\n");
+ }
+
+ /* Now we're ready to roll! */
+ ast_verb(3, "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
+ "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d] \n",
+ initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
+ minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold, maximumWordLength);
+
+ /* Set read format to signed linear so we get signed linear frames in */
+ readFormat = chan->readformat;
+ if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0 ) {
+ ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to set to linear mode, giving up\n", chan->name );
+ pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
+ pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
+ return;
+ }
+
+ /* Create a new DSP that will detect the silence */
+ if (!(silenceDetector = ast_dsp_new())) {
+ ast_log(LOG_WARNING, "AMD: Channel [%s]. Unable to create silence detector :(\n", chan->name );
+ pbx_builtin_setvar_helper(chan , "AMDSTATUS", "");
+ pbx_builtin_setvar_helper(chan , "AMDCAUSE", "");
+ return;
+ }
+
+ /* Set silence threshold to specified value */
+ ast_dsp_set_threshold(silenceDetector, silenceThreshold);
+
+ /* Now we go into a loop waiting for frames from the channel */
+ while ((res = ast_waitfor(chan, totalAnalysisTime)) > -1) {
+ /* If we fail to read in a frame, that means they hung up */
+ if (!(f = ast_read(chan))) {
+ ast_verb(3, "AMD: Channel [%s]. HANGUP\n", chan->name);
+ ast_debug(1, "Got hangup\n");
+ strcpy(amdStatus, "HANGUP");
+ break;
+ }
+
+ if (f->frametype == AST_FRAME_VOICE) {
+ /* If the total time exceeds the analysis time then give up as we are not too sure */
+ framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
+ iTotalTime += framelength;
+ if (iTotalTime >= totalAnalysisTime) {
+ ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name );
+ ast_frfree(f);
+ strcpy(amdStatus , "NOTSURE");
+ sprintf(amdCause , "TOOLONG-%d", iTotalTime);
+ break;
+ }
+
+ /* Feed the frame of audio into the silence detector and see if we get a result */
+ dspsilence = 0;
+ ast_dsp_silence(silenceDetector, f, &dspsilence);
+ if (dspsilence) {
+ silenceDuration = dspsilence;
+
+ if (silenceDuration >= betweenWordsSilence) {
+ if (currentState != STATE_IN_SILENCE ) {
+ previousState = currentState;
+ ast_verb(3, "AMD: Channel [%s]. Changed state to STATE_IN_SILENCE\n", chan->name);
+ }
+ /* Find words less than word duration */
+ if (consecutiveVoiceDuration < minimumWordLength && consecutiveVoiceDuration > 0){
+ ast_verb(3, "AMD: Channel [%s]. Short Word Duration: %d\n", chan->name, consecutiveVoiceDuration);
+ }
+ currentState = STATE_IN_SILENCE;
+ consecutiveVoiceDuration = 0;
+ }
+
+ if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
+ ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
+ chan->name, silenceDuration, initialSilence);
+ ast_frfree(f);
+ strcpy(amdStatus , "MACHINE");
+ sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
+ break;
+ }
+
+ if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
+ ast_verb(3, "AMD: Channel [%s]. HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
+ chan->name, silenceDuration, afterGreetingSilence);
+ ast_frfree(f);
+ strcpy(amdStatus , "HUMAN");
+ sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
+ break;
+ }
+
+ } else {
+ consecutiveVoiceDuration += framelength;
+ voiceDuration += framelength;
+
+ /* If I have enough consecutive voice to say that I am in a Word, I can only increment the
+ number of words if my previous state was Silence, which means that I moved into a word. */
+ if (consecutiveVoiceDuration >= minimumWordLength && currentState == STATE_IN_SILENCE) {
+ iWordsCount++;
+ ast_verb(3, "AMD: Channel [%s]. Word detected. iWordsCount:%d\n", chan->name, iWordsCount);
+ previousState = currentState;
+ currentState = STATE_IN_WORD;
+ }
+ if (consecutiveVoiceDuration >= maximumWordLength){
+ ast_verb(3, "AMD: Channel [%s]. Maximum Word Length detected. [%d]\n", chan->name, consecutiveVoiceDuration);
+ ast_frfree(f);
+ strcpy(amdStatus , "MACHINE");
+ sprintf(amdCause , "MAXWORDLENGTH-%d", consecutiveVoiceDuration);
+ break;
+ }
+ if (iWordsCount >= maximumNumberOfWords) {
+ ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: iWordsCount:%d\n", chan->name, iWordsCount);
+ ast_frfree(f);
+ strcpy(amdStatus , "MACHINE");
+ sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
+ break;
+ }
+
+ if (inGreeting == 1 && voiceDuration >= greeting) {
+ ast_verb(3, "AMD: Channel [%s]. ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", chan->name, voiceDuration, greeting);
+ ast_frfree(f);
+ strcpy(amdStatus , "MACHINE");
+ sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
+ break;
+ }
+
+ if (voiceDuration >= minimumWordLength ) {
+ if (silenceDuration > 0)
+ ast_verb(3, "AMD: Channel [%s]. Detected Talk, previous silence duration: %d\n", chan->name, silenceDuration);
+ silenceDuration = 0;
+ }
+ if (consecutiveVoiceDuration >= minimumWordLength && inGreeting == 0){
+ /* Only go in here once to change the greeting flag when we detect the 1st word */
+ if (silenceDuration > 0)
+ ast_verb(3, "AMD: Channel [%s]. Before Greeting Time: silenceDuration: %d voiceDuration: %d\n", chan->name, silenceDuration, voiceDuration);
+ inInitialSilence = 0;
+ inGreeting = 1;
+ }
+
+ }
+ }
+ ast_frfree(f);
+ }
+
+ if (!res) {
+ /* It took too long to get a frame back. Giving up. */
+ ast_verb(3, "AMD: Channel [%s]. Too long...\n", chan->name);
+ strcpy(amdStatus , "NOTSURE");
+ sprintf(amdCause , "TOOLONG-%d", iTotalTime);
+ }
+
+ /* Set the status and cause on the channel */
+ pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
+ pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
+
+ /* Restore channel read format */
+ if (readFormat && ast_set_read_format(chan, readFormat))
+ ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name);
+
+ /* Free the DSP used to detect silence */
+ ast_dsp_free(silenceDetector);
+
+ return;
+}
+
+
+static int amd_exec(struct ast_channel *chan, void *data)
+{
+ isAnsweringMachine(chan, data);
+
+ return 0;
+}
+
+static int load_config(int reload)
+{
+ struct ast_config *cfg = NULL;
+ char *cat = NULL;
+ struct ast_variable *var = NULL;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+
+ if (!(cfg = ast_config_load("amd.conf", config_flags))) {
+ ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
+ return -1;
+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
+ return 0;
+
+ cat = ast_category_browse(cfg, NULL);
+
+ while (cat) {
+ if (!strcasecmp(cat, "general") ) {
+ var = ast_variable_browse(cfg, cat);
+ while (var) {
+ if (!strcasecmp(var->name, "initial_silence")) {
+ dfltInitialSilence = atoi(var->value);
+ } else if (!strcasecmp(var->name, "greeting")) {
+ dfltGreeting = atoi(var->value);
+ } else if (!strcasecmp(var->name, "after_greeting_silence")) {
+ dfltAfterGreetingSilence = atoi(var->value);
+ } else if (!strcasecmp(var->name, "silence_threshold")) {
+ dfltSilenceThreshold = atoi(var->value);
+ } else if (!strcasecmp(var->name, "total_analysis_time")) {
+ dfltTotalAnalysisTime = atoi(var->value);
+ } else if (!strcasecmp(var->name, "min_word_length")) {
+ dfltMinimumWordLength = atoi(var->value);
+ } else if (!strcasecmp(var->name, "between_words_silence")) {
+ dfltBetweenWordsSilence = atoi(var->value);
+ } else if (!strcasecmp(var->name, "maximum_number_of_words")) {
+ dfltMaximumNumberOfWords = atoi(var->value);
+ } else if (!strcasecmp(var->name, "maximum_word_length")) {
+ dfltMaximumWordLength = atoi(var->value);
+
+ } else {
+ ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
+ app, cat, var->name, var->lineno);
+ }
+ var = var->next;
+ }
+ }
+ cat = ast_category_browse(cfg, cat);
+ }
+
+ ast_config_destroy(cfg);
+
+ ast_verb(3, "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
+ "totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] maximumWordLength [%d]\n",
+ dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
+ dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold, dfltMaximumWordLength);
+
+ return 0;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+ if (load_config(0))
+ return AST_MODULE_LOAD_DECLINE;
+ if (ast_register_application(app, amd_exec, synopsis, descrip))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload(void)
+{
+ if (load_config(1))
+ return AST_MODULE_LOAD_DECLINE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
+ .load = load_module,
+ .unload = unload_module,
+ .reload = reload,
+ );
diff --git a/trunk/apps/app_authenticate.c b/trunk/apps/app_authenticate.c
new file mode 100644
index 000000000..3a3e7582e
--- /dev/null
+++ b/trunk/apps/app_authenticate.c
@@ -0,0 +1,212 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Execute arbitrary authenticate commands
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/app.h"
+#include "asterisk/astdb.h"
+#include "asterisk/utils.h"
+
+enum {
+ OPT_ACCOUNT = (1 << 0),
+ OPT_DATABASE = (1 << 1),
+ OPT_MULTIPLE = (1 << 3),
+ OPT_REMOVE = (1 << 4),
+} auth_option_flags;
+
+AST_APP_OPTIONS(auth_app_options, {
+ AST_APP_OPTION('a', OPT_ACCOUNT),
+ AST_APP_OPTION('d', OPT_DATABASE),
+ AST_APP_OPTION('m', OPT_MULTIPLE),
+ AST_APP_OPTION('r', OPT_REMOVE),
+});
+
+
+static char *app = "Authenticate";
+
+static char *synopsis = "Authenticate a user";
+
+static char *descrip =
+" Authenticate(password[,options[,maxdigits]]): This application asks the caller\n"
+"to enter a given password in order to continue dialplan execution. If the password\n"
+"begins with the '/' character, it is interpreted as a file which contains a list of\n"
+"valid passwords, listed 1 password per line in the file.\n"
+" When using a database key, the value associated with the key can be anything.\n"
+"Users have three attempts to authenticate before the channel is hung up.\n"
+" Options:\n"
+" a - Set the channels' account code to the password that is entered\n"
+" d - Interpret the given path as database key, not a literal file\n"
+" m - Interpret the given path as a file which contains a list of account\n"
+" codes and password hashes delimited with ':', listed one per line in\n"
+" the file. When one of the passwords is matched, the channel will have\n"
+" its account code set to the corresponding account code in the file.\n"
+" r - Remove the database key upon successful entry (valid with 'd' only)\n"
+" maxdigits - maximum acceptable number of digits. Stops reading after\n"
+" maxdigits have been entered (without requiring the user to\n"
+" press the '#' key).\n"
+" Defaults to 0 - no limit - wait for the user press the '#' key.\n"
+;
+
+static int auth_exec(struct ast_channel *chan, void *data)
+{
+ int res = 0, retries, maxdigits;
+ char passwd[256], *prompt = "agent-pass", *argcopy = NULL;
+ struct ast_flags flags = {0};
+
+ AST_DECLARE_APP_ARGS(arglist,
+ AST_APP_ARG(password);
+ AST_APP_ARG(options);
+ AST_APP_ARG(maxdigits);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
+ return -1;
+ }
+
+ if (chan->_state != AST_STATE_UP) {
+ if ((res = ast_answer(chan)))
+ return -1;
+ }
+
+ argcopy = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(arglist, argcopy);
+
+ if (!ast_strlen_zero(arglist.options))
+ ast_app_parse_options(auth_app_options, &flags, NULL, arglist.options);
+
+ if (!ast_strlen_zero(arglist.maxdigits)) {
+ maxdigits = atoi(arglist.maxdigits);
+ if ((maxdigits<1) || (maxdigits>sizeof(passwd)-2))
+ maxdigits = sizeof(passwd) - 2;
+ } else {
+ maxdigits = sizeof(passwd) - 2;
+ }
+
+ /* Start asking for password */
+ for (retries = 0; retries < 3; retries++) {
+ if ((res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0)) < 0)
+ break;
+ res = 0;
+ if (arglist.password[0] == '/') {
+ if (ast_test_flag(&flags,OPT_DATABASE)) {
+ char tmp[256];
+ /* Compare against a database key */
+ if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
+ /* It's a good password */
+ if (ast_test_flag(&flags,OPT_REMOVE))
+ ast_db_del(arglist.password + 1, passwd);
+ break;
+ }
+ } else {
+ /* Compare against a file */
+ FILE *f;
+ char buf[256] = "", md5passwd[33] = "", *md5secret = NULL;
+
+ if (!(f = fopen(arglist.password, "r"))) {
+ ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
+ continue;
+ }
+
+ while (!feof(f)) {
+ fgets(buf, sizeof(buf), f);
+ if (!feof(f) && !ast_strlen_zero(buf)) {
+ buf[strlen(buf) - 1] = '\0';
+ if (ast_test_flag(&flags,OPT_MULTIPLE)) {
+ md5secret = strchr(buf, ':');
+ if (md5secret == NULL)
+ continue;
+ *md5secret = '\0';
+ md5secret++;
+ ast_md5_hash(md5passwd, passwd);
+ if (!strcmp(md5passwd, md5secret)) {
+ if (ast_test_flag(&flags,OPT_ACCOUNT))
+ ast_cdr_setaccount(chan, buf);
+ break;
+ }
+ } else {
+ if (!strcmp(passwd, buf)) {
+ if (ast_test_flag(&flags,OPT_ACCOUNT))
+ ast_cdr_setaccount(chan, buf);
+ break;
+ }
+ }
+ }
+ }
+ fclose(f);
+ if (!ast_strlen_zero(buf)) {
+ if (ast_test_flag(&flags,OPT_MULTIPLE)) {
+ if (md5secret && !strcmp(md5passwd, md5secret))
+ break;
+ } else {
+ if (!strcmp(passwd, buf))
+ break;
+ }
+ }
+ }
+ } else {
+ /* Compare against a fixed password */
+ if (!strcmp(passwd, arglist.password))
+ break;
+ }
+ prompt = "auth-incorrect";
+ }
+ if ((retries < 3) && !res) {
+ if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
+ ast_cdr_setaccount(chan, passwd);
+ if (!(res = ast_streamfile(chan, "auth-thankyou", chan->language)))
+ res = ast_waitstream(chan, "");
+ } else {
+ if (!ast_streamfile(chan, "vm-goodbye", chan->language))
+ res = ast_waitstream(chan, "");
+ res = -1;
+ }
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+ if (ast_register_application(app, auth_exec, synopsis, descrip))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");
diff --git a/trunk/apps/app_cdr.c b/trunk/apps/app_cdr.c
new file mode 100644
index 000000000..7804a806b
--- /dev/null
+++ b/trunk/apps/app_cdr.c
@@ -0,0 +1,63 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Martin Pycko <martinp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Applications connected with CDR engine
+ *
+ * \author Martin Pycko <martinp@digium.com>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/channel.h"
+#include "asterisk/module.h"
+
+static char *nocdr_descrip =
+" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n"
+"current call.\n";
+
+static char *nocdr_app = "NoCDR";
+static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call";
+
+
+static int nocdr_exec(struct ast_channel *chan, void *data)
+{
+ if (chan->cdr)
+ ast_set_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED);
+
+ return 0;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(nocdr_app);
+}
+
+static int load_module(void)
+{
+ if (ast_register_application(nocdr_app, nocdr_exec, nocdr_synopsis, nocdr_descrip))
+ return AST_MODULE_LOAD_FAILURE;
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Tell Asterisk to not maintain a CDR for the current call");
diff --git a/trunk/apps/app_chanisavail.c b/trunk/apps/app_chanisavail.c
new file mode 100644
index 000000000..67d29e6ee
--- /dev/null
+++ b/trunk/apps/app_chanisavail.c
@@ -0,0 +1,157 @@
+/*
+* Asterisk -- An open source telephony toolkit.
+*
+* Copyright (C) 1999 - 2005, Digium, Inc.
+*
+* Mark Spencer <markster@digium.com>
+* James Golovich <james@gnuinter.net>
+*
+* See http://www.asterisk.org for more information about
+* the Asterisk project. Please do not directly contact
+* any of the maintainers of this project for assistance;
+* the project provides a web site, mailing lists and IRC
+* channels for your use.
+*
+* This program is free software, distributed under the terms of
+* the GNU General Public License Version 2. See the LICENSE file
+* at the top of the source tree.
+*/
+
+/*! \file
+ *
+ * \brief Check if Channel is Available
+ *
+ * \author Mark Spencer <markster@digium.com>
+ * \author James Golovich <james@gnuinter.net>
+
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/ioctl.h>
+
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/app.h"
+#include "asterisk/devicestate.h"
+
+static char *app = "ChanIsAvail";
+
+static char *synopsis = "Check channel availability";
+
+static char *descrip =
+" ChanIsAvail(Technology/resource[&Technology2/resource2...][,options]): \n"
+"This application will check to see if any of the specified channels are\n"
+"available.\n"
+" Options:\n"
+" s - Consider the channel unavailable if the channel is in use at all.\n"
+" t - Simply checks if specified channels exist in the channel list\n"
+" (implies option s).\n"
+"This application sets the following channel variable upon completion:\n"
+" AVAILCHAN - the name of the available channel, if one exists\n"
+" AVAILORIGCHAN - the canonical channel name that was used to create the channel\n"
+" AVAILSTATUS - the status code for the available channel\n";
+
+
+static int chanavail_exec(struct ast_channel *chan, void *data)
+{
+ int res=-1, inuse=-1, option_state=0, string_compare=0;
+ int status;
+ char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur;
+ struct ast_channel *tempchan;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(reqchans);
+ AST_APP_ARG(options);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
+ return -1;
+ }
+
+ info = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(args, info);
+
+ if (args.options) {
+ if (strchr(args.options, 's'))
+ option_state = 1;
+ if (strchr(args.options, 't'))
+ string_compare = 1;
+ }
+ peers = args.reqchans;
+ if (peers) {
+ cur = peers;
+ do {
+ /* remember where to start next time */
+ rest = strchr(cur, '&');
+ if (rest) {
+ *rest = 0;
+ rest++;
+ }
+ tech = cur;
+ number = strchr(tech, '/');
+ if (!number) {
+ ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
+ return -1;
+ }
+ *number = '\0';
+ number++;
+
+ if (string_compare) {
+ /* ast_parse_device_state checks for "SIP/1234" as a channel name.
+ ast_device_state will ask the SIP driver for the channel state. */
+
+ snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
+ status = inuse = ast_parse_device_state(trychan);
+ } else if (option_state) {
+ /* If the pbx says in use then don't bother trying further.
+ This is to permit testing if someone's on a call, even if the
+ channel can permit more calls (ie callwaiting, sip calls, etc). */
+
+ snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
+ status = inuse = ast_device_state(trychan);
+ }
+ if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
+ pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
+ /* Store the originally used channel too */
+ snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
+ pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
+ snprintf(tmp, sizeof(tmp), "%d", status);
+ pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
+ ast_hangup(tempchan);
+ tempchan = NULL;
+ res = 1;
+ break;
+ } else {
+ snprintf(tmp, sizeof(tmp), "%d", status);
+ pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
+ }
+ cur = rest;
+ } while (cur);
+ }
+ if (res < 1) {
+ pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
+ pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
+ }
+
+ return 0;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+ return ast_register_application(app, chanavail_exec, synopsis, descrip);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Check channel availability");
diff --git a/trunk/apps/app_channelredirect.c b/trunk/apps/app_channelredirect.c
new file mode 100644
index 000000000..325c681ac
--- /dev/null
+++ b/trunk/apps/app_channelredirect.c
@@ -0,0 +1,93 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2006, Sergey Basmanov
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ChannelRedirect application
+ *
+ * \author Sergey Basmanov <sergey_basmanov@mail.ru>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/app.h"
+#include "asterisk/features.h"
+
+static char *app = "ChannelRedirect";
+static char *synopsis = "Redirects given channel to a dialplan target.";
+static char *descrip =
+"ChannelRedirect(channel,[[context,]extension,]priority)\n"
+" Sends the specified channel to the specified extension priority\n";
+
+
+static int asyncgoto_exec(struct ast_channel *chan, void *data)
+{
+ int res = -1;
+ char *info;
+ struct ast_channel *chan2 = NULL;
+
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(channel);
+ AST_APP_ARG(label);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "%s requires an argument (channel,[[context,]exten,]priority)\n", app);
+ return -1;
+ }
+
+ info = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, info);
+
+ if (ast_strlen_zero(args.channel) || ast_strlen_zero(args.label)) {
+ ast_log(LOG_WARNING, "%s requires an argument (channel,[[context,]exten,]priority)\n", app);
+ goto quit;
+ }
+
+ chan2 = ast_get_channel_by_name_locked(args.channel);
+ if (!chan2) {
+ ast_log(LOG_WARNING, "No such channel: %s\n", args.channel);
+ goto quit;
+ }
+
+ res = ast_parseable_goto(chan2, args.label);
+
+ ast_channel_unlock(chan2);
+quit:
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ return ast_unregister_application(app);
+}
+
+static int load_module(void)
+{
+ return ast_register_application(app, asyncgoto_exec, synopsis, descrip);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Redirects a given channel to a dialplan target");
diff --git a/trunk/apps/app_chanspy.c b/trunk/apps/app_chanspy.c
new file mode 100644
index 000000000..a29973ff4
--- /dev/null
+++ b/trunk/apps/app_chanspy.c
@@ -0,0 +1,730 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
+ * Copyright (C) 2005 - 2006, Digium, Inc.
+ *
+ * A license has been granted to Digium (via disclaimer) for the use of
+ * this code.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief ChanSpy: Listen in on any channel.
+ *
+ * \author Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <ctype.h>
+
+#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/audiohook.h"
+#include "asterisk/features.h"
+#include "asterisk/app.h"
+#include "asterisk/utils.h"
+#include "asterisk/say.h"
+#include "asterisk/pbx.h"
+#include "asterisk/translate.h"
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+
+#define AST_NAME_STRLEN 256
+
+static const char *tdesc = "Listen to a channel, and optionally whisper into it";
+static const char *app_chan = "ChanSpy";
+static const char *desc_chan =
+" ChanSpy([chanprefix][,options]): This application is used to listen to the\n"
+"audio from an Asterisk channel. This includes the audio coming in and\n"
+"out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
+"only channels beginning with this string will be spied upon.\n"
+" While spying, the following actions may be performed:\n"
+" - Dialing # cycles the volume level.\n"
+" - Dialing * will stop spying and look for another channel to spy on.\n"
+" - Dialing a series of digits followed by # builds a channel name to append\n"
+" to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
+" the digits '1234#' while spying will begin spying on the channel\n"
+" 'Agent/1234'.\n"
+" Note: The X option supersedes the three features above in that if a valid\n"
+" single digit extension exists in the correct context ChanSpy will\n"
+" exit to it. This also disables choosing a channel based on 'chanprefix'\n"
+" and a digit sequence.\n"
+" Options:\n"
+" b - Only spy on channels involved in a bridged call.\n"
+" g(grp) - Match only channels where their SPYGROUP variable is set to\n"
+" contain 'grp' in an optional : delimited list.\n"
+" q - Don't play a beep when beginning to spy on a channel, or speak the\n"
+" selected channel name.\n"
+" r[(basename)] - Record the session to the monitor spool directory. An\n"
+" optional base for the filename may be specified. The\n"
+" default is 'chanspy'.\n"
+" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
+" negative value refers to a quieter setting.\n"
+" w - Enable 'whisper' mode, so the spying channel can talk to\n"
+" the spied-on channel.\n"
+" W - Enable 'private whisper' mode, so the spying channel can\n"
+" talk to the spied-on channel but cannot listen to that\n"
+" channel.\n"
+" o - Only listen to audio coming from this channel.\n"
+" X - Allow the user to exit ChanSpy to a valid single digit\n"
+" numeric extension in the current context or the context\n"
+" specified by the SPY_EXIT_CONTEXT channel variable. The\n"
+" name of the last channel that was spied on will be stored\n"
+" in the SPY_CHANNEL variable.\n"
+;
+
+static const char *app_ext = "ExtenSpy";
+static const char *desc_ext =
+" ExtenSpy(exten[@context][,options]): This application is used to listen to the\n"
+"audio from an Asterisk channel. This includes the audio coming in and\n"
+"out of the channel being spied on. Only channels created by outgoing calls for the\n"
+"specified extension will be selected for spying. If the optional context is not\n"
+"supplied, the current channel's context will be used.\n"
+" While spying, the following actions may be performed:\n"
+" - Dialing # cycles the volume level.\n"
+" - Dialing * will stop spying and look for another channel to spy on.\n"
+" Note: The X option superseeds the two features above in that if a valid\n"
+" single digit extension exists in the correct context it ChanSpy will\n"
+" exit to it.\n"
+" Options:\n"
+" b - Only spy on channels involved in a bridged call.\n"
+" g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
+" contain 'grp' in an optional : delimited list.\n"
+" q - Don't play a beep when beginning to spy on a channel, or speak the\n"
+" selected channel name.\n"
+" r[(basename)] - Record the session to the monitor spool directory. An\n"
+" optional base for the filename may be specified. The\n"
+" default is 'chanspy'.\n"
+" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
+" negative value refers to a quieter setting.\n"
+" w - Enable 'whisper' mode, so the spying channel can talk to\n"
+" the spied-on channel.\n"
+" W - Enable 'private whisper' mode, so the spying channel can\n"
+" talk to the spied-on channel but cannot listen to that\n"
+" channel.\n"
+" o - Only listen to audio coming from this channel.\n"
+" X - Allow the user to exit ChanSpy to a valid single digit\n"
+" numeric extension in the current context or the context\n"
+" specified by the SPY_EXIT_CONTEXT channel variable. The\n"
+" name of the last channel that was spied on will be stored\n"
+" in the SPY_CHANNEL variable.\n"
+;
+
+enum {
+ OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
+ OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
+ OPTION_VOLUME = (1 << 2), /* Specify initial volume */
+ OPTION_GROUP = (1 << 3), /* Only look at channels in group */
+ OPTION_RECORD = (1 << 4),
+ OPTION_WHISPER = (1 << 5),
+ OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
+ OPTION_READONLY = (1 << 7), /* Don't mix the two channels */
+ OPTION_EXIT = (1 << 8), /* Exit to a valid single digit extension */
+} chanspy_opt_flags;
+
+enum {
+ OPT_ARG_VOLUME = 0,
+ OPT_ARG_GROUP,
+ OPT_ARG_RECORD,
+ OPT_ARG_ARRAY_SIZE,
+} chanspy_opt_args;
+
+AST_APP_OPTIONS(spy_opts, {
+ AST_APP_OPTION('q', OPTION_QUIET),
+ AST_APP_OPTION('b', OPTION_BRIDGED),
+ AST_APP_OPTION('w', OPTION_WHISPER),
+ AST_APP_OPTION('W', OPTION_PRIVATE),
+ AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
+ AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
+ AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
+ AST_APP_OPTION('o', OPTION_READONLY),
+ AST_APP_OPTION('X', OPTION_EXIT),
+});
+
+
+struct chanspy_translation_helper {
+ /* spy data */
+ struct ast_audiohook spy_audiohook;
+ struct ast_audiohook whisper_audiohook;
+ int fd;
+ int volfactor;
+};
+
+static void *spy_alloc(struct ast_channel *chan, void *data)
+{
+ /* just store the data pointer in the channel structure */
+ return data;
+}
+
+static void spy_release(struct ast_channel *chan, void *data)
+{
+ /* nothing to do */
+}
+
+static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
+{
+ struct chanspy_translation_helper *csth = data;
+ struct ast_frame *f = NULL;
+
+ ast_audiohook_lock(&csth->spy_audiohook);
+ if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
+ /* Channel is already gone more than likely */
+ ast_audiohook_unlock(&csth->spy_audiohook);
+ return -1;
+ }
+
+ f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
+
+ ast_audiohook_unlock(&csth->spy_audiohook);
+
+ if (!f)
+ return 0;
+
+ if (ast_write(chan, f)) {
+ ast_frfree(f);
+ return -1;
+ }
+
+ if (csth->fd)
+ write(csth->fd, f->data, f->datalen);
+
+ ast_frfree(f);
+
+ return 0;
+}
+
+static struct ast_generator spygen = {
+ .alloc = spy_alloc,
+ .release = spy_release,
+ .generate = spy_generate,
+};
+
+static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_audiohook *audiohook)
+{
+ int res = 0;
+ struct ast_channel *peer = NULL;
+
+ ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
+
+ res = ast_audiohook_attach(chan, audiohook);
+
+ if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
+ ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
+
+ return res;
+}
+
+static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd,
+ const struct ast_flags *flags, char *exitcontext)
+{
+ struct chanspy_translation_helper csth;
+ int running = 0, res, x = 0;
+ char inp[24] = {0};
+ char *name;
+ struct ast_frame *f;
+ struct ast_silence_generator *silgen = NULL;
+
+ if (ast_check_hangup(chan) || ast_check_hangup(spyee))
+ return 0;
+
+ name = ast_strdupa(spyee->name);
+ ast_verb(2, "Spying on channel %s\n", name);
+
+ memset(&csth, 0, sizeof(csth));
+
+ ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
+
+ if (start_spying(spyee, chan, &csth.spy_audiohook)) {
+ ast_audiohook_destroy(&csth.spy_audiohook);
+ return 0;
+ }
+
+ if (ast_test_flag(flags, OPTION_WHISPER)) {
+ ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
+ start_spying(spyee, chan, &csth.whisper_audiohook);
+ }
+
+ csth.volfactor = *volfactor;
+
+ if (csth.volfactor) {
+ csth.spy_audiohook.options.read_volume = csth.volfactor;
+ csth.spy_audiohook.options.write_volume = csth.volfactor;
+ }
+
+ csth.fd = fd;
+
+ if (ast_test_flag(flags, OPTION_PRIVATE))
+ silgen = ast_channel_start_silence_generator(chan);
+ else
+ ast_activate_generator(chan, &spygen, &csth);
+
+ /* We can no longer rely on 'spyee' being an actual channel;
+ it can be hung up and freed out from under us. However, the
+ channel destructor will put NULL into our csth.spy.chan
+ field when that happens, so that is our signal that the spyee
+ channel has gone away.
+ */
+
+ /* Note: it is very important that the ast_waitfor() be the first
+ condition in this expression, so that if we wait for some period
+ of time before receiving a frame from our spying channel, we check
+ for hangup on the spied-on channel _after_ knowing that a frame
+ has arrived, since the spied-on channel could have gone away while
+ we were waiting
+ */
+ while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
+ if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
+ running = -1;
+ break;
+ }
+
+ if (ast_test_flag(flags, OPTION_WHISPER) && f->frametype == AST_FRAME_VOICE) {
+ ast_audiohook_lock(&csth.whisper_audiohook);
+ ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
+ ast_audiohook_unlock(&csth.whisper_audiohook);
+ ast_frfree(f);
+ continue;
+ }
+
+ res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
+ ast_frfree(f);
+ if (!res)
+ continue;
+
+ if (x == sizeof(inp))
+ x = 0;
+
+ if (res < 0) {
+ running = -1;
+ break;
+ }
+
+ if (ast_test_flag(flags, OPTION_EXIT)) {
+ char tmp[2];
+ tmp[0] = res;
+ tmp[1] = '\0';
+ if (!ast_goto_if_exists(chan, exitcontext, tmp, 1)) {
+ ast_debug(1, "Got DTMF %c, goto context %s\n", tmp[0], exitcontext);
+ pbx_builtin_setvar_helper(chan, "SPY_CHANNEL", name);
+ running = -2;
+ break;
+ } else {
+ ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
+ }
+ } else if (res >= '0' && res <= '9') {
+ inp[x++] = res;
+ }
+
+ if (res == '*') {
+ running = 0;
+ break;
+ } else if (res == '#') {
+ if (!ast_strlen_zero(inp)) {
+ running = atoi(inp);
+ break;
+ }
+
+ (*volfactor)++;
+ if (*volfactor > 4)
+ *volfactor = -4;
+ ast_verb(3, "Setting spy volume on %s to %d\n", chan->name, *volfactor);
+
+ csth.volfactor = *volfactor;
+ csth.spy_audiohook.options.read_volume = csth.volfactor;
+ csth.spy_audiohook.options.write_volume = csth.volfactor;
+ }
+ }
+
+ if (ast_test_flag(flags, OPTION_PRIVATE))
+ ast_channel_stop_silence_generator(chan, silgen);
+ else
+ ast_deactivate_generator(chan);
+
+ if (ast_test_flag(flags, OPTION_WHISPER)) {
+ ast_audiohook_lock(&csth.whisper_audiohook);
+ ast_audiohook_detach(&csth.whisper_audiohook);
+ ast_audiohook_unlock(&csth.whisper_audiohook);
+ ast_audiohook_destroy(&csth.whisper_audiohook);
+ }
+
+ ast_audiohook_lock(&csth.spy_audiohook);
+ ast_audiohook_detach(&csth.spy_audiohook);
+ ast_audiohook_unlock(&csth.spy_audiohook);
+ ast_audiohook_destroy(&csth.spy_audiohook);
+
+ ast_verb(2, "Done Spying on channel %s\n", name);
+
+ return running;
+}
+
+static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
+ const char *exten, const char *context)
+{
+ struct ast_channel *this;
+
+ redo:
+ if (spec)
+ this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
+ else if (exten)
+ this = ast_walk_channel_by_exten_locked(last, exten, context);
+ else
+ this = ast_channel_walk_locked(last);
+
+ if (this) {
+ ast_channel_unlock(this);
+ if (!strncmp(this->name, "Zap/pseudo", 10))
+ goto redo;
+ }
+
+ return this;
+}
+
+static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
+ int volfactor, const int fd, const char *mygroup, const char *spec,
+ const char *exten, const char *context)
+{
+ struct ast_channel *peer, *prev, *next;
+ char nameprefix[AST_NAME_STRLEN];
+ char peer_name[AST_NAME_STRLEN + 5];
+ char exitcontext[AST_MAX_CONTEXT] = "";
+ signed char zero_volume = 0;
+ int waitms;
+ int res;
+ char *ptr;
+ int num;
+
+ if (ast_test_flag(flags, OPTION_EXIT)) {
+ const char *c;
+ if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT")))
+ ast_copy_string(exitcontext, c, sizeof(exitcontext));
+ else if (!ast_strlen_zero(chan->macrocontext))
+ ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
+ else
+ ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
+ }
+
+ if (chan->_state != AST_STATE_UP)
+ ast_answer(chan);
+
+ ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
+
+ waitms = 100;
+
+ for (;;) {
+ if (!ast_test_flag(flags, OPTION_QUIET)) {
+ res = ast_streamfile(chan, "beep", chan->language);
+ if (!res)
+ res = ast_waitstream(chan, "");
+ else if (res < 0) {
+ ast_clear_flag(chan, AST_FLAG_SPYING);
+ break;
+ }
+ if (!ast_strlen_zero(exitcontext)) {
+ char tmp[2];
+ tmp[0] = res;
+ tmp[1] = '\0';
+ if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
+ goto exit;
+ else
+ ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
+ }
+ }
+
+ res = ast_waitfordigit(chan, waitms);
+ if (res < 0) {
+ ast_clear_flag(chan, AST_FLAG_SPYING);
+ break;
+ }
+ if (!ast_strlen_zero(exitcontext)) {
+ char tmp[2];
+ tmp[0] = res;
+ tmp[1] = '\0';
+ if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
+ goto exit;
+ else
+ ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
+ }
+
+ /* reset for the next loop around, unless overridden later */
+ waitms = 100;
+ peer = prev = next = NULL;
+
+ for (peer = next_channel(peer, spec, exten, context);
+ peer;
+ prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
+ const char *group;
+ int igrp = !mygroup;
+ char *groups[25];
+ int num_groups = 0;
+ char *dup_group;
+ int x;
+ char *s;
+
+ if (peer == prev)
+ break;
+
+ if (peer == chan)
+ continue;
+
+ if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
+ continue;
+
+ if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
+ continue;
+
+ if (mygroup) {
+ if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
+ dup_group = ast_strdupa(group);
+ num_groups = ast_app_separate_args(dup_group, ':', groups,
+ sizeof(groups) / sizeof(groups[0]));
+ }
+
+ for (x = 0; x < num_groups; x++) {
+ if (!strcmp(mygroup, groups[x])) {
+ igrp = 1;
+ break;
+ }
+ }
+ }
+
+ if (!igrp)
+ continue;
+
+ strcpy(peer_name, "spy-");
+ strncat(peer_name, peer->name, AST_NAME_STRLEN);
+ ptr = strchr(peer_name, '/');
+ *ptr++ = '\0';
+
+ for (s = peer_name; s < ptr; s++)
+ *s = tolower(*s);
+
+ if (!ast_test_flag(flags, OPTION_QUIET)) {
+ if (ast_fileexists(peer_name, NULL, NULL) != -1) {
+ res = ast_streamfile(chan, peer_name, chan->language);
+ if (!res)
+ res = ast_waitstream(chan, "");
+ if (res)
+ break;
+ } else
+ res = ast_say_character_str(chan, peer_name, "", chan->language);
+ if ((num = atoi(ptr)))
+ ast_say_digits(chan, atoi(ptr), "", chan->language);
+ }
+
+ waitms = 5000;
+ res = channel_spy(chan, peer, &volfactor, fd, flags, exitcontext);
+
+ if (res == -1) {
+ goto exit;
+ } else if (res == -2) {
+ res = 0;
+ goto exit;
+ } else if (res > 1 && spec) {
+ snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
+ if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
+ ast_channel_unlock(next);
+ } else {
+ /* stay on this channel */
+ next = peer;
+ }
+ peer = NULL;
+ }
+ }
+ }
+exit:
+
+ ast_clear_flag(chan, AST_FLAG_SPYING);
+
+ ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
+
+ return res;
+}
+
+static int chanspy_exec(struct ast_channel *chan, void *data)
+{
+ char *mygroup = NULL;
+ char *recbase = NULL;
+ int fd = 0;
+ struct ast_flags flags;
+ int oldwf = 0;
+ int volfactor = 0;
+ int res;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(spec);
+ AST_APP_ARG(options);
+ );
+ char *opts[OPT_ARG_ARRAY_SIZE];
+
+ data = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, data);
+
+ if (args.spec && !strcmp(args.spec, "all"))
+ args.spec = NULL;
+
+ if (args.options) {
+ ast_app_parse_options(spy_opts, &flags, opts, args.options);
+ if (ast_test_flag(&flags, OPTION_GROUP))
+ mygroup = opts[OPT_ARG_GROUP];
+
+ if (ast_test_flag(&flags, OPTION_RECORD) &&
+ !(recbase = opts[OPT_ARG_RECORD]))
+ recbase = "chanspy";
+
+ if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
+ int vol;
+
+ if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
+ ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
+ else
+ volfactor = vol;
+ }
+
+ if (ast_test_flag(&flags, OPTION_PRIVATE))
+ ast_set_flag(&flags, OPTION_WHISPER);
+ } else
+ ast_clear_flag(&flags, AST_FLAGS_ALL);
+
+ oldwf = chan->writeformat;
+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
+ return -1;
+ }
+
+ if (recbase) {
+ char filename[512];
+
+ snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
+ if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
+ ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
+ fd = 0;
+ }
+ }
+
+ res = common_exec(chan, &flags, volfactor, fd, mygroup, args.spec, NULL, NULL);
+
+ if (fd)
+ close(fd);
+
+ if (oldwf && ast_set_write_format(chan, oldwf) < 0)
+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
+
+ return res;
+}
+
+static int extenspy_exec(struct ast_channel *chan, void *data)
+{
+ char *ptr, *exten = NULL;
+ char *mygroup = NULL;
+ char *recbase = NULL;
+ int fd = 0;
+ struct ast_flags flags;
+ int oldwf = 0;
+ int volfactor = 0;
+ int res;
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(context);
+ AST_APP_ARG(options);
+ );
+
+ data = ast_strdupa(data);
+
+ AST_STANDARD_APP_ARGS(args, data);
+ if (!ast_strlen_zero(args.context) && (ptr = strchr(args.context, '@'))) {
+ exten = args.context;
+ *ptr++ = '\0';
+ args.context = ptr;
+ }
+
+ if (ast_strlen_zero(args.context))
+ args.context = ast_strdupa(chan->context);
+
+ if (args.options) {
+ char *opts[OPT_ARG_ARRAY_SIZE];
+
+ ast_app_parse_options(spy_opts, &flags, opts, args.options);
+ if (ast_test_flag(&flags, OPTION_GROUP))
+ mygroup = opts[OPT_ARG_GROUP];
+
+ if (ast_test_flag(&flags, OPTION_RECORD) &&
+ !(recbase = opts[OPT_ARG_RECORD]))
+ recbase = "chanspy";
+
+ if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
+ int vol;
+
+ if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
+ ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
+ else
+ volfactor = vol;
+ }
+
+ if (ast_test_flag(&flags, OPTION_PRIVATE))
+ ast_set_flag(&flags, OPTION_WHISPER);
+ } else
+ ast_clear_flag(&flags, AST_FLAGS_ALL);
+
+ oldwf = chan->writeformat;
+ if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
+ return -1;
+ }
+
+ if (recbase) {
+ char filename[512];
+
+ snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
+ if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, AST_FILE_MODE)) <= 0) {
+ ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
+ fd = 0;
+ }
+ }
+
+ res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, args.context);
+
+ if (fd)
+ close(fd);
+
+ if (oldwf && ast_set_write_format(chan, oldwf) < 0)
+ ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ int res = 0;
+
+ res |= ast_unregister_application(app_chan);
+ res |= ast_unregister_application(app_ext);
+
+ return res;
+}
+
+static int load_module(void)
+{
+ int res = 0;
+
+ res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
+ res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
+
+ return res;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");
diff --git a/trunk/apps/app_controlplayback.c b/trunk/apps/app_controlplayback.c
new file mode 100644
index 000000000..b6dfd898e
--- /dev/null
+++ b/trunk/apps/app_controlplayback.c
@@ -0,0 +1,168 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Trivial application to control playback of a sound file
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/pbx.h"
+#include "asterisk/app.h"
+#include "asterisk/module.h"
+
+static const char *app = "ControlPlayback";
+
+static const char *synopsis = "Play a file with fast forward and rewind";
+
+static const char *descrip =
+" ControlPlayback(file[,skipms[,ff[,rew[,stop[,pause[,restart,options]]]]]]]):\n"
+"This application will play back the given filename. By default, the '*' key\n"
+"can be used to rewind, and the '#' key can be used to fast-forward.\n"
+"Parameters:\n"
+" skipms - This is number of milliseconds to skip when rewinding or\n"
+" fast-forwarding.\n"
+" ff - Fast-forward when this DTMF digit is received.\n"
+" rew - Rewind when this DTMF digit is received.\n"
+" stop - Stop playback when this DTMF digit is received.\n"
+" pause - Pause playback when this DTMF digit is received.\n"
+" restart - Restart playback when this DTMF digit is received.\n"
+"Options:\n"
+" o(#) - Start at # ms from the beginning of the file.\n"
+"This application sets the following channel variables upon completion:\n"
+" CPLAYBACKSTATUS - This variable contains the status of the attempt as a text\n"
+" string, one of: SUCCESS | USERSTOPPED | ERROR\n"
+" CPLAYBACKOFFSET - This contains the offset in ms into the file where\n"
+" playback was at when it stopped. -1 is end of file.\n"
+" CPLAYBACKSTOPKEY - If the playback is stopped by the user this variable contains\n"
+" the key that was pressed.\n";
+
+enum {
+ OPT_OFFSET = (1 << 1),
+};
+
+enum {
+ OPT_ARG_OFFSET = 0,
+ /* must stay as the last entry ... */
+ OPT_ARG_ARRAY_LEN,
+};
+
+AST_APP_OPTIONS(cpb_opts, BEGIN_OPTIONS
+ AST_APP_OPTION_ARG('o', OPT_OFFSET, OPT_ARG_OFFSET),
+END_OPTIONS );
+
+static int is_on_phonepad(char key)
+{
+ return key == 35 || key == 42 || (key >= 48 && key <= 57);
+}
+
+static int controlplayback_exec(struct ast_channel *chan, void *data)
+{
+ int res = 0;
+ int skipms = 0;
+ long offsetms = 0;
+ char offsetbuf[20];
+ char stopkeybuf[2];
+ char *tmp;
+ struct ast_flags opts = { 0, };
+ char *opt_args[OPT_ARG_ARRAY_LEN];
+ AST_DECLARE_APP_ARGS(args,
+ AST_APP_ARG(filename);
+ AST_APP_ARG(skip);
+ AST_APP_ARG(fwd);
+ AST_APP_ARG(rev);
+ AST_APP_ARG(stop);
+ AST_APP_ARG(pause);
+ AST_APP_ARG(restart);
+ AST_APP_ARG(options);
+ );
+
+ if (ast_strlen_zero(data)) {
+ ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
+ return -1;
+ }
+
+ tmp = ast_strdupa(data);
+ AST_STANDARD_APP_ARGS(args, tmp);
+
+ if (args.argc < 1) {
+ ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
+ return -1;
+ }
+
+ skipms = args.skip ? (atoi(args.skip) ? atoi(args.skip) : 3000) : 3000;
+
+ if (!args.fwd || !is_on_phonepad(*args.fwd))
+ args.fwd = "#";
+ if (!args.rev || !is_on_phonepad(*args.rev))
+ args.rev = "*";
+ if (args.stop && !is_on_phonepad(*args.stop))
+ args.stop = NULL;
+ if (args.pause && !is_on_phonepad(*args.pause))
+ args.pause = NULL;
+ if (args.restart && !is_on_phonepad(*args.restart))
+ args.restart = NULL;
+
+ if (args.options) {
+ ast_app_parse_options(cpb_opts, &opts, opt_args, args.options);
+ if (ast_test_flag(&opts, OPT_OFFSET))
+ offsetms = atol(opt_args[OPT_ARG_OFFSET]);
+ }
+
+ res = ast_control_streamfile(chan, args.filename, args.fwd, args.rev, args.stop, args.pause, args.restart, skipms, &offsetms);
+
+ /* If we stopped on one of our stop keys, return 0 */
+ if (res > 0 && args.stop && strchr(args.stop, res)) {
+ pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
+ snprintf(stopkeybuf, sizeof(stopkeybuf), "%c", res);
+ pbx_builtin_setvar_helper(chan, "CPLAYBACKSTOPKEY", stopkeybuf);
+ res = 0;
+ } else {
+ if (res < 0) {
+ res = 0;
+ pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
+ } else
+ pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
+ }
+
+ snprintf(offsetbuf, sizeof(offsetbuf), "%ld", offsetms);
+ pbx_builtin_setvar_helper(chan, "CPLAYBACKOFFSET", offsetbuf);
+
+ return res;
+}
+
+static int unload_module(void)
+{
+ int res;
+ res = ast_unregister_application(app);
+ return res;
+}
+
+static int load_module(void)
+{
+ return ast_register_application(app, controlplayback_exec, synopsis, descrip);
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application");
diff --git a/trunk/apps/app_db.c b/trunk/apps/app_db.c
new file mode 100644
index 000000000..0cc5043ce
--- /dev/null
+++ b/trunk/apps/app_db.c
@@ -0,0 +1,139 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Digium, Inc.
+ * Copyright (C) 2003, Jefferson Noxon
+ *
+ * Mark Spencer <markster@digium.com>
+ * Jefferson Noxon <jeff@debian.org>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Database access functions
+ *
+ * \author Mark Spencer <markster@digium.com>
+ * \author Jefferson Noxon <jeff@debian.org>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/astdb.h"
+#include "asterisk/lock.h"
+
+/*! \todo XXX Remove this application after 1.4 is relased */
+static char *d_descrip =
+" DBdel(family/key): This application will delete a key from the Asterisk\n"
+"database.\n"
+" This application has been DEPRECATED in favor of the DB_DELETE function.\n";
+
+static char *dt_descrip =
+" DBdeltree(family[/keytree]): This application will delete a family or keytree\n"
+"from the Asterisk database\n";
+
+static char *d_app = "DBdel";
+static char *dt_app = "DBdeltree";
+
+static char *d_synopsis = "Delete a key from the database";
+static char *dt_synopsis = "Delete a family or keytree from the database";
+
+
+static int deltree_exec(struct ast_channel *chan, void *data)
+{
+ char *argv, *family, *keytree;
+
+ argv = ast_strdupa(data);
+
+ if (strchr(argv, '/')) {
+ family = strsep(&argv, "/");
+ keytree = strsep(&argv, "\0");
+ if (!family || !keytree) {
+ ast_debug(1, "Ignoring; Syntax error in argument\n");
+ return 0;
+ }
+ if (ast_strlen_zero(keytree))
+ keytree = 0;
+ } else {
+ family = argv;
+ keytree = 0;
+ }
+
+ if (keytree)
+ ast_verb(3, "DBdeltree: family=%s, keytree=%s\n", family, keytree);
+ else
+ ast_verb(3, "DBdeltree: family=%s\n", family);
+
+ if (ast_db_deltree(family, keytree))
+ ast_verb(3, "DBdeltree: Error deleting key from database.\n");
+
+ return 0;
+}
+
+static int del_exec(struct ast_channel *chan, void *data)
+{
+ char *argv, *family, *key;
+ static int deprecation_warning = 0;
+
+ if (!deprecation_warning) {
+ deprecation_warning = 1;
+ ast_log(LOG_WARNING, "The DBdel application has been deprecated in favor of the DB_DELETE dialplan function!\n");
+ }
+
+ argv = ast_strdupa(data);
+
+ if (strchr(argv, '/')) {
+ family = strsep(&argv, "/");
+ key = strsep(&argv, "\0");
+ if (!family || !key) {
+ ast_debug(1, "Ignoring; Syntax error in argument\n");
+ return 0;
+ }
+ ast_verb(3, "DBdel: family=%s, key=%s\n", family, key);
+ if (ast_db_del(family, key))
+ ast_verb(3, "DBdel: Error deleting key from database.\n");
+ } else {
+ ast_debug(1, "Ignoring, no parameters\n");
+ }
+
+ return 0;
+}
+
+static int unload_module(void)
+{
+ int retval;
+
+ retval = ast_unregister_application(dt_app);
+ retval |= ast_unregister_application(d_app);
+
+ return retval;
+}
+
+static int load_module(void)
+{
+ int retval;
+
+ retval = ast_register_application(d_app, del_exec, d_synopsis, d_descrip);
+ retval |= ast_register_application(dt_app, deltree_exec, dt_synopsis, dt_descrip);
+
+ return retval;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database Access Functions");
diff --git a/trunk/apps/app_dial.c b/trunk/apps/app_dial.c
new file mode 100644
index 000000000..db1f76c8d
--- /dev/null
+++ b/trunk/apps/app_dial.c
@@ -0,0 +1,2047 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2006, Digium, Inc.
+ *
+ * Mark Spencer <markster@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief dial() & retrydial() - Trivial application to dial a channel and send an URL on answer
+ *
+ * \author Mark Spencer <markster@digium.com>
+ *
+ * \ingroup applications
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
+#include "asterisk/lock.h"
+#include "asterisk/file.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
+#include "asterisk/module.h"
+#include "asterisk/translate.h"
+#include "asterisk/say.h"
+#include "asterisk/config.h"
+#include "asterisk/features.h"
+#include "asterisk/musiconhold.h"
+#include "asterisk/callerid.h"
+#include "asterisk/utils.h"
+#include "asterisk/app.h"
+#include "asterisk/causes.h"
+#include "asterisk/rtp.h"
+#include "asterisk/cdr.h"
+#include "asterisk/manager.h"
+#include "asterisk/privacy.h"
+#include "asterisk/stringfields.h"
+#include "asterisk/global_datastores.h"
+
+static char *app = "Dial";
+
+static char *synopsis = "Place a call and connect to the current channel";
+
+static char *descrip =
+" Dial(Technology/resource[&Tech2/resource2...][,timeout][,options][,URL]):\n"
+"This application will place calls to one or more specified channels. As soon\n"
+"as one of the requested channels answers, the originating channel will be\n"
+"answered, if it has not already been answered. These two channels will then\n"
+"be active in a bridged call. All other channels that were requested will then\n"
+"be hung up.\n"
+" Unless there is a timeout specified, the Dial application will wait\n"
+"indefinitely until one of the called channels answers, the user hangs up, or\n"
+"if all of the called channels are busy or unavailable. Dialplan executing will\n"
+"continue if no requested channels can be called, or if the timeout expires.\n\n"
+" This application sets the following channel variables upon completion:\n"
+" DIALEDTIME - This is the time from dialing a channel until when it\n"
+" is disconnected.\n"
+" ANSWEREDTIME - This is the amount of time for actual call.\n"
+" DIALSTATUS - This is the status of the call:\n"
+" CHANUNAVAIL | CONGESTION | NOANSWER | BUSY | ANSWER | CANCEL\n"
+" DONTCALL | TORTURE | INVALIDARGS\n"
+" For the Privacy and Screening Modes, the DIALSTATUS variable will be set to\n"
+"DONTCALL if the called party chooses to send the calling party to the 'Go Away'\n"
+"script. The DIALSTATUS variable will be set to TORTURE if the called party\n"
+"wants to send the caller to the 'torture' script.\n"
+" This application will report normal termination if the originating channel\n"
+"hangs up, or if the call is bridged and either of the parties in the bridge\n"
+"ends the call.\n"
+" The optional URL will be sent to the called party if the channel supports it.\n"
+" If the OUTBOUND_GROUP variable is set, all peer channels created by this\n"
+"application will be put into that group (as in Set(GROUP()=...).\n"
+" If the OUTBOUND_GROUP_ONCE variable is set, all peer channels created by this\n"
+"application will be put into that group (as in Set(GROUP()=...). Unlike OUTBOUND_GROUP,\n"
+"however, the variable will be unset after use.\n\n"
+" Options:\n"
+" A(x) - Play an announcement to the called party, using 'x' as the file.\n"
+" C - Reset the CDR for this call.\n"
+" c - If DIAL cancels this call, always set the flag to tell the channel\n"
+" driver that the call is answered elsewhere.\n"
+" d - Allow the calling user to dial a 1 digit extension while waiting for\n"
+" a call to be answered. Exit to that extension if it exists in the\n"
+" current context, or the context defined in the EXITCONTEXT variable,\n"
+" if it exists.\n"
+" D([called][:calling]) - Send the specified DTMF strings *after* the called\n"
+" party has answered, but before the call gets bridged. The 'called'\n"
+" DTMF string is sent to the called party, and the 'calling' DTMF\n"
+" string is sent to the calling party. Both parameters can be used\n"
+" alone.\n"
+" e - execute the 'h' extension for peer after the call ends\n"
+" f - Force the callerid of the *calling* channel to be set as the\n"
+" extension associated with the channel using a dialplan 'hint'.\n"
+" For example, some PSTNs do not allow CallerID to be set to anything\n"
+" other than the number assigned to the caller.\n"
+" g - Proceed with dialplan execution at the current extension if the\n"
+" destination channel hangs up.\n"
+" G(context^exten^pri) - If the call is answered, transfer the calling party to\n"
+" the specified priority and the called party to the specified priority+1.\n"
+" Optionally, an extension, or extension and context may be specified. \n"
+" Otherwise, the current extension is used. You cannot use any additional\n"
+" action post answer options in conjunction with this option.\n"
+" h - Allow the called party to hang up by sending the '*' DTMF digit.\n"
+" H - Allow the calling party to hang up by hitting the '*' DTMF digit.\n"
+" i - Asterisk will ignore any forwarding requests it may receive on this\n"
+" dial attempt.\n"
+" k - Allow the called party to enable parking of the call by sending\n"
+" the DTMF sequence defined for call parking in features.conf.\n"
+" K - Allow the calling party to enable parking of the call by sending\n"
+" the DTMF sequence defined for call parking in features.conf.\n"
+" L(x[:y][:z]) - Limit the call to 'x' ms. Play a warning when 'y' ms are\n"
+" left. Repeat the warning every 'z' ms. The following special\n"
+" variables can be used with this option:\n"
+" * LIMIT_PLAYAUDIO_CALLER yes|no (default yes)\n"
+" Play sounds to the caller.\n"
+" * LIMIT_PLAYAUDIO_CALLEE yes|no\n"
+" Play sounds to the callee.\n"
+" * LIMIT_TIMEOUT_FILE File to play when time is up.\n"
+" * LIMIT_CONNECT_FILE File to play when call begins.\n"
+" * LIMIT_WARNING_FILE File to play as warning if 'y' is defined.\n"
+" The default is to say the time remaining.\n"
+" m([class]) - Provide hold music to the calling party until a requested\n"
+" channel answers. A specific MusicOnHold class can be\n"
+" specified.\n"
+" M(x[^arg]) - Execute the Macro for the *called* channel before connecting\n"
+" to the calling channel. Arguments can be specified to the Macro\n"
+" using '^' as a delimeter. The Macro can set the variable\n"
+" MACRO_RESULT to specify the following actions after the Macro is\n"
+" finished executing.\n"
+" * ABORT Hangup both legs of the call.\n"
+" * CONGESTION Behave as if line congestion was encountered.\n"
+" * BUSY Behave as if a busy signal was encountered.\n"
+" * CONTINUE Hangup the called party and allow the calling party\n"
+" to continue dialplan execution at the next priority.\n"
+" * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n"
+" specified priority. Optionally, an extension, or\n"
+" extension and priority can be specified.\n"
+" You cannot use any additional action post answer options in conjunction\n"
+" with this option. Also, pbx services are not run on the peer (called) channel,\n"
+" so you will not be able to set timeouts via the TIMEOUT() function in this macro.\n"
+" n - This option is a modifier for the screen/privacy mode. It specifies\n"
+" that no introductions are to be saved in the priv-callerintros\n"
+" directory.\n"
+" N - This option is a modifier for the screen/privacy mode. It specifies\n"
+" that if callerID is present, do not screen the call.\n"
+" o - Specify that the CallerID that was present on the *calling* channel\n"
+" be set as the CallerID on the *called* channel. This was the\n"
+" behavior of Asterisk 1.0 and earlier.\n"
+" O([x]) - \"Operator Services\" mode (Zaptel channel to Zaptel channel\n"
+" only, if specified on non-Zaptel interface, it will be ignored).\n"
+" When the destination answers (presumably an operator services\n"
+" station), the originator no longer has control of their line.\n"
+" They may hang up, but the switch will not release their line\n"
+" until the destination party hangs up (the operator). Specified\n"
+" without an arg, or with 1 as an arg, the originator hanging up\n"
+" will cause the phone to ring back immediately. With a 2 specified,\n"
+" when the \"operator\" flashes the trunk, it will ring their phone\n"
+" back.\n"
+" p - This option enables screening mode. This is basically Privacy mode\n"
+" without memory.\n"
+" P([x]) - Enable privacy mode. Use 'x' as the family/key in the database if\n"
+" it is provided. The current extension is used if a database\n"
+" family/key is not specified.\n"
+" r - Indicate ringing to the calling party. Pass no audio to the calling\n"
+" party until the called channel has answered.\n"
+" S(x) - Hang up the call after 'x' seconds *after* the called party has\n"
+" answered the call.\n"
+" t - Allow the called party to transfer the calling party by sending the\n"
+" DTMF sequence defined in features.conf.\n"
+" T - Allow the calling party to transfer the called party by sending the\n"
+" DTMF sequence defined in features.conf.\n"
+" U(x[^arg]) - Execute via Gosub the routine 'x' for the *called* channel before connecting\n"
+" to the calling channel. Arguments can be specified to the Gosub\n"
+" using '^' as a delimeter. The Gosub routine can set the variable\n"
+" GOSUB_RESULT to specify the following actions after the Gosub returns.\n"
+" * ABORT Hangup both legs of the call.\n"
+" * CONGESTION Behave as if line congestion was encountered.\n"
+" * BUSY Behave as if a busy signal was encountered.\n"
+" * CONTINUE Hangup the called party and allow the calling party\n"
+" to continue dialplan execution at the next priority.\n"
+" * GOTO:<context>^<exten>^<priority> - Transfer the call to the\n"
+" specified priority. Optionally, an extension, or\n"
+" extension and priority can be specified.\n"
+" You cannot use any additional action post answer options in conjunction\n"
+" with this option. Also, pbx services are not run on the peer (called) channel,\n"
+" so you will not be able to set timeouts via the TIMEOUT() function in this routine.\n"
+" w - Allow the called party to enable recording of the call by sending\n"
+" the DTMF sequence defined for one-touch recording in features.conf.\n"
+" W - Allow the calling party to enable recording of the call by sending\n"
+" the DTMF sequence defined for one-touch recording in features.conf.\n"
+" x - Allow the called party to enable recording of the call by sending\n"
+" the DTMF sequence defined for one-touch automixmonitor in features.conf\n"
+" X - Allow the calling party to enable recording of the call by sending\n"
+" the DTMF sequence defined for one-touch automixmonitor in features.conf\n";
+
+/* RetryDial App by Anthony Minessale II <anthmct@yahoo.com> Jan/2005 */
+static char *rapp = "RetryDial";
+static char *rsynopsis = "Place a call, retrying on failure allowing optional exit extension.";
+static char *rdescrip =
+" RetryDial(announce,sleep,retries,dialargs): This application will attempt to\n"
+"place a call using the normal Dial application. If no channel can be reached,\n"
+"the 'announce' file will be played. Then, it will wait 'sleep' number of\n"
+"seconds before retying the call. After 'retires' number of attempts, the\n"
+"calling channel will continue at the next priority in the dialplan. If the\n"
+"'retries' setting is set to 0, this application will retry endlessly.\n"
+" While waiting to retry a call, a 1 digit extension may be dialed. If that\n"
+"extension exists in either the context defined in ${EXITCONTEXT} or the current\n"
+"one, The call will jump to that extension immediately.\n"
+" The 'dialargs' are specified in the same format that arguments are provided\n"
+"to the Dial application.\n";
+
+enum {
+ OPT_ANNOUNCE = (1 << 0),
+ OPT_RESETCDR = (1 << 1),
+ OPT_DTMF_EXIT = (1 << 2),
+ OPT_SENDDTMF = (1 << 3),
+ OPT_FORCECLID = (1 << 4),
+ OPT_GO_ON = (1 << 5),
+ OPT_CALLEE_HANGUP = (1 << 6),
+ OPT_CALLER_HANGUP = (1 << 7),
+ OPT_DURATION_LIMIT = (1 << 9),
+ OPT_MUSICBACK = (1 << 10),
+ OPT_CALLEE_MACRO = (1 << 11),
+ OPT_SCREEN_NOINTRO = (1 << 12),
+ OPT_SCREEN_NOCLID = (1 << 13),
+ OPT_ORIGINAL_CLID = (1 << 14),
+ OPT_SCREENING = (1 << 15),
+ OPT_PRIVACY = (1 << 16),
+ OPT_RINGBACK = (1 << 17),
+ OPT_DURATION_STOP = (1 << 18),
+ OPT_CALLEE_TRANSFER = (1 << 19),
+ OPT_CALLER_TRANSFER = (1 << 20),
+ OPT_CALLEE_MONITOR = (1 << 21),
+ OPT_CALLER_MONITOR = (1 << 22),
+ OPT_GOTO = (1 << 23),
+ OPT_OPERMODE = (1 << 24),
+ OPT_CALLEE_PARK = (1 << 25),
+ OPT_CALLER_PARK = (1 << 26),
+ OPT_IGNORE_FORWARDING = (1 << 27),
+ OPT_CALLEE_GOSUB = (1 << 28),
+ OPT_CALLEE_MIXMONITOR = (1 << 29),
+ OPT_CALLER_MIXMONITOR = (1 << 30),
+};
+
+#define DIAL_STILLGOING (1 << 31)
+#define DIAL_NOFORWARDHTML ((uint64_t)1 << 32) /* flags are now 64 bits, so keep it up! */
+#define OPT_CANCEL_ELSEWHERE ((uint64_t)1 << 33)
+#define OPT_PEER_H ((uint64_t)1 << 34)
+
+enum {
+ OPT_ARG_ANNOUNCE = 0,
+ OPT_ARG_SENDDTMF,
+ OPT_ARG_GOTO,
+ OPT_ARG_DURATION_LIMIT,
+ OPT_ARG_MUSICBACK,
+ OPT_ARG_CALLEE_MACRO,
+ OPT_ARG_CALLEE_GOSUB,
+ OPT_ARG_PRIVACY,
+ OPT_ARG_DURATION_STOP,
+ OPT_ARG_OPERMODE,
+ /* note: this entry _MUST_ be the last one in the enum */
+ OPT_ARG_ARRAY_SIZE,
+};
+
+AST_APP_OPTIONS(dial_exec_options, BEGIN_OPTIONS
+ AST_APP_OPTION_ARG('A', OPT_ANNOUNCE, OPT_ARG_ANNOUNCE),
+ AST_APP_OPTION('C', OPT_RESETCDR),
+ AST_APP_OPTION('c', OPT_CANCEL_ELSEWHERE),
+ AST_APP_OPTION('d', OPT_DTMF_EXIT),
+ AST_APP_OPTION_ARG('D', OPT_SENDDTMF, OPT_ARG_SENDDTMF),
+ AST_APP_OPTION('e', OPT_PEER_H),
+ AST_APP_OPTION('f', OPT_FORCECLID),
+ AST_APP_OPTION('g', OPT_GO_ON),
+ AST_APP_OPTION_ARG('G', OPT_GOTO, OPT_ARG_GOTO),
+ AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
+ AST_APP_OPTION('H', OPT_CALLER_HANGUP),
+ AST_APP_OPTION('i', OPT_IGNORE_FORWARDING),
+ AST_APP_OPTION('k', OPT_CALLEE_PARK),
+ AST_APP_OPTION('K', OPT_CALLER_PARK),
+ AST_APP_OPTION('k', OPT_CALLEE_PARK),
+ AST_APP_OPTION('K', OPT_CALLER_PARK),
+ AST_APP_OPTION_ARG('L', OPT_DURATION_LIMIT, OPT_ARG_DURATION_LIMIT),
+ AST_APP_OPTION_ARG('m', OPT_MUSICBACK, OPT_ARG_MUSICBACK),
+ AST_APP_OPTION_ARG('M', OPT_CALLEE_MACRO, OPT_ARG_CALLEE_MACRO),
+ AST_APP_OPTION('n', OPT_SCREEN_NOINTRO),
+ AST_APP_OPTION('N', OPT_SCREEN_NOCLID),
+ AST_APP_OPTION('o', OPT_ORIGINAL_CLID),
+ AST_APP_OPTION_ARG('O', OPT_OPERMODE, OPT_ARG_OPERMODE),
+ AST_APP_OPTION('p', OPT_SCREENING),
+ AST_APP_OPTION_ARG('P', OPT_PRIVACY, OPT_ARG_PRIVACY),
+ AST_APP_OPTION('r', OPT_RINGBACK),
+ AST_APP_OPTION_ARG('S', OPT_DURATION_STOP, OPT_ARG_DURATION_STOP),
+ AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
+ AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
+ AST_APP_OPTION_ARG('U', OPT_CALLEE_GOSUB, OPT_ARG_CALLEE_GOSUB),
+ AST_APP_OPTION('w', OPT_CALLEE_MONITOR),
+ AST_APP_OPTION('W', OPT_CALLER_MONITOR),
+ AST_APP_OPTION('x', OPT_CALLEE_MIXMONITOR),
+ AST_APP_OPTION('X', OPT_CALLER_MIXMONITOR),
+END_OPTIONS );
+
+#define CAN_EARLY_BRIDGE(flags) (!ast_test_flag64(flags, OPT_CALLEE_HANGUP | \
+ OPT_CALLER_HANGUP | OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER | \
+ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR | OPT_CALLEE_PARK | OPT_CALLER_PARK))
+
+/*
+ * The list of active channels
+ */
+struct chanlist {
+ struct chanlist *next;
+ struct ast_channel *chan;
+ uint64_t flags;
+};
+
+
+static void hanguptree(struct chanlist *outgoing, struct ast_channel *exception, int answered_elsewhere)
+{
+ /* Hang up a tree of stuff */
+ struct chanlist *oo;
+ while (outgoing) {
+ /* Hangup any existing lines we have open */
+ if (outgoing->chan && (outgoing->chan != exception)) {
+ if (answered_elsewhere)
+ ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
+ ast_hangup(outgoing->chan);
+ }
+ oo = outgoing;
+ outgoing = outgoing->next;
+ ast_free(oo);
+ }
+}
+
+#define AST_MAX_WATCHERS 256
+
+/*
+ * argument to handle_cause() and other functions.
+ */
+struct cause_args {
+ struct ast_channel *chan;
+ int busy;
+ int congestion;
+ int nochan;
+};
+
+static void handle_cause(int cause, struct cause_args *num)
+{
+ struct ast_cdr *cdr = num->chan->cdr;
+
+ switch(cause) {
+ case AST_CAUSE_BUSY:
+ if (cdr)
+ ast_cdr_busy(cdr);
+ num->busy++;
+ break;
+
+ case AST_CAUSE_CONGESTION:
+ if (cdr)
+ ast_cdr_failed(cdr);
+ num->congestion++;
+ break;
+
+ case AST_CAUSE_UNREGISTERED:
+ if (cdr)
+ ast_cdr_failed(cdr);
+ num->nochan++;
+ break;
+
+ case AST_CAUSE_NORMAL_CLEARING:
+ break;
+
+ default:
+ num->nochan++;
+ break;
+ }
+}
+
+/* free the buffer if allocated, and set the pointer to the second arg */
+#define S_REPLACE(s, new_val) \
+ do { \
+ if (s) \
+ ast_free(s); \
+ s = (new_val); \
+ } while (0)
+
+static int onedigit_goto(struct ast_channel *chan, const char *context, char exten, int pri)
+{
+ char rexten[2] = { exten, '\0' };
+
+ if (context) {
+ if (!ast_goto_if_exists(chan, context, rexten, pri))
+ return 1;
+ } else {
+ if (!ast_goto_if_exists(chan, chan->context, rexten, pri))
+ return 1;
+ else if (!ast_strlen_zero(chan->macrocontext)) {
+ if (!ast_goto_if_exists(chan, chan->macrocontext, rexten, pri))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static const char *get_cid_name(char *name, int namelen, struct ast_channel *chan)
+{
+ const char *context = S_OR(chan->macrocontext, chan->context);
+ const char *exten = S_OR(chan->macroexten, chan->exten);
+
+ return ast_get_hint(NULL, 0, name, namelen, chan, context, exten) ? name : "";
+}
+
+static void senddialevent(struct ast_channel *src, struct ast_channel *dst, const char *dialstring)
+{
+ manager_event(EVENT_FLAG_CALL, "Dial",
+ "SubEvent: Begin\r\n"
+ "Channel: %s\r\n"
+ "Destination: %s\r\n"
+ "CallerIDNum: %s\r\n"
+ "CallerIDName: %s\r\n"
+ "UniqueID: %s\r\n"
+ "DestUniqueID: %s\r\n"
+ "Dialstring: %s\r\n",
+ src->name, dst->name, S_OR(src->cid.cid_num, "<unknown>"),
+ S_OR(src->cid.cid_name, "<unknown>"), src->uniqueid,
+ dst->uniqueid, dialstring ? dialstring : "");
+}
+
+static void senddialendevent(const struct ast_channel *src, const char *dialstatus)
+{
+ manager_event(EVENT_FLAG_CALL, "Dial",
+ "SubEvent: End\r\n"
+ "Channel: %s\r\n"
+ "UniqueID: %s\r\n"
+ "DialStatus: %s\r\n",
+ src->name, src->uniqueid, dialstatus);
+}
+
+/*!
+ * helper function for wait_for_answer()
+ *
+ * XXX this code is highly suspicious, as it essentially overwrites
+ * the outgoing channel without properly deleting it.
+ */
+static void do_forward(struct chanlist *o,
+ struct cause_args *num, struct ast_flags64 *peerflags, int single)
+{
+ char tmpchan[256];
+ struct ast_channel *original = o->chan;
+ struct ast_channel *c = o->chan; /* the winner */
+ struct ast_channel *in = num->chan; /* the input channel */
+ char *stuff;
+ char *tech;
+ int cause;
+
+ ast_copy_string(tmpchan, c->call_forward, sizeof(tmpchan));
+ if ((stuff = strchr(tmpchan, '/'))) {
+ *stuff++ = '\0';
+ tech = tmpchan;
+ } else {
+ const char *forward_context = pbx_builtin_getvar_helper(c, "FORWARD_CONTEXT");
+ snprintf(tmpchan, sizeof(tmpchan), "%s@%s", c->call_forward, forward_context ? forward_context : c->context);
+ stuff = tmpchan;
+ tech = "Local";
+ }
+ /* Before processing channel, go ahead and check for forwarding */
+ ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, c->name);
+ /* If we have been told to ignore forwards, just set this channel to null and continue processing extensions normally */
+ if (ast_test_flag64(peerflags, OPT_IGNORE_FORWARDING)) {
+ ast_verb(3, "Forwarding %s to '%s/%s' prevented.\n", in->name, tech, stuff);
+ c = o->chan = NULL;
+ cause = AST_CAUSE_BUSY;
+ } else {
+ /* Setup parameters */
+ c = o->chan = ast_request(tech, in->nativeformats, stuff, &cause);
+ if (c) {
+ if (single)
+ ast_channel_make_compatible(o->chan, in);
+ ast_channel_inherit_variables(in, o->chan);
+ ast_channel_datastore_inherit(in, o->chan);
+ } else
+ ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s' (cause = %d)\n", tech, stuff, cause);
+ }
+ if (!c) {
+ ast_clear_flag64(o, DIAL_STILLGOING);
+ handle_cause(cause, num);
+ } else {
+ char *new_cid_num, *new_cid_name;
+ struct ast_channel *src;
+
+ ast_rtp_make_compatible(c, in, single);
+ if (ast_test_flag64(o, OPT_FORCECLID)) {
+ new_cid_num = ast_strdup(S_OR(in->macroexten, in->exten));
+ new_cid_name = NULL; /* XXX no name ? */
+ src = c; /* XXX possible bug in previous code, which used 'winner' ? it may have changed */
+ } else {
+ new_cid_num = ast_strdup(in->cid.cid_num);
+ new_cid_name = ast_strdup(in->cid.cid_name);
+ src = in;
+ }
+ ast_string_field_set(c, accountcode, src->accountcode);
+ c->cdrflags = src->cdrflags;
+ S_REPLACE(c->cid.cid_num, new_cid_num);
+ S_REPLACE(c->cid.cid_name, new_cid_name);
+
+ if (in->cid.cid_ani) { /* XXX or maybe unconditional ? */
+ S_REPLACE(c->cid.cid_ani, ast_strdup(in->cid.cid_ani));
+ }
+ S_REPLACE(c->cid.cid_rdnis, ast_strdup(S_OR(in->macroexten, in->exten)));
+ if (ast_call(c, tmpchan, 0)) {
+ ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
+ ast_clear_flag64(o, DIAL_STILLGOING);
+ ast_hangup(original);
+ c = o->chan = NULL;
+ num->nochan++;
+ } else {
+ senddialevent(in, c, stuff);
+ /* After calling, set callerid to extension */
+ if (!ast_test_flag64(peerflags, OPT_ORIGINAL_CLID)) {
+ char cidname[AST_MAX_EXTENSION] = "";
+ ast_set_callerid(c, S_OR(in->macroexten, in->exten), get_cid_name(cidname, sizeof(cidname), in), NULL);
+ }
+ /* Hangup the original channel now, in case we needed it */
+ ast_hangup(original);
+ }
+ }
+}
+
+/* argument used for some functions. */
+struct privacy_args {
+ int sentringing;
+ int privdb_val;
+ char privcid[256];
+ char privintro[1024];
+ char status[256];
+};
+
+static struct ast_channel *wait_for_answer(struct ast_channel *in,
+ struct chanlist *outgoing, int *to, struct ast_flags64 *peerflags,
+ struct privacy_args *pa,
+ const struct cause_args *num_in, int *result)
+{
+ struct cause_args num = *num_in;
+ int prestart = num.busy + num.congestion + num.nochan;
+ int orig = *to;
+ struct ast_channel *peer = NULL;
+ /* single is set if only one destination is enabled */
+ int single = outgoing && !outgoing->next && !ast_test_flag64(outgoing, OPT_MUSICBACK | OPT_RINGBACK);
+#ifdef HAVE_EPOLL
+ struct chanlist *epollo;
+#endif
+
+ if (single) {
+ /* Turn off hold music, etc */
+ ast_deactivate_generator(in);
+ /* If we are calling a single channel, make them compatible for in-band tone purpose */
+ ast_channel_make_compatible(outgoing->chan, in);
+ }
+
+#ifdef HAVE_EPOLL
+ for (epollo = outgoing; epollo; epollo = epollo->next)
+ ast_poll_channel_add(in, epollo->chan);
+#endif
+
+ while (*to && !peer) {
+ struct chanlist *o;
+ int pos = 0; /* how many channels do we handle */
+ int numlines = prestart;
+ struct ast_channel *winner;
+ struct ast_channel *watchers[AST_MAX_WATCHERS];
+
+ watchers[pos++] = in;
+ for (o = outgoing; o; o = o->next) {
+ /* Keep track of important channels */
+ if (ast_test_flag64(o, DIAL_STILLGOING) && o->chan)
+ watchers[pos++] = o->chan;
+ numlines++;
+ }
+ if (pos == 1) { /* only the input channel is available */
+ if (numlines == (num.busy + num.congestion + num.nochan)) {
+ ast_verb(2, "Everyone is busy/congested at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
+ if (num.busy)
+ strcpy(pa->status, "BUSY");
+ else if (num.congestion)
+ strcpy(pa->status, "CONGESTION");
+ else if (num.nochan)
+ strcpy(pa->status, "CHANUNAVAIL");
+ } else {
+ ast_verb(3, "No one is available to answer at this time (%d:%d/%d/%d)\n", numlines, num.busy, num.congestion, num.nochan);
+ }
+ *to = 0;
+ return NULL;
+ }
+ winner = ast_waitfor_n(watchers, pos, to);
+ for (o = outgoing; o; o = o->next) {
+ struct ast_frame *f;
+ struct ast_channel *c = o->chan;
+
+ if (c == NULL)
+ continue;
+ if (ast_test_flag64(o, DIAL_STILLGOING) && c->_state == AST_STATE_UP) {
+ if (!peer) {
+ ast_verb(3, "%s answered %s\n", c->name, in->name);
+ peer = c;
+ ast_copy_flags64(peerflags, o,
+ OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
+ OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
+ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+ OPT_CALLEE_PARK | OPT_CALLER_PARK |
+ OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
+ DIAL_NOFORWARDHTML);
+ ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext));
+ ast_copy_string(c->exten, "", sizeof(c->exten));
+ }
+ continue;
+ }
+ if (c != winner)
+ continue;
+ /* here, o->chan == c == winner */
+ if (!ast_strlen_zero(c->call_forward)) {
+ do_forward(o, &num, peerflags, single);
+ continue;
+ }
+ f = ast_read(winner);
+ if (!f) {
+ in->hangupcause = c->hangupcause;
+#ifdef HAVE_EPOLL
+ ast_poll_channel_del(in, c);
+#endif
+ ast_hangup(c);
+ c = o->chan = NULL;
+ ast_clear_flag64(o, DIAL_STILLGOING);
+ handle_cause(in->hangupcause, &num);
+ continue;
+ }
+ if (f->frametype == AST_FRAME_CONTROL) {
+ switch(f->subclass) {
+ case AST_CONTROL_ANSWER:
+ /* This is our guy if someone answered. */
+ if (!peer) {
+ ast_verb(3, "%s answered %s\n", c->name, in->name);
+ peer = c;
+ ast_copy_flags64(peerflags, o,
+ OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
+ OPT_CALLEE_HANGUP | OPT_CALLER_HANGUP |
+ OPT_CALLEE_MONITOR | OPT_CALLER_MONITOR |
+ OPT_CALLEE_PARK | OPT_CALLER_PARK |
+ OPT_CALLEE_MIXMONITOR | OPT_CALLER_MIXMONITOR |
+ DIAL_NOFORWARDHTML);
+ ast_copy_string(c->dialcontext, "", sizeof(c->dialcontext));
+ ast_copy_string(c->exten, "", sizeof(c->exten));
+ if (CAN_EARLY_BRIDGE(peerflags))
+ /* Setup early bridge if appropriate */
+ ast_channel_early_bridge(in, peer);
+ }
+ /* If call has been answered, then the eventual hangup is likely to be normal hangup */
+ in->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+ c->hangupcause = AST_CAUSE_NORMAL_CLEARING;
+ break;
+ case AST_CONTROL_BUSY:
+ ast_verb(3, "%s is busy\n", c->name);
+ in->hangupcause = c->hangupcause;
+ ast_hangup(c);
+ c = o->chan = NULL;
+ ast_clear_flag64(o, DIAL_STILLGOING);
+ handle_cause(AST_CAUSE_BUSY, &num);
+ break;
+ case AST_CONTROL_CONGESTION:
+ ast_verb(3, "%s is circuit-busy\n", c->name);
+ in->hangupcause = c->hangupcause;
+ ast_hangup(c);
+ c = o->chan = NULL;
+ ast_clear_flag64(o, DIAL_STILLGOING);
+ handle_cause(AST_CAUSE_CONGESTION, &num);
+ break;
+ case AST_CONTROL_RINGING:
+ ast_verb(3, "%s is ringing\n", c->name);
+ /* Setup early media if appropriate */
+ if (single && CAN_EARLY_BRIDGE(peerflags))
+ ast_channel_early_bridge(in, c);
+ if (!(pa->sentringing) && !ast_test_flag64(outgoing, OPT_MUSICBACK)) {
+ ast_indicate(in, AST_CONTROL_RINGING);
+ pa->sentringing++;
+ }
+ break;
+ case AST_CONTROL_PROGRESS:
+ ast_verb(3, "%s is making progress passing it to %s\n", c->name, in->name);
+ /* Setup early media if appropriate */
+ if (single && CAN_EARLY_BRIDGE(peerflags))
+ ast_channel_early_bridge(in, c);
+ if (!ast_test_flag64(outgoing, OPT_RINGBACK))
+ ast_indicate(in, AST_CONTROL_PROGRESS);
+ break;
+ case AST_CONTROL_VIDUPDATE:
+ ast_verb(3, "%s requested a video update, passing it to %s\n", c->name, in->name);
+ ast_indicate(in, AST_CONTROL_VIDUPDATE);
+ break;
+ case AST_CONTROL_PROCEEDING:
+ ast_verb(3, "%s is proceeding passing it to %s\n", c->name, in->name);
+ if (single && CAN_EARLY_BRIDGE(peerflags))
+ ast_channel_early_bridge(in, c);
+ if (!ast_test_flag64(outgoing, OPT_RINGBACK))
+ ast_indicate(in, AST_CONTROL_PROCEEDING);
+ break;
+ case AST_CONTROL_HOLD:
+ ast_verb(3, "Call on %s placed on hold\n", c->name);
+ ast_indicate(in, AST_CONTROL_HOLD);
+ break;
+ case AST_CONTROL_UNHOLD:
+ ast_verb(3, "Call on %s left from hold\n", c->name);
+ ast_indicate(in, AST_CONTROL_UNHOLD);
+ break;
+ case AST_CONTROL_OFFHOOK:
+ case AST_CONTROL_FLASH:
+ /* Ignore going off hook and flash */
+ break;
+ case -1:
+ if (!ast_test_flag64(outgoing, OPT_RINGBACK | OPT_MUSICBACK)) {
+ ast_verb(3, "%s stopped sounds\n", c->name);
+ ast_indicate(in, -1);
+ pa->sentringing = 0;
+ }
+ break;
+ default:
+ ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
+ }
+ } else if (single) {
+ /* XXX are we sure the logic is correct ? or we should just switch on f->frametype ? */
+ if (f->frametype == AST_FRAME_VOICE && !ast_test_flag64(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
+ if (ast_write(in, f))
+ ast_log(LOG_WARNING, "Unable to forward voice frame\n");
+ } else if (f->frametype == AST_FRAME_IMAGE && !ast_test_flag64(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
+ if (ast_write(in, f))
+ ast_log(LOG_WARNING, "Unable to forward image\n");
+ } else if (f->frametype == AST_FRAME_TEXT && !ast_test_flag64(outgoing, OPT_RINGBACK|OPT_MUSICBACK)) {
+ if (ast_write(in, f))
+ ast_log(LOG_WARNING, "Unable to send text\n");
+ } else if (f->frametype == AST_FRAME_HTML && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML)) {
+ if (ast_channel_sendhtml(in, f->subclass, f->data, f->datalen) == -1)
+ ast_log(LOG_WARNING, "Unable to send URL\n");
+ }
+ }
+ ast_frfree(f);
+ } /* end for */
+ if (winner == in) {
+ struct ast_frame *f = ast_read(in);
+#if 0
+ if (f && (f->frametype != AST_FRAME_VOICE))
+ printf("Frame type: %d, %d\n", f->frametype, f->subclass);
+ else if (!f || (f->frametype != AST_FRAME_VOICE))
+ printf("Hangup received on %s\n", in->name);
+#endif
+ if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
+ /* Got hung up */
+ *to = -1;
+ strcpy(pa->status, "CANCEL");
+ ast_cdr_noanswer(in->cdr);
+ if (f)
+ ast_frfree(f);
+ return NULL;
+ }
+
+ /* now f is guaranteed non-NULL */
+ if (f->frametype == AST_FRAME_DTMF) {
+ if (ast_test_flag64(peerflags, OPT_DTMF_EXIT)) {
+ const char *context = pbx_builtin_getvar_helper(in, "EXITCONTEXT");
+ if (onedigit_goto(in, context, (char) f->subclass, 1)) {
+ ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
+ *to = 0;
+ ast_cdr_noanswer(in->cdr);
+ *result = f->subclass;
+ strcpy(pa->status, "CANCEL");
+ ast_frfree(f);
+ return NULL;
+ }
+ }
+
+ if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP) &&
+ (f->subclass == '*')) { /* hmm it it not guaranteed to be '*' anymore. */
+ ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
+ *to = 0;
+ strcpy(pa->status, "CANCEL");
+ ast_cdr_noanswer(in->cdr);
+ ast_frfree(f);
+ return NULL;
+ }
+ }
+
+ /* Forward HTML stuff */
+ if (single && (f->frametype == AST_FRAME_HTML) && !ast_test_flag64(outgoing, DIAL_NOFORWARDHTML))
+ if (ast_channel_sendhtml(outgoing->chan, f->subclass, f->data, f->datalen) == -1)
+ ast_log(LOG_WARNING, "Unable to send URL\n");
+
+
+ if (single && ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_DTMF_BEGIN) || (f->frametype == AST_FRAME_DTMF_END))) {
+ if (ast_write(outgoing->chan, f))
+ ast_log(LOG_WARNING, "Unable to forward voice or dtmf\n");
+ }
+ if (single && (f->frametype == AST_FRAME_CONTROL) &&
+ ((f->subclass == AST_CONTROL_HOLD) ||
+ (f->subclass == AST_CONTROL_UNHOLD) ||
+ (f->subclass == AST_CONTROL_VIDUPDATE))) {
+ ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
+ ast_indicate_data(outgoing->chan, f->subclass, f->data, f->datalen);
+ }
+ ast_frfree(f);
+ }
+ if (!*to)
+ ast_verb(3, "Nobody picked up in %d ms\n", orig);
+ if (!*to || ast_check_hangup(in)) {
+ ast_cdr_noanswer(in->cdr);
+ }
+
+ }
+ if (peer && !ast_cdr_log_unanswered()) {
+ /* suppress the CDR's that didn't win */
+ struct chanlist *o;
+ for (o = outgoing; o; o = o->next) {
+ struct ast_channel *c = o->chan;
+ if (c && c != peer && c->cdr) {
+ ast_set_flag(c->cdr, AST_CDR_FLAG_POST_DISABLED);
+ }
+ }
+ } else if (!peer && !ast_cdr_log_unanswered()) {
+ /* suppress the CDR's that didn't win */
+ struct chanlist *o;
+ for (o = outgoing; o; o = o->next) {
+ struct ast_channel *c = o->chan;
+ if (c && c->cdr) {
+ ast_set_flag(c->cdr, AST_CDR_FLAG_POST_DISABLED);
+ }
+ }
+ }
+
+#ifdef HAVE_EPOLL
+ for (epollo = outgoing; epollo; epollo = epollo->next) {
+ if (epollo->chan)
+ ast_poll_channel_del(in, epollo->chan);
+ }
+#endif
+
+ return peer;
+}
+
+static void replace_macro_delimiter(char *s)
+{
+ for (; *s; s++)
+ if (*s == '^')
+ *s = ',';
+}
+
+
+/* returns true if there is a valid privacy reply */
+static int valid_priv_reply(struct ast_flags64 *opts, int res)
+{
+ if (res < '1')
+ return 0;
+ if (ast_test_flag64(opts, OPT_PRIVACY) && res <= '5')
+ return 1;
+ if (ast_test_flag64(opts, OPT_SCREENING) && res <= '4')
+ return 1;
+ return 0;
+}
+
+static int do_timelimit(struct ast_channel *chan, struct ast_bridge_config *config,
+ char *parse, unsigned int *calldurationlimit)
+{
+ char *stringp = ast_strdupa(parse);
+ char *limit_str, *warning_str, *warnfreq_str;
+ const char *var;
+ int play_to_caller = 0, play_to_callee = 0;
+ int delta;
+
+ limit_str = strsep(&stringp, ":");
+ warning_str = strsep(&stringp, ":");
+ warnfreq_str = strsep(&stringp, ":");
+
+ config->timelimit = atol(limit_str);
+ if (warning_str)
+ config->play_warning = atol(warning_str);
+ if (warnfreq_str)
+ config->warning_freq = atol(warnfreq_str);
+
+ if (!config->timelimit) {
+ ast_log(LOG_WARNING, "Dial does not accept L(%s), hanging up.\n", limit_str);
+ config->timelimit = config->play_warning = config->warning_freq = 0;
+ config->warning_sound = NULL;
+ return -1; /* error */
+ } else if ( (delta = config->play_warning - config->timelimit) > 0) {
+ int w = config->warning_freq;
+
+ /* If the first warning is requested _after_ the entire call would end,
+ and no warning frequency is requested, then turn off the warning. If
+ a warning frequency is requested, reduce the 'first warning' time by
+ that frequency until it falls within the call's total time limit.
+ Graphically:
+ timelim->| delta |<-playwarning
+ 0__________________|_________________|
+ | w | | | |
+
+ so the number of intervals to cut is 1+(delta-1)/w
+ */
+
+ if (w == 0) {
+ config->play_warning = 0;
+ } else {
+ config->play_warning -= w * ( 1 + (delta-1)/w );
+ if (config->play_warning < 1)
+ config->play_warning = config->warning_freq = 0;
+ }
+ }
+
+ var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLER");
+ play_to_caller = var ? ast_true(var) : 1;
+
+ var = pbx_builtin_getvar_helper(chan, "LIMIT_PLAYAUDIO_CALLEE");
+ play_to_callee = var ? ast_true(var) : 0;
+
+ if (!play_to_caller && !play_to_callee)
+ play_to_caller = 1;
+
+ var = pbx_builtin_getvar_helper(chan, "LIMIT_WARNING_FILE");
+ config->warning_sound = S_OR(var, "timeleft");
+
+ /* The code looking at config wants a NULL, not just "", to decide
+ * that the message should not be played, so we replace "" with NULL.
+ * Note, pbx_builtin_getvar_helper _can_ return NULL if the variable is
+ * not found.
+ */
+ var = pbx_builtin_getvar_helper(chan, "LIMIT_TIMEOUT_FILE");
+ config->end_sound = S_OR(var, NULL);
+ var = pbx_builtin_getvar_helper(chan, "LIMIT_CONNECT_FILE");
+ config->start_sound = S_OR(var, NULL);
+
+ /* undo effect of S(x) in case they are both used */
+ *calldurationlimit = 0;
+ /* more efficient to do it like S(x) does since no advanced opts */
+ if (!config->play_warning && !config->start_sound && !config->end_sound && config->timelimit) {
+ *calldurationlimit = config->timelimit / 1000;
+ ast_verb(3, "Setting call duration limit to %d seconds.\n",
+ *calldurationlimit);
+ config->timelimit = play_to_caller = play_to_callee =
+ config->play_warning = config->warning_freq = 0;
+ } else {
+ ast_verb(3, "Limit Data for this call:\n");
+ ast_verb(4, "timelimit = %ld\n", config->timelimit);
+ ast_verb(4, "play_warning = %ld\n", config->play_warning);
+ ast_verb(4, "play_to_caller = %s\n", play_to_caller ? "yes" : "no");
+ ast_verb(4, "play_to_callee = %s\n", play_to_callee ? "yes" : "no");
+ ast_verb(4, "warning_freq = %ld\n", config->warning_freq);
+ ast_verb(4, "start_sound = %s\n", S_OR(config->start_sound, ""));
+ ast_verb(4, "warning_sound = %s\n", config->warning_sound);
+ ast_verb(4, "end_sound = %s\n", S_OR(config->end_sound, ""));
+ }
+ if (play_to_caller)
+ ast_set_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
+ if (play_to_callee)
+ ast_set_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
+ return 0;
+}
+
+static int do_privacy(struct ast_channel *chan, struct ast_channel *peer,
+ struct ast_flags64 *opts, char **opt_args, struct privacy_args *pa)
+{
+
+ int res2;
+ int loopcount = 0;
+
+ /* Get the user's intro, store it in priv-callerintros/$CID,
+ unless it is already there-- this should be done before the
+ call is actually dialed */
+
+ /* all ring indications and moh for the caller has been halted as soon as the
+ target extension was picked up. We are going to have to kill some
+ time and make the caller believe the peer hasn't picked up yet */
+
+ if (ast_test_flag64(opts, OPT_MUSICBACK) && !ast_strlen_zero(opt_args[OPT_ARG_MUSICBACK])) {
+ char *original_moh = ast_strdupa(chan->musicclass);
+ ast_indicate(chan, -1);
+ ast_string_field_set(chan, musicclass, opt_args[OPT_ARG_MUSICBACK]);
+ ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
+ ast_string_field_set(chan, musicclass, original_moh);
+ } else if (ast_test_flag64(opts, OPT_RINGBACK)) {