Compare commits

..

468 Commits

Author SHA1 Message Date
Kevin P. Fleming
6fa9cd9521 Convert all release tags to Opsound music-on-hold.
For more details:
http://blogs.digium.com/2009/08/18/asterisk-music-on-hold-changes/



git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/1.0.12@212958 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2009-08-18 20:42:51 +00:00
Kevin P. Fleming
c6363dc1d7 importing files for 1.0.12 release
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/1.0.12@45429 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-10-17 23:31:12 +00:00
Kevin P. Fleming
0bd9a22495 Creating tag for the release of asterisk-1.0.12
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/1.0.12@45428 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-10-17 23:28:46 +00:00
Kevin P. Fleming
63046de1cb properly handle signed integer input
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@45336 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-10-17 17:57:36 +00:00
Kevin P. Fleming
e132aba5c9 correct yesterday's security fix so that it doesn't improperly reject valid video frames
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@32565 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-06 15:38:44 +00:00
Russell Bryant
4196243583 backport the chan_iax2 security fix from 1.2 and trunk ...
ensure that the received number of bytes is included in all IAX2 incoming 
frame analysis checks (fixes a known vulnerability)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@32428 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-06-05 22:03:16 +00:00
Russell Bryant
9ce061aa3f fix memory leak with DelayedRetry (issue #6157)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@7914 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2006-01-09 22:03:42 +00:00
Russell Bryant
168ed954eb check array bounds when parsing arguments to AGI (issue #5868)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@7558 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-12-20 20:23:20 +00:00
Russell Bryant
0d1660a369 properly reset the 'next' pointer when duplicating the cdr (issue #5921)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@7467 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-12-13 07:40:57 +00:00
Kevin P. Fleming
ebb8253d2f remove extraneous svn:executable properties
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@7221 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-29 18:24:39 +00:00
Kevin P. Fleming
11f81ad761 remove remaining .cvsignore files
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@7220 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-29 18:09:49 +00:00
Kevin P. Fleming
ad8786f355 branch renames
remove unneeded branches


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.0@7199 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-27 16:04:52 +00:00
Russell Bryant
17fd431b31 remove misleading message
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@7179 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-21 17:58:38 +00:00
Russell Bryant
45c9175c77 re-add explicit poll support for Darwin
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@7177 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-21 16:53:51 +00:00
Russell Bryant
8355d829bb re-add the CHANGES file as ChangeLog since that's how it was for all of the
other 1.0 releases


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@7176 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-21 16:37:10 +00:00
Russell Bryant
b14b81d8b4 remove the CHANGES file from v1-0
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@7175 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-21 16:27:55 +00:00
Admin Commit
e875a17b48 This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@7173 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-21 15:09:31 +00:00
Russell Bryant
7f9f2f6543 add a couple missing queue_log entries (issue #5422)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6959 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-04 05:44:06 +00:00
Russell Bryant
b2cfc35315 Remove ancient copy/paste error (issue #5541)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6921 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-01 01:32:58 +00:00
Russell Bryant
31c57904fd Actually write audio to file in get_voice (issue #5547)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6920 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-01 01:28:43 +00:00
Russell Bryant
0ead801f25 prevent possible seg fault (issue #5502)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6919 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-01 00:57:42 +00:00
Russell Bryant
009b812d76 removed unused variable (issue #5455)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6840 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-10-21 17:42:53 +00:00
Russell Bryant
a0d4959fc5 add hello world prompt to 1.0 for Jared
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6810 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-10-17 22:23:52 +00:00
Admin Commit
11c11d27bc This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6809 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-10-17 22:23:52 +00:00
Russell Bryant
6b36952664 correctly fix build issues on Mac OSX Tiger by using a more generic means
for determining wheter poll and dlfcn functionality needs to be provided


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6707 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-10-01 01:58:20 +00:00
Russell Bryant
afdd1c5512 fix 'say phonetic' (issue #5268)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6706 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-10-01 01:37:14 +00:00
Russell Bryant
ac303de4aa fix incorrect CLI tab completion (issue #5041)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6647 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-25 17:26:52 +00:00
Russell Bryant
508b3ba688 Null out call number on release complete when number is unallocated (bug #4633)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6646 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-25 17:24:53 +00:00
Russell Bryant
75b0c4445a Fix cut/paste error (issue #5282)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6637 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-24 21:24:35 +00:00
Russell Bryant
2f5ced421e Fix CLI memory leak (issue #5035)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6636 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-24 21:19:42 +00:00
Russell Bryant
d09714e12b ensure that user events are correctly identified (issue #5200)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6572 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-13 23:40:00 +00:00
Russell Bryant
52171d4c26 fix crash on amd64 (issue #5210)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6570 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-13 23:31:57 +00:00
Russell Bryant
8bd93a96ac don't allow call waiting during the initial ringing (issue #5188)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6569 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-09-13 23:22:18 +00:00
Russell Bryant
5a80b57ccf backport "Fix accidental RTCP/RTP linkage"
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6419 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-26 16:56:07 +00:00
Russell Bryant
b2fb3d501c spell them words cowrecktly (issue #4964)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6418 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-26 16:31:36 +00:00
Russell Bryant
6cf8ee01a6 ensure buffers are large enough for ENUMLookup (issue #4943)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6417 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-26 16:26:37 +00:00
Russell Bryant
153119a7bc make message more gooder (issue #4979)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6416 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-26 16:20:51 +00:00
Russell Bryant
9b8ba163f2 fix format string (issue #4945)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6414 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-26 15:54:25 +00:00
Russell Bryant
bfac0241be fix crash related to saving a changed password (bug #4976)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6392 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-24 15:39:25 +00:00
Kevin P. Fleming
09f5f15a72 ensure buffer is adequately sized for complex frames (issue #4974)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6387 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-23 17:42:54 +00:00
Matthew Fredrickson
84957104b2 Commit backport of fix to DTMF detection during overlap mode
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6348 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-22 16:47:22 +00:00
Russell Bryant
312008513e revert SIGHUP patch to restore original behavior for 1.0 (bug #4854)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6347 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-22 05:47:37 +00:00
Russell Bryant
08630905fa Fix poll error condition causing memory corruption (bug #4915)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6311 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-08 18:58:19 +00:00
Russell Bryant
83ef83a5f8 terminate 'send text' with a newline (bug #4632)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6310 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-08 18:15:32 +00:00
Russell Bryant
2595998b8f copy the monitor over when masquerading (bug #3809)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6287 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-05 00:02:09 +00:00
Russell Bryant
7fe4d52579 prevent mem leak (bug #4842)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6286 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-04 23:45:54 +00:00
Russell Bryant
39d4e1253b fix qop to be RFC compliant (bug #4841)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6285 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-04 23:31:50 +00:00
Russell Bryant
f7eada3cff fix potential crash in close_mailbox (bug #4800)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6284 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-04 23:03:56 +00:00
Russell Bryant
405ff91e92 unmask SIGHUP before exec'ing AGI scripts (bug #4854)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6283 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-04 22:52:15 +00:00
Russell Bryant
ce07ed72c0 add some more aliases from RFC's 3841 and 4028 (bug #4889)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6282 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-04 22:39:23 +00:00
Russell Bryant
150fc177cd fix broken logic (bug #4879)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6281 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-04 20:26:36 +00:00
Mark Spencer
c73ad9e6f9 Fix memory leak
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6276 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-03 20:22:27 +00:00
Russell Bryant
cf638de6ad make sure iaxs gets initialized (bug #4856)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6252 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-08-01 14:48:26 +00:00
Russell Bryant
40ea953811 add note about fix to LEN
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6241 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-28 17:42:43 +00:00
Russell Bryant
8061ba32c3 fix potential seg fault when using LEN() with a string greater than 80 characters (bug #4839)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6240 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-28 17:40:46 +00:00
Russell Bryant
120e4bc237 add note about fix to chan_local
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-26 14:48:05 +00:00
Russell Bryant
4fc7030156 fix masquerading of local channels into the new channel type (bug #4529)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6222 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-26 14:46:28 +00:00
Russell Bryant
34d2254f70 add note about the app_disa change
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6220 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-25 23:45:18 +00:00
Russell Bryant
b47ed67c84 don't set the account code if one wasn't supplied (bug #4751)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6219 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-25 23:41:29 +00:00
Russell Bryant
e6f049f9bf remove some unnecessary checks
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6195 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-25 18:15:25 +00:00
Russell Bryant
7491dba549 this is my cheap hack to fix the build problem on darwin since it now has
poll.h.  If anyone can think of a cleaner way to handle this, suggestions
are welcome


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6122 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-13 18:06:48 +00:00
Russell Bryant
3e7d040f3f *** empty log message ***
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6118 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-13 14:05:48 +00:00
Russell Bryant
c78761cc7c fix typo in app description (bug #4697)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6117 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-13 14:04:28 +00:00
Russell Bryant
6b6eb7977b fix compiler warning (bug #4682)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6109 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-12 15:27:09 +00:00
Russell Bryant
a795d02a30 update the password in memory as well when using externpass (bug #4602)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6094 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-12 01:34:16 +00:00
Russell Bryant
2faf30d730 if the first user hangs up while being prompted for a pin, don't hold the
conference open (bug #4656)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6088 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-11 22:42:45 +00:00
Russell Bryant
c2a39b5c64 change insecure options to support 'port' and/or 'invite' instead of forcing
the 'port' option when using 'invite' (bug #4024)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6087 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-11 22:25:53 +00:00
Russell Bryant
ffc2c34f15 make sure an automatic log rotation doesn't result in nasty recursion (bug #4646)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6045 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-07 17:43:48 +00:00
Russell Bryant
57cb8c168c update for change to zapras
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6044 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-07 15:26:17 +00:00
Russell Bryant
f1274662f4 ensure buffer policy is restored after RAS is done with a channel (bug #4648)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6043 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-07 15:15:59 +00:00
Russell Bryant
9f6e57f90a add man pages for astgenkey, autosupport, and safe_asterisk (bug #4645)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6042 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-06 22:30:44 +00:00
Admin Commit
8ff6d5cabf This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6041 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-06 22:30:44 +00:00
Russell Bryant
298718ebaa fix misplaced shebang (bug #4643)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6040 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-07-06 22:22:21 +00:00
Russell Bryant
171872003b fix busted osp build
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6016 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-30 14:35:46 +00:00
Russell Bryant
5fe5bf08b2 fix callerid matching in extensions.conf
formatting fixes for the ChangeLog


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6014 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-29 21:02:35 +00:00
Russell Bryant
cf238fa10d when switching back to voice mode, wait for 'B' (bug #3833)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6007 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-24 22:27:10 +00:00
Russell Bryant
7e3d58e030 after a *70, re-enable call waiting on hangup (bug #3971)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6006 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-24 22:20:22 +00:00
Russell Bryant
508b530e39 merge endian.h (bug #3867)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6005 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-24 22:12:25 +00:00
Admin Commit
5e168ffd67 This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6004 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-24 22:12:25 +00:00
Russell Bryant
9e05fb4f39 print non-codec capabilities correctly (bug #3960)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@6003 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-24 21:53:02 +00:00
Russell Bryant
a2c28355e0 add note about 2nd gen
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5988 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-23 19:32:10 +00:00
Russell Bryant
0e4c9f9765 update for 1.0.8
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5980 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-23 01:00:32 +00:00
Russell Bryant
4d504015d4 correctly jump to fax extension when inside of a macro (bug #4471)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5967 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-22 14:01:26 +00:00
Russell Bryant
3e2bd82411 tweak for arm4vl (bug #4545)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5955 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-21 14:27:28 +00:00
Russell Bryant
2877470389 fix via comparison to not be case sensitive (bug #4496)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5954 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-21 14:15:55 +00:00
Russell Bryant
4a15544b22 add support for native DTMF
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5917 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-15 21:42:31 +00:00
Russell Bryant
9400e87db0 remove pointless dereference (bug #4353)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5914 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 21:07:48 +00:00
Russell Bryant
200ca9631d remove my debug output, d'oh! :)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5913 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 20:57:38 +00:00
Russell Bryant
4f1e96c0b6 Fix offset calculation for signed linear (bug #4433)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5912 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 20:49:33 +00:00
Russell Bryant
eac2ef9374 fix bounds checking (bug #4406)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5911 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 20:30:47 +00:00
Russell Bryant
dd70231e97 oops!
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5910 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 20:24:38 +00:00
Russell Bryant
02bb0b5e22 don't kill the call if tdd mode is not supported by a channel (bug #4370)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5909 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 19:45:49 +00:00
Russell Bryant
f14775e845 fix return values on systems where an unsigned char is the default (bug #4455)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5908 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 18:41:48 +00:00
Russell Bryant
ee90d54c2e update indications to be current with cvs head (inspired by bug #4440)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5905 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-14 04:21:14 +00:00
Russell Bryant
f4c2a167ed update changelog
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5904 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-13 22:22:34 +00:00
Russell Bryant
0ad6773b76 if no extension is specified on an overlap call, use the 's' extension (bug #4317)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5903 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-13 22:18:44 +00:00
Russell Bryant
320be7fff9 handle stale authentication nonces more properly (bug #4451)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5902 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-13 20:35:15 +00:00
Russell Bryant
0c2abdf74e restructure buggy parse_args routine
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5899 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-10 20:52:27 +00:00
Russell Bryant
0b3cfb26b4 fix SayUnixTime (bug #4423)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5808 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-06-01 20:56:18 +00:00
Russell Bryant
cbc30c9163 fix recording of voicemail duration (bug #4288)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5804 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 13:08:45 +00:00
Russell Bryant
71a395e3e3 fix a sizeof bug (bug #4264)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5803 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 12:58:08 +00:00
Russell Bryant
b2073cb75f correctly handle rtp padding (bug #4270)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5802 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 12:55:43 +00:00
Russell Bryant
df905cf5a2 remove seemingly bogus line (bug #4299)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5801 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 12:51:49 +00:00
Russell Bryant
cf45c660cc fix rtptimeout options for a specific peer (bug #4325)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5800 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 05:30:07 +00:00
Russell Bryant
2995096956 fix a mem leak (bug #4154)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5799 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 04:39:24 +00:00
Russell Bryant
a6e8158ddc add "Referred-by" to the aliases list (bug #4404)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5798 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 04:17:33 +00:00
Russell Bryant
68206d0890 find sound files that are in the language directory itself (bug #4399)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5797 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 03:36:45 +00:00
Russell Bryant
6dbcb94c01 update changelog for the last fix
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5796 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 03:27:59 +00:00
Russell Bryant
91f9740856 fix distinctive ring for queue members (bug #3978)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5795 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 03:22:34 +00:00
Russell Bryant
083cf7af1d fix mem leak (bug #4318)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5794 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 02:57:15 +00:00
Russell Bryant
984142aebe Fix reply digest selection of size (bug #4409)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5793 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 02:47:10 +00:00
Russell Bryant
29f7161c9b set DNID on incoming calls (bug #4220)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5792 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 02:34:28 +00:00
Russell Bryant
6618cec0d7 don't print an error when you receive no data until normal circumstances with recvfrom (bug #4156)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5791 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 02:24:16 +00:00
Russell Bryant
ebe377fc5c fix comment (bug #4139)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5790 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-31 02:20:30 +00:00
Russell Bryant
268eedc2f3 hopefully the last try at making this happy across
various versions of newt (bug #4388)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5781 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-28 01:40:13 +00:00
Russell Bryant
eadb02a84f fix usage of const char (bug #4288)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5771 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-26 12:21:27 +00:00
Russell Bryant
c98832d092 fix output when no help text is available for a cli command
fix a seg fault when astmm is enabled (bug #4356)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5759 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-24 10:29:12 +00:00
Russell Bryant
888c329e65 reset 'confirm' mode so DTMF can be used by Zap callees after confirming (bug #4083)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5730 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-19 03:13:31 +00:00
Russell Bryant
548ce34d97 close sip socket on unload (bug #4152)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5729 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-19 03:04:25 +00:00
Russell Bryant
2e4b4764fb fix some compilation issues for ppc (bug #4228)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5728 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-19 02:59:43 +00:00
Russell Bryant
bf1069b3ae perform variable substitution earlier so it can be used for the cidmatch as well (bug #4094)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5725 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-19 02:51:00 +00:00
Russell Bryant
f717cd2719 fix mem leak with MYSQL_USERS (bug #4287)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5703 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-16 17:54:55 +00:00
Russell Bryant
cda604fabe note default values (bug #4284)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5697 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-16 13:26:19 +00:00
Russell Bryant
6125965ff5 Remove double fout++ and comment on flag (bug #4267)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5695 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-16 03:10:20 +00:00
Russell Bryant
a6cea6892b only initialize random number generators in one place (bug #4017)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5694 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-16 03:04:59 +00:00
Russell Bryant
1031a3c36d document zap options (bug #4166)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5687 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-15 23:28:19 +00:00
Russell Bryant
89d62574ef protect ResponseTimeout and DigitTimeout apps from crashing when called in non-PBX channels (bug #4092)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5685 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-15 23:26:29 +00:00
Russell Bryant
262e9c3003 indicate default timeouts (bug #4050)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5676 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-15 16:42:25 +00:00
Russell Bryant
43e32456ca ensure that calls to gethostbyname are null terminated,
also use MAXHOSTNAMELEN where appropriate (bug #4198) (bug #4212)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5675 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-15 15:55:31 +00:00
Russell Bryant
fcb8ab5da6 allow spaces in monitor filenames (Thanks to gbdrbob for catching this one!)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5648 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-14 18:21:43 +00:00
Russell Bryant
0f5dbaf7ec initialize errno and don't report an error when poll() returns without indicating one (bug #4059)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5635 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-12 02:42:48 +00:00
Russell Bryant
8e267ac60a remove unnecessary declaration (bug #4040)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5634 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-12 02:33:33 +00:00
Russell Bryant
794d0b2c68 use ast_strlen_zero, also fix a codec config parsing error (bug #4169)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5633 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-12 02:22:56 +00:00
Russell Bryant
8c97879e99 oops, I wasn't done with this
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5632 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-12 01:47:39 +00:00
Russell Bryant
47f2779b9d *** empty log message ***
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5631 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-12 01:43:36 +00:00
Russell Bryant
c77e7ed452 add notes about file descriptors (bug #4134)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5625 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-11 03:44:07 +00:00
Russell Bryant
a9fd6fca9e fix ast config path (bug #4184)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5624 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-11 03:26:51 +00:00
Russell Bryant
57b353cebf fix compat with astmm (bug #4217)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5623 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-11 03:16:52 +00:00
Russell Bryant
07c87b82ff only unlock hintlock once (bug #4205)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5622 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-11 03:07:39 +00:00
Russell Bryant
f1c3d761aa add note about the effects of time changes (bug #4020)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5617 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-10 04:09:21 +00:00
Russell Bryant
34f9e85a11 add fixup routine (bug #3825)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5616 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-10 03:58:26 +00:00
Russell Bryant
56cf655835 fix queue URL passing (bug #3543)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5615 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-10 03:28:01 +00:00
Russell Bryant
4d1e5adfdc allow ALERTING even after PROCEEDING (bug #3963)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5614 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-10 01:39:50 +00:00
Russell Bryant
3d263c243a add missing newline to warning message (bug #4183)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5592 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-05-06 07:17:17 +00:00
Russell Bryant
334e508e66 warn about headers, too
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5503 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-26 14:30:23 +00:00
Russell Bryant
28eedd8e44 look in the correct place for sounds (bug #3983)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5478 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-15 09:39:13 +00:00
Russell Bryant
e0aaf08b3b fix unloading problems (bug #4019)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5477 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-15 07:59:59 +00:00
Russell Bryant
e16718bb2e create useful output for time left to expire (bug #4022)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5476 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-15 07:24:34 +00:00
Russell Bryant
1e70fa09cd add some newlines and fix some misspellings (bug #4027)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5475 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-15 07:15:39 +00:00
Russell Bryant
a2f752ec6c fix bogus output from 'show agents' with no name (bug #4030)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5474 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-15 07:06:40 +00:00
Russell Bryant
3ad71d439c add warning if you try to use the _. exten (bug #4032)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5472 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-15 06:44:35 +00:00
Russell Bryant
d667d39367 add missing newline (bug #4018)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5457 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-13 03:45:53 +00:00
Russell Bryant
c96d5eabad add README about incompatibility with 0.63 of FreeTDS (bug #3996)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5449 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-11 03:41:42 +00:00
Admin Commit
941ba1c5be This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5448 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-11 03:41:42 +00:00
Russell Bryant
17045b502f space out initial registrations (bug #3104)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5428 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-06 17:09:03 +00:00
Russell Bryant
916f6b627a correct 'sync' on action_originate (bug #3922)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5426 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-06 16:45:41 +00:00
Russell Bryant
e56c7ba459 correctly set amaflags (bug #3962)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5425 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-06 16:39:45 +00:00
Russell Bryant
34bc1ac241 don't define a functioning returning an int inside of a do{...}while(0) (bug #3865)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5410 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 17:08:05 +00:00
Russell Bryant
4920426fbd I just gave up sleeping to stay up all night working on bugs ...
I hope I didn't break anything!  :)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5408 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 10:45:20 +00:00
Russell Bryant
e5f2fef425 remove unimplemented option (bug #3890)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5407 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 10:26:48 +00:00
Russell Bryant
4faec1b262 fix say number with a leading zero (bug #3884)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5406 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 10:15:00 +00:00
Russell Bryant
efc4fdf079 silly sizeof ... (bug #3887)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5405 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 10:12:24 +00:00
Russell Bryant
8b6aa2741c Clear out received tag in 407/401's (bug #3885)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5404 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 10:08:53 +00:00
Russell Bryant
90fea452ac keep going even if file not found with GET DATA (bug #3878)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5403 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 09:52:05 +00:00
Russell Bryant
8451fd7f7d fix 'highpriority' for asterisk.conf (bug #3860)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5402 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 09:37:02 +00:00
Russell Bryant
ed8a15efce fix timeout with no password (bug #3589)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5401 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 09:31:11 +00:00
Russell Bryant
6bee09440d don't pass audio until the call has been acked if configured to do so (bug #3677)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5400 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 08:32:04 +00:00
Russell Bryant
d54b330a2e handle AST_FORMAT_SLINEAR endianness properly on big-endian systems (bug #3865)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5399 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 07:10:06 +00:00
Russell Bryant
621b5be6cd fix *67 (bug #3940)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5398 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 06:58:02 +00:00
Russell Bryant
687846975e fix rtpchecksums option (bug #3908)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5397 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 06:53:14 +00:00
Russell Bryant
315e0c3054 I guess we'll need the sound file if I want that last patch to actually work ...
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5396 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 06:34:54 +00:00
Russell Bryant
4f4009663c say "minus" for negative numbers (bug #3948)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5395 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 06:31:55 +00:00
Russell Bryant
48f1386fff merge kevin's patches to remove color escape sequences from the logs (bug #3929)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5394 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 06:09:27 +00:00
Russell Bryant
8f0e43be23 FreeBSD compile warning (bug #3938)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5393 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 05:59:30 +00:00
Russell Bryant
4b165caef4 check for result *after* starting the network thread (bug #3952)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5392 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 05:56:44 +00:00
Russell Bryant
4a14b7c071 fix accountcode (bug #3951)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5391 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-05 05:33:13 +00:00
Russell Bryant
e12e134ef9 reflect the correct format of ${DATETIME} in the doc (bug #3857)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5381 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-04 07:28:34 +00:00
Russell Bryant
7b319eb03a update log
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5380 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-04 07:08:36 +00:00
Russell Bryant
98d05f22ac correctly respond to an INVITE with T.38 (bug #3818)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5378 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-04 07:05:55 +00:00
Russell Bryant
7ba20c5024 fix compile warning for FreeBSD (bug #3937)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5377 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-04 06:33:26 +00:00
Russell Bryant
2e6d346313 remove duplicate checking (bug #3927)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5359 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-02 17:41:19 +00:00
Russell Bryant
8aaa9e194e find endian.h on non-linux (bug #3846)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5358 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-02 07:59:45 +00:00
Russell Bryant
60a9627192 *** empty log message ***
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5336 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-01 04:38:40 +00:00
Russell Bryant
28a319be01 process the last line, even if it doesn't have a newline char (bug #3919)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5334 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-01 04:17:42 +00:00
Russell Bryant
f066af663f fix endianness (bug #3839)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5333 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-01 04:09:45 +00:00
Russell Bryant
1e2baaf12e fix wav fomat (bug #3837)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5329 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-01 03:23:33 +00:00
Russell Bryant
f56ba6a441 ignore interrupted system calls (bug #3831)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5328 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-01 03:13:38 +00:00
Russell Bryant
2ea44416b2 add missing line for the autosupport script (bug #3828)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5327 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-04-01 02:49:21 +00:00
Russell Bryant
78f6f43d19 fix chopping off of prompts (bug #3784)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5325 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-31 22:20:15 +00:00
Russell Bryant
42b84afa40 change ',' to '.' (bug #3799)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5288 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-28 06:42:14 +00:00
Russell Bryant
be446083ab don't send a "to" on a "100 Trying", also be case insensitive when parsing the "to" tag (bug #3801)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5287 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-28 06:35:09 +00:00
Russell Bryant
61538bec92 update for reload commands (bug #3697)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5286 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-28 05:54:19 +00:00
Russell Bryant
4402a86f93 fix saying the date in spanish (bug #3642)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5285 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-28 05:40:13 +00:00
Russell Bryant
4ead78e851 look for the fax extension in the main context, as well (bug #3634)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5283 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-28 04:48:25 +00:00
Russell Bryant
d056623e60 Don't use deprecated "2" location for G.726 (rfc3551)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5262 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-25 23:41:13 +00:00
Russell Bryant
a281bef2b3 don't explode if a box running CVS head sends trunk frames with timestamps (bug #3790)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5202 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-18 17:30:05 +00:00
Matthew Fredrickson
4b30e9ee37 Fixed parking bug w/ chan_sip and loss of MOH
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5200 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-17 23:48:42 +00:00
Russell Bryant
2b1a8d34d9 look in /usr/include/speex for speex.h (bug #3761)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5186 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-17 14:43:51 +00:00
Russell Bryant
bc70235479 fix TXTCIDName (bug #3681)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5184 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-17 00:19:23 +00:00
Russell Bryant
857bf5486b update from angler
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5170 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-11 17:15:22 +00:00
Russell Bryant
4d6e2801d1 update config to clarify options for how the work in the stable branch
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5165 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-11 07:50:03 +00:00
Russell Bryant
f4a80f1609 make docs on agent groups a little bit more clear (bug #3652)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5162 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-11 06:37:59 +00:00
Russell Bryant
26d298f693 update for 1.0.7
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5160 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-10 16:43:07 +00:00
Russell Bryant
926270782f add a little note about downgrading from CVS head
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-10 08:15:05 +00:00
Russell Bryant
fd7f18421d add a check to prevent a seg fault from an unknown cause ... (bug #3496)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5122 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-02 22:32:57 +00:00
Russell Bryant
ee53dc7286 prevent crash with some extra checks while doing authentication (bug #3686)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5121 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-02 22:24:02 +00:00
Russell Bryant
d565dc3225 Be sure to process SDP if we already have an owner (bug #3701)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5120 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-02 17:38:27 +00:00
Russell Bryant
fe07794bba add autosupport script for Digium support (bug #3685)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5114 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-01 14:51:24 +00:00
Admin Commit
4aa9d15438 This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5113 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-03-01 14:51:24 +00:00
Russell Bryant
83e1402d8a release RTP ports early on SUBSCRIBE (bug #3655 / #3673)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5101 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-28 00:30:35 +00:00
Russell Bryant
f1c93a8ff3 move the processing of SDP data to after determining the user (bug #3660)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5096 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-27 02:37:23 +00:00
Russell Bryant
a004c5ca9e some more management command description updates (bug #3645)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5095 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-27 02:14:15 +00:00
Russell Bryant
d6efd17100 fix seg fault with combination of 'g' and # transfer (bug #3650)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5094 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-27 01:40:43 +00:00
Russell Bryant
3aeb519068 fix a compiler warning
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5093 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-27 01:31:30 +00:00
Russell Bryant
eb767e674f update IAXy firmware with a registration fix
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5092 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-26 19:18:22 +00:00
Russell Bryant
b4af00a20f attempt a restart on a connection error (bug #3628)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5090 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-26 18:57:14 +00:00
Russell Bryant
39e574a8bd add description for monitor management commands (bug #3610)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5089 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-26 18:23:18 +00:00
Russell Bryant
04c06471e6 keeping the changelog up to date for 1.0.6
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5080 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-25 18:14:19 +00:00
Russell Bryant
687b01f298 move function prototypes outside of functions to compile under gcc4 (bug #3662)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5079 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-25 18:11:41 +00:00
Russell Bryant
8e59e3e38c changelog for 1.0.6, thanks file!
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5072 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-24 21:26:40 +00:00
Russell Bryant
1dec1dfb9c handle server going down (bug #3597)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-21 04:44:26 +00:00
Russell Bryant
292059c9cb handle DNS failures on startup more gracefully (bug #3086)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5061 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-21 03:57:27 +00:00
Russell Bryant
63b6e2a2a1 fix misspelling of separate (bug #3607)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5052 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-19 00:41:21 +00:00
Russell Bryant
9420fee71d fix ${EXTEN:X} where X < 0 (bug #3572)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5051 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-19 00:27:52 +00:00
Russell Bryant
ece9341019 typo (bug #3557)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5030 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-14 22:47:57 +00:00
Russell Bryant
e608ffdaa9 I changed my mind on this - I don't want to needlessly break anything ...
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5028 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-14 03:06:37 +00:00
Russell Bryant
684ffcce61 update doc (bug #3526)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5027 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-14 02:56:15 +00:00
Russell Bryant
a346745899 respect A,B,C,D (bug #3538)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5026 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-14 02:16:33 +00:00
Russell Bryant
5ef097f5d7 minor fix for deadlock detection, but I hope nobody has to use it :) (bug #3531)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@5025 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-13 23:43:58 +00:00
Russell Bryant
d35a82a5b6 preserve original callerid functionality for 1.0 (bug #3490)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4994 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-09 22:53:30 +00:00
Russell Bryant
b2ab9ffaec fix potential seg fault (bug #3519)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4982 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 17:10:25 +00:00
Russell Bryant
2e88a61fa3 don't crash on undefined keys (bug #3514)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 04:41:35 +00:00
Russell Bryant
9e1d3683fa Make sure 10 byte read is considered EOF not error (bug #3505)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4978 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 04:29:19 +00:00
Russell Bryant
528d2dcff5 Make sure we always transmit the same from line (bug #3492)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4977 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 04:13:53 +00:00
Russell Bryant
40969e6b29 fix div by zero (bug #3467)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4976 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 04:05:29 +00:00
Russell Bryant
59814ed3e5 Fix wav append mode (bug #3498)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4975 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 03:53:36 +00:00
Russell Bryant
8f2106c5e3 update readme (bug #3309)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4974 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 03:38:27 +00:00
Russell Bryant
37a80ea3bc typo (bug #3483)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4973 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 03:28:11 +00:00
Russell Bryant
a46350e315 only use default cid if specified (bug #3486)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4972 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-02-07 03:25:22 +00:00
Russell Bryant
e1a6d33ed0 Fix interation of # transfer and flash hook transfer (bug #3011)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4917 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-29 07:19:10 +00:00
Russell Bryant
4979d7fbb1 handle INFO A through D (bug #3445)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4916 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-29 07:16:08 +00:00
Russell Bryant
bdcbd76e13 fix restrictcid with mysql users (bug #3442)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4915 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-29 07:06:57 +00:00
Russell Bryant
081e28667e fix simultaneous voicemail messages -- Thanks Robert! (bug #3394)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4914 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-29 06:53:33 +00:00
Russell Bryant
1ef98ac6de fix DIALEDPEERNUMBER (bug #3427)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4913 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-29 06:46:05 +00:00
Russell Bryant
b90f6b40d9 fix reloading secret options (bug #3432)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4912 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-29 06:40:09 +00:00
Russell Bryant
2bb388ebc8 fix parking (bug #3396)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4905 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-28 01:24:59 +00:00
Russell Bryant
1714f299c9 fix 'show codec' (bug #3427)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4904 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-28 01:18:25 +00:00
Russell Bryant
5571294b91 fix c++ compatibility issue (bug #3426)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4903 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-28 01:13:19 +00:00
Russell Bryant
3696407c67 don't fail register on dns error (bug #3424)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4902 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-28 00:58:09 +00:00
Russell Bryant
76b18e2d6e remove unused vars (bug #3423)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4901 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-28 00:34:43 +00:00
Russell Bryant
d9d599a84d fix penalty behavior, thanks florian!! (bug #3114)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4883 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-23 23:57:41 +00:00
Russell Bryant
36d08dc8f0 copy language (bug #3401)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4875 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-22 01:44:12 +00:00
Russell Bryant
3035547927 fix broken callerid (bug #3395)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4874 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-22 01:27:08 +00:00
Russell Bryant
517413928f add mpg123 warnings (bug #3392)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4867 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-21 05:18:35 +00:00
Russell Bryant
b3ee85ee4a fix mpg123 for non-linux (bug #3385)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4866 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-21 04:52:01 +00:00
Russell Bryant
540a2571ca update email subject (bug #3384)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4863 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-21 04:40:34 +00:00
Russell Bryant
53840ccffc rephrase my note
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4849 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-20 04:02:58 +00:00
Russell Bryant
61d87e19f1 Fix "send text" crash (bug #3378)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4848 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-20 03:38:23 +00:00
Russell Bryant
63a98a2bed Send a few more rfc2833 events on hte "down" (bug #3339)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4843 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-19 02:33:54 +00:00
Russell Bryant
4542f92842 add missing .cvsignore (bug #3373)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4842 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-19 02:29:08 +00:00
Admin Commit
fa023ceccf This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4841 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-19 02:29:08 +00:00
Russell Bryant
6c5bf0d542 give outbound channels callerid of their extension after calling (bug #2489)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4826 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 22:52:49 +00:00
Russell Bryant
a3b4b4459c update unused code ... (bug #3342)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4825 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 21:02:13 +00:00
Russell Bryant
58b1b7f825 prevent duplicate 200 ... and some formatting
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4824 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 19:29:10 +00:00
Russell Bryant
4f5f53706d various fixes (bug #3340)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4819 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 01:43:33 +00:00
Russell Bryant
a87fb09763 typo
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4818 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 01:36:48 +00:00
Russell Bryant
fb3de07e39 Don't even attempt to masquerade a channel into itself (bug #3040)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4817 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 00:43:46 +00:00
Russell Bryant
02bb7498b0 Fix ringback on outbound skinny calls (bug #3295)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4816 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 00:37:22 +00:00
Russell Bryant
8c9f25ece1 working on the correct fix (bug #3080)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4815 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-17 00:12:30 +00:00
Russell Bryant
6356638b6a Keep dead console from killing asterisk (bug #3331)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4802 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-15 19:58:41 +00:00
Russell Bryant
659eb8bd36 update for 1.0.4
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4789 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-14 05:09:42 +00:00
Russell Bryant
2ef418765c Don't allow masquerading into oneself (bug #3040)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4788 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-14 04:59:54 +00:00
Russell Bryant
33cffbd344 update firmware to version 22
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4784 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-14 04:18:33 +00:00
Russell Bryant
5d877f53ed fix global operator=yes (bug #3080)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4782 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 05:39:04 +00:00
Russell Bryant
334bd9f57d Handle syntax errors in group descriptions more gracefully (bug #3330)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4781 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 05:18:31 +00:00
Russell Bryant
a6fb9eef88 fix typo in tone detect (bug #3315)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4779 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 05:06:49 +00:00
Russell Bryant
d9d070e30b update doc (bug #3310)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4778 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 04:39:55 +00:00
Russell Bryant
73f50db89e copy musicclass (bug #3235)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4777 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 04:37:25 +00:00
Russell Bryant
d1b6552ef7 fix message sent on codec mismatch (bug #3306)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4776 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 04:34:01 +00:00
Russell Bryant
8b079c4bf2 look in another location for speex.h (bug #3283)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4775 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 04:22:07 +00:00
Russell Bryant
22db312ca1 nevermind ... (bug #3255)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4774 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 04:08:15 +00:00
Russell Bryant
fbc3e2e3ce Send "405 Method Not Allowed" if a message is received outside of a call (bug #3324)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4772 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-13 03:00:02 +00:00
Russell Bryant
d2d967d775 update help text (bug #3298)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4764 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-11 19:12:00 +00:00
Russell Bryant
c69bb18184 logging update (bug #3268)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4758 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-11 18:07:42 +00:00
Russell Bryant
dc5042762f fix silly header (bug #3288)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4730 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-09 14:58:45 +00:00
Russell Bryant
efcc597742 improve CLI command info (Thanks, Leif!) (bug #3220)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4729 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-09 14:46:45 +00:00
Russell Bryant
b0a516034f send script parameter with FastAGI (bug #3270)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4721 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-08 22:40:56 +00:00
Russell Bryant
2880956743 cosmetic fixes (bug #3271)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4720 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-08 22:18:44 +00:00
Russell Bryant
56dd7681f8 Make sure we clear out owner in SUB_REAL when moving a call (bug #3267)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4719 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-08 22:12:02 +00:00
Russell Bryant
a6d0cc6c02 fix typo (bug #3265)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4718 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-08 21:54:24 +00:00
Russell Bryant
9c92ca2d27 update docs on ANSWEREDTIME and DIALEDTIME (bug #3209)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4717 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-08 21:48:14 +00:00
Russell Bryant
f8526ef3ba fix disposition to be a string instead of an int (bug #3255)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4716 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-08 21:15:07 +00:00
Russell Bryant
96624911f0 fix SIP presence (bug #3251)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4697 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-06 19:37:55 +00:00
Russell Bryant
5967d8f2bc stop music on hold when channel is hung up instead of after the channel is destroyed (bug #3035)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4692 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-06 05:15:50 +00:00
Russell Bryant
dcd5da730a document a problem with polycom phones (bug #3129)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4671 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-05 05:59:07 +00:00
Russell Bryant
3c54495507 fix an incorrect discription and some formatting (bug #3226)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4670 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-05 05:41:24 +00:00
Russell Bryant
f9eedef7ee change option to be consistent (old option still works, too) (bug #3163)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4669 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-05 05:37:01 +00:00
Russell Bryant
de117b689e Add option to save a file after pressing '0' to go to the operator (bug #3057)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4668 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-05 05:32:47 +00:00
Admin Commit
5799a6a60c This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4667 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-05 05:32:47 +00:00
Russell Bryant
a97e1f873f putting the timestamp stuff back in ...
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4660 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-04 19:02:16 +00:00
Russell Bryant
74239cb26c I got a crash in iax that I think is related to this timestamp patch, so I am going to back it out until we get it figured out. (bug #3119)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4658 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-04 17:18:15 +00:00
Russell Bryant
fa7a75c886 Make sure to wake up sleeper on sip transfer issue (bug #2938)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4654 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-04 05:59:49 +00:00
Russell Bryant
4a187156b2 change from dos to unix text format (bug #3213)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4653 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-04 05:53:16 +00:00
Russell Bryant
f45b8fcc70 lock sooner, fix some formatting (bug #3207)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4652 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-04 05:47:49 +00:00
Russell Bryant
1db571cb37 don't exit AGI when file not found to stream (bug #3212)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4648 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-03 18:19:05 +00:00
Russell Bryant
8289500dd5 just kidding ...
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4647 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-03 18:09:01 +00:00
Russell Bryant
ec9f642dc3 add agent vars (bug #3158)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4646 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-03 18:02:04 +00:00
Russell Bryant
f2a2787b42 increase stack size for searching through contexts (bug #3182)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4645 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-03 03:07:40 +00:00
Russell Bryant
da0fb57df3 make sure to set sin_family (bug #3188)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4644 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-03 02:38:26 +00:00
Russell Bryant
10378ed083 stop sending rtp when on hold (bug #3185)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4643 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-03 02:36:24 +00:00
Russell Bryant
b0b9c0928b fix MWI with type=friend (bug #3004)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4631 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-01-02 00:32:32 +00:00
Russell Bryant
9386b25b51 add missing header
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4613 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 22:30:09 +00:00
Russell Bryant
9a81d7270e update 'show app' output (bug #3170)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4612 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 21:46:39 +00:00
Russell Bryant
29062def81 update help text (bug #3171)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4611 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 21:40:45 +00:00
Russell Bryant
ad851c87b5 fix typos (bug #3162)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4610 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 21:16:25 +00:00
Russell Bryant
b67759975d fix show dialplan for hints (bug #3074)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4609 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 20:57:41 +00:00
Russell Bryant
f4adada2e8 make cid rings configurable (bug #2889)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4608 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 20:36:57 +00:00
Russell Bryant
a4671a3d88 remove duplicate option parsing (bug #3173)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4607 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 20:07:17 +00:00
Russell Bryant
379d3a133c ignore invalid rtp packets (bug #3030)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4606 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 19:34:47 +00:00
Russell Bryant
dd8d225b4e prevent timestamp jumps (bug #3119)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4605 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 19:07:08 +00:00
Russell Bryant
78693d31e9 Re-use SIP authentication, aka "The Broadvoice patch" (bug #2917)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4604 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-30 18:30:23 +00:00
Russell Bryant
49d18cef95 fix some typos (bug #3162)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4566 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-28 12:10:02 +00:00
Russell Bryant
cc8996361c prevent seg faults
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4562 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-27 22:34:25 +00:00
Russell Bryant
8060744e05 remove unused option (bug #3127)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4548 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-23 20:25:06 +00:00
Russell Bryant
799ff464f2 Don't hold the iaxsl[x] lock while finding the peer, do it ahead of time.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4547 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-23 20:21:49 +00:00
Russell Bryant
b107f9c1c9 honor global nat setting for users (bug #3125)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4531 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-23 00:38:40 +00:00
Russell Bryant
0e39f602ea Make case in manager events consistent (bug #3116)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4530 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-22 22:49:00 +00:00
Russell Bryant
a391baf1be Remove the SIP ACK fixes at the request of Olle - This will go in when a more complete fix is available
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4528 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-22 18:26:17 +00:00
Russell Bryant
3384173257 OpenBSD fixes (bug #3120)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4526 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-22 06:18:32 +00:00
Russell Bryant
51ea5a2797 fix for sparc64 (bug #3102)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4517 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 20:49:24 +00:00
Russell Bryant
1298f6585d fix typo in ast_say_number_full_en (bug #3101)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4516 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 20:42:58 +00:00
Russell Bryant
2ebc21f175 Make sure that read/write format are set up correctly
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4515 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 20:15:29 +00:00
Russell Bryant
6c6ec855a7 Make sure we del any remaining connections (bug #2982)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4514 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 20:10:06 +00:00
Russell Bryant
10bbbf2c14 Add errno (bug #3063)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4513 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 19:56:43 +00:00
Russell Bryant
fcf810801f unregister the correct apps (bug #3089)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4512 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 15:24:43 +00:00
Russell Bryant
665cf4fb64 fix missing "sip:" in ACK (bug #2687)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4511 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-21 15:10:06 +00:00
Russell Bryant
6f60468d3d Fix SIP ACK for BYE (bug #3087)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4500 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-20 01:48:20 +00:00
Russell Bryant
00f2912aaa don't return -1 if user enters nothing (bug #3042)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4499 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-20 01:40:29 +00:00
Russell Bryant
b32ffb8190 Olle's ACK fix (bug #2687)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4498 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-20 01:32:58 +00:00
Russell Bryant
4ceafc96b1 fix parking issue (bug #3840)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4497 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-20 00:27:19 +00:00
Russell Bryant
bed2bda4f4 remove codecs/gsm/lib with make clean (bug #3031)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4496 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-20 00:24:21 +00:00
Russell Bryant
a97bf16d2d fix language handling (bug #3023)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4481 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-19 13:06:11 +00:00
Russell Bryant
8a987daf3b don't allow '#' as a voicemail password (bug #3066)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4465 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-15 23:05:28 +00:00
Russell Bryant
8d135aa5ae Fix use count for agent/local (bug #2996)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4457 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-15 19:07:10 +00:00
Russell Bryant
0a4530cead Make macro processing consistent with regular exten processing (bug #3044)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4449 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-15 03:56:10 +00:00
Russell Bryant
ad1ee839cc getting rid of utils/ that came from head
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4448 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-15 03:53:12 +00:00
Russell Bryant
1b53088a4b Fix setvar issue (bug #3010)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4420 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-10 23:19:54 +00:00
Russell Bryant
a5b4c8881e implement fmtp 16 in rtp (bug #2999)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4415 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-10 11:32:12 +00:00
Russell Bryant
2583e00e03 update comment (bug #2999)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4414 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-10 11:28:11 +00:00
Russell Bryant
7e3f8ee419 update iaxy firmware to version 20
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4407 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-09 04:59:28 +00:00
Russell Bryant
b035299213 remove unneccesary 'if'
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4403 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-08 14:42:44 +00:00
Russell Bryant
4020387145 fix case sensitivity in codec prefs
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4401 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-08 06:17:43 +00:00
Russell Bryant
3e7c0ce67f fix mem leak in free_value (bug #2990)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4397 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-07 19:43:06 +00:00
Russell Bryant
0caa4033c9 Don't hold modlock while doing reload
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4395 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-07 02:16:49 +00:00
Russell Bryant
cd65e922b2 Add missing free's in rare circumstances (bug #2985)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4394 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-06 23:15:19 +00:00
Russell Bryant
90f22a990d merge codec preference changes for SIP
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4388 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-05 05:17:51 +00:00
Russell Bryant
0b74a19625 Release call lock while we look for the peer to avoid a deadlock
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4384 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-03 23:35:36 +00:00
Russell Bryant
429432f5ff canceled voicemail emails corrupt wav (bug 2957)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4382 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-03 01:59:08 +00:00
Russell Bryant
46f97f76a5 fix error message (bug 2897)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4381 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-03 01:45:25 +00:00
Russell Bryant
ec3b5c9b5b update Festival doc (bug 2964)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4380 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-03 01:20:26 +00:00
Russell Bryant
a160a8c9d5 add missing config destroy (bug 2944)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4378 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-03 01:15:27 +00:00
Russell Bryant
65d6be272d doing <flash> *0 while on fxs causes Asterisk to crash (bug 2963)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4376 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-12-03 00:11:21 +00:00
Russell Bryant
1e75116e74 Try call if call is 0 or more (bug #2935)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4348 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-26 01:54:11 +00:00
Russell Bryant
187942d00a fix MEETMESECS (bug 2936)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4345 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 18:27:22 +00:00
Russell Bryant
418ff58e61 don't increment the timestamp on dtmf (bug 2928)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4344 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 18:16:16 +00:00
Russell Bryant
bb6333e01f change size of var_val (bug 2926)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4343 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 18:13:16 +00:00
Russell Bryant
df6c1f8b39 fix for rpid (bug 2910)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4342 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 15:19:11 +00:00
Russell Bryant
2b9417e2e5 get rid of stray '\n' (bug 2922)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4340 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 07:32:43 +00:00
Russell Bryant
f53fe9761c fix manager events that report lag time (bug 2919)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4339 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 07:24:58 +00:00
Russell Bryant
902661dd8e decrement use counter after timeout on INVITE (bug 2898)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4338 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 07:20:12 +00:00
Russell Bryant
646dc459fa Segfault if head caller times out of queue with moh running (bug 2891)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4337 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 07:13:08 +00:00
Russell Bryant
3d48bc2f61 fix repeated sequence numbers (bug 2902)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4336 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 07:04:04 +00:00
Russell Bryant
28109dedf5 fix mem leak (bug #2940)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4334 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-25 06:14:50 +00:00
Russell Bryant
10781d30d2 don't create owner twice
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4310 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-22 03:57:41 +00:00
Russell Bryant
c0c9a1a5f0 little fixes (bug #2899)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4295 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-19 13:25:17 +00:00
Russell Bryant
13e54102fd fix continuation line parsing (bug #2892)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4291 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-18 04:27:12 +00:00
Russell Bryant
f4470352ff check to see if FD's are open before closing (bug #2858)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4289 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-18 04:20:25 +00:00
Russell Bryant
77ad568144 fix tab completion issue (bug #988)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4288 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-18 04:16:47 +00:00
Russell Bryant
1b05a4639d detect sequence number rollover (bug #2887)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4286 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-18 04:03:10 +00:00
Russell Bryant
e73c4e4a44 tweaks to make valgrind happy
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4285 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-18 03:51:58 +00:00
Russell Bryant
60c2988f53 add depend support for h323 (bug #2757)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4253 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-15 02:35:35 +00:00
Russell Bryant
35dd204d76 fix for older linux systems (bug #2853)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4252 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-15 02:30:32 +00:00
Russell Bryant
8eb984caec fix setting language in chan_sip (bug #2848)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4251 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-15 02:26:08 +00:00
Russell Bryant
9801c6c63f make valgrind less chatty about res_crypto (bug #2857)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4250 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-15 02:20:20 +00:00
Russell Bryant
1b754ff59d another little typo ... to make twisted happy
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4235 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-14 00:16:02 +00:00
Russell Bryant
713ddd2172 fix little typo
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4234 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-14 00:08:03 +00:00
Russell Bryant
d3cb67a4cd allow dashes in extensions since they can be in patterns (bug #2835)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4228 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-12 15:27:30 +00:00
Russell Bryant
1f02d433b3 send full contact when poking a peer (bug #2836)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4227 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-12 14:34:01 +00:00
Russell Bryant
dbf6ad2ecd fix seg fault (bug #2772)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4226 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-12 14:29:15 +00:00
Russell Bryant
c6938534bd fix to compile chan_phone with 2.6 kernel headers (bug #2831)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4225 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-12 14:13:57 +00:00
Russell Bryant
ac659af3ea fix for Darwin/OSX (bug #2833)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4224 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-12 14:03:42 +00:00
Russell Bryant
bdabdcbf1e fix off by one (bug #2827)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4223 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-12 13:48:42 +00:00
Russell Bryant
457d6f2822 update Changelog
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4196 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-09 05:42:56 +00:00
Russell Bryant
0d23dbb490 Fix supervised transfer (bug #2813)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4194 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-09 05:28:47 +00:00
Russell Bryant
3cd77bab28 Fix verbose error (bug #2809)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4193 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-09 05:23:56 +00:00
Russell Bryant
a39d05855e fix spelling error (bug 2810)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4192 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-09 05:19:27 +00:00
Russell Bryant
66d0e5756f fix voicemail debug output (bug #2789)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4182 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-08 00:30:21 +00:00
Russell Bryant
591eb8fac1 fix sip mwi to conform to RFC (bug #2793)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4181 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-08 00:24:09 +00:00
Russell Bryant
0ae97da489 fix build for Mac OSX (bug #2803)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4179 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-08 00:08:58 +00:00
Russell Bryant
014a0a178b fixes from bug 2800
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4178 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-07 23:47:25 +00:00
Russell Bryant
5e8f6247fb update to ChangeLog ...
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4177 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-07 23:26:07 +00:00
Russell Bryant
de1c7219ea Setup fromuser properly (bug #2802)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4176 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-07 23:22:48 +00:00
Russell Bryant
7352e07e12 fix non standard characters (bug 2778)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4162 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-05 02:45:59 +00:00
Russell Bryant
bfe333ed67 fix compilation of chan_h323 (bug 2786,2790,2669)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4161 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-04 23:14:26 +00:00
Russell Bryant
ec25eab17f Use getpid (non-linux) or gettid(linux) for thread identification (bug #2745)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4153 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-03 02:03:43 +00:00
Russell Bryant
e212b875fc update changelog ...
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4152 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-02 22:42:15 +00:00
Russell Bryant
92f1ec6be4 fix say for portuguese numbers (bug #2749)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4151 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-02 22:40:11 +00:00
Russell Bryant
4443cc2107 Don't show partially-filled strings over remote console (asterisk -r) (bug #2764)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4150 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-02 22:37:47 +00:00
Russell Bryant
d612a5ce42 prevent seg fault with attempt_transfer (bug #2741)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4146 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-11-02 12:56:15 +00:00
Russell Bryant
808ecc893a fix summaries for chan_h323 cli commands (bug #2739)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4126 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-29 14:03:28 +00:00
James Golovich
1e9087357b Backport chan_zap.c part of bug 2703 to 1.0
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4111 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-27 14:41:55 +00:00
Russell Bryant
124c88fba3 fix mgcp bug (bug #2696)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4105 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-26 15:34:30 +00:00
Russell Bryant
ef3f4d29c9 fix short message issue (bug #2723)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4104 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-26 15:22:09 +00:00
Russell Bryant
67478da442 fix LOG_NOTICE message to exten@context from context@exten (bug #2725)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4103 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-26 14:42:01 +00:00
Russell Bryant
67c451783b fix show applications output for forkcdr (bug #2677)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4096 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-25 21:57:27 +00:00
Russell Bryant
517e58c5df update ChangeLog for 1.0.2 release
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4095 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-25 19:10:02 +00:00
James Golovich
b86dbdb22c Backport recent memory fixes to 1.0
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4094 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-25 17:57:25 +00:00
Russell Bryant
807bbf3461 fix debug message for voicemail email (bug #2675)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4093 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-25 00:51:27 +00:00
Russell Bryant
8b1cdad2f5 Fix user event body (bug #2713)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4092 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-25 00:48:28 +00:00
Russell Bryant
ce25d82aa7 Make sure close() is not called on a fd < 1 with a wrapper call (bug #2710)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4091 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-25 00:18:06 +00:00
Russell Bryant
d354512eca Sending SMS with no hangup supervision will hang the channel (bug #2708)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4090 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-24 21:26:29 +00:00
Russell Bryant
f0131ed0f2 fix bindaddr for BSD (bug #2668)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4089 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-24 21:24:17 +00:00
Russell Bryant
a4111e1f93 Add missing fixup (bug #2667)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4088 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-24 21:15:23 +00:00
Russell Bryant
f7098a28be make sure malloc was successful before doing memset (bug #2704)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4087 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-24 21:09:40 +00:00
Russell Bryant
fdffdc9364 Handle unknown 1xx reponses as 100 (bug #2698)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4086 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-24 21:04:32 +00:00
Russell Bryant
d91f0dadc9 fix potential segfault in MeetMeAdmin (bug #2681)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4063 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-23 12:42:16 +00:00
Russell Bryant
291309df4a Don't "ignore" on CANCEL (bug #2670)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4062 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-23 12:23:25 +00:00
Russell Bryant
eb08e2600f get rid of some compile warnings (bug #2540)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4059 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-23 12:14:47 +00:00
Russell Bryant
0faa51794d make operator=no work correctly, fix typo (bug #2665)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4058 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-23 11:55:21 +00:00
Russell Bryant
5f5017defd fix for MGCP (bug #2499)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4027 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-17 04:57:10 +00:00
Russell Bryant
737023e9d4 call ast_destroy on cfg appropriately (bug #2661)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4019 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-16 16:04:17 +00:00
Russell Bryant
e98d85bf09 Fix hangup handling with chansiavail with agent (bug #2658)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4016 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-16 15:35:23 +00:00
Jeremy McNamara
6adefd13c1 stop seg
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4011 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 23:45:09 +00:00
Russell Bryant
5c37031b1c Fix some small typos (bug #2649)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4010 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 23:11:16 +00:00
Russell Bryant
141a82674e Forget fullcontact when specific number is dialed (bug #2620)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4009 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 23:08:03 +00:00
Russell Bryant
2423b41fd9 tab completion on show dialplan from -r asterisk with large extensions.conf will segfault (bug #2634)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4008 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 22:51:14 +00:00
Russell Bryant
f85277c7b3 show output with 'pri debug' with verbosity set to zero (bug #2645)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4007 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 22:46:56 +00:00
Russell Bryant
d60b955324 fix for attended transfers (bug #2632)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4006 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 22:43:35 +00:00
Russell Bryant
663636b515 fix setlanguage seg fault (bug #2641)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4005 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-14 22:39:40 +00:00
Russell Bryant
8bccbf9afb get rid of extra error message (bug #2633)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3989 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-13 02:24:30 +00:00
Russell Bryant
1d10b782b4 add missing \n (bug #2595)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3982 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-12 02:29:08 +00:00
Russell Bryant
3cd48f9a41 fix delivery times on trunks (bug #2587)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3981 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-12 02:25:38 +00:00
Russell Bryant
d50ef1d333 change SIP_MAX_PACKET to 4096 (bug #2623)
----------------------------------------------------------------------


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3980 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-12 02:16:04 +00:00
Russell Bryant
fbcd14b30b add check for incorrect voicemail sequencing (bug #2436)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3979 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-12 01:39:21 +00:00
Russell Bryant
09ca3690b5 Fix wave file lengths (bug #2486)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3963 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-09 16:32:21 +00:00
Russell Bryant
6db145dd07 Discontiguous descending Zap channel group fails to use all members (bug #2581)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3958 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-09 00:44:30 +00:00
Russell Bryant
0ff4ffd27f fix for Nortel SIP dtmf (bug #2605)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3957 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-09 00:36:46 +00:00
Russell Bryant
ba5a68e731 chan_iax2 shouldn't use IAX/Registry on temponly peers (bug #2610)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3956 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-09 00:25:53 +00:00
Russell Bryant
df358f42e0 verbose fixes (bug #2602)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3955 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-08 23:29:50 +00:00
Russell Bryant
0e518edee4 Fix paths for app_sms (bug #2597)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3945 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-08 02:59:35 +00:00
Russell Bryant
dea58d2e88 Do not send progress when "ringing" only flag is set (bug #2553)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3944 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-08 02:50:22 +00:00
Russell Bryant
97efb246b3 Always fflush for any CDR file (not only for Master.csv) (bug #2586)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3943 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-08 02:43:08 +00:00
Russell Bryant
17a3454b92 voicemail beep shouldn't be played till we get next message number (bug #2594)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3942 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-08 00:05:36 +00:00
Russell Bryant
3680bb43cd add Rich Murphey to the CREDITS
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3941 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-07 21:51:21 +00:00
Russell Bryant
b0180d6665 Fix which one we use initreqprep vs. reqprep (bug #2591, 2596)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3940 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-07 21:47:46 +00:00
Russell Bryant
f9be91101f fix bindaddr for MGCP (bug #2579)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3925 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-06 22:26:10 +00:00
Russell Bryant
e16c9c9ecd fix MWI for SIP (bug #2582)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3924 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-06 22:15:32 +00:00
Russell Bryant
57c86cec8e fix chan_mgcp seg fault (bug #2572)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3917 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-05 21:39:00 +00:00
Russell Bryant
d600998f7e make SIP_CODEC behave as it suggests (bug #2566)
Correction: The last commit for cdr_odbc.c was actually bug #2569.


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3913 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-05 02:13:00 +00:00
Russell Bryant
a75365ea8e change to use ast_true in cdr_odbc (bug #2566)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3912 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-05 02:02:17 +00:00
Russell Bryant
8b34f224e7 Fix CDR for supervised transfer in chan_zap and chan_sip (bug #1595)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3903 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-03 20:22:41 +00:00
Russell Bryant
97d664a128 NetBSD build doesn't always find libncurses (bug #2560)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3901 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-03 18:37:37 +00:00
Russell Bryant
04bcd2ff23 Has(New)VoiceMail does not assume INBOX if no folder specified (bug #2559)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3899 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-03 16:43:29 +00:00
Russell Bryant
3f9482f7bc Use event2str consisitently in chan_zap anytime we are printing debug info about an event (bug 2548)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3873 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-02 00:12:20 +00:00
Russell Bryant
ebf15d6151 Ignore ;transport=udp from 302 Moved Temp. requests (bug #2549)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3866 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-10-01 00:32:47 +00:00
Russell Bryant
38f5196684 Ignore message type in CID Delivery (bug #2552)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3865 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-09-30 23:56:19 +00:00
Russell Bryant
31457d7be1 Fix seg fault with IAX native bridging (bug #2550)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3864 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-09-30 22:47:32 +00:00
Admin Commit
a196c598b6 This commit was manufactured by cvs2svn to create branch 'v1-0'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@3863 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2004-09-30 22:47:32 +00:00
1371 changed files with 124244 additions and 378773 deletions

View File

@@ -1 +0,0 @@
33

View File

@@ -1 +0,0 @@
33

View File

@@ -1 +1 @@
1.4.41.2
1.0.12

View File

@@ -1,11 +0,0 @@
# This is a convenience script for systems on which BSD make is the default,
# such that typing 'make' will do what people expect, instead of producing an
# error (due to incompatibilities between BSD make and GNU make).
.include "makeopts"
all::
$(MAKE)
$(.TARGETS)::
$(MAKE) $(.TARGETS)

23
BUGS
View File

@@ -1,22 +1,23 @@
Asterisk 1.0-RC-1 Known Major Bugs
==================================
* Some people still have issues with H.323
* QuickNet driver still not entirely stable
Asterisk Bug Tracking Information
=================================
To learn about and report Asterisk bugs, please visit
the official Asterisk Bug Tracker at:
To learn about and report Asterisk bugs or make feature
requests, please visit the official Asterisk Bug Tracker
at:
https://issues.asterisk.org
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
http://www.digium.com/bugtracker.html
Thank you!
Mark

374
CHANGES
View File

@@ -1,374 +0,0 @@
Changes since Asterisk 1.2:
* over 4,000 commits since 1.2
* queue member naming
* CLI commands rework
o Change the way CLI commands are structured.
o Most commands are now <module> <verb> <args>
* chan_h323 update
* RTP packetization
* SLA (Shared Line Appearance) support
* T.38 Passthrough Support for faxing in SIP
* Generic channel jitterbuffer (spawned from RTP)
* Variable Length DTMF for better DTMF compatibility
* Improved chan_iax2 scalability by using multithreading
* AEL2 has replaced the original implementation of AEL. The "2" is removed. For more details,
read: http://www.voip-info.org/wiki/view/Asterisk+AEL2
AEL is no longer considered experimental.
* New sounds; English, Spanish, and French prompts, as well as music on hold files, in
multiple Asterisk native formats.
* IMAP storage of voicemail
* Jabber/GoogleTalk integration
* New speech recognition API for interfacing to different Voice Recognition software packages
* much more customizable and portable build system
o also for asterisk-addons
* Radius CDR logging
* SNMP support
* SMDI (Simplified Message Desk Interface) support
* Redesign of MusicOnHold configuration settings
* Manager over HTTP
* Significant chan_skinny updates
* Significant chan_misdn updates
* Improved SIP transfers
* SIP MWI subscription support
* Much improved support for SIP video
* Control over SIP transfers and subscriptions (enable/disable per device)
* ChanSpy whisper mode (Whisper Paging)
* Configurable language support for saying dates and times
* Significant architecture improvements for memory usage and performance
* Media-only IAX2 transfers
* Updates to the Radio Repeater app code
* Deprecation of AgentCallbackLogin in favor of a dialplan-based solution
* uClibc builds supported
* Work done for freeBSD portability
* Work done for Solaris portability
* FreeTDS-based database can be used with Realtime
* New internal data structure, stringfields, is implemented in IAX and SIP, reducing memory consumption by about 50%.
* Use of thread local storage for reduced memory allocation/freeing and lower stack consumption
* Reorganized files into docs/ main/ configs/, including name changes in some cases
* Much effort was expended in arranging documentation in source files in doxygen format
* Improved IP TOS support for IAX and SIP
* Builtin mini HTTP server
* Added support for Sigma Designs cards.
* Frame header caching to reduce memory allocation/freeing
* Passthrough and record/playback support for G.722 wideband audio
* using mpg123 to play MP3 files for music-on-hold will be deprecated in 1.4 (start using the "native support")
* New Apps:
1. AMD() ;; Answering Machine Detection
2. ChannelRedirect() ;; asynch goto, redirect chan to context/exten/priority
3. ContinueWhile() ;; Addition to the While() suite. Acts like "continue".
4. ExitWhile() ;; Addition to the While() suite. Acts like "break".
5. ExtenSpy() ;; A close cousin to ChanSpy().
6. FollowMe() ;; findme/followme call redirect app
7. Log() ;; Send a message to the log, based on severity level.
8. MacroExclusive() ;; No more than one invocation of this macro allowed at any one time.
9. MorseCode() ;; turns strings into dits and dahs. A playground for ham radio licensees!
10. OSPAuth() ;; OSP authentication
11. QueueLog() ;; allows you to write your own events into the queue log
12. SLAStation() ;; Shared Line Appearance
13. SLATrunk() ;; Shared Line Appearance
14. SpeechCreate() ;; Voice Recognition Engine interface...
15. SpeechActivateGrammar()
16. SpeechStart()
17. SpeechBackground
18. SpeechDeactivateGrammar()
19. SpeechProcessingSound()
20. SpeechDestroy()
21. SpeechLoadGrammar()
22. SpeechUnloadGrammar()
23. StopMixMonitor() ;; to stop the MixMonitor App.
24. TryExec() ;; execute dialplan app without fatal consequences
* Apps removed:
1. CheckGroup -- do a comparison to ${GROUP()}
2. Curl -- use the function CURL() instead
3. Cut -- use the function CUT() instead
4. DateTime -- use sayunixtime() app instead.
5. DBget -- deprecated in 1.2, now removed.
6. DBput -- deprecated in 1.2, now removed.
7. Enumlookup -- use the function ENUMLOOKUP() instead
8. Eval -- use the function EVAL() instead
9. GetGroupCount -- use the function GROUP_COUNT() instead
10. GetGroupMatchCount -- use the function GROUP_MATCH_COUNT() instead
11. Intercom -- use the chan_oss module instead
12. Math -- use the function MATH() instead
13. MD5 -- use the function MD5() instead
14. SetCIDname -- use the function CALLERID(name) instead
15. SetCIDnum -- use the function CALLERID(number) instead
16. SetGroup -- use Set(GROUP=group) instead
17. SetRDNIS -- use the function CALLERID(rdnis) instead
18. Sql_postgres -- was deprecated in 1.2, now removed
19. Txtcidname -- use the function TXTCIDNAME instead
* New Dialplan Functions:
1. ARRAY()
2. BASE_64_DECODE()
3. BASE_64_ENCODE()
4. CHANNEL()
5. CURL()
6. CUT()
7. DB_DELETE()
8. FILTER()
9. GLOBAL()
10. IFTIME()
11. KEYPADHASH()
12. ODBC()
13. QUOTE()
14. RAND()
15. REALTIME()
16. SHA1()
17. SORT()
18. SPRINTF()
19. SQL_ESC()
20. STAT()
21. STRPTIME()
22. AUDIOHOOK_INHERIT()
* Apps that have changes to their interface:
1. Authenticate() -- optional maxdigits argument added.
2. ChanSpy() -- new options:
o w -- Enable 'whisper' mode, so the spying channel can talk to...
o W -- Enable 'private whisper' mode, so the spying channel can...
3. DBdel() -- now marked as DEPRECATED in favor of the DB_DELETE func
4. Dial()
o New Option: O([x]) for Zaptel operator mode
o New Option: K/k parking via dtmf tones
5. Dictate() -- optional filename argument added.
6. Directory() -- new option: e - In addition to the name, also read the extension number...
7. ForkCDR() -- new options:
o 'a' -- update answer time on new cdr
o 'A' -- Lock the orig CDR answer time against changes.
o 'D' -- Copy the disposition from the orig to the new CDR.
o 'd' -- clear the dstcannel field in the new CDR.
o 'e' -- set the end time of the original CDR.
o 'R' -- do NOT reset the new CDR.
o 's' -- Add/change var in orig CDR.
o 'T' -- Force ast_cdr_end, answer to obey LOCKED flag for the orig. CDR.
-- ast_cdr_setvar will be forced also (used by the CDR() func in write mode)
8. Meetme() -- new options:
o 'I' -- announce user join/leave without review
o 'l' -- set listen only mode (Listen only, no talking)
o 'o' -- set talker optimization - treats talkers who aren't speaking as...
o '1' -- do not play message when first person enters
9. MeetmeAdmin() -- new options:
o 'r' -- Reset one user's volume settings
o 'R' -- Reset all users volume settings
o 's' -- Lower entire conference speaking volume
o 'S' -- Raise entire conference speaking volume
o 't' -- Lower one user's talk volume
o 'T' -- Lower all users talk volume
o 'u' -- Lower one user's listen volume
o 'U' -- Lower all users listen volume
o 'v' -- Lower entire conference listening volume
o 'V' -- Raise entire conference listening volume
10. OSPFinish() : now also can return ERROR result.
11. OSPLookup() : Sets more variables, also now returns ERROR result.
12. Page() -- New option: r - record the page into a file (see 'r' for app_meetme)
13. Pickup() -- multiple extensions, PICKUPMARK; read the description!
14. Queue()
o New Argument: AGI
o New option: i
15. Random() -- is now deprecated in 1.4
16. Read() -- replace 'skip' and 'noanswer' options with 's', 'n', add 'i' option.
17. Record() -- New option: 'x' : ignore all terminator keys (DTMF) and keep recording until hangup
18. UserEvent() -- slight change in behavior. Read the description.
19. VoiceMailMain() -- new a(#) option, goes to folder # directly.
20. WaitForSilence() -- new optional 3rd arg, time delay before returning.
* Functions that have changes to their interfaces:
1. CDR -- new options: u and s
2. LANGUAGE -- Deprecated. Use CHANNEL(language) instead.
3. MUSICCLASS -- Deprecated. Use CHANNEL(musicclass) instead.
* Configuration File Changes:
1. NEW config files:
1. amd.conf -- Answering Machine Detection parameters
2. followme.conf -- parameters for the findme/followme call forwarding
3. func_odbc.conf -- define sql access functions here
4. gtalk.conf -- how to handle gtalk protocol calls
5. h323.conf -- h323 configuration
6. http.conf -- config for the builtin mini-http server in asterisk
7. jabber.conf -- jabber interface
8. jingle.conf -- jingle protocol interface config
10. res_snmp.conf -- to enable snmp in asterisk, and define full/sub agent status
11. say.conf -- define per-language rules for numbers, dates, etc.
12. skinny.conf -- for those special skinny phones you want to use...
13. sla.conf -- Shared Line Appearance config
14. smdi.conf -- SMDI messaging config
15. udptl.conf -- T38's udptl transport config
16. users.conf -- user config
2. Changes to Existing Config files:
1. In General:
o Jitterbuffer support added to several channels. Usually adds these variables to a config file:
1. jbenable
2. jbmaxsize
3. jbresyncthreshold
4. jbimpl
5. jblog
o MusicOnHold upgrade introduces two new variables:
1. mohinterpret
2. mohsuggest
2. agents.conf
o multiplelogin variable added
o maxlogintries variable added
o autologoffunavail variable added
o endcall variable added
o goodbye variable added
o createlink variable REMOVED
3. alsa.conf
o mohinterpret variable added
o Jitterbuffer variables added
4. cdr.conf
o endbeforehexten variable added
o sections for csv and radius added, with variables usegmtime, loguniqueid,
loguserfield, and radiuscfg variables.
5. cdr_tds.conf
o table variable added
6. extensions.ael
o Many upgrades. See the info at http://www.voip-info.org/wiki/view/Asterisk+AEL2
7. extensions.conf
o autofallthru now set to "yes" by default
o userscontext variable added
o added info/examples on paging and hints.
8. features.conf
o parkedplay variable added (who to beep at)
o parkedmusicclass
o atxfernoanswertimeout variable added
o parkcall variable added (one step parking)
o improved documentation for dynamic feature declarations!
o added parkedcallltransfers option to control builtin transfers with parking
o added parkedcallparking option to control one touch parking w/ parking pickup
o added parkedcallhangup option to control disconnect feature w/ parking pickup
o added parkedcallrecording option to control one-touch record w/ parking pickup
o added BRIDGE_FEATURES variable to set available features for a channel
9. iax.conf
o adsi variable added
o mohinterpret variable added
o mohsuggest variable added
o jitterbuffer updates
o iaxthreadcount variable added
o iaxmaxthreadcount variable added
o the way to specify TOS has changed.
o mailboxdetail variable has been REMOVED.
10. indications.conf
o [bg] entry added (Bulgaria).
o [il] entry added (Israel)
o [in] entry added (India)
o [jp] entry added (Japan)
o [my] entry added (Malaysia)
o [th] entry added (Thailand)
11. manager.conf
o webenabled variable added
o httptimeout variable added
o timestampevents variable added
12. mgcp.conf
o Jitterbuffer support added
13. misdn.conf
o l1watcher_timeout variable added
o pp_l2_check variable added
o echocancelwhenbridged variable added
o echotraining variable added
o max_incoming variable added
o max_outgoing variable added
14. modules.conf
o a comment for preloading res_speech.so is added
o mention of global symbols is removed
o obsolesced entries for chan_modem_* and app_intercom have been removed
15. musiconhold.conf
o the default is now to do native moh from /var/lib/asterisk/moh
16. osp.conf
o authpolicy variable added
17. oss.conf
o debug variable added
o device variable added
o mixer variable added
o boost variable added
o callerid variable added
o autohangup variable added
o queuesize variable added
o frags variable added
o JitterBuffer support
o sections to define alternate sound cards
18. queues.conf
o autofill variable added
o monitor-type variable added
o musiconhold is now musicclass, with a difference in interpretation
o autofill variable added
o autopause variable added
o setinterfacevar variable added
o ringinuse variable added
19. res_odbc.conf
o pooling variable added
20. rpt.conf
o duplex variable added
o tailmessagetime variable added
o tailsquashedtime variable added
o tailmessages variable added
21. rtp.conf
o rtcpinterval varaible added
22. sip.conf
o allowguest variable can't be set to 'osp'
o allowoverlap variable added
o allowtransfer variable added
o limitonpeer variable added
o directrtpsetup variable added
o buggymwi variable added
o ospauth variable REMOVED
o notifyhold variable added
o autoframing variable added
o tos variable REMOVED
o tos_sip variable added
o tos_audio variable added
o tos_video variable added
o minexpiry variable added
o t1min variable added
o musicclass variable REMOVED
o mohinterpret variable added
o mohsuggest variable added
o allowsubscribe variable added
o videosupport variable added
o maxcallbitrate variable added
o g726nonstandard variable added
o dumphistory variable added
o t38pt_udptl variable added
o t38pt_rtp variable added
o t38pt_tcp variable added
o rfc2833compensate variable added
o matchexterniplocally variable added
o canreinvite variable can also now be set to 'nonat'
o rtsavesysname variable added
o JitterBuffer support added
o t38pt_usertpsource variable added
o regcontext variable can contains multiple contexts separated by an '&'
23. skinny.conf
o port variable renamed to bindport
o JitterBuffer support added
o model variable REMOVED
o mohinterpret variable added
o mohsuggest variable added
o speeddial variable added
o addon variable added
24. voicemail.conf
o userscontext variable added
o smdiport variable added
o attachfmt variable added
o volgain variable added
o tempgreetwarn variable added
25. zapata.conf
o pritimer variable has improved documentation
o New signalling method: fgccama
o New signalling method: fgccamamf
o outsignalling variable added
o distinctiveringaftercid variable added
o cidsignalling now also accepts v23_jp, and smdi
o usesmdi variable added
o smdiport variable added
o mohinterpret variable added
o mohsuggest variable added
o JitterBuffer support added
* Removed Codecs/Channels:
1. codec_g723 was removed because the actual codec implementation it was designed to use is not distributable
2. chan_modem_* and related modules are gone because the kernel support for those interfaces is old, buggy and unsupported
* New Utils:
1. aelparse -- compile .ael files outside of asterisk
* New manager events:
1. OriginateResponse event comes to replace OriginateSuccess and OriginateFailure
* iLBC source code no longer included (see UPGRADE.txt for details)
* New CLI command "pri show version" that shows the current version of libpri
that the library was built against (requires a version of libpri since this API
feature was added).

341
COPYING
View File

@@ -1,341 +0,0 @@
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.

136
CREDITS
View File

@@ -1,6 +1,6 @@
=== DEVELOPMENT SUPPORT ===
We'd like to thank the following companies for helping fund development of
I'd like to thank the following companies for helping fund development of
Asterisk:
Pilosoft, Inc. - for supporting ADSI development in Asterisk
@@ -13,8 +13,6 @@ 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
=== WISHLIST CONTRIBUTERS ===
@@ -27,151 +25,51 @@ Wasim - Hangup detect
* 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 1.0 maintainer and misc. enhancements
russelb@clemson.edu
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@yahoo.com http://www.asterlink.com
Anthony Minessale - Countless big and small fixes, and relentless forward push
anthmct@yahoo.com http://www.asterlink.com
James Golovich - Innumerable contributions
You can find him and asterisk-perl at http://asterisk.gnuinter.net
You can find him and asterisk-perl at http://asterisk.gnuinter.net
Andre Bierwirth - Extension hints and status
Oliver Daudey - ISDN4Linux fixes
Pauline Middelink - ISDN4Linux patches and some general patches.
She can be found at http://www.polyware.nl/~middelink/En/
She can be found at http://www.polyware.nl/~middelink/En/
Jean-Denis Girard - Various contributions from the South Pacific Islands
jd-girard@esoft.pf http://www.esoft.pf
William Jordan / Vonage - MySQL enhancements to Voicemail
jd-girard@esoft.pf http://www.esoft.pf
William Jordan / Vonage - MySQL enhancmenets to Voicemail
wjordan@vonage.com
Jac Kersing - Various fixes
Steven Critchfield - Seek and Trunc functions for playback and recording
critch@basesys.com
critch@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@oa.com.au
format, and various fixes. Can be contacted at mahmut@oa.com.au
James Dennis - Cisco SIP compatibility patches to work with SIP service
providers. Can be contacted at asterisk@jdennis.net
Tilghman Lesher - ast_localtime(); ast_say_date_with_format();
GotoIfTime, Random, SayUnixTime, HasNewVoicemail applications;
CUT, SORT, EVAL, CURL, FIELDQTY, STRFTIME, QUEUEAGENT* functions;
and other innumerable bug fixes. http://asterisk.drunkcoder.com/
providers. Can be contacted at asterisk@jdennis.net
Tilghman Lesher - - Route lookup code; ast_localtime(), ast_say_date_with_format();
GotoIfTime, Random, SayUnixTime, HasNewVoicemail, and Cut applications,
along with various other patches. http://asterisk.drunkcoder.com/
Jayson Vantuyl - Manager protocol changes, various other bugs.
jvantuyl@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@sigmasoft.com
dialplan include verification, route lookup on OpenBSD, various other
bugs. tholo@sigmasoft.com
Brian West - ODBC support and Bug Marshaling
Josh Roberson - chan_zap reload support, Advanced Voicemail Features, other misc. patches,
and Bug Marshalling. - josh@asteriasgi.com, http://www.asteriasgi.com
William Waites - syslog support, SIP NAT traversal for SIP-UA. ww@styx.org
Rich Murphey - Porting to FreeBSD, NetBSD, OpenBSD, and Darwin.
rich@whiteoaklabs.com http://whiteoaklabs.com
Simon Lockhart - Porting to Solaris (based on work of Logan ???)
simon@slimey.org
Olle E. Johansson - SIP RFC compliance, documentation and testing, testing, testing
oej@edvina.net, http://edvina.net
Steve Kann - new jitter buffer for IAX2
stevek@stevek.com
Constantine Filin - major contributions to the Asterisk Realtime Architecture
Steve Murphy - privacy support, $[ ] parser upgrade, AEL2 parser upgrade
Claude Patry - bug fixes, feature enhancements, and bug marshalling
cpatry@gmail.com
Miroslav Nachev, miro@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@securax.be
Roy Sigurd Karlsbakk - providing funding for generic jitterbuffer development
roy@karlsbakk.net, Briiz Telecom AS
Voop A/S, Nuvio Inc, Inotel S.A and Foniris Telecom A/S - funding for rewrite of SIP transfers
Philippe Sultan - RADIUS CDR module
INRIA, http://www.inria.fr/
John Martin, Aupix - Improved video support in the SIP channel
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@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@gdspartners.com
Bartosz Supczinski - Support for Polish added by DIR (www.dir.pl) Bartosz.Supczinski@dir.pl
James Rothenberger - Support for IMAP storage integration added by OneBizTone LLC Work funded by University of Pennsylvania jar@onebiztone.com
Paul Cadach - Bringing chan_h323 up to date, bug fixes, and more!
=== 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@clapper.org>
=== HOLD MUSIC ===
Music provided by www.opsound.org
=== 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
I 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,
@@ -196,7 +94,7 @@ And the copyright on the ADPCM source:
Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
Netherlands.
All Rights Reserved
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,

32271
ChangeLog

File diff suppressed because it is too large Load Diff

View File

@@ -2,16 +2,19 @@ A PBX is only really useful if you can get calls into it. Of course, you
can use Asterisk with VoIP calls (SIP, H.323, IAX), but you can also talk
to the real PSTN through various cards.
Supported Hardware is divided into two general groups: DAHDI devices and
non-DAHDI devices. The DAHDI compatible hardware supports pseudo-TDM
conferencing and all call features through chan_dahdi, whereas non-DAHDI
Supported Hardware is divided into two general groups: Zaptel devices and
non-zaptel devices. The Zaptel compatible hardware supports pseudo-TDM
conferencing and all call features through chan_zap, whereas non-zaptel
compatible hardware may have different features.
DAHDI compatible hardware
Zaptel compatible hardware
==========================
-- Digium (Primary author of Asterisk)
http://www.digium.com, http://store.digium.com
http://www.digium.com, http://store.yahoo.com/asteriskpbx
* Wildcard X100P - Single FXO interface connects to Loopstart phone
line
* Wildcard T400P (obsolete) - Quad T1 interface connects to four T1/PRI
interfaces. Supports RBS and PRI voice and PPP, FR, and HDLC data.
@@ -25,13 +28,16 @@ DAHDI compatible hardware
* Wildcard E100P - Single E1 interface connects to a single E1/PRI (or PRA)
interface. Supports PRA/PRI, EuroISDN voice and PPP, FR, HDLC data.
* Wildcard S100U - Single FXS interface connects to a standard analog
telephone.
* Wildcard TDM400P - Quad Modular FXS interface connects to standard
analog telephones.
* Wildcard TE410P - Quad T1/E1 switchable interface. Supports PRI and
RBS signalling, as well as PPP, FR, and HDLC data modes.
Non-DAHDI compatible hardware
Non-zaptel compatible hardware
==============================
-- QuickNet, Inc.
@@ -43,26 +49,16 @@ Non-DAHDI compatible hardware
* Internet LineJack - Single FXS or FXO interface. Supports Linux
telephony interface.
mISDN compatible hardware
=========================
mISDN homepage: http://www.isdn4linux.de/mISDN/
Any adapter with an mISDN driver should be compatible with
chan_misdn. See misdn.txt for information.
-- beroNet
http://www.beronet.com
* BN4S0 - 4 Port BRI card (TE/NT)
* BN8S0 - 8 Port BRI card (TE/NT)
* Billion Card - Single Port BRI card (TE (/NT with crossed cable) )
Miscellaneous other interfaces
==============================
-- ISDN4Linux
http://www.isdn4linux.de/
* Any ISDN terminal adapter supported by isdn4linux should provide
connectivity.
-- ALSA
http://www.alsa-project.org

384
LICENSE
View File

@@ -1,61 +1,341 @@
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. These components are also distributed under the
GPL version 2 as well.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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.
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.
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).
Preamble
Specific permission is also granted to link Asterisk with OpenSSL, OpenH323
and/or the UW IMAP Toolkit and distribute the resulting binary files.
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.
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.
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.
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
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.
If you have any questions regarding our licensing policy, please
contact us:
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.
+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/pbx.digium.com (via IAX2)
licensing@digium.com (via email)
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.
Digium, Inc.
445 Jan Davis Drive
Huntsville, AL 35806
USA
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.

1159
Makefile

File diff suppressed because it is too large Load Diff

View File

@@ -1,112 +0,0 @@
#
# 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
#
ifeq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
_ASTCFLAGS+=${GC_CFLAGS}
endif
ifneq ($(findstring STATIC_BUILD,$(MENUSELECT_CFLAGS)),)
STATIC_BUILD=-static
endif
include $(ASTTOPDIR)/Makefile.rules
comma:=,
$(addsuffix .o,$(C_MODS)): _ASTCFLAGS+=-DAST_MODULE=\"$*\" $(MENUSELECT_OPTS_$*:%=-D%) $(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_INCLUDE))
$(addsuffix .oo,$(CC_MODS)): _ASTCFLAGS+=-DAST_MODULE=\"$*\" $(MENUSELECT_OPTS_$*:%=-D%) $(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_INCLUDE))
$(LOADABLE_MODS:%=%.so): _ASTCFLAGS+=-fPIC
$(LOADABLE_MODS:%=%.so): LIBS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LIB))
$(LOADABLE_MODS:%=%.so): _ASTLDFLAGS+=$(foreach dep,$(MENUSELECT_DEPENDS_$*),$(value $(dep)_LDFLAGS))
$(addsuffix .so,$(filter $(LOADABLE_MODS),$(C_MODS))): %.so: %.o
$(addsuffix .so,$(filter $(LOADABLE_MODS),$(CC_MODS))): %.so: %.oo
modules.link: $(addsuffix .o,$(filter $(EMBEDDED_MODS),$(C_MODS)))
modules.link: $(addsuffix .oo,$(filter $(EMBEDDED_MODS),$(CC_MODS)))
.PHONY: clean uninstall _all moduleinfo makeopts
ifneq ($(LOADABLE_MODS),)
_all: $(LOADABLE_MODS:%=%.so)
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 %.o,$^)); do echo "INPUT (../$${file})" >> $@; done
@for file in $(patsubst %,$(SUBDIR)/%,$(filter-out %.o,$^)); do echo "INPUT (../$${file})" >> $@; done
clean::
rm -f *.so *.o *.oo *.s *.i *.ii
rm -f .*.d
rm -f modules.link
install:: all
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

View File

@@ -1,136 +0,0 @@
#
# Asterisk -- A telephony toolkit for Linux.
#
# Makefile rules
#
# Copyright (C) 2006-2008, Digium, Inc.
#
# Kevin P. Fleming <kpfleming@digium.com>
#
# This program is free software, distributed under the terms of
# the GNU General Public License
#
# 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
# If 'make' decides to create intermediate files to satisfy a build requirement
# (like producing a .i from a .c), we want to keep them, so tell make to keep
# all intermediate files
.SECONDARY:
# extra cflags to build dependencies. Recursively expanded.
MAKE_DEPS=-MD -MT $@ -MF .$(subst /,_,$@).d -MP
ifeq ($(NOISY_BUILD),)
ECHO_PREFIX=@
CMD_PREFIX=@
else
ECHO_PREFIX=@\#
CMD_PREFIX=
endif
OPTIMIZE?=-O6
ifneq ($(findstring darwin,$(OSARCH)),)
ifeq ($(shell /usr/bin/sw_vers -productVersion | cut -c1-4),10.6)
# Snow Leopard has an issue with this optimization flag on large files (like chan_sip)
OPTIMIZE+=-fno-inline-functions
endif
endif
ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),)
_ASTCFLAGS+=$(OPTIMIZE)
else
_ASTCFLAGS+=-O0
endif
# shortcuts for common combinations of flags; these must be recursively expanded so that
# per-target settings will be applied
CC_CFLAGS=$(PTHREAD_CFLAGS) $(_ASTCFLAGS) $(ASTCFLAGS)
CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(_ASTCFLAGS) $(ASTCFLAGS))
ifeq ($(GNU_LD),1)
SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(if $(wildcard $(subst .so,.exports,$@)),$(subst .so,.exports,$@),$(ASTTOPDIR)/default.exports)
endif
CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS) $(ASTLDFLAGS)
CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS) $(ASTLDFLAGS)
CC_LIBS=$(PTHREAD_LIBS) $(LIBS)
CXX_LIBS=$(PTHREAD_LIBS) $(LIBS)
# determine whether to double-compile so that the optimizer can report code path problems
# this is only done when developer mode and DONT_OPTIMIZE are both enabled
# in that case, we run the preprocessor to produce a .i or .ii file from the source
# code, then compile once with optimizer enabled (and the output to /dev/null),
# and if that doesn't fail then compile again with optimizer disabled
ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS))$(AST_DEVMODE),DONT_OPTIMIZEyes)
COMPILE_DOUBLE=yes
endif
%.o: %.s
$(ECHO_PREFIX) echo " [AS] $< -> $@"
ifeq ($(COMPILE_DOUBLE),yes)
$(CMD_PREFIX) $(CC) -o /dev/null -c $< $(OPTIMIZE) $(CC_CFLAGS)
endif
$(CMD_PREFIX) $(CC) -o $@ -c $< $(CC_CFLAGS)
%.o: %.i
$(ECHO_PREFIX) echo " [CCi] $< -> $@"
ifeq ($(COMPILE_DOUBLE),yes)
$(CMD_PREFIX) $(CC) -o /dev/null -c $< $(OPTIMIZE) $(CC_CFLAGS)
endif
$(CMD_PREFIX) $(CC) -o $@ -c $< $(CC_CFLAGS)
ifneq ($(COMPILE_DOUBLE),yes)
%.o: %.c
$(ECHO_PREFIX) echo " [CC] $< -> $@"
$(CMD_PREFIX) $(CC) -o $@ -c $< $(MAKE_DEPS) $(CC_CFLAGS)
endif
%.i: %.c
$(ECHO_PREFIX) echo " [CPP] $< -> $@"
$(CMD_PREFIX) $(CC) -o $@ -E $< $(MAKE_DEPS) $(CC_CFLAGS)
%.oo: %.ii
$(ECHO_PREFIX) echo " [CXXi] $< -> $@"
ifeq ($(COMPILE_DOUBLE),yes)
$(CMD_PREFIX) $(CXX) -o /dev/null -c $< $(OPTIMIZE) $(CXX_CFLAGS)
endif
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(CXX_CFLAGS)
ifneq ($(COMPILE_DOUBLE),yes)
%.oo: %.cc
$(ECHO_PREFIX) echo " [CXX] $< -> $@"
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(MAKE_DEPS) $(CXX_CFLAGS)
endif
%.ii: %.cc
$(ECHO_PREFIX) echo " [CPP] $< -> $@"
$(CMD_PREFIX) $(CXX) -o $@ -E $< $(MAKE_DEPS) $(CXX_CFLAGS)
%.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 $@ $(CC_LDFLAGS_SO) $^ $(CC_LIBS)
%.so: %.oo
$(ECHO_PREFIX) echo " [LDXX] $^ -> $@"
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(CXX_LDFLAGS_SO) $^ $(CXX_LIBS)
%: %.o
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(_ASTLDFLAGS) $^ $(CXX_LIBS) $(ASTLDFLAGS)
dist-clean:: clean

185
README
View File

@@ -1,17 +1,12 @@
The Asterisk(R) Open Source PBX
The Asterisk Open Source PBX
by Mark Spencer <markster@digium.com>
and the Asterisk.org developer community
Copyright (C) 2001-2009 Digium, Inc.
and other copyright holders.
Copyright (C) 2001-2004 Digium
================================================================
* 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.
the SECURITY file before you attempt to configure an Asterisk server.
* WHAT IS ASTERISK?
* 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
@@ -19,137 +14,95 @@ 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
In addition you'll find lot's 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.
* LICENSING
Asterisk is distributed under GNU General Public License. The GPL also
must apply to all loadable modules as well, except as defined below.
* SUPPORTED OPERATING SYSTEMS
Digium, Inc. (formerly Linux Support Services) retains copyright to all
of the core Asterisk system, and therefore can grant, at its sole discretion,
the ability for companies, individuals, or organizations to create proprietary
or Open Source (but non-GPL'd) modules which may be dynamically linked at
runtime with the portions of Asterisk which fall under our copyright
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 exemption in your GPL'd
products (although if you've written a module for Asterisk we would
strongly encourage you to make the same exemption that we do).
Specific permission is also granted to OpenSSL and OpenH323 to link to
Asterisk.
If you have any questions, whatsoever, regarding our licensing policy,
please contact us.
Modules that are GPL-licensed and not available under Digium's
licensing scheme are added to the Asterisk-addons CVS module.
* REQUIRED COMPONENTS
== 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.
Currently, the Asterisk Open Source PBX is only known to run on the
Linux OS, although it may be portable to other UNIX-like operating systems
(like FreeBSD) as well.
== 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:
First, be sure you've got supported hardware (but note that you don't need ANY hardware, not even a soundcard) to install and run Asterisk. Supported are:
* 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
* Full Duplex Sound Card supported by Linux
* Adtran Atlas 800 Plus
* ISDN4Linux compatible ISDN card
* Tormenta Dual T1 card (www.bsdtelephony.com.mx)
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.
Hint: CAPI compatible ISDN cards can be run using the add-on channel chan_capi.
* UPGRADING FROM AN EARLIER VERSION
So let's proceed:
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.
1) Run "make"
2) Run "make install"
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
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"
"make samples"
Doing so will overwrite any existing config files you have.
Doing so will overwrite any existing config files you have. If you are lacking a soundcard you won't be able to use the DIAL command on the console, though.
Finally, you can launch Asterisk in the foreground mode (not a daemon)
with:
Finally, you can launch Asterisk with:
# asterisk -vvvc
./asterisk -vvvc
You'll see a bunch of verbose messages fly by your screen as Asterisk
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
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
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) than 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
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
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,
@@ -158,12 +111,12 @@ 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 chan_dahdi.conf, one might specify:
Entries of the form 'variable=value' set the value of some parameter in
asterisk. For example, in tormenta.conf, one might specify:
switchtype=national
in order to indicate to Asterisk that the switch they are connecting to is
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:
@@ -174,18 +127,18 @@ configuration file read:
switchtype = dms100
channel => 25-47
the "national" switchtype would be applied to channels one through
Then, 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
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
the channels 25 through 47 of the tormenta 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
Those using SIP phones should be aware the 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
@@ -203,7 +156,7 @@ 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.
@@ -243,20 +196,18 @@ these changes to take effect.
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.
See the doc directory for more documentation.
Finally, you may wish to visit the web site and join the mailing list if
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
http://www.asterisk.org/index.php?menu=support
Welcome to the growing worldwide community of Asterisk users!
Welcome to the growing worldwide community of Asterisk users!
Mark Spencer
----
Asterisk is a trademark belonging to Digium, inc

View File

@@ -1,295 +0,0 @@
==================
| Best Practices |
==================
The purpose of this document is to define best practices when working with
Asterisk in order to minimize possible security breaches and to provide tried
examples in field deployments. This is a living document and is subject to
change over time as best practices are defined.
--------
Sections
--------
* Filtering Data:
How to protect yourself from redial attacks
* Proper Device Naming:
Why to not use numbered extensions for devices
* Secure Passwords:
Secure passwords limit your risk to brute force attacks
* Reducing Pattern Match Typos:
Using the 'same' prefix, or using Goto()
----------------
Additional Links
----------------
Additional links that contain useful information about best practices or
security are listed below.
* Seven Steps to Better SIP Security:
http://blogs.digium.com/2009/03/28/sip-security/
* Asterisk VoIP Security (webinar):
http://www.asterisk.org/security/webinar/
==============
Filtering Data
==============
In the Asterisk dialplan, several channel variables contain data potentially
supplied by outside sources. This could lead to a potential security concern
where those outside sources may send cleverly crafted strings of data which
could be utilized, e.g. to place calls to unexpected locations.
An example of this can be found in the use of pattern matching and the ${EXTEN}
channel variable. Note that ${EXTEN} is not the only system created channel
variable, so it is important to be aware of where the data you're using is
coming from.
For example, this common dialplan takes 2 or more characters of data, starting
with a number 0-9, and then accepts any additional information supplied by the
request.
[NOTE: We use SIP in this example, but is not limited to SIP only; protocols
such as Jabber/XMPP or IAX2 are also susceptible to the same sort of
injection problem.]
[incoming]
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
exten => _X.,n,Dial(SIP/${EXTEN})
exten => _X.,n,Hangup()
This dialplan may be utilized to accept calls to extensions, which then dial a
numbered device name configured in one of the channel configuration files (such
as sip.conf, iax.conf, etc...) (see the section Proper Device Naming for more
information on why this approach is flawed).
The example we've given above looks harmless enough until you take into
consideration that several channel technologies accept characters that could
be utilized in a clever attack. For example, instead of just sending a request
to dial extension 500 (which in our example above would create the string
SIP/500 and is then used by the Dial() application to place a call), someone
could potentially send a string like "500&SIP/itsp/14165551212".
The string "500&SIP/itsp/14165551212" would then be contained within the
${EXTEN} channel variable, which is then utilized by the Dial() application in
our example, thereby giving you the dialplan line of:
exten => _X.,n,Dial(SIP/500&SIP/itsp/14165551212)
Our example above has now provided someone with a method to place calls out of
your ITSP in a place where you didn't expect to allow it. There are a couple of
ways in which you can mitigate this impact: stricter pattern matching, or using
the FILTER() dialplan function.
Strict Pattern Matching
-----------------------
The simple way to mitigate this problem is with a strict pattern match that does
not utilize the period (.) or bang (!) characters to match on one-or-more
characters or zero-or-more characters (respectively). To fine tune our example
to only accept three digit extensions, we could change our pattern match to
be:
exten => _XXX,n,Dial(SIP/${EXTEN})
In this way, we have minimized our impact because we're not allowing anything
other than the numbers zero through nine. But in some cases we really do need to
handle variable pattern matches, such as when dialing international numbers
or when we want to handle something like a SIP URI. In this case, we'll need to
utilize the FILTER() dialplan function.
Using FILTER()
--------------
The FILTER() dialplan function is used to filter strings by only allowing
characters that you have specified. This is a perfect candidate for controlling
which characters you want to pass to the Dial() application, or any other
application which will contain dynamic information passed to Asterisk from an
external source. Lets take a look at how we can use FILTER() to control what
data we allow.
Using our previous example to accept any string length of 2 or more characters,
starting with a number of zero through nine, we can use FILTER() to limit what
we will accept to just numbers. Our example would then change to something like:
[incoming]
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
exten => _X.,n,Dial(SIP/${FILTER(0123456789,${EXTEN})})
exten => _X.,n,Hangup()
Note how we've wrapped the ${EXTEN} channel variable with the FILTER() function
which will then only pass back characters that fit into the numerical range that
we've defined.
Alternatively, if we didn't want to utilize the FILTER() function within the
Dial() application directly, we could save the value to a channel variable,
which has a side effect of being usable in other locations of your dialplan if
necessary, and to handle error checking in a separate location.
[incoming]
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0123456789,${EXTEN})})
exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
exten => _X.,n,Hangup()
Now we can use the ${SAFE_EXTEN} channel variable anywhere throughout the rest
of our dialplan, knowing we've already filtered it. We could also perform an
error check to verify that what we've received in ${EXTEN} also matches the data
passed back by FILTER(), and to fail the call if things do not match.
[incoming]
exten => _X.,1,Verbose(2,Incoming call to extension ${EXTEN})
exten => _X.,n,Set(SAFE_EXTEN=${FILTER(0123456789,${EXTEN})})
exten => _X.,n,GotoIf($[${EXTEN} != ${SAFE_EXTEN}]?error,1)
exten => _X.,n,Dial(SIP/${SAFE_EXTEN})
exten => _X.,n,Hangup()
exten => error,1,Verbose(2,Values of EXTEN and SAFE_EXTEN did not match.)
exten => error,n,Verbose(2,EXTEN: "${EXTEN}" -- SAFE_EXTEN: "${SAFE_EXTEN}")
exten => error,n,Playback(silence/1&invalid)
exten => error,n,Hangup()
Another example would be using FILTER() to control the characters we accept when
we're expecting to get a SIP URI for dialing.
[incoming]
exten => _[0-9a-zA-Z].,1,Verbose(2,Incoming call to extension ${EXTEN})
exten => _[0-9a-zA-Z].,n,Dial(SIP/${FILTER(.@0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,${EXTEN})
exten => _[0-9a-zA-Z].,n,Hangup()
Of course the FILTER() function doesn't check the formatting of the incoming
request. There is also the REGEX() dialplan function which can be used to
determine if the string passed to it matches the regular expression you've
created, and to take proper action on whether it matches or not. The creation of
regular expressions is left as an exercise for the reader.
More information about the FILTER() and REGEX() dialplan functions can be found
by typing "core show function FILTER" and "core show function REGEX" from your
Asterisk console.
====================
Proper Device Naming
====================
In Asterisk, the concept of an extension number being tied to a specific device
does not exist. Asterisk is aware of devices it can call or receive calls from,
and how you define in your dialplan how to reach those devices is up to you.
Because it has become common practice to think of a specific device as having an
extension number associated with it, it only becomes natural to think about
naming your devices the same as the extension number you're providing it. But
by doing this, you're limiting the powerful concept of separating user from
extensions, and extensions from devices.
It can also be a security hazard to name your devices with a number, as this can
open you up to brute force attacks. Many of the current exploits deal with
device configurations which utilize a number, and even worse, a password that
matches the devices name. For example, take a look at this poorly created device
in sip.conf:
[1000]
type=friend
context=international_dialing
secret=1000
As implied by the context, we've permitted a device named 1000 with a password
of 1000 to place calls internationally. If your PBX system is accessible via
the internet, then your system will be vulnerable to expensive international
calls. Even if your system is not accessible via the internet, people within
your organization could get access to dialing rules you'd prefer to reserve only
for certain people.
A more secure example for the device would be to use something like the MAC
address of the device, along with a strong password (see the section Secure
Passwords). The following example would be more secure:
[0004f2040001]
type=friend
context=international_dialing
secret=aE3%B8*$jk^G
Then in your dialplan, you would reference the device via the MAC address of the
device (or if using the softphone, a MAC address of a network interface on the
computer).
Also note that you should NOT use this password, as it will likely be one of the
first ones added to the dictionary for brute force attacks.
================
Secure Passwords
================
Secure passwords are necessary in many (if not all) environments, and Asterisk
is certainly no exception, especially when it comes to expensive long distance
calls that could potentially cost your company hundreds or thousands of dollars
on an expensive monthly phone bill, with little to no recourse to fight the
charges.
Whenever you are positioned to add a password to your system, whether that is
for a device configuration, a database connection, or any other secure
connection, be sure to use a secure password. A good example of a secure
password would be something like:
aE3%B8*$jk^G
Our password also contains 12 characters with a mixture of upper and
lower case characters, numbers, and symbols. Because these passwords are likely
to only be entered once, or loaded via a configuration file, there is
no need to create simple passwords, even in testing. Some of the holes found in
production systems used for exploitations involve finding the one test extension
that contains a weak password that was forgotten prior to putting a system into
production.
Using a web search you can find several online password generators such as
http://www.strongpasswordgenerator.com or there are several scripts that can be
used to generate a strong password.
============================
Reducing Pattern Match Typos
============================
As of Asterisk 1.6.2, a new method for reducing the number of complex pattern
matches you need to enter, which can reduce typos in your dialplan, has been
implemented. Traditionally, a dialplan with a complex pattern match would look
something like:
exten => _[3-5]XXX,1,Verbose(Incoming call to ${EXTEN})
exten => _[3-5]XXX,n,Set(DEVICE=${DB(device/mac_address/${EXTEN})})
exten => _[3-5]XXX,n,Set(TECHNOLOGY=${DB(device/technology/${EXTEN})})
exten => _[3-5]XXX,n,GotoIf($[${ISNULL(${TECHNOLOGY})} | ${ISNULL(${DEVICE})}]?error,1)
exten => _[3-5]XXX,n,Dial(${TECHNOLOGY}/${DEVICE},${GLOBAL(TIMEOUT)})
exten => _[3-5]XXX,n,Set(vmFlag=${IF($[${DIALSTATUS} = BUSY]?b:u)})
exten => _[3-5]XXX,n,Voicemail(${EXTEN}@${GLOBAL(VOICEMAIL_CONTEXT)},${vmFlag})
exten => _[3-5]XXX,n,Hangup()
exten => error,1,Verbose(2,Unable to lookup technology or device for extension)
exten => error,n,Playback(silence/1&num-not-in-db)
exten => error,n,Hangup()
Of course there exists the possibility for a typo when retyping the pattern
match _[3-5]XXX which will match on extensions 3000 through 5999. We can
minimize this error by utilizing the same => prefix on all lines beyond the
first one. Our same dialplan with using same => would look like the following:
exten => _[3-5]XXX,1,Verbose(Incoming call to ${EXTEN})
same => n,Set(DEVICE=${DB(device/mac_address/${EXTEN})})
same => n,Set(TECHNOLOGY=${DB(device/technology/${EXTEN})})
same => n,GotoIf($[${ISNULL(${TECHNOLOGY})} | ${ISNULL(${DEVICE})}]?error,1)
same => n,Dial(${TECHNOLOGY}/${DEVICE},${GLOBAL(TIMEOUT)})
same => n,Set(vmFlag=${IF($[${DIALSTATUS} = BUSY]?b:u)})
same => n,Voicemail(${EXTEN}@${GLOBAL(VOICEMAIL_CONTEXT)},${vmFlag})
same => n,Hangup()
exten => error,1,Verbose(2,Unable to lookup technology or device for extension)
same => n,Playback(silence/1&num-not-in-db)
same => n,Hangup()

22
README.opsound Normal file
View File

@@ -0,0 +1,22 @@
About Hold Music
================
These files were obtained from http://opsound.org, where the authors placed them
under the Creative Commons Attribution-Share Alike 2.5 license, a copy of which
may be found at http://creativecommons.org.
Credits
================
macroform-cold_day - Paul Shuler (Macroform)
paulshuler@gmail.com - http://macroform.bandcamp.com/
macroform-robot_dity - Paul Shuler (Macroform)
paulshuler@gmail.com - http://macroform.bandcamp.com/
macroform-the_simplicity - Paul Shuler (Macroform)
paulshuler@gmail.com - http://macroform.bandcamp.com/
manolo_camp-morning_coffee - Manolo Camp
beatbastard@gmx.net - http://ccmixter.org/people/ManoloCamp
reno_project-system - Reno Project
renoproject@hotmail.com - http://www.jamendo.com/en/album/23661

41
SECURITY Normal file
View File

@@ -0,0 +1,41 @@
==== Security Notes with Asterisk ====
PLEASE READ THE FOLLOWING IMPORTANT SECURITY RELATED INFORMATION.
IMPROPER CONFIGURATION OF ASTERISK COULD ALLOW UNAUTHORIZED USE OF YOUR
FACILITIES, POTENTIALLY INCURRING SUBSTANTIAL CHARGES.
First and foremost remember this:
USE THE EXTENSION CONTEXTS TO ISOLATE OUTGOING OR TOLL SERVICES FROM ANY
INCOMING CONNECTIONS.
You should consider that if any channel, incoming line, etc can enter an
extension context that it has the capability of accessing any extension
within that context.
Therefore, you should NOT allow access to outgoing or toll services in
contexts that are accessible (especially without a password) from incoming
channels, be they IAX channels, FX or other trunks, or even untrusted
stations within you network. In particular, never ever put outgoing toll
services in the "default" context. To make things easier, you can include
the "default" context within other private contexts by using:
include => default
in the appropriate section. A well designed PBX might look like this:
[longdistance]
exten => _91NXXNXXXXXX,1,Dial(Zap/g2/${EXTEN:1})
include => local
[local]
exten => _9NXXNXXX,1,Dial(Zap/g2/${EXTEN:1})
include => default
[default]
exten => 6123,Dial(Zap/1)
DON'T FORGET TO TAKE THE DEMO CONTEXT OUT OF YOUR DEFAULT CONTEXT. There
isn't really a security reason, it just will keep people from wanting to
play with your asterisk setup remotely.

View File

@@ -1,210 +0,0 @@
=========================================================
=== Information for upgrading from Asterisk 1.0 to 1.2
===
===
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
=== UPGRADE.txt -- Upgrade info for 1.2 to 1.4
=========================================================
Compiling:
* The Asterisk 1.2 source code now uses C language features
supported only by 'modern' C compilers. Generally, this means GCC
version 3.0 or higher, although some GCC 2.96 releases will also
work. Some non-GCC compilers that support C99 and the common GCC
extensions (including anonymous structures and unions) will also
work. All releases of GCC 2.95 do _not_ have the requisite feature
support; systems using that compiler will need to be upgraded to
a more recent compiler release.
Dialplan Expressions:
* The dialplan expression parser (which handles $[ ... ] constructs)
has gone through a major upgrade, but has one incompatible change:
spaces are no longer required around expression operators, including
string comparisons. However, you can now use quoting to keep strings
together for comparison. For more details, please read the
doc/README.variables file, and check over your dialplan for possible
problems.
Agents:
* The default for ackcall has been changed to "no" instead of "yes"
because of a bug which caused the "yes" behavior to generally act like
"no". You may need to adjust the value if your agents behave
differently than you expect with respect to acknowledgement.
* The AgentCallBackLogin application now requires a second '|' before
specifying an extension@context. This is to distinguish the options
string from the extension, so that they do not conflict. See
'show application AgentCallbackLogin' for more details.
Parking:
* Parking behavior has changed slightly; when a parked call times out,
Asterisk will attempt to deliver the call back to the extension that
parked it, rather than the 's' extension. If that extension is busy
or unavailable, the parked call will be lost.
Dialing:
* The Caller*ID of the outbound leg is now the extension that was
called, rather than the Caller*ID of the inbound leg of the call. The
"o" flag for Dial can be used to restore the original behavior if
desired. Note that if you are looking for the originating callerid
from the manager event, there is a new manager event "Dial" which
provides the source and destination channels and callerid.
IAX:
* The naming convention for IAX channels has changed in two ways:
1. The call number follows a "-" rather than a "/" character.
2. The name of the channel has been simplified to IAX2/peer-callno,
rather than IAX2/peer@peer-callno or even IAX2/peer@peer/callno.
SIP:
* The global option "port" in 1.0.X that is used to set which port to
bind to has been changed to "bindport" to be more consistent with
the other channel drivers and to avoid confusion with the "port"
option for users/peers.
* The "Registry" event now uses "Username" rather than "User" for
consistency with IAX.
Applications:
* With the addition of dialplan functions (which operate similarly
to variables), the SetVar application has been renamed to Set.
* The CallerPres application has been removed. Use SetCallerPres
instead. It accepts both numeric and symbolic names.
* The applications GetGroupCount, GetGroupMatchCount, SetGroup, and
CheckGroup have been deprecated in favor of functions. Here is a
table of their replacements:
GetGroupCount([groupname][@category] GROUP_COUNT([groupname][@category]) Set(GROUPCOUNT=${GROUP_COUNT()})
GroupMatchCount(groupmatch[@category]) GROUP_MATCH_COUNT(groupmatch[@category]) Set(GROUPCOUNT=${GROUP_MATCH_COUNT(SIP/.*)})
SetGroup(groupname[@category]) GROUP([category])=groupname Set(GROUP()=test)
CheckGroup(max[@category]) N/A GotoIf($[ ${GROUP_COUNT()} > 5 ]?103)
Note that CheckGroup does not have a direct replacement. There is
also a new function called GROUP_LIST() which will return a space
separated list of all of the groups set on a channel. The GROUP()
function can also return the name of the group set on a channel when
used in a read environment.
* The applications DBGet and DBPut have been deprecated in favor of
functions. Here is a table of their replacements:
DBGet(foo=family/key) Set(foo=${DB(family/key)})
DBPut(family/key=${foo}) Set(DB(family/key)=${foo})
* The application SetLanguage has been deprecated in favor of the
function LANGUAGE().
SetLanguage(fr) Set(LANGUAGE()=fr)
The LANGUAGE function can also return the currently set language:
Set(MYLANG=${LANGUAGE()})
* The applications AbsoluteTimeout, DigitTimeout, and ResponseTimeout
have been deprecated in favor of the function TIMEOUT(timeouttype):
AbsoluteTimeout(300) Set(TIMEOUT(absolute)=300)
DigitTimeout(15) Set(TIMEOUT(digit)=15)
ResponseTimeout(15) Set(TIMEOUT(response)=15)
The TIMEOUT() function can also return the currently set timeouts:
Set(DTIMEOUT=${TIMEOUT(digit)})
* The applications SetCIDName, SetCIDNum, and SetRDNIS have been
deprecated in favor of the CALLERID(datatype) function:
SetCIDName(Joe Cool) Set(CALLERID(name)=Joe Cool)
SetCIDNum(2025551212) Set(CALLERID(number)=2025551212)
SetRDNIS(2024561414) Set(CALLERID(RDNIS)=2024561414)
* The application Record now uses the period to separate the filename
from the format, rather than the colon.
* The application VoiceMail now supports a 'temporary' greeting for each
mailbox. This greeting can be recorded by using option 4 in the
'mailbox options' menu, and 'change your password' option has been
moved to option 5.
* The application VoiceMailMain now only matches the 'default' context if
none is specified in the arguments. (This was the previously
documented behavior, however, we didn't follow that behavior.) The old
behavior can be restored by setting searchcontexts=yes in voicemail.conf.
Queues:
* A queue is now considered empty not only if there are no members but if
none of the members are available (e.g. agents not logged on). To
restore the original behavior, use "leavewhenempty=strict" or
"joinwhenempty=strict" instead of "=yes" for those options.
* It is now possible to use multi-digit extensions in the exit context
for a queue (although you should not have overlapping extensions,
as there is no digit timeout). This means that the EXITWITHKEY event
in queue_log can now contain a key field with more than a single
character in it.
Extensions:
* By default, there is a new option called "autofallthrough" in
extensions.conf that is set to yes. Asterisk 1.0 (and earlier)
behavior was to wait for an extension to be dialed after there were no
more extensions to execute. "autofallthrough" changes this behavior
so that the call will immediately be terminated with BUSY,
CONGESTION, or HANGUP based on Asterisk's best guess. If you are
writing an extension for IVR, you must use the WaitExten application
if "autofallthrough" is set to yes.
AGI:
* AGI scripts did not always get SIGHUP at the end, previously. That
behavior has been fixed. If you do not want your script to terminate
at the end of AGI being called (e.g. on a hangup) then set SIGHUP to
be ignored within your application.
* CallerID is reported with agi_callerid and agi_calleridname instead
of a single parameter holding both.
Music On Hold:
* The preferred format for musiconhold.conf has changed; please see the
sample configuration file for the new format. The existing format
is still supported but will generate warnings when the module is loaded.
chan_modem:
* All the chan_modem channel drivers (aopen, bestdata and i4l) are deprecated
in this release, and will be removed in the next major Asterisk release.
Please migrate to chan_misdn for ISDN interfaces; there is no upgrade
path for aopen and bestdata modem users.
MeetMe:
* The conference application now allows users to increase/decrease their
speaking volume and listening volume (independently of each other and
other users); the 'admin' and 'user' menus have changed, and new sound
files are included with this release. However, if a user calling in
over a Zaptel channel that does NOT have hardware DTMF detection
increases their speaking volume, it is likely they will no longer be
able to enter/exit the menu or make any further adjustments, as the
software DTMF detector will not be able to recognize the DTMF coming
from their device.
GetVar Manager Action:
* Previously, the behavior of the GetVar manager action reported the value
of a variable in the following manner:
> name: value
This has been changed to a manner similar to the SetVar action and is now
> Variable: name
> Value: value

View File

@@ -1,529 +0,0 @@
=========================================================
=== Information for upgrading from Asterisk 1.2 to 1.4
===
===
=== UPGRADE-1.2.txt -- Upgrade info for 1.0 to 1.2
=== UPGRADE.txt -- Upgrade info for 1.2 to 1.4
=========================================================
IAX2:
* The firmware for the IAXy has been removed from Asterisk. It can be
downloaded from http://downloads.digium.com/pub/iaxy/. To have Asterisk
install the firmware into its proper location, place the firmware in the
contrib/firmware/iax/ directory in the Asterisk source tree before running
"make install".
* There have been some changes to the IAX2 protocol to address the security
concerns documented in the security advisory AST-2009-006. Please see the
IAX2 security document, doc/IAX2-security.pdf, for information regarding
backwards compatibility with versions of Asterisk that do not contain these
changes to IAX2.
Build Process (configure script):
Asterisk now uses an autoconf-generated configuration script to learn how it
should build itself for your system. As it is a standard script, running:
$ ./configure --help
will show you all the options available. This script can be used to tell the
build process what libraries you have on your system (if it cannot find them
automatically), which libraries you wish to have ignored even though they may
be present, etc.
You must run the configure script before Asterisk will build, although it will
attempt to automatically run it for you with no options specified; for most
users, that will result in a similar build to what they would have had before
the configure script was added to the build process (except for having to run
'make' again after the configure script is run). Note that the configure script
does NOT need to be re-run just to rebuild Asterisk; you only need to re-run it
when your system configuration changes or you wish to build Asterisk with
different options.
Build Process (module selection):
The Asterisk source tree now includes a basic module selection and build option
selection tool called 'menuselect'. Run 'make menuselect' to make your choices.
In this tool, you can disable building of modules that you don't care about,
turn on/off global options for the build and see which modules will not
(and cannot) be built because your system does not have the required external
dependencies installed.
The resulting file from menuselect is called 'menuselect.makeopts'. Note that
the resulting menuselect.makeopts file generally contains which modules *not*
to build. The modules listed in this file indicate which modules have unmet
dependencies, a present conflict, or have been disabled by the user in the
menuselect interface. Compiler Flags can also be set in the menuselect
interface. In this case, the resulting file contains which CFLAGS are in use,
not which ones are not in use.
If you would like to save your choices and have them applied against all
builds, the file can be copied to '~/.asterisk.makeopts' or
'/etc/asterisk.makeopts'.
Build Process (Makefile targets):
The 'valgrind' and 'dont-optimize' targets have been removed; their functionality
is available by enabling the DONT_OPTIMIZE setting in the 'Compiler Flags' menu
in the menuselect tool.
It is now possible to run most make targets against a single subdirectory; from
the top level directory, for example, 'make channels' will run 'make all' in the
'channels' subdirectory. This also is true for 'clean', 'distclean' and 'depend'.
Sound (prompt) and Music On Hold files:
Beginning with Asterisk 1.4, the sound files and music on hold files supplied for
use with Asterisk have been replaced with new versions produced from high quality
master recordings, and are available in three languages (English, French and
Spanish) and in five formats (WAV (uncompressed), mu-Law, a-Law, GSM and G.729).
In addition, the music on hold files provided by opsound.org Music are now available
in the same five formats, but no longer available in MP3 format.
The Asterisk 1.4 tarball packages will only include English prompts in GSM format,
(as were supplied with previous releases) and the opsound.org MOH files in WAV format.
All of the other variations can be installed by running 'make menuselect' and
selecting the packages you wish to install; when you run 'make install', those
packages will be downloaded and installed along with the standard files included
in the tarball.
If for some reason you expect to not have Internet access at the time you will be
running 'make install', you can make your package selections using menuselect and
then run 'make sounds' to download (only) the sound packages; this will leave the
sound packages in the 'sounds' subdirectory to be used later during installation.
WARNING: Asterisk 1.4 supports a new layout for sound files in multiple languages;
instead of the alternate-language files being stored in subdirectories underneath
the existing files (for French, that would be digits/fr, letters/fr, phonetic/fr,
etc.) the new layout creates one directory under /var/lib/asterisk/sounds for the
language itself, then places all the sound files for that language under that
directory and its subdirectories. This is the layout that will be created if you
select non-English languages to be installed via menuselect, HOWEVER Asterisk does
not default to this layout and will not find the files in the places it expects them
to be. If you wish to use this layout, make sure you put 'languageprefix=yes' in your
/etc/asterisk/asterisk.conf file, so that Asterisk will know how the files were
installed.
PBX Core:
* The (very old and undocumented) ability to use BYEXTENSION for dialing
instead of ${EXTEN} has been removed.
* Builtin (res_features) transfer functionality attempts to use the context
defined in TRANSFER_CONTEXT variable of the transferer channel first. If
not set, it uses the transferee variable. If not set in any channel, it will
attempt to use the last non macro context. If not possible, it will default
to the current context.
* The autofallthrough setting introduced in Asterisk 1.2 now defaults to 'yes';
if your dialplan relies on the ability to 'run off the end' of an extension
and wait for a new extension without using WaitExten() to accomplish that,
you will need set autofallthrough to 'no' in your extensions.conf file.
Language Support:
* Support for Taiwanese was incorrectly supported with the "tw" language code.
In reality, the "tw" language code is reserved for the Twi language, native
to Ghana. If you were previously using the "tw" language code, you should
switch to using either "zh" (for Mandarin Chinese) or "zh_TW" for Taiwan
specific localizations. Additionally, "mx" should be changed to "es_MX",
Georgian was incorrectly specified as "ge" but should be "ka", and Czech is
"cs", not "cz".
Command Line Interface:
* 'show channels concise', designed to be used by applications that will parse
its output, previously used ':' characters to separate fields. However, some
of those fields can easily contain that character, making the output not
parseable. The delimiter has been changed to '!'.
Applications:
* In previous Asterisk releases, many applications would jump to priority n+101
to indicate some kind of status or error condition. This functionality was
marked deprecated in Asterisk 1.2. An option to disable it was provided with
the default value set to 'on'. The default value for the global priority
jumping option is now 'off'.
* The applications Cut, Sort, DBGet, DBPut, SetCIDNum, SetCIDName, SetRDNIS,
AbsoluteTimeout, DigitTimeout, ResponseTimeout, SetLanguage, GetGroupCount,
and GetGroupMatchCount were all deprecated in version 1.2, and therefore have
been removed in this version. You should use the equivalent dialplan
function in places where you have previously used one of these applications.
* The application SetGlobalVar has been deprecated. You should replace uses
of this application with the following combination of Set and GLOBAL():
Set(GLOBAL(name)=value). You may also access global variables exclusively by
using the GLOBAL() dialplan function, instead of relying on variable
interpolation falling back to globals when no channel variable is set.
* The application SetVar has been renamed to Set. The syntax SetVar was marked
deprecated in version 1.2 and is no longer recognized in this version. The
use of Set with multiple argument pairs has also been deprecated. Please
separate each name/value pair into its own dialplan line.
* app_read has been updated to use the newer options codes, using "skip" or
"noanswer" will not work. Use s or n. Also there is a new feature i, for
using indication tones, so typing in skip would give you unexpected results.
* OSPAuth is added to authenticate OSP tokens in in_bound call setup messages.
* The CONNECT event in the queue_log from app_queue now has a second field
in addition to the holdtime field. It contains the unique ID of the
queue member channel that is taking the call. This is useful when trying
to link recording filenames back to a particular call from the queue.
* The old/current behavior of app_queue has a serial type behavior
in that the queue will make all waiting callers wait in the queue
even if there is more than one available member ready to take
calls until the head caller is connected with the member they
were trying to get to. The next waiting caller in line then
becomes the head caller, and they are then connected with the
next available member and all available members and waiting callers
waits while this happens. This cycle continues until there are
no more available members or waiting callers, whichever comes first.
The new behavior, enabled by setting autofill=yes in queues.conf
either at the [general] level to default for all queues or
to set on a per-queue level, makes sure that when the waiting
callers are connecting with available members in a parallel fashion
until there are no more available members or no more waiting callers,
whichever comes first. This is probably more along the lines of how
one would expect a queue should work and in most cases, you will want
to enable this new behavior. If you do not specify or comment out this
option, it will default to "no" to keep backward compatability with the old
behavior.
* Queues depend on the channel driver reporting the proper state
for each member of the queue. To get proper signalling on
queue members that use the SIP channel driver, you need to
enable a call limit (could be set to a high value so it
is not put into action) and also make sure that both inbound
and outbound calls are accounted for.
Example:
[general]
limitonpeer = yes
[peername]
type=friend
call-limit=10
* The app_queue application now has the ability to use MixMonitor to
record conversations queue members are having with queue callers. Please
see configs/queues.conf.sample for more information on this option.
* The app_queue application strategy called 'roundrobin' has been deprecated
for this release. Users are encouraged to use 'rrmemory' instead, since it
provides more 'true' round-robin call delivery. For the Asterisk 1.6 release,
'rrmemory' will be renamed 'roundrobin'.
* The app_queue application option called 'monitor-join' has been deprecated
for this release. Users are encouraged to use 'monitor-type=mixmonitor' instead,
since it provides the same functionality but is not dependent on soxmix or some
other external program in order to mix the audio.
* app_meetme: The 'm' option (monitor) is renamed to 'l' (listen only), and
the 'm' option now provides the functionality of "initially muted".
In practice, most existing dialplans using the 'm' flag should not notice
any difference, unless the keypad menu is enabled, allowing the user
to unmute themsleves.
* ast_play_and_record would attempt to cancel the recording if a DTMF
'0' was received. This behavior was not documented in most of the
applications that used ast_play_and_record and the return codes from
ast_play_and_record weren't checked for properly.
ast_play_and_record has been changed so that '0' no longer cancels a
recording. If you want to allow DTMF digits to cancel an
in-progress recording use ast_play_and_record_full which allows you
to specify which DTMF digits can be used to accept a recording and
which digits can be used to cancel a recording.
* ast_app_messagecount has been renamed to ast_app_inboxcount. There is now a
new ast_app_messagecount function which takes a single context/mailbox/folder
mailbox specification and returns the message count for that folder only.
This addresses the deficiency of not being able to count the number of
messages in folders other than INBOX and Old.
* The exit behavior of the AGI applications has changed. Previously, when
a connection to an AGI server failed, the application would cause the channel
to immediately stop dialplan execution and hangup. Now, the only time that
the AGI applications will cause the channel to stop dialplan execution is
when the channel itself requests hangup. The AGI applications now set an
AGISTATUS variable which will allow you to find out whether running the AGI
was successful or not.
Previously, there was no way to handle the case where Asterisk was unable to
locally execute an AGI script for some reason. In this case, dialplan
execution will continue as it did before, but the AGISTATUS variable will be
set to "FAILURE".
A locally executed AGI script can now exit with a non-zero exit code and this
failure will be detected by Asterisk. If an AGI script exits with a non-zero
exit code, the AGISTATUS variable will be set to "FAILURE" as opposed to
"SUCCESS".
* app_voicemail: The ODBC_STORAGE capability now requires the extended table format
previously used only by EXTENDED_ODBC_STORAGE. This means that you will need to update
your table format using the schema provided in doc/odbcstorage.txt
* app_waitforsilence: Fixes have been made to this application which changes the
default behavior with how quickly it returns. You can maintain "old-style" behavior
with the addition/use of a third "timeout" parameter.
Please consult the application documentation and make changes to your dialplan
if appropriate.
Manager:
* After executing the 'status' manager action, the "Status" manager events
included the header "CallerID:" which was actually only the CallerID number,
and not the full CallerID string. This header has been renamed to
"CallerIDNum". For compatibility purposes, the CallerID parameter will remain
until after the release of 1.4, when it will be removed. Please use the time
during the 1.4 release to make this transition.
* The AgentConnect event now has an additional field called "BridgedChannel"
which contains the unique ID of the queue member channel that is taking the
call. This is useful when trying to link recording filenames back to
a particular call from the queue.
* app_userevent has been modified to always send Event: UserEvent with the
additional header UserEvent: <userspec>. Also, the Channel and UniqueID
headers are not automatically sent, unless you specify them as separate
arguments. Please see the application help for the new syntax.
* app_meetme: Mute and Unmute events are now reported via the Manager API.
Native Manager API commands MeetMeMute and MeetMeUnmute are provided, which
are easier to use than "Action Command:". The MeetMeStopTalking event has
also been deprecated in favor of the already existing MeetmeTalking event
with a "Status" of "on" or "off" added.
* OriginateFailure and OriginateSuccess events were replaced by event
OriginateResponse with a header named "Response" to indicate success or
failure
Variables:
* The builtin variables ${CALLERID}, ${CALLERIDNAME}, ${CALLERIDNUM},
${CALLERANI}, ${DNID}, ${RDNIS}, ${DATETIME}, ${TIMESTAMP}, ${ACCOUNTCODE},
and ${LANGUAGE} have all been deprecated in favor of their related dialplan
functions. You are encouraged to move towards the associated dialplan
function, as these variables will be removed in a future release.
* The CDR-CSV variables uniqueid, userfield, and basing time on GMT are now
adjustable from cdr.conf, instead of recompiling.
* OSP applications exports several new variables, ${OSPINHANDLE},
${OSPOUTHANDLE}, ${OSPINTOKEN}, ${OSPOUTTOKEN}, ${OSPCALLING},
${OSPINTIMELIMIT}, and ${OSPOUTTIMELIMIT}
* Builtin transfer functionality sets the variable ${TRANSFERERNAME} in the new
created channel. This variables holds the channel name of the transferer.
* The dial plan variable PRI_CAUSE will be removed from future versions
of Asterisk.
It is replaced by adding a cause value to the hangup() application.
Functions:
* The function ${CHECK_MD5()} has been deprecated in favor of using an
expression: $[${MD5(<string>)} = ${saved_md5}].
* The 'builtin' functions that used to be combined in pbx_functions.so are
now built as separate modules. If you are not using 'autoload=yes' in your
modules.conf file then you will need to explicitly load the modules that
contain the functions you want to use.
* The ENUMLOOKUP() function with the 'c' option (for counting the number of
records), but the lookup fails to match any records, the returned value will
now be "0" instead of blank.
* The REALTIME() function is now available in version 1.4 and app_realtime has
been deprecated in favor of the new function. app_realtime will be removed
completely with the version 1.6 release so please take the time between
releases to make any necessary changes
* The QUEUEAGENTCOUNT() function has been deprecated in favor of
QUEUE_MEMBER_COUNT().
The IAX2 channel:
* It is possible that previous configurations depended on the order in which
peers and users were specified in iax.conf for forcing the order in which
chan_iax2 matched against them. This behavior is going away and is considered
deprecated in this version. Avoid having ambiguous peer and user entries and
to make things easy on yourself, always set the "username" option for users
so that the remote end can match on that exactly instead of trying to infer
which user you want based on host.
If you would like to go ahead and use the new behavior which doesn't use the
order in the config file to influence matching order, then change the
MAX_PEER_BUCKETS define in chan_iax2.c to a value greater than one. An
example is provided there. By changing this, you will get *much* better
performance on systems that do a lot of peer and user lookups as they will be
stored in memory in a much more efficient manner.
* The "mailboxdetail" option has been deprecated. Previously, if this option
was not enabled, the 2 byte MSGCOUNT information element would be set to all
1's to indicate there there is some number of messages waiting. With this
option enabled, the number of new messages were placed in one byte and the
number of old messages are placed in the other. This is now the default
(and the only) behavior.
The SIP channel:
* The "incominglimit" setting is replaced by the "call-limit" setting in
sip.conf.
* OSP support code is removed from SIP channel to OSP applications. ospauth
option in sip.conf is removed to osp.conf as authpolicy. allowguest option
in sip.conf cannot be set as osp anymore.
* The Asterisk RTP stack has been changed in regards to RFC2833 reception
and transmission. Packets will now be sent with proper duration instead of all
at once. If you are receiving calls from a pre-1.4 Asterisk installation you
will want to turn on the rfc2833compensate option. Without this option your
DTMF reception may act poorly.
* The $SIPUSERAGENT dialplan variable is deprecated and will be removed
in coming versions of Asterisk. Please use the dialplan function
SIPCHANINFO(useragent) instead.
* The ALERT_INFO dialplan variable is deprecated and will be removed
in coming versions of Asterisk. Please use the dialplan application
sipaddheader() to add the "Alert-Info" header to the outbound invite.
* The "canreinvite" option has changed. canreinvite=yes used to disable
re-invites if you had NAT=yes. In 1.4, you need to set canreinvite=nonat
to disable re-invites when NAT=yes. This is propably what you want.
The settings are now: "yes", "no", "nonat", "update". Please consult
sip.conf.sample for detailed information.
The Zap channel:
* Support for MFC/R2 has been removed, as it has not been functional for some
time and it has no maintainer.
The Agent channel:
* Callback mode (AgentCallbackLogin) is now deprecated, since the entire function
it provided can be done using dialplan logic, without requiring additional
channel and module locks (which frequently caused deadlocks). An example of
how to do this using AEL dialplan is in doc/queues-with-callback-members.txt.
The G726-32 codec:
* It has been determined that previous versions of Asterisk used the wrong codeword
packing order for G726-32 data. This version supports both available packing orders,
and can transcode between them. It also now selects the proper order when
negotiating with a SIP peer based on the codec name supplied in the SDP. However,
there are existing devices that improperly request one order and then use another;
Sipura and Grandstream ATAs are known to do this, and there may be others. To
be able to continue to use these devices with this version of Asterisk and the
G726-32 codec, a configuration parameter called 'g726nonstandard' has been added
to sip.conf, so that Asterisk can use the packing order expected by the device (even
though it requested a different order). In addition, the internal format number for
G726-32 has been changed, and the old number is now assigned to AAL2-G726-32. The
result of this is that this version of Asterisk will be able to interoperate over
IAX2 with older versions of Asterisk, as long as this version is told to allow
'g726aal2' instead of 'g726' as the codec for the call.
Installation:
* On BSD systems, the installation directories have changed to more "FreeBSDish"
directories. On startup, Asterisk will look for the main configuration in
/usr/local/etc/asterisk/asterisk.conf
If you have an old installation, you might want to remove the binaries and
move the configuration files to the new locations. The following directories
are now default:
ASTLIBDIR /usr/local/lib/asterisk
ASTVARLIBDIR /usr/local/share/asterisk
ASTETCDIR /usr/local/etc/asterisk
ASTBINDIR /usr/local/bin/asterisk
ASTSBINDIR /usr/local/sbin/asterisk
Music on Hold:
* The music on hold handling has been changed in some significant ways in hopes
to make it work in a way that is much less confusing to users. Behavior will
not change if the same configuration is used from older versions of Asterisk.
However, there are some new configuration options that will make things work
in a way that makes more sense.
Previously, many of the channel drivers had an option called "musicclass" or
something similar. This option set what music on hold class this channel
would *hear* when put on hold. Some people expected (with good reason) that
this option was to configure what music on hold class to play when putting
the bridged channel on hold. This option has now been deprecated.
Two new music on hold related configuration options for channel drivers have
been introduced. Some channel drivers support both options, some just one,
and some support neither of them. Check the sample configuration files to see
which options apply to which channel driver.
The "mohsuggest" option specifies which music on hold class to suggest to the
bridged channel when putting them on hold. The only way that this class can
be overridden is if the bridged channel has a specific music class set that
was done in the dialplan using Set(CHANNEL(musicclass)=something).
The "mohinterpret" option is similar to the old "musicclass" option. It
specifies which music on hold class this channel would like to listen to when
put on hold. This music class is only effective if this channel has no music
class set on it from the dialplan and the bridged channel putting this one on
hold had no "mohsuggest" setting.
The IAX2 and Zap channel drivers have an additional feature for the
"mohinterpret" option. If this option is set to "passthrough", then these
channel drivers will pass through the HOLD message in signalling instead of
starting music on hold on the channel. An example for how this would be
useful is in an enterprise network of Asterisk servers. When one phone on one
server puts a phone on a different server on hold, the remote server will be
responsible for playing the hold music to its local phone that was put on
hold instead of the far end server across the network playing the music.
CDR Records:
* The behavior of the "clid" field of the CDR has always been that it will
contain the callerid ANI if it is set, or the callerid number if ANI was not
set. When using the "callerid" option for various channel drivers, some
would set ANI and some would not. This has been cleared up so that all
channel drivers set ANI. If you would like to change the callerid number
on the channel from the dialplan and have that change also show up in the
CDR, then you *must* set CALLERID(ANI) as well as CALLERID(num).
* cdr_pgsql now assumes the encoding of strings it is handed are in LATIN9,
which should cover most uses of the extended ASCII set. If your strings
use a different encoding in Asterisk, the "encoding" parameter may be set
to specify the correct character set.
API:
* There are some API functions that were not previously prefixed with the 'ast_'
prefix but now are; these include the ADSI, ODBC and AGI interfaces. If you
have a module that uses the services provided by res_adsi, res_odbc, or
res_agi, you will need to add ast_ prefixes to the functions that you call
from those modules.
Formats:
* format_wav: The GAIN preprocessor definition has been changed from 2 to 0
in Asterisk 1.4. This change was made in response to user complaints of
choppiness or the clipping of loud signal peaks. The GAIN preprocessor
definition will be retained in Asterisk 1.4, but will be removed in a
future release. The use of GAIN for the increasing of voicemail message
volume should use the 'volgain' option in voicemail.conf
iLBC Codec:
* Previously, the Asterisk source code distribution included the iLBC
encoder/decoder source code, from Global IP Solutions
(http://www.gipscorp.com). This code is not licensed for
distribution, and thus has been removed from the Asterisk source
code distribution. If you wish to use codec_ilbc to support iLBC
channels in Asterisk, you can run the contrib/scripts/get_ilbc_source.sh
script to download the source and put it in the proper place in
the Asterisk build tree. Once that is done you can follow your normal
steps of building Asterisk. You will need to run 'menuselect' and enable
the iLBC codec in the 'Codec Translators' category.

View File

@@ -1,105 +0,0 @@
=========================================================
=== Information for upgrading from Zaptel to DAHDI ===
=========================================================
As announced in early 2008, Digium is renaming the Zaptel telephony
interface project to DAHDI (Digium Asterisk Hardware Device Interface)
to accommodate the desires of the owner of the Zaptel trademark for
telephony purposes.
This version of Asterisk can be built using either Zaptel or DAHDI,
and has many changes to make the use of DAHDI as easy as possible for
existing users with dialplans, CDR parsers, AMI applications, and
others that expect Zaptel to be in use.
First, the modules that directly use services from Zaptel/DAHDI have been
renamed; the new names are:
chan_zap.so -> chan_dahdi.so
app_zapbarge.so -> app_dahdibarge.so
app_zapras.so -> app_dahdiras.so
app_zapscan.so -> app_dahdiscan.so
codec_zap.so -> codec_dahdi.so
However, in spite of the file name changes, the channels and
applications provided by these modules can still be used with 'Zap'
style names; see below for more information.
Second, there are have been a number of efforts made to ensure that
existing systems will not have to have any major configuration changes
made solely because Asterisk was built against DAHDI instead of
Zaptel. This includes:
chan_dahdi.so:
This module will determine which channel name ('Zap' or 'DAHDI')
should be used for incoming and outgoing channels based on the
build-time choice of telephony drivers. However, if you wish to
continue using the 'Zap' channel name even though you built Asterisk
against the DAHDI drivers, you can add the following line to the
[options] section of your /etc/asterisk/asterisk.conf file:
dahdichanname = no
All CLI commands that begin with 'zap' are now available as 'dahdi'
commands as well; the 'zap' variants will report that they are
deprecated the first time you use each one in an Asterisk instance,
but they will otherwise operate just as they did in previous versions.
All Asterisk Manager Interface (AMI) actions that begin with 'Zap'
are also available with 'DAHDI' prefixes.
The ZapSendKeypadFacility dialplan application is now available as
DAHDISendKeypadFacility as well; the Zap variant will report a deprecation
warning but will otherwise operate as it did it in previous
versions.
The configuration for the channel driver will be read from
/etc/asterisk/chan_dahdi.conf unless 'dahdichanname' has been set to
'no' in asterisk.conf; if that is done, then the configuration will
be read from /etc/asterisk/zapata.conf, just as it was in previous
versions.
app_dahdibarge.so:
The ZapBarge application is now available as DAHDIBarge as well; the
ZapBarge variant will report a deprecation warning when used, but
will otherwise operate as it did in previous versions. Regardless of
which application name is used, the application will restrict itself
to channels of the proper type, based on the 'dahdichanname' setting
in asterisk.conf.
app_dahdiras.so:
The ZapRAS application is now available as DAHDIRAS as well; the
ZapRAS variant will report a deprecation warning when used, but will
otherwise operate as it did in previous versions. Regardless of
which application name is used, the application will restrict itself
to channels of the proper type, based on the 'dahdichanname' setting
in asterisk.conf.
app_dahdiscan.so:
The ZapScan application is now available as DAHDIScan as well; the
ZapScan variant will report a deprecation warning when used, but will
otherwise operate as it did in previous versions. Regardless of
which application name is used, the application will restrict itself
to channels of the proper type, based on the 'dahdichanname' setting
in asterisk.conf.
app_flash.so:
This application has not had any name changes, but will report its
usage (via 'show application flash') as being for either DAHDI or
Zaptel channels based on the 'dahdichanname' setting in
asterisk.conf.
app_chanspy.so:
This application will transparently create 'DAHDI' or 'Zap' channels
as needed, based on the 'dahdichanname' setting in asterisk.conf.
app_meetme.so:
This application will transparently create 'DAHDI' or 'Zap' channels
as needed, based on the 'dahdichanname' setting in asterisk.conf.

409
acl.c Normal file
View File

@@ -0,0 +1,409 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Various sorts of access control
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <asterisk/acl.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/utils.h>
#include <asterisk/lock.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <sys/ioctl.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
#include <fcntl.h>
#include <net/route.h>
AST_MUTEX_DEFINE_STATIC(routeseq_lock);
#endif
struct ast_ha {
/* Host access rule */
struct in_addr netaddr;
struct in_addr netmask;
int sense;
struct ast_ha *next;
};
/* Default IP - if not otherwise set, don't breathe garbage */
static struct in_addr __ourip = { 0x00000000 };
struct my_ifreq {
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "eth0", "ppp0", etc. */
struct sockaddr_in ifru_addr;
};
/* Free HA structure */
void ast_free_ha(struct ast_ha *ha)
{
struct ast_ha *hal;
while(ha) {
hal = ha;
ha = ha->next;
free(hal);
}
}
/* Copy HA structure */
static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
{
memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
to->sense = from->sense;
}
/* Create duplicate of ha structure */
static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
{
struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
/* Copy from original to new object */
ast_copy_ha(original, new_ha);
return(new_ha);
}
/* Create duplicate HA link list */
/* Used in chan_sip2 templates */
struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
{
struct ast_ha *start=original;
struct ast_ha *ret = NULL;
struct ast_ha *link,*prev=NULL;
while(start) {
link = ast_duplicate_ha(start); /* Create copy of this object */
if (prev)
prev->next = link; /* Link previous to this object */
if (!ret)
ret = link; /* Save starting point */
start = start->next; /* Go to next object */
prev = link; /* Save pointer to this object */
}
return (ret); /* Return start of list */
}
struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
{
struct ast_ha *ha = malloc(sizeof(struct ast_ha));
char *nm="255.255.255.255";
char tmp[256] = "";
struct ast_ha *prev = NULL;
struct ast_ha *ret;
int x,z;
unsigned int y;
ret = path;
while(path) {
prev = path;
path = path->next;
}
if (ha) {
strncpy(tmp, stuff, sizeof(tmp) - 1);
nm = strchr(tmp, '/');
if (!nm)
nm = "255.255.255.255";
else {
*nm = '\0';
nm++;
}
if (!strchr(nm, '.')) {
if ((sscanf(nm, "%i", &x) == 1) && (x >= 0) && (x <= 32)) {
y = 0;
for (z=0;z<x;z++) {
y >>= 1;
y |= 0x80000000;
}
ha->netmask.s_addr = htonl(y);
}
} else if (!inet_aton(nm, &ha->netmask)) {
ast_log(LOG_WARNING, "%s not a valid netmask\n", nm);
free(ha);
return path;
}
if (!inet_aton(tmp, &ha->netaddr)) {
ast_log(LOG_WARNING, "%s not a valid IP\n", tmp);
free(ha);
return path;
}
ha->netaddr.s_addr &= ha->netmask.s_addr;
if (!strncasecmp(sense, "p", 1)) {
ha->sense = AST_SENSE_ALLOW;
} else {
ha->sense = AST_SENSE_DENY;
}
ha->next = NULL;
if (prev)
prev->next = ha;
else
ret = ha;
}
ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n",stuff, nm);
return ret;
}
int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
{
/* Start optimistic */
int res = AST_SENSE_ALLOW;
while(ha) {
char iabuf[INET_ADDRSTRLEN];
char iabuf2[INET_ADDRSTRLEN];
/* DEBUG */
ast_log(LOG_DEBUG,
"##### Testing %s with %s\n",
ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
/* For each rule, if this address and the netmask = the net address
apply the current rule */
if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == (ha->netaddr.s_addr))
res = ha->sense;
ha = ha->next;
}
return res;
}
int ast_get_ip(struct sockaddr_in *sin, char *value)
{
struct hostent *hp;
struct ast_hostent ahp;
hp = ast_gethostbyname(value, &ahp);
if (hp) {
memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
} else {
ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
return -1;
}
return 0;
}
/* iface is the interface (e.g. eth0); address is the return value */
int ast_lookup_iface(char *iface, struct in_addr *address) {
int mysock, res = 0;
struct my_ifreq ifreq;
memset(&ifreq, 0, sizeof(ifreq));
strncpy(ifreq.ifrn_name,iface,sizeof(ifreq.ifrn_name) - 1);
mysock = socket(PF_INET,SOCK_DGRAM,IPPROTO_IP);
res = ioctl(mysock,SIOCGIFADDR,&ifreq);
close(mysock);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
memcpy((char *)address,(char *)&__ourip,sizeof(__ourip));
return -1;
} else {
memcpy((char *)address,(char *)&ifreq.ifru_addr.sin_addr,sizeof(ifreq.ifru_addr.sin_addr));
return 0;
}
}
int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
{
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
struct sockaddr_in *sin;
struct sockaddr *sa;
struct {
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
char iabuf[INET_ADDRSTRLEN];
char *cp, *p;
int i, l, s, seq, flags;
pid_t pid = getpid();
static int routeseq; /* Protected by "routeseq_lock" mutex */
p = ast_strdupa(ast_inet_ntoa(iabuf, sizeof(iabuf), *them));
memset(us, 0, sizeof(struct in_addr));
memset(&m_rtmsg, 0, sizeof(m_rtmsg));
m_rtmsg.m_rtm.rtm_type = RTM_GET;
m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
ast_mutex_lock(&routeseq_lock);
seq = ++routeseq;
ast_mutex_unlock(&routeseq_lock);
m_rtmsg.m_rtm.rtm_seq = seq;
m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_IFA;
m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
sin = (struct sockaddr_in *)m_rtmsg.m_space;
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_addr = *them;
if ((s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) {
ast_log(LOG_ERROR, "Error opening routing socket\n");
return -1;
}
flags = fcntl(s, F_GETFL);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
if (write(s, (char *)&m_rtmsg, m_rtmsg.m_rtm.rtm_msglen) < 0) {
ast_log(LOG_ERROR, "Error writing to routing socket: %s\n", strerror(errno));
close(s);
return -1;
}
do {
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
} while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != seq || m_rtmsg.m_rtm.rtm_pid != pid));
if (l < 0) {
if (errno != EAGAIN)
ast_log(LOG_ERROR, "Error reading from routing socket\n");
close(s);
return -1;
}
close(s);
if (m_rtmsg.m_rtm.rtm_version != RTM_VERSION) {
ast_log(LOG_ERROR, "Unsupported route socket protocol version\n");
return -1;
}
if (m_rtmsg.m_rtm.rtm_msglen != l)
ast_log(LOG_WARNING, "Message length mismatch, in packet %d, returned %d\n",
m_rtmsg.m_rtm.rtm_msglen, l);
if (m_rtmsg.m_rtm.rtm_errno) {
ast_log(LOG_ERROR, "RTM_GET got %s (%d)\n",
strerror(m_rtmsg.m_rtm.rtm_errno), m_rtmsg.m_rtm.rtm_errno);
return -1;
}
cp = (char *)m_rtmsg.m_space;
if (m_rtmsg.m_rtm.rtm_addrs)
for (i = 1; i; i <<= 1)
if (m_rtmsg.m_rtm.rtm_addrs & i) {
sa = (struct sockaddr *)cp;
if (i == RTA_IFA && sa->sa_family == AF_INET) {
sin = (struct sockaddr_in *)sa;
*us = sin->sin_addr;
ast_log(LOG_DEBUG, "Found route to %s, output from our address %s.\n", p, ast_inet_ntoa(iabuf, sizeof(iabuf), *us));
return 0;
}
cp += sa->sa_len > 0 ?
(1 + ((sa->sa_len - 1) | (sizeof(long) - 1))) :
sizeof(long);
}
ast_log(LOG_DEBUG, "No route found for address %s!\n", p);
return -1;
#else
FILE *PROC;
unsigned int remote_ip;
int res = 1;
char line[256];
remote_ip = them->s_addr;
PROC = fopen("/proc/net/route","r");
if (!PROC) {
bzero(us,sizeof(struct in_addr));
return -1;
}
/* First line contains headers */
fgets(line,sizeof(line),PROC);
while (!feof(PROC)) {
char iface[256];
unsigned int dest, gateway, mask;
int i,fieldnum;
char *fields[40];
fgets(line,sizeof(line),PROC);
fieldnum = 0;
for (i=0;i<sizeof(line);i++) {
char *offset;
fields[fieldnum++] = line + i;
offset = strchr(line + i,'\t');
if (offset == NULL) {
/* Exit loop */
break;
} else if (fieldnum >= 9) {
/* Short-circuit: can't break at 8, since the end of field 7 is figured when fieldnum=8 */
break;
} else {
*offset = '\0';
i = offset - line;
}
}
if (fieldnum >= 8) {
sscanf(fields[0],"%s",iface);
sscanf(fields[1],"%x",&dest);
sscanf(fields[2],"%x",&gateway);
sscanf(fields[7],"%x",&mask);
#if 0
{ char iabuf[INET_ADDRSTRLEN];
printf("Addr: %s %08x Dest: %08x Mask: %08x\n", ast_inet_ntoa(iabuf, sizeof(iabuf), *them), remote_ip, dest, mask); }
#endif
/* Looks simple, but here is the magic */
if (((remote_ip & mask) ^ dest) == 0) {
res = ast_lookup_iface(iface,us);
break;
}
}
}
fclose(PROC);
if (res == 1) {
ast_log(LOG_WARNING, "Yikes! No default route?!!\n");
bzero(us,sizeof(struct in_addr));
return -2;
} else if (res) {
/* We've already warned in subroutine */
return -1;
}
return 0;
#endif
}
int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
{
char ourhost[MAXHOSTNAMELEN]="";
struct ast_hostent ahp;
struct hostent *hp;
struct in_addr saddr;
/* just use the bind address if it is nonzero */
if (ntohl(bindaddr.sin_addr.s_addr)) {
memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
return 0;
}
/* try to use our hostname */
if (gethostname(ourhost, sizeof(ourhost)-1)) {
ast_log(LOG_WARNING, "Unable to get hostname\n");
} else {
hp = ast_gethostbyname(ourhost, &ahp);
if (hp) {
memcpy(ourip, hp->h_addr, sizeof(*ourip));
return 0;
}
}
/* A.ROOT-SERVERS.NET. */
if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
return 0;
return -1;
}

View File

@@ -30,18 +30,12 @@
---------------------------------------------------------------------------
Issue Date: 26/08/2003
This file contains the code for implementing encryption and decryption
for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It
can optionally be replaced by code written in assembler using NASM. For
further details see the file aesopt.h
*/
/*! \file
*
* \brief This file contains the code for implementing encryption and decryption
* for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It
* can optionally be replaced by code written in assembler using NASM. For
* further details see the file aesopt.h
*
* \author Dr Brian Gladman <brg@gladman.me.uk>
*/
#include "aesopt.h"
#if defined(__cplusplus)

View File

@@ -30,17 +30,11 @@
---------------------------------------------------------------------------
Issue Date: 26/08/2003
This file contains the code for implementing the key schedule for AES
(Rijndael) for block and key sizes of 16, 24, and 32 bytes. See aesopt.h
for further details including optimisation.
*/
/*! \file
*
* \brief This file contains the code for implementing the key schedule for AES
* (Rijndael) for block and key sizes of 16, 24, and 32 bytes. See aesopt.h
* for further details including optimisation.
*
* \author Dr Brian Gladman <brg@gladman.me.uk>
*/
#include "aesopt.h"
#if defined(__cplusplus)

View File

@@ -135,7 +135,7 @@
#ifndef _AESOPT_H
#define _AESOPT_H
#include "asterisk/aes.h"
#include <asterisk/aes.h>
#include "asterisk/endian.h"
/* CONFIGURATION - USE OF DEFINES
@@ -147,6 +147,7 @@
#if clauses.
*/
/* BYTE ORDER IN 32-BIT WORDS
To obtain the highest speed on processors with 32-bit words, this code

View File

@@ -1,49 +1,43 @@
#
# Asterisk -- A telephony toolkit for Linux.
#
# Makefile for AGI-related stuff
# Makefile for PBX frontends (dynamically loaded)
#
# Copyright (C) 1999-2006, Digium
# Copyright (C) 1999, Mark Spencer
#
# Mark Spencer <markster@digium.com>
# Mark Spencer <markster@linux-support.net>
#
# 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
AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi
CFLAGS+=
ifeq ($(OSARCH),SunOS)
LIBS+=-lsocket -lnsl
endif
include $(ASTTOPDIR)/Makefile.rules
_ASTCFLAGS+=-DSTANDALONE
all: $(AGIS)
strcompat.c: ../main/strcompat.c
@cp $< $@
eagi-test: eagi-test.o strcompat.o
eagi-sphinx-test: eagi-sphinx-test.o
all: depend $(AGIS)
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
eagi-test: eagi-test.o
$(CC) $(CFLAGS) -o eagi-test eagi-test.o
eagi-sphinx-test: eagi-sphinx-test.o
$(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o
clean:
rm -f *.so *.o look eagi-test eagi-sphinx-test
rm -f .*.d *.s *.i
rm -f strcompat.c
rm -f *.so *.o look .depend eagi-test eagi-sphinx-test
ifneq ($(wildcard .*.d),)
include .*.d
%.so : %.o
$(CC) -shared -Xlinker -x -o $@ $<
ifneq ($(wildcard .depend),)
include .depend
endif
depend: .depend
.depend:
../mkdep $(CFLAGS) `ls *.c`

View File

@@ -18,10 +18,6 @@
#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"
@@ -70,9 +66,7 @@ static int read_environment(void)
char *val;
/* Read environment */
for(;;) {
if (!fgets(buf, sizeof(buf), stdin)) {
return -1;
}
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '\0';
@@ -123,9 +117,7 @@ static char *wait_result(void)
return NULL;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
if (!fgets(astresp, sizeof(astresp), stdin)) {
return NULL;
}
fgets(astresp, sizeof(astresp), stdin);
if (feof(stdin)) {
fprintf(stderr, "Got hungup on apparently\n");
return NULL;
@@ -136,10 +128,9 @@ static char *wait_result(void)
}
if (FD_ISSET(AUDIO_FILENO, &fds)) {
res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
if ((res > 0) && (sphinx_sock > -1)) {
if (write(sphinx_sock, audiobuf, res) < 0) {
fprintf(stderr, "write() failed: %s\n", strerror(errno));
}
if (res > 0) {
if (sphinx_sock > -1)
write(sphinx_sock, audiobuf, res);
}
}
if ((sphinx_sock > -1) && FD_ISSET(sphinx_sock, &fds)) {
@@ -214,7 +205,7 @@ int main(int argc, char *argv[])
connect_sphinx();
tmp = getenv("agi_enhanced");
if (tmp) {
if (sscanf(tmp, "%30d.%30d", &ver, &subver) != 2)
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
if (ver < 1) {

View File

@@ -12,10 +12,6 @@
#include <string.h>
#include <sys/select.h>
#include "asterisk.h"
#include "asterisk/compat.h"
#define AUDIO_FILENO (STDERR_FILENO + 1)
static int read_environment(void)
@@ -24,9 +20,7 @@ static int read_environment(void)
char *val;
/* Read environment */
for(;;) {
if (!fgets(buf, sizeof(buf), stdin)) {
return -1;
}
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '\0';
@@ -70,9 +64,7 @@ static char *wait_result(void)
return NULL;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
if (!fgets(astresp, sizeof(astresp), stdin)) {
return NULL;
}
fgets(astresp, sizeof(astresp), stdin);
if (feof(stdin)) {
fprintf(stderr, "Got hungup on apparently\n");
return NULL;
@@ -156,7 +148,7 @@ int main(int argc, char *argv[])
}
tmp = getenv("agi_enhanced");
if (tmp) {
if (sscanf(tmp, "%30d.%30d", &ver, &subver) != 2)
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
if (ver < 1) {

View File

@@ -1,488 +0,0 @@
#!/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;
}
}

View File

@@ -1,33 +1,17 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* u-Law to Signed linear conversion
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief u-Law to Signed linear conversion
*
* \author Mark Spencer <markster@digium.com>
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/alaw.h"
#include <asterisk/alaw.h>
#define AMI_MASK 0x55
@@ -71,7 +55,7 @@ static inline short int alaw2linear (unsigned char alaw)
int seg;
alaw ^= AMI_MASK;
i = ((alaw & 0x0F) << 4) + 8 /* rounding error */;
i = ((alaw & 0x0F) << 4);
seg = (((int) alaw & 0x70) >> 4);
if (seg)
i = (i + 0x100) << (seg - 1);

1020
app.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +1,104 @@
#
# Asterisk -- A telephony toolkit for Linux.
#
# Makefile for PBX applications
# Makefile for PBX frontends (dynamically loaded)
#
# Copyright (C) 1999-2006, Digium, Inc.
# Copyright (C) 1999, Mark Spencer
#
# Mark Spencer <markster@linux-support.net>
#
# This program is free software, distributed under the terms of
# the GNU General Public License
#
-include ../menuselect.makeopts ../menuselect.makedeps
USE_MYSQL_VM_INTERFACE=0
USE_POSTGRES_VM_INTERFACE=0
MENUSELECT_CATEGORY=APPS
MENUSELECT_DESCRIPTION=Applications
#APPS=app_dial.so app_playback.so app_directory.so app_intercom.so app_mp3.so
APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\
app_system.so app_echo.so app_record.so app_image.so app_url.so app_disa.so \
app_qcall.so app_adsiprog.so app_getcpeid.so app_milliwatt.so \
app_zapateller.so app_setcallerid.so app_festival.so \
app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
app_authenticate.so app_softhangup.so app_lookupblacklist.so \
app_waitforring.so app_privacy.so app_db.so app_chanisavail.so \
app_enumlookup.so app_transfer.so app_setcidnum.so app_cdr.so \
app_hasnewvoicemail.so app_sayunixtime.so app_cut.so app_read.so \
app_setcdruserfield.so app_random.so app_ices.so app_eval.so \
app_nbscat.so app_sendtext.so app_exec.so app_sms.so \
app_groupcount.so app_txtcidname.so app_controlplayback.so \
app_talkdetect.so app_alarmreceiver.so app_userevent.so app_verbose.so \
app_test.so app_forkcdr.so
ALL_C_MODS:=$(patsubst %.c,%,$(wildcard app_*.c))
ALL_CC_MODS:=$(patsubst %.cc,%,$(wildcard app_*.cc))
C_MODS:=$(filter-out $(MENUSELECT_APPS),$(ALL_C_MODS))
CC_MODS:=$(filter-out $(MENUSELECT_APPS),$(ALL_CC_MODS))
LOADABLE_MODS:=$(C_MODS) $(CC_MODS)
ifneq ($(findstring apps,$(MENUSELECT_EMBED)),)
EMBEDDED_MODS:=$(LOADABLE_MODS)
LOADABLE_MODS:=
ifneq (${OSARCH},Darwin)
APPS+=app_intercom.so
endif
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)
#APPS+=app_sql_postgres.so
#APPS+=app_sql_odbc.so
#APPS+=app_rpt.so
APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
APPS+=$(shell if [ -f /usr/local/include/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
APPS+=$(shell if [ -f /usr/include/osp/osp.h ]; then echo "app_osplookup.so" ; fi)
CFLAGS+=-fPIC
ifeq ($(USE_POSTGRES_VM_INTERFACE),1)
CFLAGS+=-DUSEPOSTGRESVM
endif
all: _all
ifeq ($(USE_MYSQL_VM_INTERFACE),1)
CFLAGS+=-DUSEMYSQLVM
endif
include $(ASTTOPDIR)/Makefile.moddir_rules
all: $(APPS)
clean:
rm -f *.so *.o look .depend
%.so : %.o
$(CC) $(SOLINK) -o $@ $<
app_rpt.so : app_rpt.o
$(CC) $(SOLINK) -o $@ $< -ltonezone
install: all
for x in $(APPS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done
rm -f $(DESTDIR)$(MODULES_DIR)/app_datetime.so
app_voicemail.so : app_voicemail.o
ifeq ($(USE_MYSQL_VM_INTERFACE),1)
$(CC) $(SOLINK) -o $@ $(MLFLAGS) $< -L/usr/lib/mysql -lmysqlclient -lz
else
ifeq ($(USE_POSTGRES_VM_INTERFACE),1)
$(CC) $(SOLINK) -o $@ $(MLFLAGS) $< -lpq
else
$(CC) $(SOLINK) -o $@ $(MLFLAGS) $<
endif
endif
app_sql_postgres.o: app_sql_postgres.c
$(CC) -pipe -I/usr/local/pgsql/include $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
app_sql_postgres.so: app_sql_postgres.o
$(CC) $(SOLINK) -o $@ $< -L/usr/local/pgsql/lib -lpq
app_sql_odbc.so: app_sql_odbc.o
$(CC) $(SOLINK) -o $@ $< -lodbc
look: look.c
$(CC) -pipe -O6 -g look.c -o look -lncurses
ifneq ($(wildcard .depend),)
include .depend
endif
depend: .depend
.depend:
../mkdep $(CFLAGS) `ls *.c`
env:
env

View File

@@ -1,39 +1,26 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Program Asterisk ADSI Scripts into phone
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \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 <sys/types.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/adsi.h>
#include <asterisk/options.h>
#include <asterisk/utils.h>
#include <asterisk/lock.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <unistd.h>
@@ -43,15 +30,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <errno.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/adsi.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "../asterisk.h"
#include "../astconf.h"
static char *tdesc = "Asterisk ADSI Programming Application";
static char *app = "ADSIProg";
@@ -60,8 +42,13 @@ 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";
" ADSIProg(script): Programs an ADSI Phone with the given script.\n"
"If none is specified, the default is used. Returns 0 unless CPE\n"
"is hungup.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
struct adsi_event {
int id;
@@ -172,9 +159,9 @@ struct adsi_script {
struct adsi_flag flags[7];
/* Stuff from adsi script */
unsigned char sec[5];
char sec[5];
char desc[19];
unsigned char fdn[5];
char fdn[5];
int ver;
};
@@ -195,7 +182,7 @@ static int process_token(void *out, char *src, int maxlen, int argtype)
if (!(argtype & ARG_NUMBER))
return -1;
/* Octal value */
if (sscanf(src, "%30o", (int *)out) != 1)
if (sscanf(src, "%o", (int *)out) != 1)
return -1;
if (argtype & ARG_STRING) {
/* Convert */
@@ -205,7 +192,7 @@ static int process_token(void *out, char *src, int maxlen, int argtype)
if (!(argtype & ARG_NUMBER))
return -1;
/* Hex value */
if (sscanf(src + 2, "%30x", (unsigned int *)out) != 1)
if (sscanf(src + 2, "%x", (unsigned int *)out) != 1)
return -1;
if (argtype & ARG_STRING) {
/* Convert */
@@ -215,7 +202,7 @@ static int process_token(void *out, char *src, int maxlen, int argtype)
if (!(argtype & ARG_NUMBER))
return -1;
/* Hex value */
if (sscanf(src, "%30d", (int *)out) != 1)
if (sscanf(src, "%d", (int *)out) != 1)
return -1;
if (argtype & ARG_STRING) {
/* Convert */
@@ -413,7 +400,7 @@ static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, ch
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));
strncpy(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname) - 1);
state->flags[state->numflags].id = state->numflags + 1;
state->numflags++;
return &state->flags[state->numflags-1];
@@ -516,7 +503,7 @@ static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name,
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));
strncpy(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname) - 1);
state->keys[state->numkeys].id = state->numkeys + 2;
state->numkeys++;
return &state->keys[state->numkeys-1];
@@ -532,7 +519,7 @@ static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name
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));
strncpy(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname) - 1);
state->subs[state->numsubs].id = state->numsubs;
state->numsubs++;
return &state->subs[state->numsubs-1];
@@ -551,7 +538,7 @@ static struct adsi_state *getstatebyname(struct adsi_script *state, char *name,
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));
strncpy(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname) - 1);
state->states[state->numstates].id = state->numstates + 1;
state->numstates++;
return &state->states[state->numstates-1];
@@ -570,7 +557,7 @@ static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *na
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));
strncpy(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname) - 1);
state->displays[state->numdisplays].id = state->numdisplays + 1;
state->numdisplays++;
return &state->displays[state->numdisplays-1];
@@ -1056,7 +1043,7 @@ static int adsi_process(struct adsi_script *state, char *buf, char *script, int
break;
}
} else {
ast_copy_string(tmp2, tmp, sizeof(tmp2));
strncpy(tmp2, tmp, sizeof(tmp2) - 1);
}
if (strlen(tmp2) > 18) {
ast_log(LOG_WARNING, "Truncating full name to 18 characters at line %d of %s\n", lineno, script);
@@ -1349,7 +1336,7 @@ static struct adsi_script *compile_script(char *script)
int x, err;
struct adsi_script *scr;
if (script[0] == '/')
ast_copy_string(fn, script, sizeof(fn));
strncpy(fn, script, sizeof(fn) - 1);
else
snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, script);
f = fopen(fn, "r");
@@ -1357,16 +1344,17 @@ static struct adsi_script *compile_script(char *script)
ast_log(LOG_WARNING, "Can't open file '%s'\n", fn);
return NULL;
}
if (!(scr = ast_calloc(1, sizeof(*scr)))) {
scr = malloc(sizeof(struct adsi_script));
if (!scr) {
fclose(f);
ast_log(LOG_WARNING, "Out of memory loading script '%s'\n", fn);
return NULL;
}
memset(scr, 0, sizeof(struct adsi_script));
/* Create "main" as first subroutine */
getsubbyname(scr, "main", NULL, 0);
while(!feof(f)) {
if (!fgets(buf, sizeof(buf), f)) {
continue;
}
fgets(buf, sizeof(buf), f);
if (!feof(f)) {
lineno++;
/* Trim off trailing return */
@@ -1437,18 +1425,18 @@ static int adsi_prog(struct ast_channel *chan, char *script)
{
struct adsi_script *scr;
int x;
unsigned char buf[1024];
char buf[1024];
int bytes;
scr = compile_script(script);
if (!scr)
return -1;
/* Start an empty ADSI Session */
if (ast_adsi_load_session(chan, NULL, 0, 1) < 1)
if (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)) {
if (adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
/* User rejected us for some reason */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "User rejected download attempt\n");
@@ -1462,7 +1450,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
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)) {
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
return -1;
}
@@ -1475,7 +1463,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
#endif
}
if (bytes) {
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
return -1;
}
@@ -1486,7 +1474,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
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)) {
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
return -1;
}
@@ -1499,7 +1487,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
#endif
}
if (bytes) {
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
return -1;
}
@@ -1510,7 +1498,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
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)) {
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
return -1;
}
@@ -1523,7 +1511,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
#endif
}
if (bytes) {
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
return -1;
}
@@ -1531,11 +1519,11 @@ static int adsi_prog(struct ast_channel *chan, char *script)
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)
bytes += adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
bytes += adsi_set_line(buf, ADSI_INFO_PAGE, 1);
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
return -1;
if (ast_adsi_end_download(chan)) {
if (adsi_end_download(chan)) {
/* Download failed for some reason */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Download attempt failed\n");
@@ -1544,21 +1532,18 @@ static int adsi_prog(struct ast_channel *chan, char *script)
return -1;
}
free(scr);
ast_adsi_unload_session(chan);
adsi_unload_session(chan);
return 0;
}
static int adsi_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
u = ast_module_user_add(chan);
if (ast_strlen_zero(data))
struct localuser *u;
if (!data || ast_strlen_zero(data))
data = "asterisk.adsi";
if (!ast_adsi_available(chan)) {
LOCAL_USER_ADD(u);
if (!adsi_available(chan)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "ADSI Unavailable on CPE. Not bothering to try.\n");
} else {
@@ -1566,27 +1551,34 @@ static int adsi_exec(struct ast_channel *chan, void *data)
ast_verbose(VERBOSE_PREFIX_3 "ADSI Available on CPE. Attempting Upload.\n");
res = adsi_prog(chan, data);
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
ast_module_user_hangup_all();
res = ast_unregister_application(app);
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, adsi_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk ADSI Programming Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,38 +1,38 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 2004 - 2005 Steve Rodgers
* Central Station Alarm receiver for Ademco Contact ID
*
* Copyright (C) 2004 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>
*
* the GNU General Public License
*
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
*
* Use at your own risk. Please consult the GNU GPL license document included with Asterisk. *
* Use at your own risk. Please consult the GNU GPL license document included with Asterisk details. *
*
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/ulaw.h>
#include <asterisk/options.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 <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -41,23 +41,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <unistd.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/options.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"
@@ -68,19 +51,19 @@ struct event_node{
typedef struct event_node event_node_t;
static char *tdesc = "Alarm Receiver for Asterisk";
static char *app = "AlarmReceiver";
static char *synopsis = "Provide support for receiving alarm reports from a burglar or fire alarm panel";
static char *synopsis = "Provide support for receving 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";
"Alarm receiver application for Asterisk. Only 1 signalling format is supported at this time:\n"
"Ademco Contact ID. This application should be called whenever there is an alarm panel calling in\n"
"to dump its events. The application will handshake with the alarm panel, and receive events,\n"
"validate them, handshake them, and store them until the panel hangs up. Once the panel hangs up,\n"
"the application will run the command line specified by the eventcmd setting in alarmreceiver.conf\n"
"and pipe the events to the standard input of the application. Alarmreceiver.conf also contains settings\n"
"for DTMF timing, and for the loudness of the acknowledgement tones.\n";
/* Config Variables */
@@ -93,10 +76,18 @@ 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";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
/*
* Attempt to access a database variable and increment it,
* provided that the user defined db-family in alarmreceiver.conf
@@ -112,7 +103,7 @@ static void database_increment( char *key )
char value[16];
if (ast_strlen_zero(db_family))
if(!strlen(db_family))
return; /* If not defined, don't do anything */
res = ast_db_get(db_family, key, value, sizeof(value) - 1);
@@ -125,7 +116,7 @@ static void database_increment( char *key )
return;
}
sscanf(value, "%30u", &v);
sscanf(value, "%u", &v);
v++;
if(option_verbose >= 4)
@@ -136,7 +127,7 @@ static void database_increment( char *key )
res = ast_db_put(db_family, key, value);
if((res)&&(option_verbose >= 4))
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error\n");
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error");
return;
}
@@ -206,7 +197,6 @@ static int send_tone_burst(struct ast_channel *chan, float freq, int duration, i
i += wf.datalen / 8;
if (i > duration) {
ast_frfree(f);
break;
}
if (ast_write(chan, &wf)){
@@ -214,7 +204,6 @@ static int send_tone_burst(struct ast_channel *chan, float freq, int duration, i
ast_verbose(VERBOSE_PREFIX_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;
}
}
@@ -224,6 +213,20 @@ static int send_tone_burst(struct ast_channel *chan, float freq, int duration, i
return res;
}
/*
* Return the difference in milliseconds between two timeval structs
*/
static int ms_diff(struct timeval *tv1, struct timeval *tv2){
int ms;
ms = (tv1->tv_sec - tv2->tv_sec) * 1000;
ms += (tv1->tv_usec - tv2->tv_usec) / 1000;
return(ms);
}
/*
* 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
@@ -241,12 +244,14 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
int i = 0;
int r;
struct ast_frame *f;
struct timeval lastdigittime;
struct timeval now, lastdigittime;
lastdigittime = ast_tvnow();
gettimeofday(&lastdigittime,NULL);
for(;;){
gettimeofday(&now,NULL);
/* if outa time, leave */
if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
if (ms_diff(&now,&lastdigittime) >
((i > 0) ? sdto : fdto)){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
@@ -291,7 +296,7 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
if(i >= length)
break;
lastdigittime = ast_tvnow();
gettimeofday(&lastdigittime,NULL);
}
digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
@@ -313,8 +318,8 @@ static int write_metadata( FILE *logfile, char *signalling_type, struct ast_chan
char timestamp[80];
/* Extract the caller ID location */
if (chan->cid.cid_num)
ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
strncpy(workstring, chan->callerid, sizeof(workstring) - 1);
workstring[sizeof(workstring) - 1] = '\0';
ast_callerid_parse(workstring, &cn, &cl);
@@ -389,11 +394,11 @@ static int log_events(struct ast_channel *chan, char *signalling_type, event_no
FILE *logfile;
event_node_t *elp = event;
if (!ast_strlen_zero(event_spool_dir)) {
if(strlen(event_spool_dir)){
/* Make a template */
ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
strncpy(workstring, event_spool_dir, sizeof(workstring) - 1);
strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
/* Make the temporary file */
@@ -513,7 +518,7 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
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;
got_some_digits = (strlen(event)) ? 1 : 0;
ack_retries++;
}
continue;
@@ -549,12 +554,13 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
checksum = checksum % 15;
if (checksum) {
if(checksum){
database_increment("checksum-errors");
if (option_verbose >= 2)
if(option_verbose >= 2){
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Nonzero checksum\n");
ast_log(LOG_DEBUG, "AlarmReceiver: Nonzero checksum\n");
continue;
}
}
/* Check the message type for correctness */
@@ -571,14 +577,20 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
events_received++;
/* Queue the Event */
if (!(enew = ast_calloc(1, sizeof(*enew)))) {
/* Queue the Event */
if((enew = malloc(sizeof(event_node_t))) == NULL){
if(option_verbose >= 1)
ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
res = -1;
break;
break;
}
memset(enew, 0, sizeof(event_node_t));
enew->next = NULL;
ast_copy_string(enew->data, event, sizeof(enew->data));
strncpy(enew->data, event, sizeof(enew->data) - 1);
/*
* Insert event onto end of list
@@ -626,13 +638,13 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
static int alarmreceiver_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
struct localuser *u;
event_node_t *elp, *efree;
char signalling_type[64] = "";
event_node_t *event_head = NULL;
u = ast_module_user_add(chan);
LOCAL_USER_ADD(u);
/* Set write and read formats to ULAW */
@@ -641,19 +653,17 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
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);
ast_module_user_remove(u);
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);
ast_module_user_remove(u);
return -1;
}
/* Set default values for this invokation of the application */
ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
strncpy(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type) - 1);
/* Answer the channel if it is not already */
@@ -666,7 +676,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
res = ast_answer(chan);
if (res) {
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return -1;
}
}
@@ -705,7 +715,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
* Do we exec a command line at the end?
*/
if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
if((!res) && (strlen(event_app)) && (event_head)){
ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
ast_safe_system(event_app);
}
@@ -721,7 +731,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return 0;
}
@@ -733,17 +743,16 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
static int load_config(void)
{
struct ast_config *cfg;
const char *p;
char *p;
/* Read in the config file */
cfg = ast_config_load(ALMRCV_CONFIG);
cfg = ast_load(ALMRCV_CONFIG);
if(!cfg){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
return 0;
}
else{
@@ -751,7 +760,7 @@ static int load_config(void)
p = ast_variable_retrieve(cfg, "general", "eventcmd");
if(p){
ast_copy_string(event_app, p, sizeof(event_app));
strncpy(event_app, p, sizeof(event_app) - 1);
event_app[sizeof(event_app) - 1] = '\0';
}
@@ -791,26 +800,26 @@ static int load_config(void)
p = ast_variable_retrieve(cfg, "general", "eventspooldir");
if(p){
ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
strncpy(event_spool_dir, p, sizeof(event_spool_dir) - 1);
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));
strncpy(time_stamp_format, p, sizeof(time_stamp_format) - 1);
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));
strncpy(db_family, p, sizeof(db_family) - 1);
db_family[sizeof(db_family) - 1] = '\0';
}
ast_config_destroy(cfg);
ast_destroy(cfg);
}
return 1;
return 0;
}
@@ -819,23 +828,31 @@ static int load_config(void)
*/
static int unload_module(void)
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
load_config();
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
if(load_config())
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
else
return AST_MODULE_LOAD_DECLINE;
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");

View File

@@ -1,432 +0,0 @@
/*
* 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.
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/options.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])\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"
"This application sets the following channel variable 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";
#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;
/* Set to the lowest ms value provided in amd.conf or application parameters */
static int dfltMaxWaitTimeForFrame = 50;
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 = 0;
int inInitialSilence = 1;
int inGreeting = 0;
int voiceDuration = 0;
int silenceDuration = 0;
int iTotalTime = 0;
int iWordsCount = 0;
int currentState = STATE_IN_WORD;
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 maxWaitTimeForFrame = dfltMaxWaitTimeForFrame;
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);
);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_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);
} else if (option_debug)
ast_log(LOG_DEBUG, "AMD using the default parameters.\n");
/* Find lowest ms value, that will be max wait time for a frame */
if (maxWaitTimeForFrame > initialSilence)
maxWaitTimeForFrame = initialSilence;
if (maxWaitTimeForFrame > greeting)
maxWaitTimeForFrame = greeting;
if (maxWaitTimeForFrame > afterGreetingSilence)
maxWaitTimeForFrame = afterGreetingSilence;
if (maxWaitTimeForFrame > totalAnalysisTime)
maxWaitTimeForFrame = totalAnalysisTime;
if (maxWaitTimeForFrame > minimumWordLength)
maxWaitTimeForFrame = minimumWordLength;
if (maxWaitTimeForFrame > betweenWordsSilence)
maxWaitTimeForFrame = betweenWordsSilence;
/* Now we're ready to roll! */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
"totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n",
initialSilence, greeting, afterGreetingSilence, totalAnalysisTime,
minimumWordLength, betweenWordsSilence, maximumNumberOfWords, silenceThreshold );
/* 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, 2 * maxWaitTimeForFrame)) > -1) {
/* If we fail to read in a frame, that means they hung up */
if (!(f = ast_read(chan))) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: HANGUP\n");
if (option_debug)
ast_log(LOG_DEBUG, "Got hangup\n");
strcpy(amdStatus, "HANGUP");
res = 1;
break;
}
if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_NULL || f->frametype == AST_FRAME_CNG) {
/* If the total time exceeds the analysis time then give up as we are not too sure */
if (f->frametype == AST_FRAME_VOICE) {
framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
} else {
framelength = 2 * maxWaitTimeForFrame;
}
iTotalTime += framelength;
if (iTotalTime >= totalAnalysisTime) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_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 */
if (f->frametype != AST_FRAME_VOICE)
dspsilence += 2 * maxWaitTimeForFrame;
else {
dspsilence = 0;
ast_dsp_silence(silenceDetector, f, &dspsilence);
}
if (dspsilence > 0) {
silenceDuration = dspsilence;
if (silenceDuration >= betweenWordsSilence) {
if (currentState != STATE_IN_SILENCE ) {
previousState = currentState;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: Changed state to STATE_IN_SILENCE\n");
}
currentState = STATE_IN_SILENCE;
consecutiveVoiceDuration = 0;
}
if (inInitialSilence == 1 && silenceDuration >= initialSilence) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: silenceDuration:%d initialSilence:%d\n",
silenceDuration, initialSilence);
ast_frfree(f);
strcpy(amdStatus , "MACHINE");
sprintf(amdCause , "INITIALSILENCE-%d-%d", silenceDuration, initialSilence);
res = 1;
break;
}
if (silenceDuration >= afterGreetingSilence && inGreeting == 1) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: HUMAN: silenceDuration:%d afterGreetingSilence:%d\n",
silenceDuration, afterGreetingSilence);
ast_frfree(f);
strcpy(amdStatus , "HUMAN");
sprintf(amdCause , "HUMAN-%d-%d", silenceDuration, afterGreetingSilence);
res = 1;
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++;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: Word detected. iWordsCount:%d\n", iWordsCount);
previousState = currentState;
currentState = STATE_IN_WORD;
}
if (iWordsCount >= maximumNumberOfWords) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: iWordsCount:%d\n", iWordsCount);
ast_frfree(f);
strcpy(amdStatus , "MACHINE");
sprintf(amdCause , "MAXWORDS-%d-%d", iWordsCount, maximumNumberOfWords);
res = 1;
break;
}
if (inGreeting == 1 && voiceDuration >= greeting) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: ANSWERING MACHINE: voiceDuration:%d greeting:%d\n", voiceDuration, greeting);
ast_frfree(f);
strcpy(amdStatus , "MACHINE");
sprintf(amdCause , "LONGGREETING-%d-%d", voiceDuration, greeting);
res = 1;
break;
}
if (voiceDuration >= minimumWordLength ) {
silenceDuration = 0;
inInitialSilence = 0;
inGreeting = 1;
}
}
}
ast_frfree(f);
}
if (!res) {
/* It took too long to get a frame back. Giving up. */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_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)
{
struct ast_module_user *u = NULL;
u = ast_module_user_add(chan);
isAnsweringMachine(chan, data);
ast_module_user_remove(u);
return 0;
}
static void load_config(void)
{
struct ast_config *cfg = NULL;
char *cat = NULL;
struct ast_variable *var = NULL;
if (!(cfg = ast_config_load("amd.conf"))) {
ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
return;
}
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 {
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);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
"totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n",
dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold );
return;
}
static int unload_module(void)
{
ast_module_user_hangup_all();
return ast_unregister_application(app);
}
static int load_module(void)
{
load_config();
return ast_register_application(app, amd_exec, synopsis, descrip);
}
static int reload(void)
{
load_config();
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
.load = load_module,
.unload = unload_module,
.reload = reload,
);

View File

@@ -1,254 +1,172 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Execute arbitrary authenticate commands
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \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/logger.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>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.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"
#include "asterisk/options.h"
enum {
OPT_ACCOUNT = (1 << 0),
OPT_DATABASE = (1 << 1),
OPT_JUMP = (1 << 2),
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('j', OPT_JUMP),
AST_APP_OPTION('m', OPT_MULTIPLE),
AST_APP_OPTION('r', OPT_REMOVE),
});
static char *tdesc = "Authentication Application";
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. If the\n"
"passsword is invalid, the 'j' option is specified, and priority n+101 exists,\n"
"dialplan execution will continnue at this location.\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"
" j - Support jumping to n+101 if authentication fails\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"
;
" Authenticate(password[|options]): Requires a user to enter a"
"given password in order to continue execution. If the\n"
"password begins with the '/' character, it is interpreted as\n"
"a file which contains a list of valid passwords (1 per line).\n"
"an optional set of opions may be provided by concatenating any\n"
"of the following letters:\n"
" a - Set account code to the password that is entered\n"
" d - Interpret path as database key, not literal file\n"
" r - Remove database key upon successful entry (valid with 'd' only)\n"
"\n"
"When using a database key, the value associated with the key can be\n"
"anything.\n"
"Returns 0 if the user enters a valid password within three\n"
"tries, or -1 otherwise (or on hangup).\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int auth_exec(struct ast_channel *chan, void *data)
{
int res=0;
int retries;
struct ast_module_user *u;
struct localuser *u;
char password[256]="";
char passwd[256];
char *opts;
char *prompt;
int maxdigits;
char *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)) {
if (!data || ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
return -1;
}
u = ast_module_user_add(chan);
LOCAL_USER_ADD(u);
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
if (res) {
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
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;
}
strncpy(password, data, sizeof(password) - 1);
opts=strchr(password, '|');
if (opts) {
*opts = 0;
opts++;
} else
opts = "";
/* Start asking for password */
prompt = "agent-pass";
for (retries = 0; retries < 3; retries++) {
res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0);
res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
if (res < 0)
break;
res = 0;
if (arglist.password[0] == '/') {
if (ast_test_flag(&flags,OPT_DATABASE)) {
if (password[0] == '/') {
if (strchr(opts, 'd')) {
char tmp[256];
/* Compare against a database key */
if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
if (!ast_db_get(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);
if (strchr(opts, 'r')) {
ast_db_del(password + 1, passwd);
}
break;
}
} else {
/* Compare against a file */
FILE *f;
f = fopen(arglist.password, "r");
f = fopen(password, "r");
if (f) {
char buf[256] = "";
char md5passwd[33] = "";
char *md5secret = NULL;
while (!feof(f)) {
if (!fgets(buf, sizeof(buf), f)) {
continue;
}
if (!ast_strlen_zero(buf)) {
size_t len = strlen(buf);
if (buf[len - 1] == '\n')
buf[len - 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;
}
}
while(!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f) && !ast_strlen_zero(buf)) {
buf[strlen(buf) - 1] = '\0';
if (!ast_strlen_zero(buf) && !strcmp(passwd, 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;
}
}
if (!ast_strlen_zero(buf) && !strcmp(passwd, buf))
break;
} else
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
}
} else {
/* Compare against a fixed password */
if (!strcmp(passwd, arglist.password))
if (!strcmp(passwd, password))
break;
}
prompt="auth-incorrect";
}
if ((retries < 3) && !res) {
if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
if (strchr(opts, 'a'))
ast_cdr_setaccount(chan, passwd);
res = ast_streamfile(chan, "auth-thankyou", chan->language);
if (!res)
res = ast_waitstream(chan, "");
} else {
if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0) {
res = 0;
} else {
if (!ast_streamfile(chan, "vm-goodbye", chan->language))
res = ast_waitstream(chan, "");
res = -1;
}
if (!res)
res = ast_streamfile(chan, "vm-goodbye", chan->language);
if (!res)
res = ast_waitstream(chan, "");
res = -1;
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
ast_module_user_hangup_all();
res = ast_unregister_application(app);
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, auth_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,78 +1,66 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Applictions connected with CDR engine
*
* Copyright (C) 2003, Digium
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Applications connected with CDR engine
*
* Martin Pycko <martinp@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
#include <asterisk/channel.h>
#include <asterisk/module.h>
#include <asterisk/pbx.h>
#include <stdlib.h>
#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
static char *nocdr_descrip =
" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n"
"current call.\n";
static char *tdesc = "Make sure asterisk doesn't save CDR for a certain call";
static char *nocdr_descrip = "NoCDR(): makes sure there won't be any CDR written for a certain call";
static char *nocdr_app = "NoCDR";
static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call";
static char *nocdr_synopsis = "Make sure asterisk doesn't save CDR for a certain call";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int nocdr_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
u = ast_module_user_add(chan);
if (chan->cdr) {
ast_set_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED);
ast_cdr_free(chan->cdr);
chan->cdr = NULL;
}
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(nocdr_app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(nocdr_app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(nocdr_app, nocdr_exec, nocdr_synopsis, nocdr_descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Tell Asterisk to not maintain a CDR for the current call");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,104 +1,69 @@
/*
* 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
* Asterisk -- A telephony toolkit for Linux.
*
* Check if Channel is Available
*
* \brief Check if Channel is Available
*
* \author Mark Spencer <markster@digium.com>
* \author James Golovich <james@gnuinter.net>
* \ingroup applications
* Copyright (C) 2003, Digium
*
* Mark Spencer <markster@digium.com>
* James Golovich <james@gnuinter.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/app.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
#include "asterisk/options.h"
static char *tdesc = "Check if channel is available";
static char *app = "ChanIsAvail";
static char *synopsis = "Check channel availability";
static char *synopsis = "Check if channel is available";
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. Note that the AVAILSTATUS variable is used for both device state\n"
"and cause code. It is therefore possible for it to give a value that may\n"
"indicate a device is available when it is not. It is suggested that the\n"
"AVAILORIGCHAN variable is used instead to see whether a device is available\n"
"or not.\n"
"The following variables will be set by this application:\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"
" Options:\n"
" s - Consider the channel unavailable if the channel is in use at all\n"
" j - Support jumping to priority n+101 if no channel is available\n";
" ChanIsAvail(Technology/resource[&Technology2/resource2...]): \n"
"Checks is any of the requested channels are available. If none\n"
"of the requested channels are available the new priority will be\n"
"n+101 (unless such a priority does not exist or on error, in which\n"
"case ChanIsAvail will return -1).\n"
"If any of the requested channels are available, the next priority will be n+1,\n"
"the channel variable ${AVAILCHAN} will be set to the name of the available channel\n"
"and the ChanIsAvail app will return 0.\n"
"${AVAILORIGCHAN} is the canonical channel name that was used to create the channel.\n"
"${AVAILSTATUS} is the status code for the channel.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int chanavail_exec(struct ast_channel *chan, void *data)
{
int res=-1, inuse=-1, option_state=0, priority_jump=0;
int status;
struct ast_module_user *u;
char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur;
int res=-1;
struct localuser *u;
char info[512], tmp[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)) {
if (!data) {
ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
return -1;
}
LOCAL_USER_ADD(u);
u = ast_module_user_add(chan);
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, 'j'))
priority_jump = 1;
}
peers = args.reqchans;
strncpy(info, (char *)data, sizeof(info)-1);
peers = info;
if (peers) {
cur = peers;
do {
@@ -112,67 +77,61 @@ static int chanavail_exec(struct ast_channel *chan, void *data)
number = strchr(tech, '/');
if (!number) {
ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
ast_module_user_remove(u);
return -1;
}
*number = '\0';
number++;
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))) {
if ((tempchan = ast_request(tech, chan->nativeformats, number))) {
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", "");
if (priority_jump || ast_opt_priority_jumping) {
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
ast_module_user_remove(u);
return -1;
}
}
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority+=100;
else
return -1;
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return 0;
}
static int unload_module(void)
int unload_module(void)
{
int res = 0;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, chanavail_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Check channel availability");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,145 +0,0 @@
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.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"
#include "asterisk/options.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;
struct ast_module_user *u;
char *info, *context, *exten, *priority;
int prio = 1;
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;
}
u = ast_module_user_add(chan);
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;
}
/* Parsed right to left, so standard parsing won't work */
context = strsep(&args.label, "|");
exten = strsep(&args.label, "|");
if (exten) {
priority = strsep(&args.label, "|");
if (!priority) {
priority = exten;
exten = context;
context = NULL;
}
} else {
priority = context;
context = NULL;
}
/* ast_findlabel_extension does not convert numeric priorities; it only does a lookup */
if (!(prio = atoi(priority)) && !(prio = ast_findlabel_extension(chan2, S_OR(context, chan2->context),
S_OR(exten, chan2->exten), priority, chan2->cid.cid_num))) {
ast_log(LOG_WARNING, "'%s' is not a known priority or label\n", priority);
goto chanquit;
}
if (option_debug > 1)
ast_log(LOG_DEBUG, "Attempting async goto (%s) to %s|%s|%d\n", args.channel, S_OR(context, chan2->context), S_OR(exten, chan2->exten), prio);
if (chan2->pbx) {
ast_channel_lock(chan2);
ast_set_flag(chan2, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
ast_channel_unlock(chan2);
}
if (ast_async_goto_if_exists(chan2, S_OR(context, chan2->context), S_OR(exten, chan2->exten), prio))
ast_log(LOG_WARNING, "%s failed for %s\n", app, args.channel);
else
res = 0;
chanquit:
ast_mutex_unlock(&chan2->lock);
quit:
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, asyncgoto_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel Redirect");

View File

@@ -1,887 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
* Copyright (C) 2005 - 2008, 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>
* \author Joshua Colp <jcolp@digium.com>
* \author Russell Bryant <russell@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/features.h"
#include "asterisk/options.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
/* "Zap/pseudo" is ten characters.
* "DAHDI/pseudo" is twelve characters.
*/
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"
" 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'.\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"
;
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"
" 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'.\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"
;
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 */
} 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),
});
static int next_unique_id_to_use = 0;
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, *cur;
ast_audiohook_lock(&csth->spy_audiohook);
if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
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;
for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
if (ast_write(chan, cur)) {
ast_frfree(f);
return -1;
}
if (csth->fd) {
if (write(csth->fd, cur->data, cur->datalen) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
}
}
}
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, const char *spychan_name, struct ast_audiohook *audiohook)
{
int res;
struct ast_channel *peer;
ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
ast_set_flag(audiohook, AST_AUDIOHOOK_TRIGGER_SYNC | AST_AUDIOHOOK_SMALL_QUEUE);
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;
}
struct chanspy_ds {
struct ast_channel *chan;
char unique_id[20];
ast_mutex_t lock;
};
static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
int *volfactor, int fd, const struct ast_flags *flags)
{
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;
struct ast_channel *spyee = NULL;
const char *spyer_name;
ast_channel_lock(chan);
spyer_name = ast_strdupa(chan->name);
ast_channel_unlock(chan);
ast_mutex_lock(&spyee_chanspy_ds->lock);
while ((spyee = spyee_chanspy_ds->chan) && ast_channel_trylock(spyee)) {
/* avoid a deadlock here, just in case spyee is masqueraded and
* chanspy_ds_chan_fixup() is called with the channel locked */
DEADLOCK_AVOIDANCE(&spyee_chanspy_ds->lock);
}
ast_mutex_unlock(&spyee_chanspy_ds->lock);
if (!spyee)
return 0;
/* We now hold the channel lock on spyee */
if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
ast_channel_unlock(spyee);
return 0;
}
name = ast_strdupa(spyee->name);
if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_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, spyer_name, &csth.spy_audiohook)) {
ast_audiohook_destroy(&csth.spy_audiohook);
ast_channel_unlock(spyee);
return 0;
}
if (ast_test_flag(flags, OPTION_WHISPER)) {
ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
start_spying(spyee, spyer_name, &csth.whisper_audiohook);
}
ast_channel_unlock(spyee);
spyee = NULL;
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 (res == '*') {
running = 0;
break;
} else if (res == '#') {
if (!ast_strlen_zero(inp)) {
running = atoi(inp);
break;
}
(*volfactor)++;
if (*volfactor > 4)
*volfactor = -4;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_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;
} else if (res >= '0' && res <= '9') {
inp[x++] = res;
}
}
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);
if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
return running;
}
/*!
* \note This relies on the embedded lock to be recursive, as it may be called
* due to a call to chanspy_ds_free with the lock held there.
*/
static void chanspy_ds_destroy(void *data)
{
struct chanspy_ds *chanspy_ds = data;
/* Setting chan to be NULL is an atomic operation, but we don't want this
* value to change while this lock is held. The lock is held elsewhere
* while it performs non-atomic operations with this channel pointer */
ast_mutex_lock(&chanspy_ds->lock);
chanspy_ds->chan = NULL;
ast_mutex_unlock(&chanspy_ds->lock);
}
static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
{
struct chanspy_ds *chanspy_ds = data;
ast_mutex_lock(&chanspy_ds->lock);
chanspy_ds->chan = new_chan;
ast_mutex_unlock(&chanspy_ds->lock);
}
static const struct ast_datastore_info chanspy_ds_info = {
.type = "chanspy",
.destroy = chanspy_ds_destroy,
.chan_fixup = chanspy_ds_chan_fixup,
};
static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
{
struct ast_channel *chan;
if (!chanspy_ds) {
return NULL;
}
ast_mutex_lock(&chanspy_ds->lock);
while ((chan = chanspy_ds->chan)) {
struct ast_datastore *datastore;
if (ast_channel_trylock(chan)) {
DEADLOCK_AVOIDANCE(&chanspy_ds->lock);
continue;
}
if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
ast_channel_datastore_remove(chan, datastore);
/* chanspy_ds->chan is NULL after this call */
chanspy_ds_destroy(datastore->data);
datastore->data = NULL;
ast_channel_datastore_free(datastore);
}
ast_channel_unlock(chan);
break;
}
ast_mutex_unlock(&chanspy_ds->lock);
return NULL;
}
/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
{
struct ast_datastore *datastore = NULL;
ast_mutex_lock(&chanspy_ds->lock);
if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, chanspy_ds->unique_id))) {
ast_mutex_unlock(&chanspy_ds->lock);
chanspy_ds = chanspy_ds_free(chanspy_ds);
ast_channel_unlock(chan);
return NULL;
}
chanspy_ds->chan = chan;
datastore->data = chanspy_ds;
ast_channel_datastore_add(chan, datastore);
return chanspy_ds;
}
static struct chanspy_ds *next_channel(struct ast_channel *chan,
const struct ast_channel *last, const char *spec,
const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
{
struct ast_channel *this;
char channel_name[AST_CHANNEL_NAME];
static size_t PSEUDO_CHAN_LEN = 0;
if (!PSEUDO_CHAN_LEN) {
PSEUDO_CHAN_LEN = *dahdi_chan_name_len + strlen("/pseudo");
}
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)
return NULL;
snprintf(channel_name, AST_CHANNEL_NAME, "%s/pseudo", dahdi_chan_name);
if (!strncmp(this->name, channel_name, PSEUDO_CHAN_LEN)) {
last = this;
ast_channel_unlock(this);
goto redo;
} else if (this == chan) {
last = this;
ast_channel_unlock(this);
goto redo;
}
return setup_chanspy_ds(this, chanspy_ds);
}
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)
{
char nameprefix[AST_NAME_STRLEN];
char peer_name[AST_NAME_STRLEN + 5];
signed char zero_volume = 0;
int waitms;
int res;
char *ptr;
int num;
int num_spyed_upon = 1;
struct chanspy_ds chanspy_ds = { 0, };
ast_mutex_init(&chanspy_ds.lock);
snprintf(chanspy_ds.unique_id, sizeof(chanspy_ds.unique_id), "%d", ast_atomic_fetchadd_int(&next_unique_id_to_use, +1));
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 (;;) {
struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
struct ast_channel *prev = NULL, *peer = NULL;
if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
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;
}
}
res = ast_waitfordigit(chan, waitms);
if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING);
break;
}
/* reset for the next loop around, unless overridden later */
waitms = 100;
num_spyed_upon = 0;
for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
peer_chanspy_ds;
chanspy_ds_free(peer_chanspy_ds), prev = peer,
peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
const char *group;
int igrp = !mygroup;
char *groups[25];
int num_groups = 0;
char dup_group[512];
int x;
char *s;
peer = peer_chanspy_ds->chan;
ast_mutex_unlock(&peer_chanspy_ds->lock);
if (peer == prev) {
ast_channel_unlock(peer);
chanspy_ds_free(peer_chanspy_ds);
break;
}
if (ast_check_hangup(chan)) {
ast_channel_unlock(peer);
chanspy_ds_free(peer_chanspy_ds);
break;
}
if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
ast_channel_unlock(peer);
continue;
}
if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
ast_channel_unlock(peer);
continue;
}
if (mygroup) {
if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
ast_copy_string(dup_group, group, sizeof(dup_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) {
ast_channel_unlock(peer);
continue;
}
strcpy(peer_name, "spy-");
strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
ptr = strchr(peer_name, '/');
*ptr++ = '\0';
for (s = peer_name; s < ptr; s++)
*s = tolower(*s);
/* We have to unlock the peer channel here to avoid a deadlock.
* So, when we need to dereference it again, we have to lock the
* datastore and get the pointer from there to see if the channel
* is still valid. */
ast_channel_unlock(peer);
if (!ast_test_flag(flags, OPTION_QUIET)) {
if (ast_fileexists(peer_name, NULL, NULL) > 0) {
res = ast_streamfile(chan, peer_name, chan->language);
if (!res)
res = ast_waitstream(chan, "");
if (res) {
chanspy_ds_free(peer_chanspy_ds);
break;
}
} else
res = ast_say_character_str(chan, peer_name, "", chan->language);
if ((num = atoi(ptr)))
ast_say_digits(chan, atoi(ptr), "", chan->language);
}
res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags);
num_spyed_upon++;
if (res == -1) {
chanspy_ds_free(peer_chanspy_ds);
break;
} else if (res > 1 && spec) {
struct ast_channel *next;
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
} else {
/* stay on this channel, if it is still valid */
ast_mutex_lock(&peer_chanspy_ds->lock);
if (peer_chanspy_ds->chan) {
ast_channel_lock(peer_chanspy_ds->chan);
next_chanspy_ds = peer_chanspy_ds;
peer_chanspy_ds = NULL;
} else {
/* the channel is gone */
ast_mutex_unlock(&peer_chanspy_ds->lock);
next_chanspy_ds = NULL;
}
}
peer = NULL;
}
}
if (res == -1 || ast_check_hangup(chan))
break;
}
ast_clear_flag(chan, AST_FLAG_SPYING);
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
ast_mutex_lock(&chanspy_ds.lock);
ast_mutex_unlock(&chanspy_ds.lock);
ast_mutex_destroy(&chanspy_ds.lock);
return res;
}
static int chanspy_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char *options = NULL;
char *spec = NULL;
char *argv[2];
char *mygroup = NULL;
char *recbase = NULL;
int fd = 0;
struct ast_flags flags;
int oldwf = 0;
int argc = 0;
int volfactor = 0;
int res;
data = ast_strdupa(data);
u = ast_module_user_add(chan);
if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
spec = argv[0];
if (argc > 1)
options = argv[1];
if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
spec = NULL;
}
if (options) {
char *opts[OPT_ARG_ARRAY_SIZE];
ast_app_parse_options(spy_opts, &flags, opts, 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], "%30d", &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");
ast_module_user_remove(u);
return -1;
}
if (recbase) {
char filename[PATH_MAX];
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, 0644)) <= 0) {
ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
fd = 0;
}
}
res = common_exec(chan, &flags, volfactor, fd, mygroup, 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");
ast_module_user_remove(u);
return res;
}
static int extenspy_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char *options = NULL;
char *exten = NULL;
char *context = NULL;
char *argv[2];
char *mygroup = NULL;
char *recbase = NULL;
int fd = 0;
struct ast_flags flags;
int oldwf = 0;
int argc = 0;
int volfactor = 0;
int res;
data = ast_strdupa(data);
u = ast_module_user_add(chan);
if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
context = argv[0];
if (!ast_strlen_zero(argv[0]))
exten = strsep(&context, "@");
if (ast_strlen_zero(context))
context = ast_strdupa(chan->context);
if (argc > 1)
options = argv[1];
}
if (options) {
char *opts[OPT_ARG_ARRAY_SIZE];
ast_app_parse_options(spy_opts, &flags, opts, 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], "%30d", &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");
ast_module_user_remove(u);
return -1;
}
if (recbase) {
char filename[PATH_MAX];
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, 0644)) <= 0) {
ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
fd = 0;
}
}
res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
if (fd)
close(fd);
if (oldwf && ast_set_write_format(chan, oldwf) < 0)
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res = 0;
res |= ast_unregister_application(app_chan);
res |= ast_unregister_application(app_ext);
ast_module_user_hangup_all();
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");

View File

@@ -1,168 +1,138 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Trivial application to control playback a sound file
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/app.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
static char *tdesc = "Control Playback Application";
static const char *app = "ControlPlayback";
static char *app = "ControlPlayback";
static const char *synopsis = "Play a file with fast forward and rewind";
static 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"
" j - Jump to priority n+101 if the requested file is not found.\n"
"This application sets the following channel variable upon completion:\n"
" CPLAYBACKSTATUS - This variable contains the status of the attempt as a text\n"
" string, one of: SUCCESS | USERSTOPPED | ERROR\n";
static char *descrip =
"ControlPlayback(filename[|skipms[|ffchar[|rewchar[|stopchar[|pausechr]]]]]):\n"
" Plays back a given filename (do not put extension). Options may also\n"
" be included following a pipe symbol. You can use * and # to rewind and\n"
" fast forward the playback specified. If 'stopchar' is added the file will\n"
" terminate playback when 'stopchar' is pressed. Returns -1 if the channel\n"
" was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
" Example: exten => 1234,1,ControlPlayback(file|4000|*|#|1|0)\n\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int is_on_phonepad(char key)
{
return key == 35 || key == 42 || (key >= 48 && key <= 57);
return (key == 35 || key == 42 || (key >= 48 && key <= 57)) ? 1 : 0;
}
static int controlplayback_exec(struct ast_channel *chan, void *data)
{
int res = 0, priority_jump = 0;
int res = 0;
int skipms = 0;
struct ast_module_user *u;
char *tmp;
int argc;
char *argv[8];
enum arg_ids {
arg_file = 0,
arg_skip = 1,
arg_fwd = 2,
arg_rev = 3,
arg_stop = 4,
arg_pause = 5,
arg_restart = 6,
options = 7,
};
if (ast_strlen_zero(data)) {
struct localuser *u;
char tmp[256];
char *skip = NULL, *fwd = NULL, *rev = NULL, *stop = NULL, *pause = NULL, *file = NULL;
if (!data || ast_strlen_zero((char *)data)) {
ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
tmp = ast_strdupa(data);
memset(argv, 0, sizeof(argv));
strncpy(tmp, (char *)data, sizeof(tmp)-1);
file = tmp;
argc = ast_app_separate_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0]));
if (argc < 1) {
ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
ast_module_user_remove(u);
return -1;
if ((skip=strchr(tmp,'|'))) {
*skip++ = '\0';
fwd=strchr(skip,'|');
if (fwd) {
*fwd++ = '\0';
rev = strchr(fwd,'|');
if (rev) {
*rev++ = '\0';
stop = strchr(rev,'|');
if (stop) {
*stop++ = '\0';
pause = strchr(stop,'|');
if (pause) {
*pause++ = '\0';
}
}
}
}
}
skipms = argv[arg_skip] ? atoi(argv[arg_skip]) : 3000;
skipms = skip ? atoi(skip) : 3000;
if (!skipms)
skipms = 3000;
if (!argv[arg_fwd] || !is_on_phonepad(*argv[arg_fwd]))
argv[arg_fwd] = "#";
if (!argv[arg_rev] || !is_on_phonepad(*argv[arg_rev]))
argv[arg_rev] = "*";
if (argv[arg_stop] && !is_on_phonepad(*argv[arg_stop]))
argv[arg_stop] = NULL;
if (argv[arg_pause] && !is_on_phonepad(*argv[arg_pause]))
argv[arg_pause] = NULL;
if (argv[arg_restart] && !is_on_phonepad(*argv[arg_restart]))
argv[arg_restart] = NULL;
if (!fwd || !is_on_phonepad(*fwd))
fwd = "#";
if (!rev || !is_on_phonepad(*rev))
rev = "*";
if (stop && !is_on_phonepad(*stop))
stop = NULL;
if (pause && !is_on_phonepad(*pause))
pause = NULL;
if (argv[options]) {
if (strchr(argv[options], 'j'))
priority_jump = 1;
}
LOCAL_USER_ADD(u);
res = ast_control_streamfile(chan, argv[arg_file], argv[arg_fwd], argv[arg_rev], argv[arg_stop], argv[arg_pause], argv[arg_restart], skipms);
res = ast_control_streamfile(chan, file, fwd, rev, stop, pause, skipms);
LOCAL_USER_REMOVE(u);
/* If we stopped on one of our stop keys, return 0 */
if (res > 0 && argv[arg_stop] && strchr(argv[arg_stop], res)) {
if(stop && strchr(stop, res))
res = 0;
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
} else {
if (res < 0) {
if (priority_jump || ast_opt_priority_jumping) {
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
ast_log(LOG_WARNING, "ControlPlayback tried to jump to priority n+101 as requested, but priority didn't exist\n");
}
}
res = 0;
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
} else
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, controlplayback_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

198
apps/app_cut.c Normal file
View File

@@ -0,0 +1,198 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Cut application
*
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <app_cut__v003@the-tilghman.com>
*
* $Id$
*
* This code is released by the author with no restrictions on usage.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
/* Maximum length of any variable */
#define MAXRESULT 1024
static char *tdesc = "Cuts up variables";
static char *app_cut = "Cut";
static char *cut_synopsis = "Splits a variable's content using the specified delimiter";
static char *cut_descrip =
"Usage: Cut(newvar=varname,delimiter,fieldspec)\n"
" newvar - new variable created from result string\n"
" varname - variable you want cut\n"
" delimiter - defaults to '-'\n"
" fieldspec - number of the field you want (1-based offset)\n"
" may also be specified as a range (with -)\n"
" or group of ranges and fields (with &)\n"
" Returns 0 or -1 on hangup or error.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int cut_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char *s, *newvar=NULL, *varname=NULL, *delimiter=NULL, *field=NULL;
int args_okay = 0;
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data) {
s = ast_strdupa((char *)data);
if (s) {
newvar = strsep(&s, "=");
if (newvar && (newvar[0] != '\0')) {
varname = strsep(&s, "|");
if (varname && (varname[0] != '\0')) {
delimiter = strsep(&s, "|");
if (delimiter) {
field = strsep(&s, "|");
if (field) {
args_okay = 1;
}
}
}
}
} else {
ast_log(LOG_ERROR, "Out of memory\n");
res = -1;
}
}
if (args_okay) {
char d, ds[2];
char *tmp = alloca(strlen(varname) + 4);
char varvalue[MAXRESULT], *tmp2=varvalue;
char retstring[MAXRESULT];
memset(retstring, 0, MAXRESULT);
if (tmp) {
snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
memset(varvalue, 0, sizeof(varvalue));
} else {
ast_log(LOG_ERROR, "Out of memory");
return -1;
}
if (delimiter[0])
d = delimiter[0];
else
d = '-';
/* String form of the delimiter, for use with strsep(3) */
snprintf(ds, sizeof(ds), "%c", d);
pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
if (tmp2) {
int curfieldnum = 1;
while ((tmp2 != NULL) && (field != NULL)) {
char *nextgroup = strsep(&field, "&");
int num1 = 0, num2 = MAXRESULT;
char trashchar;
if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
/* range with both start and end */
} else if (sscanf(nextgroup, "-%d", &num2) == 1) {
/* range with end */
num1 = 0;
} else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
/* range with start */
num2 = MAXRESULT;
} else if (sscanf(nextgroup, "%d", &num1) == 1) {
/* single number */
num2 = num1;
} else {
ast_log(LOG_ERROR, "Cut(): Illegal range '%s'\n", nextgroup);
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
return -1;
}
/* Get to start, if any */
if (num1 > 0) {
while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
tmp2 = index(tmp2, d) + 1;
curfieldnum++;
}
}
/* Most frequent problem is the expectation of reordering fields */
if ((num1 > 0) && (curfieldnum > num1)) {
ast_log(LOG_WARNING, "Cut(): we're already past the field you wanted?\n");
}
/* Re-null tmp2 if we added 1 to NULL */
if (tmp2 == (char *)NULL + 1)
tmp2 = NULL;
/* Output fields until we either run out of fields or num2 is reached */
while ((tmp2 != NULL) && (curfieldnum <= num2)) {
char *tmp3 = strsep(&tmp2, ds);
int curlen = strlen(retstring);
if (strlen(retstring)) {
snprintf(retstring + curlen, MAXRESULT - curlen, "%c%s", d, tmp3);
} else {
snprintf(retstring, MAXRESULT, "%s", tmp3);
}
curfieldnum++;
}
}
}
pbx_builtin_setvar_helper(chan, newvar, retstring);
}
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app_cut);
}
int load_module(void)
{
return ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,306 +0,0 @@
/*
* 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 an ISDN RAS
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>dahdi</depend>
<depend>working_fork</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/ioctl.h>
#include <sys/wait.h>
#ifdef __linux__
#include <sys/signal.h>
#else
#include <signal.h>
#endif /* __linux__ */
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include "asterisk/dahdi_compat.h"
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
static char *dahdi_app = "DAHDIRAS";
static char *zap_app = "ZapRAS";
static char *dahdi_synopsis = "Executes DAHDI ISDN RAS application";
static char *zap_synopsis = "Executes Zaptel ISDN RAS application";
static char *dahdi_descrip =
" DAHDIRAS(args): Executes a RAS server using pppd on the given channel.\n"
"The channel must be a clear channel (i.e. PRI source) and a DAHDI\n"
"channel to be able to use this function (no modem emulation is included).\n"
"Your pppd must have the DAHDI plugin available. Arguments should be\n"
"separated by | characters.\n";
static char *zap_descrip =
" ZapRAS(args): Executes a RAS server using pppd on the given channel.\n"
"The channel must be a clear channel (i.e. PRI source) and a Zaptel\n"
"channel to be able to use this function (no modem emulation is included).\n"
"Your pppd must have the Zaptel plugin available. Arguments should be\n"
"separated by | characters.\n";
#define PPP_MAX_ARGS 32
#define PPP_EXEC "/usr/sbin/pppd"
static pid_t spawn_ras(struct ast_channel *chan, char *args)
{
pid_t pid;
int x;
char *c;
char *argv[PPP_MAX_ARGS];
int argc = 0;
char *stringp=NULL;
sigset_t fullset, oldset;
#ifdef HAVE_CAP
cap_t cap;
#endif
sigfillset(&fullset);
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
/* Start by forking */
pid = fork();
if (pid) {
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
return pid;
}
#ifdef HAVE_CAP
cap = cap_from_text("cap_net_admin-eip");
if (cap_set_proc(cap)) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
}
cap_free(cap);
#endif
/* Restore original signal handlers */
for (x=0;x<NSIG;x++)
signal(x, SIG_DFL);
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
/* Execute RAS on File handles */
dup2(chan->fds[0], STDIN_FILENO);
/* Drop high priority */
if (ast_opt_high_priority)
ast_set_priority(0);
/* Close other file descriptors */
for (x=STDERR_FILENO + 1;x<1024;x++)
close(x);
/* Reset all arguments */
memset(argv, 0, sizeof(argv));
/* First argument is executable, followed by standard
arguments for DAHDI PPP */
argv[argc++] = PPP_EXEC;
argv[argc++] = "nodetach";
/* And all the other arguments */
stringp=args;
c = strsep(&stringp, "|");
while(c && strlen(c) && (argc < (PPP_MAX_ARGS - 4))) {
argv[argc++] = c;
c = strsep(&stringp, "|");
}
argv[argc++] = "plugin";
#ifdef HAVE_ZAPTEL
argv[argc++] = "zaptel.so";
#else
argv[argc++] = "dahdi.so";
#endif
argv[argc++] = "stdin";
/* Finally launch PPP */
execv(PPP_EXEC, argv);
fprintf(stderr, "Failed to exec PPPD!\n");
exit(1);
}
static void run_ras(struct ast_channel *chan, char *args)
{
pid_t pid;
int status;
int res;
int signalled = 0;
struct dahdi_bufferinfo savebi;
int x;
res = ioctl(chan->fds[0], DAHDI_GET_BUFINFO, &savebi);
if(res) {
ast_log(LOG_WARNING, "Unable to check buffer policy on channel %s\n", chan->name);
return;
}
pid = spawn_ras(chan, args);
if (pid < 0) {
ast_log(LOG_WARNING, "Failed to spawn RAS\n");
} else {
for (;;) {
res = wait4(pid, &status, WNOHANG, NULL);
if (!res) {
/* Check for hangup */
if (chan->_softhangup && !signalled) {
ast_log(LOG_DEBUG, "Channel '%s' hungup. Signalling RAS at %d to die...\n", chan->name, pid);
kill(pid, SIGTERM);
signalled=1;
}
/* Try again */
sleep(1);
continue;
}
if (res < 0) {
ast_log(LOG_WARNING, "wait4 returned %d: %s\n", res, strerror(errno));
}
if (option_verbose > 2) {
if (WIFEXITED(status)) {
ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with status %d\n", chan->name, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated with signal %d\n",
chan->name, WTERMSIG(status));
} else {
ast_verbose(VERBOSE_PREFIX_3 "RAS on %s terminated weirdly.\n", chan->name);
}
}
/* Throw back into audio mode */
x = 1;
ioctl(chan->fds[0], DAHDI_AUDIOMODE, &x);
/* Restore saved values */
res = ioctl(chan->fds[0], DAHDI_SET_BUFINFO, &savebi);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set buffer policy on channel %s\n", chan->name);
}
break;
}
}
}
static int exec(struct ast_channel *chan, void *data)
{
int res=-1;
char *args;
struct ast_module_user *u;
struct dahdi_params ztp;
if (!data)
data = "";
u = ast_module_user_add(chan);
args = ast_strdupa(data);
/* Answer the channel if it's not up */
if (chan->_state != AST_STATE_UP)
ast_answer(chan);
if (strcasecmp(chan->tech->type, dahdi_chan_name)) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a %s channel\n", chan->name, dahdi_chan_name);
sleep(2);
} else {
memset(&ztp, 0, sizeof(ztp));
if (ioctl(chan->fds[0], DAHDI_GET_PARAMS, &ztp)) {
ast_log(LOG_WARNING, "Unable to get parameters\n");
} else if (ztp.sigtype != DAHDI_SIG_CLEAR) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Channel %s is not a clear channel\n", chan->name);
} else {
/* Everything should be okay. Run PPP. */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Starting RAS on %s\n", chan->name);
/* Execute RAS */
run_ras(chan, args);
}
}
ast_module_user_remove(u);
return res;
}
static int exec_warn(struct ast_channel *chan, void *data)
{
ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", zap_app, dahdi_app);
return exec(chan, data);
}
static int unload_module(void)
{
int res = 0;
if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
res |= ast_unregister_application(dahdi_app);
}
res |= ast_unregister_application(zap_app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res = 0;
if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
res |= ast_register_application(dahdi_app, exec, dahdi_synopsis, dahdi_descrip);
}
res |= ast_register_application(zap_app, exec_warn, zap_synopsis, zap_descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DAHDI RAS Application");

View File

@@ -1,389 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* Modified from app_zapbarge by David Troy <dave@toad.net>
*
* Special thanks to comphealth.com for sponsoring this
* GPL application.
*
* 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 Zap Scanner
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>dahdi</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/say.h"
#include "asterisk/dahdi_compat.h"
static char *app = "DAHDIScan";
static char *deprecated_app = "ZapScan";
static char *synopsis = "Scan Zap channels to monitor calls";
static char *descrip =
" ZapScan([group]) allows a call center manager to monitor Zap channels in\n"
"a convenient way. Use '#' to select the next channel and use '*' to exit\n"
"Limit scanning to a channel GROUP by setting the option group argument.\n";
#define CONF_SIZE 160
static struct ast_channel *get_zap_channel_locked(int num) {
char name[80];
snprintf(name,sizeof(name),"%s/%d-1", dahdi_chan_name, num);
return ast_get_channel_by_name_locked(name);
}
static int careful_write(int fd, unsigned char *data, int len)
{
int res;
while(len) {
res = write(fd, data, len);
if (res < 1) {
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "Failed to write audio data to conference: %s\n", strerror(errno));
return -1;
} else
return 0;
}
len -= res;
data += res;
}
return 0;
}
static int conf_run(struct ast_channel *chan, int confno, int confflags)
{
int fd;
struct dahdi_confinfo ztc;
struct ast_frame *f;
struct ast_channel *c;
struct ast_frame fr;
int outfd;
int ms;
int nfds;
int res;
int flags;
int retryzap;
int origfd;
int ret = -1;
char input[4];
int ic=0;
struct dahdi_bufferinfo bi;
char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
char *buf = __buf + AST_FRIENDLY_OFFSET;
/* Set it into U-law mode (write) */
if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
ast_log(LOG_WARNING, "Unable to set '%s' to write ulaw mode\n", chan->name);
goto outrun;
}
/* Set it into U-law mode (read) */
if (ast_set_read_format(chan, AST_FORMAT_ULAW) < 0) {
ast_log(LOG_WARNING, "Unable to set '%s' to read ulaw mode\n", chan->name);
goto outrun;
}
ast_indicate(chan, -1);
retryzap = strcasecmp(chan->tech->type, "Zap");
zapretry:
origfd = chan->fds[0];
if (retryzap) {
fd = open(DAHDI_FILE_PSEUDO, O_RDWR);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
goto outrun;
}
/* Make non-blocking */
flags = fcntl(fd, F_GETFL);
if (flags < 0) {
ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
close(fd);
goto outrun;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
close(fd);
goto outrun;
}
/* Setup buffering information */
memset(&bi, 0, sizeof(bi));
bi.bufsize = CONF_SIZE;
bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
bi.numbufs = 4;
if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
close(fd);
goto outrun;
}
nfds = 1;
} else {
/* XXX Make sure we're not running on a pseudo channel XXX */
fd = chan->fds[0];
nfds = 0;
}
memset(&ztc, 0, sizeof(ztc));
/* Check to see if we're in a conference... */
ztc.chan = 0;
if (ioctl(fd, DAHDI_GETCONF, &ztc)) {
ast_log(LOG_WARNING, "Error getting conference\n");
close(fd);
goto outrun;
}
if (ztc.confmode) {
/* Whoa, already in a conference... Retry... */
if (!retryzap) {
ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
retryzap = 1;
goto zapretry;
}
}
memset(&ztc, 0, sizeof(ztc));
/* Add us to the conference */
ztc.chan = 0;
ztc.confno = confno;
ztc.confmode = DAHDI_CONF_MONITORBOTH;
if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
ast_log(LOG_WARNING, "Error setting conference\n");
close(fd);
goto outrun;
}
ast_log(LOG_DEBUG, "Placed channel %s in ZAP channel %d monitor\n", chan->name, confno);
for(;;) {
outfd = -1;
ms = -1;
c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
if (c) {
if (c->fds[0] != origfd) {
if (retryzap) {
/* Kill old pseudo */
close(fd);
}
ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
retryzap = 0;
goto zapretry;
}
f = ast_read(c);
if (!f)
break;
if(f->frametype == AST_FRAME_DTMF) {
if(f->subclass == '#') {
ret = 0;
break;
}
else if (f->subclass == '*') {
ret = -1;
break;
}
else {
input[ic++] = f->subclass;
}
if(ic == 3) {
input[ic++] = '\0';
ic=0;
ret = atoi(input);
ast_verbose(VERBOSE_PREFIX_3 "Zapscan: change channel to %d\n",ret);
break;
}
}
if (fd != chan->fds[0]) {
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass == AST_FORMAT_ULAW) {
/* Carefully write */
careful_write(fd, f->data, f->datalen);
} else
ast_log(LOG_WARNING, "Huh? Got a non-ulaw (%d) frame in the conference\n", f->subclass);
}
}
ast_frfree(f);
} else if (outfd > -1) {
res = read(outfd, buf, CONF_SIZE);
if (res > 0) {
memset(&fr, 0, sizeof(fr));
fr.frametype = AST_FRAME_VOICE;
fr.subclass = AST_FORMAT_ULAW;
fr.datalen = res;
fr.samples = res;
fr.data = buf;
fr.offset = AST_FRIENDLY_OFFSET;
if (ast_write(chan, &fr) < 0) {
ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
/* break; */
}
} else
ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
}
}
if (f)
ast_frfree(f);
if (fd != chan->fds[0])
close(fd);
else {
/* Take out of conference */
/* Add us to the conference */
ztc.chan = 0;
ztc.confno = 0;
ztc.confmode = 0;
if (ioctl(fd, DAHDI_SETCONF, &ztc)) {
ast_log(LOG_WARNING, "Error setting conference\n");
}
}
outrun:
return ret;
}
static int conf_exec(struct ast_channel *chan, void *data)
{
int res=-1;
struct ast_module_user *u;
int confflags = 0;
int confno = 0;
char confstr[80] = "", *tmp = NULL;
struct ast_channel *tempchan = NULL, *lastchan = NULL,*ichan = NULL;
struct ast_frame *f;
char *desired_group;
int input=0,search_group=0;
u = ast_module_user_add(chan);
if (chan->_state != AST_STATE_UP)
ast_answer(chan);
desired_group = ast_strdupa(data);
if(!ast_strlen_zero(desired_group)) {
ast_verbose(VERBOSE_PREFIX_3 "Scanning for group %s\n", desired_group);
search_group = 1;
}
for (;;) {
if (ast_waitfor(chan, 100) < 0)
break;
f = ast_read(chan);
if (!f)
break;
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
ast_frfree(f);
break;
}
ast_frfree(f);
ichan = NULL;
if(input) {
ichan = get_zap_channel_locked(input);
input = 0;
}
tempchan = ichan ? ichan : ast_channel_walk_locked(tempchan);
if ( !tempchan && !lastchan )
break;
if (tempchan && search_group) {
const char *mygroup;
if((mygroup = pbx_builtin_getvar_helper(tempchan, "GROUP")) && (!strcmp(mygroup, desired_group))) {
ast_verbose(VERBOSE_PREFIX_3 "Found Matching Channel %s in group %s\n", tempchan->name, desired_group);
} else {
ast_mutex_unlock(&tempchan->lock);
lastchan = tempchan;
continue;
}
}
if (tempchan && (!strcmp(tempchan->tech->type, "Zap")) && (tempchan != chan) ) {
ast_verbose(VERBOSE_PREFIX_3 "Zap channel %s is in-use, monitoring...\n", tempchan->name);
ast_copy_string(confstr, tempchan->name, sizeof(confstr));
ast_mutex_unlock(&tempchan->lock);
if ((tmp = strchr(confstr,'-'))) {
*tmp = '\0';
}
confno = atoi(strchr(confstr,'/') + 1);
ast_stopstream(chan);
ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL);
res = conf_run(chan, confno, confflags);
if (res<0) break;
input = res;
} else if (tempchan)
ast_mutex_unlock(&tempchan->lock);
lastchan = tempchan;
}
ast_module_user_remove(u);
return res;
}
static int conf_exec_warn(struct ast_channel *chan, void *data)
{
ast_log(LOG_WARNING, "Use of the command %s is deprecated, please use %s instead.\n", deprecated_app, app);
return conf_exec(chan, data);
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
ast_register_application(deprecated_app, conf_exec_warn, synopsis, descrip);
return ast_register_application(app, conf_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Scan Zap channels application");

81
apps/app_datetime.c Normal file
View File

@@ -0,0 +1,81 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Time of day - Report the time of day
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/say.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
static char *tdesc = "Date and Time";
static char *app = "DateTime";
static char *synopsis = "Say the date and time";
static char *descrip =
" DateTime(): Says the current date and time. Returns -1 on hangup or 0\n"
"otherwise.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int datetime_exec(struct ast_channel *chan, void *data)
{
int res=0;
time_t t;
struct localuser *u;
LOCAL_USER_ADD(u);
time(&t);
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (!res)
res = ast_say_datetime(chan, t, "", chan->language);
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, datetime_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,88 +1,86 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Database access functions
*
* Copyright (C) 1999, Mark Spencer
* Copyright (C) 2003, Jefferson Noxon
*
* Mark Spencer <markster@digium.com>
* Mark Spencer <markster@linux-support.net>
* 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.
* the GNU General Public License
*/
/*! \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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <asterisk/options.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/astdb.h>
#include <asterisk/lock.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/options.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/astdb.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
static char *tdesc = "Database access functions for Asterisk extension logic";
static char *g_descrip =
" DBget(varname=family/key): Retrieves a value from the Asterisk\n"
"database and stores it in the given variable. Always returns 0. If the\n"
"requested key is not found, jumps to priority n+101 if available.\n";
static char *p_descrip =
" DBput(family/key=value): Stores the given value in the Asterisk\n"
"database. Always returns 0.\n";
/*! \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";
" DBdel(family/key): Deletes a key from the Asterisk database. Always\n"
"returns 0.\n";
static char *dt_descrip =
" DBdeltree(family[/keytree]): This application will delete a family or keytree\n"
"from the Asterisk database\n";
" DBdeltree(family[/keytree]): Deletes a family or keytree from the Asterisk\n"
"database. Always returns 0.\n";
static char *g_app = "DBget";
static char *p_app = "DBput";
static char *d_app = "DBdel";
static char *dt_app = "DBdeltree";
static char *g_synopsis = "Retrieve a value from the database";
static char *p_synopsis = "Store a value in the database";
static char *d_synopsis = "Delete a key from the database";
static char *dt_synopsis = "Delete a family or keytree from the database";
STANDARD_LOCAL_USER;
static int deltree_exec(struct ast_channel *chan, void *data)
LOCAL_USER_DECL;
static int deltree_exec (struct ast_channel *chan, void *data)
{
int arglen;
char *argv, *family, *keytree;
struct ast_module_user *u;
u = ast_module_user_add(chan);
arglen = strlen (data);
argv = alloca (arglen + 1);
if (!argv) { /* Why would this fail? */
ast_log (LOG_DEBUG, "Memory allocation failed\n");
return 0;
}
memcpy (argv, data, arglen + 1);
argv = ast_strdupa(data);
if (strchr(argv, '/')) {
family = strsep(&argv, "/");
keytree = strsep(&argv, "\0");
if (strchr (argv, '/')) {
family = strsep (&argv, "/");
keytree = strsep (&argv, "\0");
if (!family || !keytree) {
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
ast_module_user_remove(u);
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
return 0;
}
if (ast_strlen_zero(keytree))
if (!strlen (keytree))
keytree = 0;
} else {
family = argv;
@@ -91,77 +89,167 @@ static int deltree_exec(struct ast_channel *chan, void *data)
if (option_verbose > 2) {
if (keytree)
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: family=%s, keytree=%s\n", family, keytree);
ast_verbose (VERBOSE_PREFIX_3 "DBdeltree: family=%s, keytree=%s\n", family, keytree);
else
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: family=%s\n", family);
ast_verbose (VERBOSE_PREFIX_3 "DBdeltree: family=%s\n", family);
}
if (ast_db_deltree(family, keytree)) {
if (ast_db_deltree (family, keytree)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: Error deleting key from database.\n");
ast_verbose (VERBOSE_PREFIX_3 "DBdeltree: Error deleting key from database.\n");
}
ast_module_user_remove(u);
return 0;
}
static int del_exec(struct ast_channel *chan, void *data)
static int del_exec (struct ast_channel *chan, void *data)
{
int arglen;
char *argv, *family, *key;
struct ast_module_user *u;
static int deprecation_warning = 0;
u = ast_module_user_add(chan);
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");
arglen = strlen (data);
argv = alloca (arglen + 1);
if (!argv) { /* Why would this fail? */
ast_log (LOG_DEBUG, "Memory allocation failed\n");
return 0;
}
memcpy (argv, data, arglen + 1);
argv = ast_strdupa(data);
if (strchr(argv, '/')) {
family = strsep(&argv, "/");
key = strsep(&argv, "\0");
if (strchr (argv, '/')) {
family = strsep (&argv, "/");
key = strsep (&argv, "\0");
if (!family || !key) {
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
ast_module_user_remove(u);
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
return 0;
}
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "DBdel: family=%s, key=%s\n", family, key);
if (ast_db_del(family, key)) {
ast_verbose (VERBOSE_PREFIX_3 "DBdel: family=%s, key=%s\n", family, key);
if (ast_db_del (family, key)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "DBdel: Error deleting key from database.\n");
ast_verbose (VERBOSE_PREFIX_3 "DBdel: Error deleting key from database.\n");
}
} else {
ast_log(LOG_DEBUG, "Ignoring, no parameters\n");
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
}
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
static int put_exec (struct ast_channel *chan, void *data)
{
int arglen;
char *argv, *value, *family, *key;
arglen = strlen (data);
argv = alloca (arglen + 1);
if (!argv) { /* Why would this fail? */
ast_log (LOG_DEBUG, "Memory allocation failed\n");
return 0;
}
memcpy (argv, data, arglen + 1);
if (strchr (argv, '/') && strchr (argv, '=')) {
family = strsep (&argv, "/");
key = strsep (&argv, "=");
value = strsep (&argv, "\0");
if (!value || !family || !key) {
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
return 0;
}
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "DBput: family=%s, key=%s, value=%s\n", family, key, value);
if (ast_db_put (family, key, value)) {
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "DBput: Error writing value to database.\n");
}
} else {
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
}
return 0;
}
static int get_exec (struct ast_channel *chan, void *data)
{
int arglen;
char *argv, *varname, *family, *key;
char dbresult[256];
arglen = strlen (data);
argv = alloca (arglen + 1);
if (!argv) { /* Why would this fail? */
ast_log (LOG_DEBUG, "Memory allocation failed\n");
return 0;
}
memcpy (argv, data, arglen + 1);
if (strchr (argv, '=') && strchr (argv, '/')) {
varname = strsep (&argv, "=");
family = strsep (&argv, "/");
key = strsep (&argv, "\0");
if (!varname || !family || !key) {
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
return 0;
}
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "DBget: varname=%s, family=%s, key=%s\n", varname, family, key);
if (!ast_db_get (family, key, dbresult, sizeof (dbresult) - 1)) {
pbx_builtin_setvar_helper (chan, varname, dbresult);
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "DBget: set variable %s to %s\n", varname, dbresult);
} else {
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "DBget: Value not found in database.\n");
/* Send the call to n+101 priority, where n is the current priority */
if (ast_exists_extension (chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority += 100;
}
} else {
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
}
return 0;
}
int unload_module (void)
{
int retval;
retval = ast_unregister_application(dt_app);
retval |= ast_unregister_application(d_app);
STANDARD_HANGUP_LOCALUSERS;
retval = ast_unregister_application (dt_app);
retval |= ast_unregister_application (d_app);
retval |= ast_unregister_application (p_app);
retval |= ast_unregister_application (g_app);
return retval;
}
static int load_module(void)
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);
retval = ast_register_application (g_app, get_exec, g_synopsis, g_descrip);
if (!retval)
retval = ast_register_application (p_app, put_exec, p_synopsis, p_descrip);
if (!retval)
retval = ast_register_application (d_app, del_exec, d_synopsis, d_descrip);
if (!retval)
retval = ast_register_application (dt_app, deltree_exec, dt_synopsis, dt_descrip);
return retval;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database Access Functions");
char *description (void)
{
return tdesc;
}
int usecount (void)
{
int res;
STANDARD_USECOUNT (res);
return res;
}
char *key ()
{
return ASTERISK_GPL_KEY;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,349 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005, Anthony Minessale II
*
* Anthony Minessale II <anthmct@yahoo.com>
*
* Donated by Sangoma Technologies <http://www.samgoma.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 Virtual Dictation Machine Application For Asterisk
*
* \author Anthony Minessale II <anthmct@yahoo.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/say.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
static char *app = "Dictate";
static char *synopsis = "Virtual Dictation Machine";
static char *desc = " Dictate([<base_dir>[|<filename>]])\n"
"Start dictation machine using optional base dir for files.\n";
typedef enum {
DFLAG_RECORD = (1 << 0),
DFLAG_PLAY = (1 << 1),
DFLAG_TRUNC = (1 << 2),
DFLAG_PAUSE = (1 << 3),
} dflags;
typedef enum {
DMODE_INIT,
DMODE_RECORD,
DMODE_PLAY
} dmodes;
#define ast_toggle_flag(it,flag) if(ast_test_flag(it, flag)) ast_clear_flag(it, flag); else ast_set_flag(it, flag)
static int play_and_wait(struct ast_channel *chan, char *file, char *digits)
{
int res = -1;
if (!ast_streamfile(chan, file, chan->language)) {
res = ast_waitstream(chan, digits);
}
return res;
}
static int dictate_exec(struct ast_channel *chan, void *data)
{
char *path = NULL, filein[256], *filename = "";
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(base);
AST_APP_ARG(filename);
);
char dftbase[256];
char *base;
struct ast_flags flags = {0};
struct ast_filestream *fs;
struct ast_frame *f = NULL;
struct ast_module_user *u;
int ffactor = 320 * 80,
res = 0,
done = 0,
oldr = 0,
lastop = 0,
samples = 0,
speed = 1,
digit = 0,
len = 0,
maxlen = 0,
mode = 0;
u = ast_module_user_add(chan);
snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR);
if (!ast_strlen_zero(data)) {
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
} else
args.argc = 0;
if (args.argc && !ast_strlen_zero(args.base)) {
base = args.base;
} else {
base = dftbase;
}
if (args.argc > 1 && args.filename) {
filename = args.filename;
}
oldr = chan->readformat;
if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)) < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode.\n");
ast_module_user_remove(u);
return -1;
}
ast_answer(chan);
ast_safe_sleep(chan, 200);
for (res = 0; !res;) {
if (ast_strlen_zero(filename)) {
if (ast_app_getdata(chan, "dictate/enter_filename", filein, sizeof(filein), 0) ||
ast_strlen_zero(filein)) {
res = -1;
break;
}
} else {
ast_copy_string(filein, filename, sizeof(filein));
filename = "";
}
mkdir(base, 0755);
len = strlen(base) + strlen(filein) + 2;
if (!path || len > maxlen) {
path = alloca(len);
memset(path, 0, len);
maxlen = len;
} else {
memset(path, 0, maxlen);
}
snprintf(path, len, "%s/%s", base, filein);
fs = ast_writefile(path, "raw", NULL, O_CREAT|O_APPEND, 0, 0700);
mode = DMODE_PLAY;
memset(&flags, 0, sizeof(flags));
ast_set_flag(&flags, DFLAG_PAUSE);
digit = play_and_wait(chan, "dictate/forhelp", AST_DIGIT_ANY);
done = 0;
speed = 1;
res = 0;
lastop = 0;
samples = 0;
while (!done && ((res = ast_waitfor(chan, -1)) > -1) && fs && (f = ast_read(chan))) {
if (digit) {
struct ast_frame fr = {AST_FRAME_DTMF, digit};
ast_queue_frame(chan, &fr);
digit = 0;
}
if ((f->frametype == AST_FRAME_DTMF)) {
int got = 1;
switch(mode) {
case DMODE_PLAY:
switch(f->subclass) {
case '1':
ast_set_flag(&flags, DFLAG_PAUSE);
mode = DMODE_RECORD;
break;
case '2':
speed++;
if (speed > 4) {
speed = 1;
}
res = ast_say_number(chan, speed, AST_DIGIT_ANY, chan->language, (char *) NULL);
break;
case '7':
samples -= ffactor;
if(samples < 0) {
samples = 0;
}
ast_seekstream(fs, samples, SEEK_SET);
break;
case '8':
samples += ffactor;
ast_seekstream(fs, samples, SEEK_SET);
break;
default:
got = 0;
}
break;
case DMODE_RECORD:
switch(f->subclass) {
case '1':
ast_set_flag(&flags, DFLAG_PAUSE);
mode = DMODE_PLAY;
break;
case '8':
ast_toggle_flag(&flags, DFLAG_TRUNC);
lastop = 0;
break;
default:
got = 0;
}
break;
default:
got = 0;
}
if (!got) {
switch(f->subclass) {
case '#':
done = 1;
continue;
break;
case '*':
ast_toggle_flag(&flags, DFLAG_PAUSE);
if (ast_test_flag(&flags, DFLAG_PAUSE)) {
digit = play_and_wait(chan, "dictate/pause", AST_DIGIT_ANY);
} else {
digit = play_and_wait(chan, mode == DMODE_PLAY ? "dictate/playback" : "dictate/record", AST_DIGIT_ANY);
}
break;
case '0':
ast_set_flag(&flags, DFLAG_PAUSE);
digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
switch(mode) {
case DMODE_PLAY:
digit = play_and_wait(chan, "dictate/play_help", AST_DIGIT_ANY);
break;
case DMODE_RECORD:
digit = play_and_wait(chan, "dictate/record_help", AST_DIGIT_ANY);
break;
}
if (digit == 0) {
digit = play_and_wait(chan, "dictate/both_help", AST_DIGIT_ANY);
} else if (digit < 0) {
done = 1;
break;
}
break;
}
}
} else if (f->frametype == AST_FRAME_VOICE) {
switch(mode) {
struct ast_frame *fr;
int x;
case DMODE_PLAY:
if (lastop != DMODE_PLAY) {
if (ast_test_flag(&flags, DFLAG_PAUSE)) {
digit = play_and_wait(chan, "dictate/playback_mode", AST_DIGIT_ANY);
if (digit == 0) {
digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
} else if (digit < 0) {
break;
}
}
if (lastop != DFLAG_PLAY) {
lastop = DFLAG_PLAY;
ast_closestream(fs);
if (!(fs = ast_openstream(chan, path, chan->language)))
break;
ast_seekstream(fs, samples, SEEK_SET);
chan->stream = NULL;
}
lastop = DMODE_PLAY;
}
if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
for (x = 0; x < speed; x++) {
if ((fr = ast_readframe(fs))) {
ast_write(chan, fr);
samples += fr->samples;
ast_frfree(fr);
fr = NULL;
} else {
samples = 0;
ast_seekstream(fs, 0, SEEK_SET);
}
}
}
break;
case DMODE_RECORD:
if (lastop != DMODE_RECORD) {
int oflags = O_CREAT | O_WRONLY;
if (ast_test_flag(&flags, DFLAG_PAUSE)) {
digit = play_and_wait(chan, "dictate/record_mode", AST_DIGIT_ANY);
if (digit == 0) {
digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
} else if (digit < 0) {
break;
}
}
lastop = DMODE_RECORD;
ast_closestream(fs);
if ( ast_test_flag(&flags, DFLAG_TRUNC)) {
oflags |= O_TRUNC;
digit = play_and_wait(chan, "dictate/truncating_audio", AST_DIGIT_ANY);
} else {
oflags |= O_APPEND;
}
fs = ast_writefile(path, "raw", NULL, oflags, 0, 0700);
if (ast_test_flag(&flags, DFLAG_TRUNC)) {
ast_seekstream(fs, 0, SEEK_SET);
ast_clear_flag(&flags, DFLAG_TRUNC);
} else {
ast_seekstream(fs, 0, SEEK_END);
}
}
if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
res = ast_writestream(fs, f);
}
break;
}
}
ast_frfree(f);
}
}
if (oldr) {
ast_set_read_format(chan, oldr);
}
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
return res;
}
static int load_module(void)
{
return ast_register_application(app, dictate_exec, synopsis, desc);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine");

View File

@@ -1,181 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005, Joshua Colp
*
* Joshua Colp <jcolp@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 Directed Call Pickup Support
*
* \author Joshua Colp <jcolp@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
#define PICKUPMARK "PICKUPMARK"
static const char *app = "Pickup";
static const char *synopsis = "Directed Call Pickup";
static const char *descrip =
" Pickup(extension[@context][&extension2@context...]): This application can pickup any ringing channel\n"
"that is calling the specified extension. If no context is specified, the current\n"
"context will be used. If you use the special string \"PICKUPMARK\" for the context parameter, for example\n"
"10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n"
"as \"extension\".";
/* Perform actual pickup between two channels */
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
{
int res = 0;
if (option_debug)
ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
if ((res = ast_answer(chan))) {
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
return -1;
}
if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
return -1;
}
if ((res = ast_channel_masquerade(target, chan))) {
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
return -1;
}
return res;
}
/* Helper function that determines whether a channel is capable of being picked up */
static int can_pickup(struct ast_channel *chan)
{
if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
return 1;
else
return 0;
}
/* Attempt to pick up specified extension with context */
static int pickup_by_exten(struct ast_channel *chan, char *exten, char *context)
{
int res = -1;
struct ast_channel *target = NULL;
while ((target = ast_channel_walk_locked(target))) {
if ((!strcasecmp(target->macroexten, exten) || !strcasecmp(target->exten, exten)) &&
!strcasecmp(target->dialcontext, context) &&
(chan != target) && can_pickup(target)) {
res = pickup_do(chan, target);
ast_channel_unlock(target);
break;
}
ast_channel_unlock(target);
}
return res;
}
/* Attempt to pick up specified mark */
static int pickup_by_mark(struct ast_channel *chan, char *mark)
{
int res = -1;
const char *tmp = NULL;
struct ast_channel *target = NULL;
while ((target = ast_channel_walk_locked(target))) {
if ((tmp = pbx_builtin_getvar_helper(target, PICKUPMARK)) &&
!strcasecmp(tmp, mark) &&
can_pickup(target)) {
res = pickup_do(chan, target);
ast_channel_unlock(target);
break;
}
ast_channel_unlock(target);
}
return res;
}
/* Main application entry point */
static int pickup_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u = NULL;
char *tmp = ast_strdupa(data);
char *exten = NULL, *context = NULL;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Pickup requires an argument (extension)!\n");
return -1;
}
u = ast_module_user_add(chan);
/* Parse extension (and context if there) */
while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
if ((context = strchr(exten, '@')))
*context++ = '\0';
if (context && !strcasecmp(context, PICKUPMARK)) {
if (!pickup_by_mark(chan, exten))
break;
} else {
if (!pickup_by_exten(chan, exten, context ? context : chan->context))
break;
}
ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
}
ast_module_user_remove(u);
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, pickup_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");

View File

@@ -1,213 +1,64 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Provide a directory of extensions
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 Provide a directory of extensions
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/config.h>
#include <asterisk/say.h>
#include <asterisk/utils.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include "../asterisk.h"
#include "../astconf.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#ifdef ODBC_STORAGE
#include <errno.h>
#include <sys/mman.h>
#include "asterisk/res_odbc.h"
static char odbc_database[80] = "asterisk";
static char odbc_table[80] = "voicemessages";
static char vmfmts[80] = "wav";
#endif
static char *tdesc = "Extension Directory";
static char *app = "Directory";
static char *synopsis = "Provide directory of voicemail extensions";
static char *descrip =
" Directory(vm-context[|dial-context[|options]]): This application will present\n"
"the calling channel with a directory of extensions from which they can search\n"
"by name. The list of names and corresponding extensions is retrieved from the\n"
"voicemail configuration file, voicemail.conf.\n"
" This application will immediately exit if one of the following DTMF digits are\n"
"received and the extension to jump to exists:\n"
" 0 - Jump to the 'o' extension, if it exists.\n"
" * - Jump to the 'a' extension, if it exists.\n\n"
" Parameters:\n"
" vm-context - This is the context within voicemail.conf to use for the\n"
" Directory.\n"
" dial-context - This is the dialplan context to use when looking for an\n"
" extension that the user has selected, or when jumping to the\n"
" 'o' or 'a' extension.\n\n"
" Options:\n"
" e - In addition to the name, also read the extension number to the\n"
" caller before presenting dialing options.\n"
" f - Allow the caller to enter the first name of a user in the directory\n"
" instead of using the last name.\n";
" Directory(vm-context[|dial-context[|options]]): Presents the user with a directory\n"
"of extensions from which they may select by name. The list of names \n"
"and extensions is discovered from voicemail.conf. The vm-context argument\n"
"is required, and specifies the context of voicemail.conf to use. The\n"
"dial-context is the context to use for dialing the users, and defaults to\n"
"the vm-context if unspecified. The 'f' option causes the directory to match\n"
"based on the first name in voicemail.conf instead of the last name.\n"
"Returns 0 unless the user hangs up. It also sets up the channel on exit\n"
"to enter the extension the user selected.\n";
/* For simplicity, I'm keeping the format compatible with the voicemail config,
but i'm open to suggestions for isolating it */
#define VOICEMAIL_CONFIG "voicemail.conf"
#define DIRECTORY_CONFIG "voicemail.conf"
/* How many digits to read in */
#define NUMDIGITS 3
STANDARD_LOCAL_USER;
#ifdef ODBC_STORAGE
struct generic_prepare_struct {
const char *sql;
const char *param;
};
LOCAL_USER_DECL;
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
{
struct generic_prepare_struct *gps = data;
SQLHSTMT stmt;
int res;
res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
return NULL;
}
res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", (char *)gps->sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return NULL;
}
if (!ast_strlen_zero(gps->param))
SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->param), 0, (void *)gps->param, 0, NULL);
return stmt;
}
static void retrieve_file(char *dir)
{
int x = 0;
int res;
int fd=-1;
size_t fdlen = 0;
void *fdm = MAP_FAILED;
SQLHSTMT stmt;
char sql[256];
char fmt[80]="", empty[10] = "";
char *c;
SQLLEN colsize;
char full_fn[256];
struct odbc_obj *obj;
struct generic_prepare_struct gps = { .sql = sql, .param = dir };
obj = ast_odbc_request_obj(odbc_database, 1);
if (obj) {
do {
ast_copy_string(fmt, vmfmts, sizeof(fmt));
c = strchr(fmt, '|');
if (c)
*c = '\0';
if (!strcasecmp(fmt, "wav49"))
strcpy(fmt, "WAV");
snprintf(full_fn, sizeof(full_fn), "%s.%s", dir, fmt);
snprintf(sql, sizeof(sql), "SELECT recording FROM %s WHERE dir=? AND msgnum=-1", odbc_table);
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
if (!stmt) {
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
break;
}
res = SQLFetch(stmt);
if (res == SQL_NO_DATA) {
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
break;
} else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
break;
}
fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
if (fd < 0) {
ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
break;
}
res = SQLGetData(stmt, 1, SQL_BINARY, empty, 0, &colsize);
fdlen = colsize;
if (fd > -1) {
char tmp[1]="";
lseek(fd, fdlen - 1, SEEK_SET);
if (write(fd, tmp, 1) != 1) {
close(fd);
fd = -1;
break;
}
if (fd > -1)
fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
}
if (fdm != MAP_FAILED) {
memset(fdm, 0, fdlen);
res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, fdlen, &colsize);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
break;
}
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
} while (0);
ast_odbc_release_obj(obj);
} else
ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
if (fdm != MAP_FAILED)
munmap(fdm, fdlen);
if (fd > -1)
close(fd);
return;
}
#endif
static char *convert(const char *lastname)
static char *convert(char *lastname)
{
char *tmp;
int lcount = 0;
tmp = ast_malloc(NUMDIGITS + 1);
tmp = malloc(NUMDIGITS + 1);
if (tmp) {
while((*lastname > 32) && lcount < NUMDIGITS) {
switch(toupper(*lastname)) {
@@ -277,195 +128,105 @@ static char *convert(const char *lastname)
* '1' for selected entry from directory
* '*' for skipped entry from directory
*/
static int play_mailbox_owner(struct ast_channel *chan, char *context,
char *dialcontext, char *ext, char *name, int readext,
int fromappvm)
{
static int play_mailbox_owner(struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name) {
int res = 0;
int loop;
int loop = 3;
char fn[256];
char fn2[256];
/* Check for the VoiceMail2 greeting first */
snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet",
ast_config_AST_SPOOL_DIR, context, ext);
#ifdef ODBC_STORAGE
retrieve_file(fn);
#endif
(char *)ast_config_AST_SPOOL_DIR, context, ext);
if (ast_fileexists(fn, NULL, chan->language) <= 0) {
/* no file, check for an old-style Voicemail greeting */
snprintf(fn, sizeof(fn), "%s/vm/%s/greet",
ast_config_AST_SPOOL_DIR, ext);
}
#ifdef ODBC_STORAGE
retrieve_file(fn);
#endif
/* Otherwise, check for an old-style Voicemail greeting */
snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet",
(char *)ast_config_AST_SPOOL_DIR, ext);
if (ast_fileexists(fn, NULL, chan->language) > 0) {
res = ast_stream_and_wait(chan, fn, chan->language, AST_DIGIT_ANY);
res = ast_streamfile(chan, fn, chan->language);
if (!res) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
}
ast_stopstream(chan);
/* If Option 'e' was specified, also read the extension number with the name */
if (readext) {
ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY);
res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
} else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
res = ast_streamfile(chan, fn2, chan->language);
if (!res) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
}
ast_stopstream(chan);
} else {
res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
if (!ast_strlen_zero(name) && readext) {
ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY);
res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
}
res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext,
AST_DIGIT_ANY, chan->language);
}
#ifdef ODBC_STORAGE
ast_filedelete(fn, NULL);
#endif
for (loop = 3 ; loop > 0; loop--) {
if (!res)
res = ast_stream_and_wait(chan, "dir-instr", chan->language, AST_DIGIT_ANY);
if (!res)
while (loop) {
if (!res) {
res = ast_streamfile(chan, "dir-instr", chan->language);
}
if (!res) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
}
if (!res) {
res = ast_waitfordigit(chan, 3000);
}
ast_stopstream(chan);
if (res < 0) /* User hungup, so jump out now */
break;
if (res == '0') {
if (!ast_goto_if_exists(chan, dialcontext, "o", 1) ||
(!ast_strlen_zero(chan->macrocontext) &&
!ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
/* return 1 to indicate goto has been performed */
return '1';
}
if (res > -1) {
switch (res) {
case '1':
/* Name selected */
loop = 0;
if (ast_exists_extension(chan,dialcontext,ext,1,chan->callerid)) {
strncpy(chan->exten, ext, sizeof(chan->exten)-1);
chan->priority = 0;
strncpy(chan->context, dialcontext, sizeof(chan->context)-1);
} else {
ast_log(LOG_WARNING,
"Can't find extension '%s' in context '%s'. "
"Did you pass the wrong context to Directory?\n",
ext, dialcontext);
res = -1;
}
break;
case '*':
/* Skip to next match in list */
loop = 0;
break;
default:
/* Not '1', or '*', so decrement number of tries */
res = 0;
loop--;
break;
} /* end switch */
} /* end if */
else {
/* User hungup, so jump out now */
loop = 0;
}
if (res == '1') { /* Name selected */
if (fromappvm) {
/* We still want to set the exten though */
ast_copy_string(chan->exten, ext, sizeof(chan->exten));
} else {
if (ast_goto_if_exists(chan, dialcontext, ext, 1)) {
ast_log(LOG_WARNING,
"Can't find extension '%s' in context '%s'. "
"Did you pass the wrong context to Directory?\n",
ext, dialcontext);
res = -1;
}
}
break;
}
if (res == '*') /* Skip to next match in list */
break;
if (res == '#')
break;
/* Not '1', or '*', so decrement number of tries */
res = 0;
}
} /* end while */
return(res);
}
static struct ast_config *realtime_directory(char *context)
{
struct ast_config *cfg;
struct ast_config *rtdata;
struct ast_category *cat;
struct ast_variable *var;
char *mailbox;
const char *fullname;
const char *hidefromdir;
char tmp[100];
/* Load flat file config. */
cfg = ast_config_load(VOICEMAIL_CONFIG);
if (!cfg) {
/* Loading config failed. */
ast_log(LOG_WARNING, "Loading config failed.\n");
return NULL;
}
/* Get realtime entries, categorized by their mailbox number
and present in the requested context */
rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL);
/* if there are no results, just return the entries from the config file */
if (!rtdata)
return cfg;
/* Does the context exist within the config file? If not, make one */
cat = ast_category_get(cfg, context);
if (!cat) {
cat = ast_category_new(context);
if (!cat) {
ast_log(LOG_WARNING, "Out of memory\n");
ast_config_destroy(cfg);
if (rtdata) {
ast_config_destroy(rtdata);
}
return NULL;
}
ast_category_append(cfg, cat);
}
mailbox = NULL;
while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
fullname ? fullname : "",
hidefromdir ? hidefromdir : "no");
var = ast_variable_new(mailbox, tmp);
if (var)
ast_variable_append(cat, var);
else
ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
}
ast_config_destroy(rtdata);
return cfg;
}
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm)
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *context, char *dialcontext, char digit, int last)
{
/* Read in the first three digits.. "digit" is the first digit, already read */
char ext[NUMDIGITS + 1], *cat;
char ext[NUMDIGITS + 1];
char name[80] = "";
struct ast_variable *v;
int res;
int found=0;
int lastuserchoice = 0;
char *start, *conv, *stringp = NULL;
const char *pos;
int breakout = 0;
char *start, *pos, *conv,*stringp=NULL;
if (ast_strlen_zero(context)) {
if (!context || ast_strlen_zero(context)) {
ast_log(LOG_WARNING,
"Directory must be called with an argument "
"(context in which to interpret extensions)\n");
return -1;
}
if (digit == '0') {
if (!ast_goto_if_exists(chan, dialcontext, "o", 1) ||
(!ast_strlen_zero(chan->macrocontext) &&
!ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
return 0;
} else {
ast_log(LOG_WARNING, "Can't find extension 'o' in current context. "
"Not Exiting the Directory!\n");
res = 0;
}
}
if (digit == '*') {
if (!ast_goto_if_exists(chan, dialcontext, "a", 1) ||
(!ast_strlen_zero(chan->macrocontext) &&
!ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) {
return 0;
} else {
ast_log(LOG_WARNING, "Can't find extension 'a' in current context. "
"Not Exiting the Directory!\n");
res = 0;
}
}
memset(ext, 0, sizeof(ext));
ext[0] = digit;
res = 0;
@@ -478,18 +239,18 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
while(v) {
/* Find a candidate extension */
start = strdup(v->value);
if (start && !strcasestr(start, "hidefromdir=yes")) {
if (start) {
stringp=start;
strsep(&stringp, ",");
pos = strsep(&stringp, ",");
if (pos) {
ast_copy_string(name, pos, sizeof(name));
strncpy(name, pos, sizeof(name) - 1);
/* Grab the last name */
if (last && strrchr(pos,' '))
pos = strrchr(pos, ' ') + 1;
conv = convert(pos);
if (conv) {
if (!strncmp(conv, ext, strlen(ext))) {
if (!strcmp(conv, ext)) {
/* Match! */
found++;
free(conv);
@@ -506,7 +267,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
if (v) {
/* We have a match -- play a greeting if they have it */
res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm);
res = play_mailbox_owner(chan, context, dialcontext, v->name, name);
switch (res) {
case -1:
/* user pressed '1' but extension does not exist, or
@@ -515,20 +276,17 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
lastuserchoice = 0;
break;
case '1':
/* user pressed '1' and extensions exists;
play_mailbox_owner will already have done
a goto() on the channel
*/
/* user pressed '1' and extensions exists */
lastuserchoice = res;
strncpy(chan->context, dialcontext, sizeof(chan->context) - 1);
strncpy(chan->exten, v->name, sizeof(chan->exten) - 1);
chan->priority = 0;
break;
case '*':
/* user pressed '*' to skip something found */
lastuserchoice = res;
res = 0;
break;
case '#':
lastuserchoice = res;
return 0;
default:
break;
}
@@ -536,66 +294,11 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
}
}
if (!res && ucfg) {
/* Search users.conf for all names which start with those digits */
for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) {
if (!strcasecmp(cat, "general"))
continue;
if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
continue;
/* Find all candidate extensions */
if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) {
ast_copy_string(name, pos, sizeof(name));
/* Grab the last name */
if (last && strrchr(pos,' '))
pos = strrchr(pos, ' ') + 1;
conv = convert(pos);
if (conv) {
if (!strcmp(conv, ext)) {
/* Match! */
found++;
/* We have a match -- play a greeting if they have it */
res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm);
switch (res) {
case -1:
/* user pressed '1' but extension does not exist, or
* user hungup
*/
lastuserchoice = 0;
breakout = 1;
break;
case '1':
/* user pressed '1' and extensions exists;
play_mailbox_owner will already have done
a goto() on the channel
*/
lastuserchoice = res;
breakout = 1;
break;
case '*':
/* user pressed '*' to skip something found */
lastuserchoice = res;
breakout = 0;
res = 0;
break;
default:
breakout = 1;
break;
}
free(conv);
if (breakout)
break;
}
else
free(conv);
}
}
}
}
if (lastuserchoice != '1') {
res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language);
if (found)
res = ast_streamfile(chan, "dir-nomore", chan->language);
else
res = ast_streamfile(chan, "dir-nomatch", chan->language);
if (!res)
res = 1;
return res;
@@ -608,115 +311,93 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
static int directory_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
struct ast_config *cfg, *ucfg;
struct localuser *u;
struct ast_config *cfg;
int last = 1;
int readext = 0;
int fromappvm = 0;
const char *dirintro;
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(vmcontext);
AST_APP_ARG(dialcontext);
AST_APP_ARG(options);
);
char *context, *dialcontext, *dirintro, *options;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
if (!data) {
ast_log(LOG_WARNING, "directory requires an argument (context[,dialcontext])\n");
return -1;
}
u = ast_module_user_add(chan);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.options) {
if (strchr(args.options, 'f'))
last = 0;
if (strchr(args.options, 'e'))
readext = 1;
if (strchr(args.options, 'v'))
fromappvm = 1;
}
if (ast_strlen_zero(args.dialcontext))
args.dialcontext = args.vmcontext;
cfg = realtime_directory(args.vmcontext);
cfg = ast_load(DIRECTORY_CONFIG);
if (!cfg) {
ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
ast_module_user_remove(u);
ast_log(LOG_WARNING, "Unable to open directory configuration %s\n", DIRECTORY_CONFIG);
return -1;
}
ucfg = ast_config_load("users.conf");
dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
if (ast_strlen_zero(dirintro))
LOCAL_USER_ADD(u);
top:
context = ast_strdupa(data);
dialcontext = strchr(context, '|');
if (dialcontext) {
*dialcontext = '\0';
dialcontext++;
options = strchr(dialcontext, '|');
if (options) {
*options = '\0';
options++;
if (strchr(options, 'f'))
last = 0;
}
} else
dialcontext = context;
dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
if (!dirintro || ast_strlen_zero(dirintro))
dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
if (ast_strlen_zero(dirintro))
dirintro = last ? "dir-intro" : "dir-intro-fn";
/* the above prompts probably should be modified to include 0 for dialing operator
and # for exiting (continues in dialplan) */
if (!dirintro || ast_strlen_zero(dirintro)) {
if (last)
dirintro = "dir-intro";
else
dirintro = "dir-intro-fn";
}
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
for (;;) {
if (!res)
res = ast_stream_and_wait(chan, dirintro, chan->language, AST_DIGIT_ANY);
ast_stopstream(chan);
if (!res)
res = ast_waitfordigit(chan, 5000);
if (!res)
res = ast_streamfile(chan, dirintro, chan->language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (!res)
res = ast_waitfordigit(chan, 5000);
if (res > 0) {
res = do_directory(chan, cfg, context, dialcontext, res, last);
if (res > 0) {
res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm);
if (res > 0) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res >= 0)
continue;
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res >= 0) {
goto top;
}
}
break;
}
if (ucfg)
ast_config_destroy(ucfg);
ast_config_destroy(cfg);
ast_module_user_remove(u);
ast_destroy(cfg);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
#ifdef ODBC_STORAGE
struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG);
const char *tmp;
if (cfg) {
if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
ast_copy_string(odbc_database, tmp, sizeof(odbc_database));
}
if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) {
ast_copy_string(odbc_table, tmp, sizeof(odbc_table));
}
if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) {
ast_copy_string(vmfmts, tmp, sizeof(vmfmts));
}
ast_config_destroy(cfg);
} else
ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n");
#endif
return ast_register_application(app, directory_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,80 +1,66 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* DISA -- Direct Inward System Access Application 6/20/2001
*
* Copyright (C) 2001, Linux Support Services, Inc.
*
* Jim Dixon <jim@lambdatel.com>
*
* Made only slightly more sane by 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 DISA -- Direct Inward System Access Application
*
* \author Jim Dixon <jim@lambdatel.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/indications.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/ulaw.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/time.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/app.h"
#include "asterisk/indications.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/ulaw.h"
#include "asterisk/callerid.h"
#include "asterisk/stringfields.h"
static char *tdesc = "DISA (Direct Inward System Access) Application";
static char *app = "DISA";
static char *synopsis = "DISA (Direct Inward System Access)";
static char *descrip =
"DISA(<numeric passcode>[|<context>]) or DISA(<filename>)\n"
"The DISA, Direct Inward System Access, application allows someone from \n"
"outside the telephone switch (PBX) to obtain an \"internal\" system \n"
"dialtone and to place calls from it as if they were placing a call from \n"
"within the switch.\n"
"DISA plays a dialtone. The user enters their numeric passcode, followed by\n"
"the pound sign (#). If the passcode is correct, the user is then given\n"
"DISA (Direct Inward System Access) -- Allows someone from outside\n"
"the telephone switch (PBX) to obtain an \"internal\" system dialtone\n"
"and to place calls from it as if they were placing a call from within\n"
"the switch. A user calls a number that connects to the DISA application\n"
"and is given dialtone. The user enters their passcode, followed by the\n"
"pound sign (#). If the passcode is correct, the user is then given\n"
"system dialtone on which a call may be placed. Obviously, this type\n"
"of access has SERIOUS security implications, and GREAT care must be\n"
"taken NOT to compromise your security.\n\n"
"There is a possibility of accessing DISA without password. Simply\n"
"exchange your password with \"no-password\".\n\n"
" Example: exten => s,1,DISA(no-password|local)\n\n"
"Be aware that using this compromises the security of your PBX.\n\n"
"exchange your password with no-password.\n\n"
" Example: exten => s,1,DISA,no-password|local\n\n"
"but be aware of using this for your security compromising.\n\n"
"The arguments to this application (in extensions.conf) allow either\n"
"specification of a single global passcode (that everyone uses), or\n"
"individual passcodes contained in a file. It also allows specification\n"
"specification of a single global password (that everyone uses), or\n"
"individual passwords contained in a file. It also allow specification\n"
"of the context on which the user will be dialing. If no context is\n"
"specified, the DISA application defaults the context to \"disa\".\n"
"Presumably a normal system will have a special context set up\n"
"for DISA use with some or a lot of restrictions. \n\n"
"specified, the DISA application defaults the context to \"disa\"\n"
"presumably that a normal system will have a special context set up\n"
"for DISA use with some or a lot of restrictions. The arguments are\n"
"one of the following:\n\n"
" numeric-passcode\n"
" numeric-passcode|context\n"
" full-pathname-of-file-that-contains-passcodes\n\n"
"The file that contains the passcodes (if used) allows specification\n"
"of either just a passcode (defaulting to the \"disa\" context, or\n"
"passcode|context on each line of the file. The file may contain blank\n"
@@ -82,27 +68,35 @@ static char *descrip =
"above arguments may have |new-callerid-string appended to them, to\n"
"specify a new (different) callerid to be used for this call, for\n"
"example: numeric-passcode|context|\"My Phone\" <(234) 123-4567> or \n"
"full-pathname-of-passcode-file|\"My Phone\" <(234) 123-4567>. Last\n"
"but not least, |mailbox[@context] may be appended, which will cause\n"
"a stutter-dialtone (indication \"dialrecall\") to be used, if the\n"
"specified mailbox contains any new messages, for example:\n"
"numeric-passcode|context||1234 (w/a changing callerid). Note that\n"
"full-pathname-of-passcode-file|\"My Phone\" <(234) 123-4567>. Note that\n"
"in the case of specifying the numeric-passcode, the context must be\n"
"specified if the callerid is specified also.\n\n"
"If login is successful, the application looks up the dialed number in\n"
"the specified (or default) context, and executes it if found.\n"
"If the user enters an invalid extension and extension \"i\" (invalid) \n"
"exists in the context, it will be used. Also, if you set the 5th argument\n"
"to 'NOANSWER', the DISA application will not answer initially.\n";
"If login is successful, the application parses the dialed number in\n"
"the specified (or default) context, and returns 0 with the new extension\n"
"context filled-in and the priority set to 1, so that the PBX may\n"
"re-apply the routing tables to it and complete the call normally.";
static void play_dialtone(struct ast_channel *chan, char *mailbox)
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int firstdigittimeout = 20000; /* 20 seconds first digit timeout */
static int digittimeout = 10000; /* 10 seconds subsequent digit timeout */
static int ms_diff(struct timeval *tv1, struct timeval *tv2)
{
int ms;
ms = (tv1->tv_sec - tv2->tv_sec) * 1000;
ms += (tv1->tv_usec - tv2->tv_usec) / 1000;
return(ms);
}
static void play_dialtone(struct ast_channel *chan)
{
const struct tone_zone_sound *ts = NULL;
if(ast_app_has_voicemail(mailbox, NULL))
ts = ast_get_indication_tone(chan->zone, "dialrecall");
else
ts = ast_get_indication_tone(chan->zone, "dial");
ts = ast_get_indication_tone(chan->zone, "dial");
if (ts)
ast_playtones_start(chan, 0, ts->data, 0);
else
@@ -111,92 +105,77 @@ static void play_dialtone(struct ast_channel *chan, char *mailbox)
static int disa_exec(struct ast_channel *chan, void *data)
{
int i,j,k,x,did_ignore,special_noanswer;
int firstdigittimeout = 20000;
int digittimeout = 10000;
struct ast_module_user *u;
char *tmp, exten[AST_MAX_EXTENSION],acctcode[20]="";
char pwline[256];
char ourcidname[256],ourcidnum[256];
int i,j,k,x,did_ignore;
struct localuser *u;
char tmp[256],arg2[256]="",exten[AST_MAX_EXTENSION],acctcode[20]="";
char *ourcontext,*ourcallerid;
struct ast_frame *f;
struct timeval lastdigittime;
struct timeval lastout, now, lastdigittime;
int res;
time_t rstart;
FILE *fp;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(passcode);
AST_APP_ARG(context);
AST_APP_ARG(cid);
AST_APP_ARG(mailbox);
AST_APP_ARG(noanswer);
);
char *stringp=NULL;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
return -1;
}
u = ast_module_user_add(chan);
if (chan->pbx) {
firstdigittimeout = chan->pbx->rtimeout*1000;
digittimeout = chan->pbx->dtimeout*1000;
}
if (ast_set_write_format(chan,AST_FORMAT_ULAW)) {
ast_log(LOG_WARNING, "Unable to set write format to Mu-law on %s\n", chan->name);
ast_module_user_remove(u);
return -1;
}
if (ast_set_read_format(chan,AST_FORMAT_ULAW)) {
ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n", chan->name);
ast_module_user_remove(u);
return -1;
}
ast_log(LOG_DEBUG, "Digittimeout: %d\n", digittimeout);
ast_log(LOG_DEBUG, "Responsetimeout: %d\n", firstdigittimeout);
tmp = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, tmp);
if (ast_strlen_zero(args.context))
args.context = "disa";
if (ast_strlen_zero(args.mailbox))
args.mailbox = "";
ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
special_noanswer = 0;
if ((!args.noanswer) || strcmp(args.noanswer,"NOANSWER"))
if (ast_set_write_format(chan,AST_FORMAT_ULAW))
{
if (chan->_state != AST_STATE_UP) {
/* answer */
ast_answer(chan);
}
} else special_noanswer = 1;
ast_log(LOG_WARNING, "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, "Unable to set read format to Mu-law on %s\n",chan->name);
return -1;
}
lastout.tv_sec = lastout.tv_usec = 0;
if (!data || !strlen((char *)data)) {
ast_log(LOG_WARNING, "disa requires an argument (passcode/passcode file)\n");
return -1;
}
strncpy(tmp, (char *)data, sizeof(tmp)-1);
stringp=tmp;
strsep(&stringp, "|");
ourcontext = strsep(&stringp, "|");
/* if context specified, save 2nd arg and parse third */
if (ourcontext) {
strncpy(arg2,ourcontext, sizeof(arg2) - 1);
ourcallerid = strsep(&stringp,"|");
}
/* if context not specified, use "disa" */
else {
arg2[0] = 0;
ourcallerid = NULL;
ourcontext = "disa";
}
LOCAL_USER_ADD(u);
if (chan->_state != AST_STATE_UP)
{
/* answer */
ast_answer(chan);
}
i = k = x = 0; /* k is 0 for pswd entry, 1 for ext entry */
did_ignore = 0;
exten[0] = 0;
acctcode[0] = 0;
/* can we access DISA without password? */
ast_log(LOG_DEBUG, "Context: %s\n",args.context);
ast_log(LOG_DEBUG, "Context: %s\n",ourcontext);
if (!strcasecmp(args.passcode, "no-password")) {
if (!strcasecmp(tmp, "no-password"))
{;
k |= 1; /* We have the password */
ast_log(LOG_DEBUG, "DISA no-password login success\n");
}
lastdigittime = ast_tvnow();
gettimeofday(&lastdigittime,NULL);
play_dialtone(chan, args.mailbox);
play_dialtone(chan);
for (;;) {
for(;;)
{
gettimeofday(&now,NULL);
/* if outa time, give em reorder */
if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
((k&2) ? digittimeout : firstdigittimeout)) {
if (ms_diff(&now,&lastdigittime) >
((k&2) ? digittimeout : firstdigittimeout))
{
ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
((k&1) ? "extension" : "password"),chan->name);
break;
@@ -207,116 +186,108 @@ static int disa_exec(struct ast_channel *chan, void *data)
}
f = ast_read(chan);
if (f == NULL) {
ast_module_user_remove(u);
if (f == NULL)
{
LOCAL_USER_REMOVE(u);
return -1;
}
if ((f->frametype == AST_FRAME_CONTROL) &&
(f->subclass == AST_CONTROL_HANGUP)) {
(f->subclass == AST_CONTROL_HANGUP))
{
ast_frfree(f);
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return -1;
}
if (f->frametype == AST_FRAME_VOICE) {
ast_frfree(f);
continue;
}
/* if not DTMF, just do it again */
if (f->frametype != AST_FRAME_DTMF) {
/* if not DTMF, just do it again */
if (f->frametype != AST_FRAME_DTMF)
{
ast_frfree(f);
continue;
}
j = f->subclass; /* save digit */
ast_frfree(f);
if (i == 0) {
if (i == 0)
{
k|=2; /* We have the first digit */
ast_playtones_stop(chan);
}
lastdigittime = ast_tvnow();
gettimeofday(&lastdigittime,NULL);
/* got a DTMF tone */
if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
if (!(k&1)) { /* if in password state */
if (j == '#') { /* end of password */
if (i < AST_MAX_EXTENSION) /* if still valid number of digits */
{
if (!(k&1)) /* if in password state */
{
if (j == '#') /* end of password */
{
/* see if this is an integer */
if (sscanf(args.passcode,"%30d",&j) < 1) { /* nope, it must be a filename */
fp = fopen(args.passcode,"r");
if (!fp) {
ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
ast_module_user_remove(u);
if (sscanf(tmp,"%d",&j) < 1)
{ /* nope, it must be a filename */
fp = fopen(tmp,"r");
if (!fp)
{
ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",tmp,chan->name);
LOCAL_USER_REMOVE(u);
return -1;
}
pwline[0] = 0;
while(fgets(pwline,sizeof(pwline) - 1,fp)) {
if (!pwline[0])
continue;
if (pwline[strlen(pwline) - 1] == '\n')
pwline[strlen(pwline) - 1] = 0;
if (!pwline[0])
continue;
/* skip comments */
if (pwline[0] == '#')
continue;
if (pwline[0] == ';')
continue;
AST_STANDARD_APP_ARGS(args, pwline);
ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
/* password must be in valid format (numeric) */
if (sscanf(args.passcode,"%30d", &j) < 1)
continue;
/* if we got it */
if (!strcmp(exten,args.passcode)) {
if (ast_strlen_zero(args.context))
args.context = "disa";
if (ast_strlen_zero(args.mailbox))
args.mailbox = "";
break;
}
tmp[0] = 0;
while(fgets(tmp,sizeof(tmp) - 1,fp))
{
char *stringp=NULL,*stringp2;
if (!tmp[0]) continue;
if (tmp[strlen(tmp) - 1] == '\n')
tmp[strlen(tmp) - 1] = 0;
if (!tmp[0]) continue;
/* skip comments */
if (tmp[0] == '#') continue;
if (tmp[0] == ';') continue;
stringp=tmp;
strsep(&stringp, "|");
stringp2=strsep(&stringp, "|");
if (stringp2) {
ourcontext=stringp2;
stringp2=strsep(&stringp, "|");
if (stringp2) ourcallerid=stringp2;
}
}
/* password must be in valid format (numeric) */
if (sscanf(tmp,"%d",&j) < 1) continue;
/* if we got it */
if (!strcmp(exten,tmp)) break;
}
fclose(fp);
}
/* compare the two */
if (strcmp(exten,args.passcode)) {
}
/* compare the two */
if (strcmp(exten,tmp))
{
ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
goto reorder;
}
/* password good, set to dial state */
ast_log(LOG_DEBUG,"DISA on chan %s password is good\n",chan->name);
play_dialtone(chan, args.mailbox);
play_dialtone(chan);
k|=1; /* In number mode */
i = 0; /* re-set buffer pointer */
exten[sizeof(acctcode)] = 0;
ast_copy_string(acctcode, exten, sizeof(acctcode));
strncpy(acctcode,exten, sizeof(acctcode) - 1);
exten[0] = 0;
ast_log(LOG_DEBUG,"Successful DISA log-in on chan %s\n", chan->name);
ast_log(LOG_DEBUG,"Successful DISA log-in on chan %s\n",chan->name);
continue;
}
} else {
if (j == '#') { /* end of extension .. maybe */
if (i == 0 &&
(ast_matchmore_extension(chan, args.context, "#", 1, chan->cid.cid_num) ||
ast_exists_extension(chan, args.context, "#", 1, chan->cid.cid_num)) ) {
/* Let the # be the part of, or the entire extension */
} else {
break;
}
}
}
exten[i++] = j; /* save digit */
exten[i] = 0;
if (!(k&1))
continue; /* if getting password, continue doing it */
/* if this exists */
if (!(k&1)) continue; /* if getting password, continue doing it */
/* if this exists */
if (ast_ignore_pattern(args.context, exten)) {
play_dialtone(chan, "");
if (ast_ignore_pattern(ourcontext, exten)) {
play_dialtone(chan);
did_ignore = 1;
} else
if (did_ignore) {
@@ -324,50 +295,39 @@ static int disa_exec(struct ast_channel *chan, void *data)
did_ignore = 0;
}
/* if can do some more, do it */
if (!ast_matchmore_extension(chan,args.context,exten,1, chan->cid.cid_num)) {
/* if can do some more, do it */
if (!ast_matchmore_extension(chan,ourcontext,exten,1, chan->callerid)) {
break;
}
}
}
if (k == 3) {
int recheck = 0;
struct ast_flags flags = { AST_CDR_FLAG_POSTED };
if (!ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
exten[0] = 'i';
exten[1] = '\0';
recheck = 1;
}
if (!recheck || ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
ast_playtones_stop(chan);
/* We're authenticated and have a target extension */
if (!ast_strlen_zero(args.cid)) {
ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
}
if (!ast_strlen_zero(acctcode))
ast_string_field_set(chan, accountcode, acctcode);
if (special_noanswer) flags.flags = 0;
ast_cdr_reset(chan->cdr, &flags);
ast_explicit_goto(chan, args.context, exten, 1);
ast_module_user_remove(u);
return 0;
if ((k==3) && (ast_exists_extension(chan,ourcontext,exten,1, chan->callerid)))
{
ast_playtones_stop(chan);
/* We're authenticated and have a valid extension */
if (ourcallerid && *ourcallerid)
{
if (chan->callerid) free(chan->callerid);
chan->callerid = strdup(ourcallerid);
}
strncpy(chan->exten, exten, sizeof(chan->exten) - 1);
strncpy(chan->context, ourcontext, sizeof(chan->context) - 1);
if (!ast_strlen_zero(acctcode))
strncpy(chan->accountcode, acctcode, sizeof(chan->accountcode) - 1);
chan->priority = 0;
ast_cdr_init(chan->cdr,chan);
LOCAL_USER_REMOVE(u);
return 0;
}
/* Received invalid, but no "i" extension exists in the given context */
reorder:
ast_indicate(chan,AST_CONTROL_CONGESTION);
/* something is invalid, give em reorder for several seconds */
time(&rstart);
while(time(NULL) < rstart + 10) {
while(time(NULL) < rstart + 10)
{
if (ast_waitfor(chan, -1) < 0)
break;
f = ast_read(chan);
@@ -376,24 +336,34 @@ reorder:
ast_frfree(f);
}
ast_playtones_stop(chan);
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return -1;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, disa_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key(void)
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,176 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2004 - 2005, Anthony Minessale II.
*
* Anthony Minessale <anthmct@yahoo.com>
*
* 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 Application to dump channel variables
*
* \author Anthony Minessale <anthmct@yahoo.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
static char *app = "DumpChan";
static char *synopsis = "Dump Info About The Calling Channel";
static char *desc =
" DumpChan([<min_verbose_level>])\n"
"Displays information on channel and listing of all channel\n"
"variables. If min_verbose_level is specified, output is only\n"
"displayed when the verbose level is currently set to that number\n"
"or greater. \n";
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
{
struct timeval now;
long elapsed_seconds = 0;
int hour = 0, min = 0, sec = 0;
char cgrp[BUFSIZ/2];
char pgrp[BUFSIZ/2];
char formatbuf[BUFSIZ/2];
now = ast_tvnow();
memset(buf, 0, size);
if (!c)
return 0;
if (c->cdr) {
elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
hour = elapsed_seconds / 3600;
min = (elapsed_seconds % 3600) / 60;
sec = elapsed_seconds % 60;
}
snprintf(buf,size,
"Name= %s\n"
"Type= %s\n"
"UniqueID= %s\n"
"CallerID= %s\n"
"CallerIDName= %s\n"
"DNIDDigits= %s\n"
"RDNIS= %s\n"
"State= %s (%d)\n"
"Rings= %d\n"
"NativeFormat= %s\n"
"WriteFormat= %s\n"
"ReadFormat= %s\n"
"1stFileDescriptor= %d\n"
"Framesin= %d %s\n"
"Framesout= %d %s\n"
"TimetoHangup= %ld\n"
"ElapsedTime= %dh%dm%ds\n"
"Context= %s\n"
"Extension= %s\n"
"Priority= %d\n"
"CallGroup= %s\n"
"PickupGroup= %s\n"
"Application= %s\n"
"Data= %s\n"
"Blocking_in= %s\n",
c->name,
c->tech->type,
c->uniqueid,
S_OR(c->cid.cid_num, "(N/A)"),
S_OR(c->cid.cid_name, "(N/A)"),
S_OR(c->cid.cid_dnid, "(N/A)"),
S_OR(c->cid.cid_rdnis, "(N/A)"),
ast_state2str(c->_state),
c->_state,
c->rings,
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->nativeformats),
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->writeformat),
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->readformat),
c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)c->whentohangup,
hour,
min,
sec,
c->context,
c->exten,
c->priority,
ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
( c->appl ? c->appl : "(N/A)" ),
( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
return 0;
}
static int dumpchan_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char vars[BUFSIZ * 4];
char info[1024];
int level = 0;
static char *line = "================================================================================";
u = ast_module_user_add(chan);
if (!ast_strlen_zero(data))
level = atoi(data);
pbx_builtin_serialize_variables(chan, vars, sizeof(vars));
serialize_showchan(chan, info, sizeof(info));
if (option_verbose >= level)
ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, vars, line);
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, dumpchan_exec, synopsis, desc);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dump Info About The Calling Channel");

View File

@@ -1,105 +1,100 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Echo application -- play back what you hear to evaluate latency
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Echo application -- play back what you hear to evaluate latency
*
* \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/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
static char *tdesc = "Simple Echo Application";
static char *app = "Echo";
static char *synopsis = "Echo audio, video, or DTMF back to the calling party";
static char *synopsis = "Echo audio read back to the user";
static char *descrip =
" Echo(): This application will echo any audio, video, or DTMF frames read from\n"
"the calling channel back to itself. If the DTMF digit '#' is received, the\n"
"application will exit.\n";
" Echo(): Echo audio read from channel back to the channel. Returns 0\n"
"if the user exits with the '#' key, or -1 if the user hangs up.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int echo_exec(struct ast_channel *chan, void *data)
{
int res = -1;
int format;
struct ast_module_user *u;
u = ast_module_user_add(chan);
format = ast_best_codec(chan->nativeformats);
ast_set_write_format(chan, format);
ast_set_read_format(chan, format);
while (ast_waitfor(chan, -1) > -1) {
struct ast_frame *f = ast_read(chan);
if (!f) {
int res=-1;
struct localuser *u;
struct ast_frame *f;
LOCAL_USER_ADD(u);
ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
/* Do our thing here */
while(ast_waitfor(chan, -1) > -1) {
f = ast_read(chan);
if (!f)
break;
}
f->delivery.tv_sec = 0;
f->delivery.tv_usec = 0;
if (ast_write(chan, f)) {
ast_frfree(f);
goto end;
}
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
res = 0;
ast_frfree(f);
goto end;
if (f->frametype == AST_FRAME_VOICE) {
if (ast_write(chan, f))
break;
} else if (f->frametype == AST_FRAME_VIDEO) {
if (ast_write(chan, f))
break;
} else if (f->frametype == AST_FRAME_DTMF) {
if (f->subclass == '#') {
res = 0;
break;
} else
if (ast_write(chan, f))
break;
}
ast_frfree(f);
}
end:
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, echo_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Echo Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

203
apps/app_enumlookup.c Normal file
View File

@@ -0,0 +1,203 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Time of day - Report the time of day
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/options.h>
#include <asterisk/config.h>
#include <asterisk/module.h>
#include <asterisk/enum.h>
#include <asterisk/utils.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
static char *tdesc = "ENUM Lookup";
static char *app = "EnumLookup";
static char *synopsis = "Lookup number in ENUM";
static char *descrip =
" EnumLookup(exten): Looks up an extension via ENUM and sets\n"
"the variable 'ENUM'. For VoIP URIs this variable will \n"
"look like 'TECHNOLOGY/URI' with the appropriate technology.\n"
"Returns -1 on hangup, or 0 on completion regardless of whether the \n"
"lookup was successful. \n"
"Currently, the enumservices SIP, H323, IAX, IAX2 and TEL are recognized. \n"
"A good SIP, H323, IAX or IAX2 entry will result in normal priority handling, \n"
"whereas a good TEL entry will increase the priority by 51 (if existing).\n"
"If the lookup was *not* successful and there exists a priority n + 101,\n"
"then that priority will be taken next.\n" ;
#define ENUM_CONFIG "enum.conf"
static char h323driver[80] = "";
#define H323DRIVERDEFAULT "H323"
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int enumlookup_exec(struct ast_channel *chan, void *data)
{
int res=0;
char tech[80];
char dest[80];
char tmp[256];
char *c,*t;
struct localuser *u;
if (!data || ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n");
res = 1;
}
LOCAL_USER_ADD(u);
if (!res) {
res = ast_get_enum(chan, data, dest, sizeof(dest), tech, sizeof(tech));
printf("ENUM got '%d'\n", res);
}
LOCAL_USER_REMOVE(u);
/* Parse it out */
if (res > 0) {
if (!strcasecmp(tech, "SIP")) {
c = dest;
if (!strncmp(c, "sip:", 4))
c += 4;
snprintf(tmp, sizeof(tmp), "SIP/%s", c);
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
} else if (!strcasecmp(tech, "h323")) {
c = dest;
if (!strncmp(c, "h323:", 5))
c += 5;
snprintf(tmp, sizeof(tmp), "%s/%s", h323driver, c);
/* do a s!;.*!! on the H323 URI */
t = strchr(c,';');
if (t)
*t = 0;
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
} else if (!strcasecmp(tech, "iax")) {
c = dest;
if (!strncmp(c, "iax:", 4))
c += 4;
snprintf(tmp, sizeof(tmp), "IAX/%s", c);
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
} else if (!strcasecmp(tech, "iax2")) {
c = dest;
if (!strncmp(c, "iax2:", 5))
c += 5;
snprintf(tmp, sizeof(tmp), "IAX2/%s", c);
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
} else if (!strcasecmp(tech, "tel")) {
c = dest;
if (!strncmp(c, "tel:", 4))
c += 4;
if (c[0] != '+') {
ast_log(LOG_NOTICE, "tel: uri must start with a \"+\" (got '%s')\n", c);
res = 0;
} else {
/* now copy over the number, skipping all non-digits and stop at ; or NULL */
t = tmp;
while( *c && (*c != ';') && (t - tmp < (sizeof(tmp) - 1))) {
if (isdigit(*c))
*t++ = *c;
c++;
}
*t = 0;
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
ast_log(LOG_NOTICE, "tel: ENUM set to \"%s\"\n", tmp);
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 51, chan->callerid))
chan->priority += 50;
else
res = 0;
}
} else if (!ast_strlen_zero(tech)) {
ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
res = 0;
}
}
if (!res) {
/* Look for a "busy" place */
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority += 100;
} else if (res > 0)
res = 0;
return res;
}
static int load_config(void)
{
struct ast_config *cfg;
char *s;
cfg = ast_load(ENUM_CONFIG);
if (cfg) {
if (!(s=ast_variable_retrieve(cfg, "general", "h323driver"))) {
strncpy(h323driver, H323DRIVERDEFAULT, sizeof(h323driver) - 1);
} else {
strncpy(h323driver, s, sizeof(h323driver) - 1);
}
ast_destroy(cfg);
return 0;
}
ast_log(LOG_NOTICE, "No ENUM Config file, using defaults\n");
return 0;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
int res;
res = ast_register_application(app, enumlookup_exec, synopsis, descrip);
if (res)
return(res);
if ((res=load_config())) {
return(res);
}
return(0);
}
int reload(void)
{
return(load_config());
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

101
apps/app_eval.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Eval application
*
* Copyright (c) 2004 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <app_eval__v001@the-tilghman.com>
*
* $Id$
*
* This code is released by the author with no restrictions on usage.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
/* Maximum length of any variable */
#define MAXRESULT 1024
static char *tdesc = "Reevaluates strings";
static char *app_eval = "Eval";
static char *eval_synopsis = "Evaluates a string";
static char *eval_descrip =
"Usage: Eval(newvar=somestring)\n"
" Normally Asterisk evaluates variables inline. But what if you want to\n"
"store variable offsets in a database, to be evaluated later? Eval is\n"
"the answer, by allowing a string to be evaluated twice in the dialplan,\n"
"the first time as part of the normal dialplan, and the second using Eval.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int eval_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char *s, *newvar=NULL, tmp[MAXRESULT];
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data) {
s = ast_strdupa((char *)data);
if (s) {
newvar = strsep(&s, "=");
if (newvar && (newvar[0] != '\0')) {
memset(tmp, 0, MAXRESULT);
pbx_substitute_variables_helper(chan, s, tmp, MAXRESULT - 1);
pbx_builtin_setvar_helper(chan, newvar, tmp);
}
} else {
ast_log(LOG_ERROR, "Out of memory\n");
res = -1;
}
}
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app_eval);
}
int load_module(void)
{
return ast_register_application(app_eval, eval_exec, eval_synopsis, eval_descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,221 +1,113 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
* Portions copyright (c) 2006, Philipp Dunkel.
* Exec application
*
* Tilghman Lesher <app_exec__v002@the-tilghman.com>
* Copyright (c) 2004 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <app_exec__v001@the-tilghman.com>
*
* $Id$
*
* This code is released by the author with no restrictions on usage.
*
* 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.
*
*/
/*! \file
*
* \brief Exec application
*
* \author Tilghman Lesher <app_exec__v002@the-tilghman.com>
* \author Philipp Dunkel <philipp.dunkel@ebox.at>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
/* Maximum length of any variable */
#define MAXRESULT 1024
/*! Note
*
* The key difference between these two apps is exit status. In a
* nutshell, Exec tries to be transparent as possible, behaving
* in exactly the same way as if the application it calls was
* directly invoked from the dialplan.
*
* TryExec, on the other hand, provides a way to execute applications
* and catch any possible fatal error without actually fatally
* affecting the dialplan.
*/
static char *tdesc = "Executes applications";
static char *app_exec = "Exec";
static char *exec_synopsis = "Executes dialplan application";
static char *exec_synopsis = "Exec(Appname(arguments))";
static char *exec_descrip =
"Usage: Exec(appname(arguments))\n"
"Exec(appname(arguments))\n"
" Allows an arbitrary application to be invoked even when not\n"
"hardcoded into the dialplan. If the underlying application\n"
"terminates the dialplan, or if the application cannot be found,\n"
"Exec will terminate the dialplan.\n"
" To invoke external applications, see the application System.\n"
" If you would like to catch any error instead, see TryExec.\n";
"hardcoded into the dialplan. Returns whatever value the\n"
"app returns or -2 when the app cannot be found.\n";
static char *app_tryexec = "TryExec";
static char *tryexec_synopsis = "Executes dialplan application, always returning";
static char *tryexec_descrip =
"Usage: TryExec(appname(arguments))\n"
" Allows an arbitrary application to be invoked even when not\n"
"hardcoded into the dialplan. To invoke external applications\n"
"see the application System. Always returns to the dialplan.\n"
"The channel variable TRYSTATUS will be set to:\n"
" SUCCESS if the application returned zero\n"
" FAILED if the application returned non-zero\n"
" NOAPP if the application was not found or was not specified\n";
STANDARD_LOCAL_USER;
static char *app_execif = "ExecIf";
static char *execif_synopsis = "Executes dialplan application, conditionally";
static char *execif_descrip =
"Usage: ExecIF (<expr>|<app>|<data>)\n"
"If <expr> is true, execute and return the result of <app>(<data>).\n"
"If <expr> is true, but <app> is not found, then the application\n"
"will return a non-zero value.\n";
LOCAL_USER_DECL;
static int exec_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
char *s, *appname, *endargs, args[MAXRESULT] = "";
struct localuser *u;
char *s, *appname, *endargs, args[MAXRESULT];
struct ast_app *app;
u = ast_module_user_add(chan);
LOCAL_USER_ADD(u);
memset(args, 0, MAXRESULT);
/* Check and parse arguments */
if (data) {
s = ast_strdupa(data);
appname = strsep(&s, "(");
s = ast_strdupa((char *)data);
if (s) {
endargs = strrchr(s, ')');
if (endargs)
*endargs = '\0';
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
}
if (appname) {
app = pbx_findapp(appname);
if (app) {
res = pbx_exec(chan, app, args);
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
res = -1;
appname = strsep(&s, "(");
if (s) {
endargs = strrchr(s, ')');
if (endargs)
*endargs = '\0';
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
}
if (appname) {
app = pbx_findapp(appname);
if (app) {
res = pbx_exec(chan, app, args, 1);
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
res = -2;
}
}
} else {
ast_log(LOG_ERROR, "Out of memory\n");
res = -1;
}
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int tryexec_exec(struct ast_channel *chan, void *data)
int unload_module(void)
{
int res=0;
struct ast_module_user *u;
char *s, *appname, *endargs, args[MAXRESULT] = "";
struct ast_app *app;
u = ast_module_user_add(chan);
/* Check and parse arguments */
if (data) {
s = ast_strdupa(data);
appname = strsep(&s, "(");
if (s) {
endargs = strrchr(s, ')');
if (endargs)
*endargs = '\0';
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
}
if (appname) {
app = pbx_findapp(appname);
if (app) {
res = pbx_exec(chan, app, args);
pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOAPP");
}
}
}
ast_module_user_remove(u);
return 0;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app_exec);
}
static int execif_exec(struct ast_channel *chan, void *data)
int load_module(void)
{
int res = 0;
struct ast_module_user *u;
char *myapp = NULL;
char *mydata = NULL;
char *expr = NULL;
struct ast_app *app = NULL;
u = ast_module_user_add(chan);
expr = ast_strdupa(data);
if ((myapp = strchr(expr,'|'))) {
*myapp = '\0';
myapp++;
if ((mydata = strchr(myapp,'|'))) {
*mydata = '\0';
mydata++;
} else
mydata = "";
if (pbx_checkcondition(expr)) {
if ((app = pbx_findapp(myapp))) {
res = pbx_exec(chan, app, mydata);
} else {
ast_log(LOG_WARNING, "Could not find application! (%s)\n", myapp);
res = -1;
}
}
} else {
ast_log(LOG_ERROR,"Invalid Syntax.\n");
res = -1;
}
ast_module_user_remove(u);
return res;
return ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
}
static int unload_module(void)
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_unregister_application(app_exec);
res |= ast_unregister_application(app_tryexec);
res |= ast_unregister_application(app_execif);
ast_module_user_hangup_all();
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
int res = ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
res |= ast_register_application(app_tryexec, tryexec_exec, tryexec_synopsis, tryexec_descrip);
res |= ast_register_application(app_execif, execif_exec, execif_synopsis, execif_descrip);
return res;
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Executes dialplan applications");

View File

@@ -1,601 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Kevin P. Fleming <kpfleming@digium.com>
*
* Portions taken from the file-based music-on-hold work
* created by Anthony Minessale II in res_musiconhold.c
*
* 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 External IVR application interface
*
* \author Kevin P. Fleming <kpfleming@digium.com>
*
* \note Portions taken from the file-based music-on-hold work
* created by Anthony Minessale II in res_musiconhold.c
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>working_fork</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/linkedlists.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
static const char *app = "ExternalIVR";
static const char *synopsis = "Interfaces with an external IVR application";
static const char *descrip =
" ExternalIVR(command[|arg[|arg...]]): Forks a process to run the supplied command,\n"
"and starts a generator on the channel. The generator's play list is\n"
"controlled by the external application, which can add and clear entries\n"
"via simple commands issued over its stdout. The external application\n"
"will receive all DTMF events received on the channel, and notification\n"
"if the channel is hung up. The application will not be forcibly terminated\n"
"when the channel is hung up.\n"
"See doc/externalivr.txt for a protocol specification.\n";
/* XXX the parser in gcc 2.95 gets confused if you don't put a space between 'name' and the comma */
#define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
struct playlist_entry {
AST_LIST_ENTRY(playlist_entry) list;
char filename[1];
};
struct ivr_localuser {
struct ast_channel *chan;
AST_LIST_HEAD(playlist, playlist_entry) playlist;
AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
int abort_current_sound;
int playing_silence;
int option_autoclear;
};
struct gen_state {
struct ivr_localuser *u;
struct ast_filestream *stream;
struct playlist_entry *current;
int sample_queue;
};
static void send_child_event(FILE *handle, const char event, const char *data,
const struct ast_channel *chan)
{
char tmp[256];
if (!data) {
snprintf(tmp, sizeof(tmp), "%c,%10d", event, (int)time(NULL));
} else {
snprintf(tmp, sizeof(tmp), "%c,%10d,%s", event, (int)time(NULL), data);
}
fprintf(handle, "%s\n", tmp);
ast_chan_log(LOG_DEBUG, chan, "sent '%s'\n", tmp);
}
static void *gen_alloc(struct ast_channel *chan, void *params)
{
struct ivr_localuser *u = params;
struct gen_state *state;
if (!(state = ast_calloc(1, sizeof(*state))))
return NULL;
state->u = u;
return state;
}
static void gen_closestream(struct gen_state *state)
{
if (!state->stream)
return;
ast_closestream(state->stream);
state->u->chan->stream = NULL;
state->stream = NULL;
}
static void gen_release(struct ast_channel *chan, void *data)
{
struct gen_state *state = data;
gen_closestream(state);
free(data);
}
/* caller has the playlist locked */
static int gen_nextfile(struct gen_state *state)
{
struct ivr_localuser *u = state->u;
char *file_to_stream;
u->abort_current_sound = 0;
u->playing_silence = 0;
gen_closestream(state);
while (!state->stream) {
state->current = AST_LIST_REMOVE_HEAD(&u->playlist, list);
if (state->current) {
file_to_stream = state->current->filename;
} else {
file_to_stream = "silence/10";
u->playing_silence = 1;
}
if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
if (!u->playing_silence) {
continue;
} else {
break;
}
}
}
return (!state->stream);
}
static struct ast_frame *gen_readframe(struct gen_state *state)
{
struct ast_frame *f = NULL;
struct ivr_localuser *u = state->u;
if (u->abort_current_sound ||
(u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
gen_closestream(state);
AST_LIST_LOCK(&u->playlist);
gen_nextfile(state);
AST_LIST_UNLOCK(&u->playlist);
}
if (!(state->stream && (f = ast_readframe(state->stream)))) {
if (state->current) {
AST_LIST_LOCK(&u->finishlist);
AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
AST_LIST_UNLOCK(&u->finishlist);
state->current = NULL;
}
if (!gen_nextfile(state))
f = ast_readframe(state->stream);
}
return f;
}
static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
{
struct gen_state *state = data;
struct ast_frame *f = NULL;
int res = 0;
state->sample_queue += samples;
while (state->sample_queue > 0) {
if (!(f = gen_readframe(state)))
return -1;
res = ast_write(chan, f);
ast_frfree(f);
if (res < 0) {
ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
return -1;
}
state->sample_queue -= f->samples;
}
return res;
}
static struct ast_generator gen =
{
alloc: gen_alloc,
release: gen_release,
generate: gen_generate,
};
static struct playlist_entry *make_entry(const char *filename)
{
struct playlist_entry *entry;
if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */
return NULL;
strcpy(entry->filename, filename);
return entry;
}
static int app_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *lu;
struct playlist_entry *entry;
const char *args = data;
int child_stdin[2] = { 0,0 };
int child_stdout[2] = { 0,0 };
int child_stderr[2] = { 0,0 };
int res = -1;
int test_available_fd = -1;
int gen_active = 0;
int pid;
char *argv[32];
int argc = 1;
char *buf, *command;
FILE *child_commands = NULL;
FILE *child_errors = NULL;
FILE *child_events = NULL;
struct ivr_localuser foo = {
.playlist = AST_LIST_HEAD_INIT_VALUE,
.finishlist = AST_LIST_HEAD_INIT_VALUE,
};
struct ivr_localuser *u = &foo;
sigset_t fullset, oldset;
lu = ast_module_user_add(chan);
sigfillset(&fullset);
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
u->abort_current_sound = 0;
u->chan = chan;
if (ast_strlen_zero(args)) {
ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
ast_module_user_remove(lu);
return -1;
}
buf = ast_strdupa(data);
argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));
if (pipe(child_stdin)) {
ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
goto exit;
}
if (pipe(child_stdout)) {
ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
goto exit;
}
if (pipe(child_stderr)) {
ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
goto exit;
}
if (chan->_state != AST_STATE_UP) {
ast_answer(chan);
}
if (ast_activate_generator(chan, &gen, u) < 0) {
ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
goto exit;
} else
gen_active = 1;
pid = fork();
if (pid < 0) {
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
goto exit;
}
if (!pid) {
/* child process */
int i;
#ifdef HAVE_CAP
cap_t cap = cap_from_text("cap_net_admin-eip");
if (cap_set_proc(cap)) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
}
cap_free(cap);
#endif
signal(SIGPIPE, SIG_DFL);
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
if (ast_opt_high_priority)
ast_set_priority(0);
dup2(child_stdin[0], STDIN_FILENO);
dup2(child_stdout[1], STDOUT_FILENO);
dup2(child_stderr[1], STDERR_FILENO);
for (i = STDERR_FILENO + 1; i < 1024; i++)
close(i);
execv(argv[0], argv);
fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
_exit(1);
} else {
/* parent process */
int child_events_fd = child_stdin[1];
int child_commands_fd = child_stdout[0];
int child_errors_fd = child_stderr[0];
struct ast_frame *f;
int ms;
int exception;
int ready_fd;
int waitfds[2] = { child_errors_fd, child_commands_fd };
struct ast_channel *rchan;
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
close(child_stdin[0]);
child_stdin[0] = 0;
close(child_stdout[1]);
child_stdout[1] = 0;
close(child_stderr[1]);
child_stderr[1] = 0;
if (!(child_events = fdopen(child_events_fd, "w"))) {
ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n");
goto exit;
}
if (!(child_commands = fdopen(child_commands_fd, "r"))) {
ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n");
goto exit;
}
if (!(child_errors = fdopen(child_errors_fd, "r"))) {
ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n");
goto exit;
}
test_available_fd = open("/dev/null", O_RDONLY);
setvbuf(child_events, NULL, _IONBF, 0);
setvbuf(child_commands, NULL, _IONBF, 0);
setvbuf(child_errors, NULL, _IONBF, 0);
res = 0;
while (1) {
if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
res = -1;
break;
}
if (ast_check_hangup(chan)) {
ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
send_child_event(child_events, 'H', NULL, chan);
res = -1;
break;
}
ready_fd = 0;
ms = 100;
errno = 0;
exception = 0;
rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms);
if (!AST_LIST_EMPTY(&u->finishlist)) {
AST_LIST_LOCK(&u->finishlist);
while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
send_child_event(child_events, 'F', entry->filename, chan);
free(entry);
}
AST_LIST_UNLOCK(&u->finishlist);
}
if (rchan) {
/* the channel has something */
f = ast_read(chan);
if (!f) {
ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
send_child_event(child_events, 'H', NULL, chan);
res = -1;
break;
}
if (f->frametype == AST_FRAME_DTMF) {
send_child_event(child_events, f->subclass, NULL, chan);
if (u->option_autoclear) {
if (!u->abort_current_sound && !u->playing_silence)
send_child_event(child_events, 'T', NULL, chan);
AST_LIST_LOCK(&u->playlist);
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
send_child_event(child_events, 'D', entry->filename, chan);
free(entry);
}
if (!u->playing_silence)
u->abort_current_sound = 1;
AST_LIST_UNLOCK(&u->playlist);
}
} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
send_child_event(child_events, 'H', NULL, chan);
ast_frfree(f);
res = -1;
break;
}
ast_frfree(f);
} else if (ready_fd == child_commands_fd) {
char input[1024];
if (exception || feof(child_commands)) {
ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
res = -1;
break;
}
if (!fgets(input, sizeof(input), child_commands))
continue;
command = ast_strip(input);
ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);
if (strlen(input) < 4)
continue;
if (input[0] == 'S') {
if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
send_child_event(child_events, 'Z', NULL, chan);
strcpy(&input[2], "exception");
}
if (!u->abort_current_sound && !u->playing_silence)
send_child_event(child_events, 'T', NULL, chan);
AST_LIST_LOCK(&u->playlist);
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
send_child_event(child_events, 'D', entry->filename, chan);
free(entry);
}
if (!u->playing_silence)
u->abort_current_sound = 1;
entry = make_entry(&input[2]);
if (entry)
AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
AST_LIST_UNLOCK(&u->playlist);
} else if (input[0] == 'A') {
if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
send_child_event(child_events, 'Z', NULL, chan);
strcpy(&input[2], "exception");
}
entry = make_entry(&input[2]);
if (entry) {
AST_LIST_LOCK(&u->playlist);
AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
AST_LIST_UNLOCK(&u->playlist);
}
} else if (input[0] == 'H') {
ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
send_child_event(child_events, 'H', NULL, chan);
break;
} else if (input[0] == 'O') {
if (!strcasecmp(&input[2], "autoclear"))
u->option_autoclear = 1;
else if (!strcasecmp(&input[2], "noautoclear"))
u->option_autoclear = 0;
else
ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
}
} else if (ready_fd == child_errors_fd) {
char input[1024];
if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) {
ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
res = -1;
break;
}
if (fgets(input, sizeof(input), child_errors)) {
command = ast_strip(input);
ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
}
} else if ((ready_fd < 0) && ms) {
if (errno == 0 || errno == EINTR)
continue;
ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
break;
}
}
}
exit:
if (gen_active)
ast_deactivate_generator(chan);
if (child_events)
fclose(child_events);
if (child_commands)
fclose(child_commands);
if (child_errors)
fclose(child_errors);
if (test_available_fd > -1) {
close(test_available_fd);
}
if (child_stdin[0])
close(child_stdin[0]);
if (child_stdin[1])
close(child_stdin[1]);
if (child_stdout[0])
close(child_stdout[0]);
if (child_stdout[1])
close(child_stdout[1]);
if (child_stderr[0])
close(child_stderr[0]);
if (child_stderr[1])
close(child_stderr[1]);
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
free(entry);
ast_module_user_remove(lu);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, app_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");

View File

@@ -1,39 +1,26 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Connect to festival
*
* Copyright (C) 2002, Christos Ricudis
*
* Christos Ricudis <ricudis@itc.auth.gr>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Connect to festival
*
* \author Christos Ricudis <ricudis@itc.auth.gr>
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>working_fork</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/md5.h>
#include <asterisk/config.h>
#include <asterisk/utils.h>
#include <asterisk/lock.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -49,24 +36,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/md5.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/options.h"
#define FESTIVAL_CONFIG "festival.conf"
static char *tdesc = "Simple Festival Interface";
static char *app = "Festival";
static char *synopsis = "Say text to the user";
@@ -76,6 +51,9 @@ static char *descrip =
"play it to the user, allowing any given interrupt keys to immediately terminate and return\n"
"the value, or 'any' to allow any number back (useful in dialplan)\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static char *socket_receive_file_to_buff(int fd,int *size)
{
@@ -90,10 +68,7 @@ static char *socket_receive_file_to_buff(int fd,int *size)
char c;
bufflen = 1024;
if (!(buff = ast_malloc(bufflen)))
{
/* TODO: Handle memory allocation failure */
}
buff = (char *)malloc(bufflen);
*size=0;
for (k=0; file_stuff_key[k] != '\0';)
@@ -103,10 +78,7 @@ static char *socket_receive_file_to_buff(int fd,int *size)
if ((*size)+k+1 >= bufflen)
{ /* +1 so you can add a NULL if you want */
bufflen += bufflen/4;
if (!(buff = ast_realloc(buff, bufflen)))
{
/* TODO: Handle memory allocation failure */
}
buff = (char *)realloc(buff,bufflen);
}
if (file_stuff_key[k] == c)
k++;
@@ -138,39 +110,17 @@ static int send_waveform_to_fd(char *waveform, int length, int fd) {
#ifdef __PPC__
char c;
#endif
sigset_t fullset, oldset;
#ifdef HAVE_CAP
cap_t cap;
#endif
sigfillset(&fullset);
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
res = fork();
if (res < 0)
ast_log(LOG_WARNING, "Fork failed\n");
if (res) {
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
return res;
}
#ifdef HAVE_CAP
cap = cap_from_text("cap_net_admin-eip");
if (cap_set_proc(cap)) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
}
cap_free(cap);
#endif
for (x=0;x<256;x++) {
if (x != fd)
close(x);
}
if (ast_opt_high_priority)
ast_set_priority(0);
signal(SIGPIPE, SIG_DFL);
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
/*IAS */
res = fork();
if (res < 0)
ast_log(LOG_WARNING, "Fork failed\n");
if (res)
return res;
for (x=0;x<256;x++) {
if (x != fd)
close(x);
}
//IAS
#ifdef __PPC__
for( x=0; x<length; x+=2)
{
@@ -180,9 +130,7 @@ static int send_waveform_to_fd(char *waveform, int length, int fd) {
}
#endif
if (write(fd,waveform,length) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
}
write(fd,waveform,length);
close(fd);
exit(0);
}
@@ -200,9 +148,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
struct ast_frame f;
char offset[AST_FRIENDLY_OFFSET];
char frdata[2048];
} myf = {
.f = { 0, },
};
} myf;
if (pipe(fds)) {
ast_log(LOG_WARNING, "Unable to create pipe\n");
@@ -213,8 +159,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
if (chan->_state != AST_STATE_UP)
ast_answer(chan);
ast_stopstream(chan);
ast_indicate(chan, -1);
owriteformat = chan->writeformat;
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
@@ -262,18 +207,17 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
myf.f.subclass = AST_FORMAT_SLINEAR;
myf.f.datalen = res;
myf.f.samples = res / 2;
myf.f.mallocd = 0;
myf.f.offset = AST_FRIENDLY_OFFSET;
myf.f.src = __PRETTY_FUNCTION__;
myf.f.data = myf.frdata;
if (ast_write(chan, &myf.f) < 0) {
res = -1;
ast_frfree(f);
break;
}
if (res < needed) { /* last frame */
if (res < needed) { // last frame
ast_log(LOG_DEBUG, "Last frame\n");
res=0;
ast_frfree(f);
break;
}
} else {
@@ -286,9 +230,8 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
}
close(fds[0]);
close(fds[1]);
/* if (pid > -1) */
/* kill(pid, SIGKILL); */
// if (pid > -1)
// kill(pid, SIGKILL);
if (!res && owriteformat)
ast_set_write_format(chan, owriteformat);
return res;
@@ -304,16 +247,16 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
{
int usecache;
int res=0;
struct ast_module_user *u;
struct localuser *u;
struct sockaddr_in serv_addr;
struct hostent *serverhost;
struct ast_hostent ahp;
int fd;
FILE *fs;
const char *host;
const char *cachedir;
const char *temp;
const char *festivalcommand;
char *host;
char *cachedir;
char *temp;
char *festivalcommand;
int port=1314;
int n;
char ack[4];
@@ -333,22 +276,13 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
int fdesc = -1;
char buffer[16384];
int seekpos = 0;
char *data;
char data[256] = "";
char *intstr;
struct ast_config *cfg;
char *newfestivalcommand;
if (ast_strlen_zero(vdata)) {
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
return -1;
}
u = ast_module_user_add(chan);
cfg = ast_config_load(FESTIVAL_CONFIG);
cfg = ast_load(FESTIVAL_CONFIG);
if (!cfg) {
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
ast_module_user_remove(u);
return -1;
}
if (!(host = ast_variable_retrieve(cfg, "general", "host"))) {
@@ -369,34 +303,20 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
}
if (!(festivalcommand = ast_variable_retrieve(cfg, "general", "festivalcommand"))) {
festivalcommand = "(tts_textasterisk \"%s\" 'file)(quit)\n";
} else { /* This else parses the festivalcommand that we're sent from the config file for \n's, etc */
int i, j;
newfestivalcommand = alloca(strlen(festivalcommand) + 1);
for (i = 0, j = 0; i < strlen(festivalcommand); i++) {
if (festivalcommand[i] == '\\' && festivalcommand[i + 1] == 'n') {
newfestivalcommand[j++] = '\n';
i++;
} else if (festivalcommand[i] == '\\') {
newfestivalcommand[j++] = festivalcommand[i + 1];
i++;
} else
newfestivalcommand[j++] = festivalcommand[i];
}
newfestivalcommand[j] = '\0';
festivalcommand = newfestivalcommand;
}
data = ast_strdupa(vdata);
intstr = strchr(data, '|');
if (intstr) {
if (!vdata || ast_strlen_zero(vdata)) {
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
ast_destroy(cfg);
return -1;
}
strncpy(data, vdata, sizeof(data) - 1);
if ((intstr = strchr(data, '|'))) {
*intstr = '\0';
intstr++;
if (!strcasecmp(intstr, "any"))
intstr = AST_DIGIT_ANY;
}
LOCAL_USER_ADD(u);
ast_log(LOG_DEBUG, "Text passed to festival server : %s\n",(char *)data);
/* Connect to local festival server */
@@ -404,8 +324,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
if (fd < 0) {
ast_log(LOG_WARNING,"festival_client: can't get socket\n");
ast_config_destroy(cfg);
ast_module_user_remove(u);
ast_destroy(cfg);
return -1;
}
memset(&serv_addr, 0, sizeof(serv_addr));
@@ -414,8 +333,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
serverhost = ast_gethostbyname(host, &ahp);
if (serverhost == (struct hostent *)0) {
ast_log(LOG_WARNING,"festival_client: gethostbyname failed\n");
ast_config_destroy(cfg);
ast_module_user_remove(u);
ast_destroy(cfg);
return -1;
}
memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
@@ -425,8 +343,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) {
ast_log(LOG_WARNING,"festival_client: connect to server failed\n");
ast_config_destroy(cfg);
ast_module_user_remove(u);
ast_destroy(cfg);
return -1;
}
@@ -453,25 +370,17 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
writecache=1;
strln=strlen((char *)data);
ast_log(LOG_DEBUG,"line length : %d\n",strln);
if (write(fdesc,&strln,sizeof(int)) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
}
if (write(fdesc,data,strln) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
}
write(fdesc,&strln,sizeof(int));
write(fdesc,data,strln);
seekpos=lseek(fdesc,0,SEEK_CUR);
ast_log(LOG_DEBUG,"Seek position : %d\n",seekpos);
}
} else {
if (read(fdesc,&strln,sizeof(int)) != sizeof(int)) {
ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
}
read(fdesc,&strln,sizeof(int));
ast_log(LOG_DEBUG,"Cache file exists, strln=%d, strlen=%d\n",strln,(int)strlen((char *)data));
if (strlen((char *)data)==strln) {
ast_log(LOG_DEBUG,"Size OK\n");
if (read(fdesc,&bigstring,strln) != strln) {
ast_log(LOG_WARNING, "read() failed: %s\n", strerror(errno));
}
read(fdesc,&bigstring,strln);
bigstring[strln] = 0;
if (strcmp(bigstring,data)==0) {
readcache=1;
@@ -500,9 +409,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
if (writecache==1) {
ast_log(LOG_DEBUG,"Writing result to cache...\n");
while ((strln=read(fd,buffer,16384))!=0) {
if (write(fdesc,buffer,strln) < 0) {
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
}
write(fdesc,buffer,strln);
}
close(fd);
close(fdesc);
@@ -516,23 +423,8 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
/* This assumes only one waveform will come back, also LP is unlikely */
wave = 0;
do {
int read_data;
for (n=0; n < 3; )
{
read_data = read(fd,ack+n,3-n);
/* this avoids falling in infinite loop
* in case that festival server goes down
* */
if ( read_data == -1 )
{
ast_log(LOG_WARNING,"Unable to read from cache/festival fd\n");
close(fd);
ast_config_destroy(cfg);
ast_module_user_remove(u);
return -1;
}
n += read_data;
}
n += read(fd,ack+n,3-n);
ack[3] = '\0';
if (strcmp(ack,"WV\n") == 0) { /* receive a waveform */
ast_log(LOG_DEBUG,"Festival WV command\n");
@@ -554,32 +446,37 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
}
} while (strcmp(ack,"OK\n") != 0);
close(fd);
ast_config_destroy(cfg);
ast_module_user_remove(u);
ast_destroy(cfg);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
struct ast_config *cfg = ast_config_load(FESTIVAL_CONFIG);
if (!cfg) {
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
return AST_MODULE_LOAD_DECLINE;
}
ast_config_destroy(cfg);
return ast_register_application(app, festival_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Festival Interface");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,81 +1,58 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to flash a zap trunk
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 App to flash a DAHDI trunk
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
/*** MODULEINFO
<depend>dahdi</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/options.h>
#include <sys/ioctl.h>
#ifdef __linux__
#include <linux/zaptel.h>
#else
#include <zaptel.h>
#endif /* __linux__ */
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/options.h"
#include "asterisk/dahdi_compat.h"
static char *tdesc = "Flash zap trunk application";
static char *app = "Flash";
static char *dahdi_synopsis = "Flashes a DAHDI trunk";
static char *synopsis = "Flashes a Zap Trunk";
static char *dahdi_descrip =
"Performs a flash on a DAHDI trunk. This can be used\n"
"to access features provided on an incoming analogue circuit\n"
"such as conference and call waiting. Use with SendDTMF() to\n"
"perform external transfers\n";
static char *descrip =
" Flash(): Sends a flash on a zap trunk. This is only a hack for\n"
"people who want to perform transfers and such via AGI and is generally\n"
"quite useless otherwise. Returns 0 on success or -1 if this is not\n"
"a zap trunk\n";
static char *zap_synopsis = "Flashes a Zap trunk";
STANDARD_LOCAL_USER;
static char *zap_descrip =
"Performs a flash on a Zap trunk. This can be used\n"
"to access features provided on an incoming analogue circuit\n"
"such as conference and call waiting. Use with SendDTMF() to\n"
"perform external transfers\n";
LOCAL_USER_DECL;
static inline int zt_wait_event(int fd)
{
/* Avoid the silly zt_waitevent which ignores a bunch of events */
int i,j=0;
i = DAHDI_IOMUX_SIGEVENT;
if (ioctl(fd, DAHDI_IOMUX, &i) == -1) return -1;
if (ioctl(fd, DAHDI_GETEVENT, &j) == -1) return -1;
i = ZT_IOMUX_SIGEVENT;
if (ioctl(fd, ZT_IOMUX, &i) == -1) return -1;
if (ioctl(fd, ZT_GETEVENT, &j) == -1) return -1;
return j;
}
@@ -83,16 +60,16 @@ static int flash_exec(struct ast_channel *chan, void *data)
{
int res = -1;
int x;
struct ast_module_user *u;
struct dahdi_params ztp;
u = ast_module_user_add(chan);
if (!strcasecmp(chan->tech->type, dahdi_chan_name)) {
struct localuser *u;
struct zt_params ztp;
LOCAL_USER_ADD(u);
if (!strcasecmp(chan->type, "Zap")) {
memset(&ztp, 0, sizeof(ztp));
res = ioctl(chan->fds[0], DAHDI_GET_PARAMS, &ztp);
res = ioctl(chan->fds[0], ZT_GET_PARAMS, &ztp);
if (!res) {
if (ztp.sigtype & __DAHDI_SIG_FXS) {
x = DAHDI_FLASH;
res = ioctl(chan->fds[0], DAHDI_HOOK, &x);
if (ztp.sigtype & __ZT_SIG_FXS) {
x = ZT_FLASH;
res = ioctl(chan->fds[0], ZT_HOOK, &x);
if (!res || (errno == EINPROGRESS)) {
if (res) {
/* Wait for the event to finish */
@@ -108,29 +85,35 @@ static int flash_exec(struct ast_channel *chan, void *data)
} else
ast_log(LOG_WARNING, "Unable to get parameters of %s: %s\n", chan->name, strerror(errno));
} else
ast_log(LOG_WARNING, "%s is not a DAHDI channel\n", chan->name);
ast_module_user_remove(u);
ast_log(LOG_WARNING, "%s is not a Zap channel\n", chan->name);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, flash_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
if (*dahdi_chan_mode == CHAN_ZAP_MODE) {
return ast_register_application(app, flash_exec, zap_synopsis, zap_descrip);
} else {
return ast_register_application(app, flash_exec, dahdi_synopsis, dahdi_descrip);
}
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Flash channel application");

File diff suppressed because it is too large Load Diff

View File

@@ -1,267 +1,91 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Anthony Minessale anthmct@yahoo.com
* Fork CDR application
* Copyright Anthony Minessale anthmct@yahoo.com
* Development of this app Sponsered/Funded by TAAN Softworks Corp
*
* 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 Fork CDR application
*
* \author Anthony Minessale anthmct@yahoo.com
*
* \note Development of this app Sponsored/Funded by TAAN Softworks Corp
*
* \ingroup applications
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/cdr.h>
#include <asterisk/module.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/cdr.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
static char *tdesc = "Fork The CDR into 2 separate entities.";
static char *app = "ForkCDR";
static char *synopsis =
"Forks the Call Data Record";
static char *descrip =
" ForkCDR([options]): Causes the Call Data Record to fork an additional\n"
"cdr record starting from the time of the fork call. This new cdr record will\n"
"be linked to end of the list of cdr records attached to the channel. The original CDR is\n"
"has a LOCKED flag set, which forces most cdr operations to skip it, except\n"
"for the functions that set the answer and end times, which ignore the LOCKED\n"
"flag. This allows all the cdr records in the channel to be 'ended' together\n"
"when the channel is closed.\n"
"The CDR() func (when setting CDR values) normally ignores the LOCKED flag also,\n"
"but has options to vary its behavior. The 'T' option (described below), can\n"
"override this behavior, but beware the risks.\n"
"\n"
"Detailed Behavior Description:\n"
"First, this app finds the last cdr record in the list, and makes\n"
"a copy of it. This new copy will be the newly forked cdr record.\n"
"Next, this new record is linked to the end of the cdr record list.\n"
"Next, The new cdr record is RESET (unless you use an option to prevent this)\n"
"This means that:\n"
" 1. All flags are unset on the cdr record\n"
" 2. the start, end, and answer times are all set to zero.\n"
" 3. the billsec and duration fields are set to zero.\n"
" 4. the start time is set to the current time.\n"
" 5. the disposition is set to NULL.\n"
"Next, unless you specified the 'v' option, all variables will be\n"
"removed from the original cdr record. Thus, the 'v' option allows\n"
"any CDR variables to be replicated to all new forked cdr records.\n"
"Without the 'v' option, the variables on the original are effectively\n"
"moved to the new forked cdr record.\n"
"Next, if the 's' option is set, the provided variable and value\n"
"are set on the original cdr record.\n"
"Next, if the 'a' option is given, and the original cdr record has an\n"
"answer time set, then the new forked cdr record will have its answer\n"
"time set to its start time. If the old answer time were carried forward,\n"
"the answer time would be earlier than the start time, giving strange\n"
"duration and billsec times.\n"
"Next, if the 'd' option was specified, the disposition is copied from\n"
"the original cdr record to the new forked cdr.\n"
"Next, if the 'D' option was specified, the destination channel field\n"
"in the new forked CDR is erased.\n"
"Next, if the 'e' option was specified, the 'end' time for the original\n"
"cdr record is set to the current time. Future hang-up or ending events\n"
"will not override this time stamp.\n"
"Next, If the 'A' option is specified, the original cdr record will have\n"
"it ANS_LOCKED flag set, which prevent future answer events\n"
"from updating the original cdr record's disposition. Normally, an\n"
"'ANSWERED' event would mark all cdr records in the chain as 'ANSWERED'.\n"
"Next, if the 'T' option is specified, the original cdr record will have\n"
"its 'DONT_TOUCH' flag set, which will force the cdr_answer, cdr_end, and\n"
"cdr_setvar functions to leave that cdr record alone.\n"
"And, last but not least, the original cdr record has its LOCKED flag\n"
"set. Almost all internal CDR functions (except for the funcs that set\n"
"the end, and answer times, and set a variable) will honor this flag\n"
"and leave a LOCKED cdr record alone.\n"
"This means that the newly created forked cdr record will affected\n"
"by events transpiring within Asterisk, with the previously noted\n"
"exceptions.\n"
" Options:\n"
" a - update the answer time on the NEW CDR just after it's been inited..\n"
" The new CDR may have been answered already, the reset that forkcdr.\n"
" does will erase the answer time. This will bring it back, but\n"
" the answer time will be a copy of the fork/start time. It will.\n"
" only do this if the initial cdr was indeed already answered..\n"
" A - Lock the original CDR against the answer time being updated.\n"
" This will allow the disposition on the original CDR to remain the same.\n"
" d - Copy the disposition forward from the old cdr, after the .\n"
" init..\n"
" D - Clear the dstchannel on the new CDR after reset..\n"
" e - end the original CDR. Do this after all the necc. data.\n"
" is copied from the original CDR to the new forked CDR..\n"
" R - do NOT reset the new cdr..\n"
" s(name=val) - Set the CDR var 'name' in the original CDR, with value.\n"
" 'val'.\n"
" T - Mark the original CDR with a DONT_TOUCH flag. setvar, answer, and end\n"
" cdr funcs will obey this flag; normally they don't honor the LOCKED\n"
" flag set on the original CDR record.\n"
" Beware-- using this flag may cause CDR's not to have their end times\n"
" updated! It is suggested that if you specify this flag, you might\n"
" wish to use the 'e' flag as well!\n"
" v - When the new CDR is forked, it gets a copy of the vars attached\n"
" to the current CDR. The vars attached to the original CDR are removed\n"
" unless this option is specified.\n";
" ForkCDR(): Causes the Call Data Record to fork an additional\n"
"cdr record starting from the time of the fork call\n";
enum {
OPT_SETANS = (1 << 0),
OPT_SETDISP = (1 << 1),
OPT_RESETDEST = (1 << 2),
OPT_ENDCDR = (1 << 3),
OPT_NORESET = (1 << 4),
OPT_KEEPVARS = (1 << 5),
OPT_VARSET = (1 << 6),
OPT_ANSLOCK = (1 << 7),
OPT_DONTOUCH = (1 << 8),
};
STANDARD_LOCAL_USER;
enum {
OPT_ARG_VARSET = 0,
/* note: this entry _MUST_ be the last one in the enum */
OPT_ARG_ARRAY_SIZE,
};
LOCAL_USER_DECL;
AST_APP_OPTIONS(forkcdr_exec_options, {
AST_APP_OPTION('a', OPT_SETANS),
AST_APP_OPTION('A', OPT_ANSLOCK),
AST_APP_OPTION('d', OPT_SETDISP),
AST_APP_OPTION('D', OPT_RESETDEST),
AST_APP_OPTION('e', OPT_ENDCDR),
AST_APP_OPTION('R', OPT_NORESET),
AST_APP_OPTION_ARG('s', OPT_VARSET, OPT_ARG_VARSET),
AST_APP_OPTION('T', OPT_DONTOUCH),
AST_APP_OPTION('v', OPT_KEEPVARS),
});
static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set)
{
struct ast_cdr *cdr;
struct ast_cdr *newcdr;
struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS };
static void ast_cdr_clone(struct ast_cdr *cdr) {
struct ast_cdr *newcdr = ast_cdr_alloc();
memcpy(newcdr,cdr,sizeof(struct ast_cdr));
newcdr->next = NULL;
ast_cdr_append(cdr,newcdr);
gettimeofday(&newcdr->start, NULL);
memset(&newcdr->answer, 0, sizeof(newcdr->answer));
ast_cdr_add_flag(cdr,AST_CDR_FLAG_CHILD|AST_CDR_FLAG_LOCKED);
}
cdr = chan->cdr;
while (cdr->next)
cdr = cdr->next;
if (!(newcdr = ast_cdr_dup(cdr)))
return;
ast_cdr_append(cdr, newcdr);
if (!ast_test_flag(&optflags, OPT_NORESET))
ast_cdr_reset(newcdr, &flags);
if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS))
ast_cdr_free_vars(cdr, 0);
if (!ast_strlen_zero(set)) {
char *varname = ast_strdupa(set), *varval;
varval = strchr(varname,'=');
if (varval) {
*varval = 0;
varval++;
ast_cdr_setvar(cdr, varname, varval, 0);
}
static void ast_cdr_fork(struct ast_channel *chan) {
if(chan && chan->cdr) {
ast_cdr_clone(chan->cdr);
}
if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer))
newcdr->answer = newcdr->start;
if (ast_test_flag(&optflags, OPT_SETDISP))
newcdr->disposition = cdr->disposition;
if (ast_test_flag(&optflags, OPT_RESETDEST))
newcdr->dstchannel[0] = 0;
if (ast_test_flag(&optflags, OPT_ENDCDR))
ast_cdr_end(cdr);
if (ast_test_flag(&optflags, OPT_ANSLOCK))
ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED);
if (ast_test_flag(&optflags, OPT_DONTOUCH))
ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH);
ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
}
static int forkcdr_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *argcopy = NULL;
struct ast_flags flags = {0};
char *opts[OPT_ARG_ARRAY_SIZE];
AST_DECLARE_APP_ARGS(arglist,
AST_APP_ARG(options);
);
int res=0;
struct localuser *u;
LOCAL_USER_ADD(u);
if (!chan->cdr) {
ast_log(LOG_WARNING, "Channel does not have a CDR\n");
return 0;
}
ast_cdr_fork(chan);
u = ast_module_user_add(chan);
argcopy = ast_strdupa(data);
AST_STANDARD_APP_ARGS(arglist, argcopy);
opts[OPT_ARG_VARSET] = 0;
if (!ast_strlen_zero(arglist.options))
ast_app_parse_options(forkcdr_exec_options, &flags, opts, arglist.options);
if (!ast_strlen_zero(data))
ast_set2_flag(chan->cdr, ast_test_flag(&flags, OPT_KEEPVARS), AST_CDR_FLAG_KEEP_VARS);
ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]);
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, forkcdr_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,47 +1,30 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Execute arbitrary system commands
*
* Copyright (C) 1999-2005, Digium
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Get ADSI CPE ID
*
* \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/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/adsi.h>
#include <asterisk/options.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/adsi.h"
#include "asterisk/options.h"
static char *tdesc = "Get ADSI CPE ID";
static char *app = "GetCPEID";
@@ -49,8 +32,12 @@ static char *synopsis = "Get ADSI CPE ID";
static char *descrip =
" GetCPEID: Obtains and displays ADSI CPE ID and other information in order\n"
"to properly setup chan_dahdi.conf for on-hook operations.\n";
"to properly setup zapata.conf for on-hook operations.\n"
"Returns -1 on hangup only.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice)
{
@@ -60,42 +47,43 @@ static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice)
for (x=0;x<4;x++)
tmp[x] = stuff[x];
tmp[4] = NULL;
return ast_adsi_print(chan, tmp, justify, voice);
return adsi_print(chan, tmp, justify, voice);
}
static int cpeid_exec(struct ast_channel *chan, void *idata)
{
int res=0;
struct ast_module_user *u;
struct localuser *u;
unsigned char cpeid[4];
int gotgeometry = 0;
int gotcpeid = 0;
int width, height, buttons;
char *data[4];
unsigned int x;
char data[4][80];
char *stuff[4];
u = ast_module_user_add(chan);
for (x = 0; x < 4; x++)
data[x] = alloca(80);
strcpy(data[0], "** CPE Info **");
strcpy(data[1], "Identifying CPE...");
strcpy(data[2], "Please wait...");
res = ast_adsi_load_session(chan, NULL, 0, 1);
LOCAL_USER_ADD(u);
stuff[0] = data[0];
stuff[1] = data[1];
stuff[2] = data[2];
stuff[3] = data[3];
memset(data, 0, sizeof(data));
strncpy(stuff[0], "** CPE Info **", sizeof(data[0]) - 1);
strncpy(stuff[1], "Identifying CPE...", sizeof(data[1]) - 1);
strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
res = adsi_load_session(chan, NULL, 0, 1);
if (res > 0) {
cpeid_setstatus(chan, data, 0);
res = ast_adsi_get_cpeid(chan, cpeid, 0);
cpeid_setstatus(chan, stuff, 0);
res = adsi_get_cpeid(chan, cpeid, 0);
if (res > 0) {
gotcpeid = 1;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Got CPEID of '%02x:%02x:%02x:%02x' on '%s'\n", cpeid[0], cpeid[1], cpeid[2], cpeid[3], chan->name);
}
if (res > -1) {
strcpy(data[1], "Measuring CPE...");
strcpy(data[2], "Please wait...");
cpeid_setstatus(chan, data, 0);
res = ast_adsi_get_cpeinfo(chan, &width, &height, &buttons, 0);
strncpy(stuff[1], "Measuring CPE...", sizeof(data[1]) - 1);
strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
cpeid_setstatus(chan, stuff, 0);
res = adsi_get_cpeinfo(chan, &width, &height, &buttons, 0);
if (res > -1) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "CPE has %d lines, %d columns, and %d buttons on '%s'\n", height, width, buttons, chan->name);
@@ -104,15 +92,15 @@ static int cpeid_exec(struct ast_channel *chan, void *idata)
}
if (res > -1) {
if (gotcpeid)
snprintf(data[1], 80, "CPEID: %02x:%02x:%02x:%02x", cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
snprintf(stuff[1], sizeof(data[1]), "CPEID: %02x:%02x:%02x:%02x", cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
else
strcpy(data[1], "CPEID Unknown");
strncpy(stuff[1], "CPEID Unknown", sizeof(data[1]) - 1);
if (gotgeometry)
snprintf(data[2], 80, "Geom: %dx%d, %d buttons", width, height, buttons);
snprintf(stuff[2], sizeof(data[2]), "Geom: %dx%d, %d buttons", width, height, buttons);
else
strcpy(data[2], "Geometry unknown");
strcpy(data[3], "Press # to exit");
cpeid_setstatus(chan, data, 1);
strncpy(stuff[2], "Geometry unknown", sizeof(data[2]) - 1);
strncpy(stuff[3], "Press # to exit", sizeof(data[3]) - 1);
cpeid_setstatus(chan, stuff, 1);
for(;;) {
res = ast_waitfordigit(chan, 1000);
if (res < 0)
@@ -122,27 +110,37 @@ static int cpeid_exec(struct ast_channel *chan, void *idata)
break;
}
}
ast_adsi_unload_session(chan);
adsi_unload_session(chan);
}
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, cpeid_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get ADSI CPE ID");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

224
apps/app_groupcount.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Group Manipulation Applications
*
* Copyright (c) 2004 Digium
*
* Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/utils.h>
static char *tdesc = "Group Management Routines";
static char *app_group_count = "GetGroupCount";
static char *app_group_set = "SetGroup";
static char *app_group_check = "CheckGroup";
static char *group_count_synopsis = "GetGroupCount([groupname][@category])";
static char *group_set_synopsis = "SetGroup(groupname[@category])";
static char *group_check_synopsis = "CheckGroup(max[@category])";
static char *group_count_descrip =
"GetGroupCount([group][@category])\n"
" Calculates the group count for the specified group, or uses\n"
"the current channel's group if not specifed (and non-empty).\n"
"Stores result in GROUPCOUNT. Always returns 0.\n";
static char *group_set_descrip =
"SetGroup(group)\n"
" Sets the channel group to the specified value. Equivalent to\n"
"SetVar(GROUP=group). Always returns 0.\n";
static char *group_check_descrip =
"CheckGroup(max)\n"
" Checks that the current number of total channels in the\n"
"current channel's group does not exceed 'max'. If the number\n"
"does not exceed 'max', we continue to the next step. If the\n"
"number does in fact exceed max, if priority n+101 exists, then\n"
"execution continues at that step, otherwise -1 is returned.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
#define DEFAULT_CATEGORY "GROUP"
static int group_get_count(char *group, char *category)
{
struct ast_channel *chan;
int count = 0;
char *test;
if (group && !ast_strlen_zero(group)) {
chan = ast_channel_walk_locked(NULL);
while(chan) {
test = pbx_builtin_getvar_helper(chan, category);
if (test && !strcasecmp(test, group))
count++;
ast_mutex_unlock(&chan->lock);
chan = ast_channel_walk_locked(chan);
}
}
return count;
}
static int group_count_exec(struct ast_channel *chan, void *data)
{
int res=0;
int count;
struct localuser *u;
char *group=NULL;
char *cat = NULL;
char ret[80]="";
char tmp[256]="";
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
group = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
}
if (cat)
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
else
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
if (!group || ast_strlen_zero(group)) {
group = pbx_builtin_getvar_helper(chan, ret);
}
count = group_get_count(group, ret);
snprintf(ret, sizeof(ret), "%d", count);
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
LOCAL_USER_REMOVE(u);
return res;
}
static int group_set_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char ret[80] = "";
char tmp[256] = "";
char *cat=NULL, *group=NULL;
LOCAL_USER_ADD(u);
/* Check and parse arguments */
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
group = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
}
if (cat)
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
else
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
if (group && !ast_strlen_zero(group)) {
pbx_builtin_setvar_helper(chan, ret, group);
} else
ast_log(LOG_WARNING, "SetGroup requires an argument (group name)\n");
LOCAL_USER_REMOVE(u);
return res;
}
static int group_check_exec(struct ast_channel *chan, void *data)
{
int res=0;
int max, count;
struct localuser *u;
char ret[80] = "";
char tmp[256] = "";
char *cat, *group;
LOCAL_USER_ADD(u);
if (data && !ast_strlen_zero(data)) {
strncpy(tmp, data, sizeof(tmp) - 1);
group = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
if ((sscanf((char *)tmp, "%i", &max) == 1) && (max > -1)) {
if (cat)
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
else
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
count = group_get_count(pbx_builtin_getvar_helper(chan, ret), ret);
if (count > max) {
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority += 100;
else
res = -1;
}
} else
ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
} else
ast_log(LOG_WARNING, "CheckGroup requires an argument(max)\n");
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
int res;
STANDARD_HANGUP_LOCALUSERS;
res = ast_unregister_application(app_group_count);
res |= ast_unregister_application(app_group_set);
res |= ast_unregister_application(app_group_check);
return res;
}
int load_module(void)
{
int res;
res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
return res;
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,7 +1,8 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Changes Copyright (c) 2004 - 2006 Todd Freeman <freeman@andrews.edu>
* HasVoicemail application
* Changes Copyright (c) 2004 Todd Freeman <freeman@andrews.edu>
*
* 95% based on HasNewVoicemail by:
*
@@ -9,217 +10,160 @@
*
* Tilghman Lesher <asterisk-hasnewvoicemail-app@the-tilghman.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.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 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.
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*! \file
*
* \brief HasVoicemail application
*
* \author Todd Freeman <freeman@andrews.edu>
*
* \note 95% based on HasNewVoicemail by
* Tilghman Lesher <asterisk-hasnewvoicemail-app@the-tilghman.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/lock.h>
#include <asterisk/utils.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
#include "../astconf.h"
static char *tdesc = "Indicator for whether a voice mailbox has messages in a given folder.";
static char *app_hasvoicemail = "HasVoicemail";
static char *hasvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
static char *hasvoicemail_synopsis = "Conditionally branches to priority + 101";
static char *hasvoicemail_descrip =
"HasVoicemail(vmbox[/folder][@context][|varname[|options]])\n"
"HasVoicemail(vmbox[@context][:folder][|varname])\n"
" Branches to priority + 101, if there is voicemail in folder indicated."
" Optionally sets <varname> to the number of messages in that folder."
" Assumes folder of INBOX if not specified.\n"
" The option string may contain zero or the following character:\n"
" 'j' -- jump to priority n+101, if there is voicemail in the folder indicated.\n"
" This application sets the following channel variable upon completion:\n"
" HASVMSTATUS The result of the voicemail check returned as a text string as follows\n"
" <# of messages in the folder, 0 for NONE>\n"
"\nThis application has been deprecated in favor of the VMCOUNT() function\n";
" Assumes folder of INBOX if not specified.\n";
static char *app_hasnewvoicemail = "HasNewVoicemail";
static char *hasnewvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
static char *hasnewvoicemail_synopsis = "Conditionally branches to priority + 101";
static char *hasnewvoicemail_descrip =
"HasNewVoicemail(vmbox[/folder][@context][|varname[|options]])\n"
"Assumes folder 'INBOX' if folder is not specified. Optionally sets <varname> to the number of messages\n"
"in that folder.\n"
" The option string may contain zero of the following character:\n"
" 'j' -- jump to priority n+101, if there is new voicemail in folder 'folder' or INBOX\n"
" This application sets the following channel variable upon completion:\n"
" HASVMSTATUS The result of the new voicemail check returned as a text string as follows\n"
" <# of messages in the folder, 0 for NONE>\n"
"\nThis application has been deprecated in favor of the VMCOUNT() function\n";
"HasNewVoicemail(vmbox[@context][|varname])\n"
" Branches to priority + 101, if there is voicemail in folder INBOX."
" Optionally sets <varname> to the number of messages in that folder.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int hasvoicemail_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char *input, *varname = NULL, *vmbox, *context = "default";
char *vmfolder;
int res=0;
struct localuser *u;
char vmpath[256], *temps, *input, *varname = NULL, *vmbox, *vmfolder = "INBOX", *context = "default";
DIR *vmdir;
struct dirent *vment;
int vmcount = 0;
static int dep_warning = 0;
int priority_jump = 0;
char tmp[12];
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(vmbox);
AST_APP_ARG(varname);
AST_APP_ARG(options);
);
if (!dep_warning) {
ast_log(LOG_WARNING, "The applications HasVoicemail and HasNewVoicemail have been deprecated. Please use the VMCOUNT() function instead.\n");
dep_warning = 1;
}
if (!data) {
ast_log(LOG_WARNING, "HasVoicemail requires an argument (vm-box[/folder][@context][|varname[|options]])\n");
ast_log(LOG_WARNING, "HasVoicemail requires an argument (vm-box[@context][:folder]|varname)\n");
return -1;
}
LOCAL_USER_ADD(u);
u = ast_module_user_add(chan);
input = ast_strdupa((char *)data);
if (input) {
temps = input;
if ((temps = strsep(&input, "|"))) {
if (input && !ast_strlen_zero(input))
varname = input;
input = temps;
}
if ((temps = strsep(&input, ":"))) {
if (input && !ast_strlen_zero(input))
vmfolder = input;
input = temps;
}
if ((vmbox = strsep(&input, "@")))
if (input && !ast_strlen_zero(input))
context = input;
if (!vmbox)
vmbox = input;
input = ast_strdupa(data);
snprintf(vmpath,sizeof(vmpath), "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR, context, vmbox, vmfolder);
if (!(vmdir = opendir(vmpath))) {
ast_log(LOG_NOTICE, "Voice mailbox %s at %s does not exist\n", vmbox, vmpath);
} else {
AST_STANDARD_APP_ARGS(args, input);
/* No matter what the format of VM, there will always be a .txt file for each message. */
while ((vment = readdir(vmdir)))
if (!strncmp(vment->d_name + 7,".txt",4))
vmcount++;
closedir(vmdir);
}
/* Set the count in the channel variable */
if (varname) {
char tmp[12];
snprintf(tmp, sizeof(tmp), "%d", vmcount);
pbx_builtin_setvar_helper(chan, varname, tmp);
}
vmbox = strsep(&args.vmbox, "@");
if (!ast_strlen_zero(args.vmbox))
context = args.vmbox;
vmfolder = strchr(vmbox, '/');
if (vmfolder) {
*vmfolder = '\0';
vmfolder++;
} else {
vmfolder = "INBOX";
}
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
vmcount = ast_app_messagecount(context, vmbox, vmfolder);
/* Set the count in the channel variable */
if (varname) {
snprintf(tmp, sizeof(tmp), "%d", vmcount);
pbx_builtin_setvar_helper(chan, varname, tmp);
}
if (vmcount > 0) {
/* Branch to the next extension */
if (priority_jump || ast_opt_priority_jumping) {
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
if (vmcount > 0) {
/* Branch to the next extension */
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
chan->priority += 100;
} else
ast_log(LOG_WARNING, "VM box %s@%s has new voicemail, but extension %s, priority %d doesn't exist\n", vmbox, context, chan->exten, chan->priority + 101);
}
}
snprintf(tmp, sizeof(tmp), "%d", vmcount);
pbx_builtin_setvar_helper(chan, "HASVMSTATUS", tmp);
ast_module_user_remove(u);
return 0;
}
static int acf_vmcount_exec(struct ast_channel *chan, char *cmd, char *argsstr, char *buf, size_t len)
{
struct ast_module_user *u;
char *context;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(vmbox);
AST_APP_ARG(folder);
);
if (ast_strlen_zero(argsstr))
return -1;
u = ast_module_user_add(chan);
buf[0] = '\0';
AST_STANDARD_APP_ARGS(args, argsstr);
if (strchr(args.vmbox, '@')) {
context = args.vmbox;
args.vmbox = strsep(&context, "@");
} else {
context = "default";
ast_log(LOG_ERROR, "Out of memory error\n");
}
if (ast_strlen_zero(args.folder)) {
args.folder = "INBOX";
}
snprintf(buf, len, "%d", ast_app_messagecount(context, args.vmbox, args.folder));
ast_module_user_remove(u);
return 0;
LOCAL_USER_REMOVE(u);
return res;
}
struct ast_custom_function acf_vmcount = {
.name = "VMCOUNT",
.synopsis = "Counts the voicemail in a specified mailbox",
.syntax = "VMCOUNT(vmbox[@context][|folder])",
.desc =
" context - defaults to \"default\"\n"
" folder - defaults to \"INBOX\"\n",
.read = acf_vmcount_exec,
};
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_custom_function_unregister(&acf_vmcount);
res |= ast_unregister_application(app_hasvoicemail);
STANDARD_HANGUP_LOCALUSERS;
res = ast_unregister_application(app_hasvoicemail);
res |= ast_unregister_application(app_hasnewvoicemail);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
int load_module(void)
{
int res;
res = ast_custom_function_register(&acf_vmcount);
res |= ast_register_application(app_hasvoicemail, hasvoicemail_exec, hasvoicemail_synopsis, hasvoicemail_descrip);
res = ast_register_application(app_hasvoicemail, hasvoicemail_exec, hasvoicemail_synopsis, hasvoicemail_descrip);
res |= ast_register_application(app_hasnewvoicemail, hasvoicemail_exec, hasnewvoicemail_synopsis, hasnewvoicemail_descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Indicator for whether a voice mailbox has messages in a given folder.");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,38 +1,24 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
/*** MODULEINFO
<depend>working_fork</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/frame.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
@@ -41,22 +27,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <fcntl.h>
#include <sys/time.h>
#include <errno.h>
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#include "../astconf.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/frame.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
#define ICES "/usr/bin/ices"
#define LOCAL_ICES "/usr/local/bin/ices"
#define path_BIN "/usr/bin/"
#define path_LOCAL "/usr/local/bin/"
static char *tdesc = "Encode and Stream via icecast and ices";
static char *app = "ICES";
@@ -65,74 +41,41 @@ static char *synopsis = "Encode and stream using 'ices'";
static char *descrip =
" ICES(config.xml) Streams to an icecast server using ices\n"
"(available separately). A configuration file must be supplied\n"
"for ices (see contrib/asterisk-ices.xml). \n";
"for ices (see examples/asterisk-ices.conf). Returns -1 on\n"
"hangup or 0 otherwise.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int icesencode(char *filename, int fd)
{
int res;
int x;
sigset_t fullset, oldset;
#ifdef HAVE_CAP
cap_t cap;
#endif
sigfillset(&fullset);
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
res = fork();
if (res < 0)
ast_log(LOG_WARNING, "Fork failed\n");
if (res) {
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
if (res)
return res;
}
/* Stop ignoring PIPE */
signal(SIGPIPE, SIG_DFL);
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
#ifdef HAVE_CAP
cap = cap_from_text("cap_net_admin-eip");
if (cap_set_proc(cap)) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
}
cap_free(cap);
#endif
if (ast_opt_high_priority)
ast_set_priority(0);
dup2(fd, STDIN_FILENO);
for (x=STDERR_FILENO + 1;x<1024;x++) {
for (x=STDERR_FILENO + 1;x<256;x++) {
if ((x != STDIN_FILENO) && (x != STDOUT_FILENO))
close(x);
}
/* Most commonly installed in /usr/local/bin
* But many places has it in /usr/bin
* As a last-ditch effort, try to use PATH
*/
execl(path_LOCAL "ices2", "ices", filename, (char *)NULL);
execl(path_BIN "ices2", "ices", filename, (char *)NULL);
execlp("ices2", "ices", filename, (char *)NULL);
if (option_debug)
ast_log(LOG_DEBUG, "Couldn't find ices version 2, attempting to use ices version 1.");
execl(path_LOCAL "ices", "ices", filename, (char *)NULL);
execl(path_BIN "ices", "ices", filename, (char *)NULL);
/* Most commonly installed in /usr/local/bin */
execl(ICES, "ices", filename, (char *)NULL);
/* But many places has it in /usr/bin */
execl(LOCAL_ICES, "ices", filename, (char *)NULL);
/* As a last-ditch effort, try to use PATH */
execlp("ices", "ices", filename, (char *)NULL);
ast_log(LOG_WARNING, "Execute of ices failed, could not be found.\n");
close(fd);
_exit(0);
ast_log(LOG_WARNING, "Execute of ices failed\n");
return -1;
}
static int ices_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
struct localuser *u;
int fds[2];
int ms = -1;
int pid = -1;
@@ -142,24 +85,20 @@ static int ices_exec(struct ast_channel *chan, void *data)
struct ast_frame *f;
char filename[256]="";
char *c;
if (ast_strlen_zero(data)) {
last.tv_usec = 0;
last.tv_sec = 0;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
return -1;
}
u = ast_module_user_add(chan);
last = ast_tv(0, 0);
if (pipe(fds)) {
ast_log(LOG_WARNING, "Unable to create pipe\n");
ast_module_user_remove(u);
return -1;
}
flags = fcntl(fds[1], F_GETFL);
fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
LOCAL_USER_ADD(u);
ast_stopstream(chan);
if (chan->_state != AST_STATE_UP)
@@ -169,7 +108,6 @@ static int ices_exec(struct ast_channel *chan, void *data)
close(fds[0]);
close(fds[1]);
ast_log(LOG_WARNING, "Answer failed!\n");
ast_module_user_remove(u);
return -1;
}
@@ -179,11 +117,10 @@ static int ices_exec(struct ast_channel *chan, void *data)
close(fds[0]);
close(fds[1]);
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
ast_module_user_remove(u);
return -1;
}
if (((char *)data)[0] == '/')
ast_copy_string(filename, (char *) data, sizeof(filename));
strncpy(filename, (char *)data, sizeof(filename) - 1);
else
snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
/* Placeholder for options */
@@ -191,6 +128,7 @@ static int ices_exec(struct ast_channel *chan, void *data)
if (c)
*c = '\0';
res = icesencode(filename, fds[0]);
close(fds[0]);
if (res >= 0) {
pid = res;
for (;;) {
@@ -213,7 +151,6 @@ static int ices_exec(struct ast_channel *chan, void *data)
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
res = -1;
ast_frfree(f);
break;
}
}
@@ -221,33 +158,39 @@ static int ices_exec(struct ast_channel *chan, void *data)
ast_frfree(f);
}
}
close(fds[0]);
close(fds[1]);
LOCAL_USER_REMOVE(u);
if (pid > -1)
kill(pid, SIGKILL);
if (!res && oreadformat)
ast_set_read_format(chan, oreadformat);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, ices_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,125 +1,89 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to transmit an image
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 App to transmit an image
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
static char *tdesc = "Image Transmission Application";
static char *app = "SendImage";
static char *synopsis = "Send an image file";
static char *descrip =
" SendImage(filename): Sends an image on a channel. \n"
"If the channel supports image transport but the image send\n"
"fails, the channel will be hung up. Otherwise, the dialplan\n"
"continues execution.\n"
"The option string may contain the following character:\n"
" 'j' -- jump to priority n+101 if the channel doesn't support image transport\n"
"This application sets the following channel variable upon completion:\n"
" SENDIMAGESTATUS The status is the result of the attempt as a text string, one of\n"
" OK | NOSUPPORT \n";
" SendImage(filename): Sends an image on a channel. If the channel\n"
"does not support image transport, and there exists a step with\n"
"priority n + 101, then execution will continue at that step.\n"
"Otherwise, execution will continue at the next priority level.\n"
"SendImage only returns 0 if the image was sent correctly or if\n"
"the channel does not support image transport, and -1 otherwise.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int sendimage_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *parse;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filename);
AST_APP_ARG(options);
);
u = ast_module_user_add(chan);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.filename)) {
ast_log(LOG_WARNING, "SendImage requires an argument (filename[|options])\n");
struct localuser *u;
if (!data || !strlen((char *)data)) {
ast_log(LOG_WARNING, "SendImage requires an argument (filename)\n");
return -1;
}
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
LOCAL_USER_ADD(u);
if (!ast_supports_images(chan)) {
/* Does not support transport */
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
pbx_builtin_setvar_helper(chan, "SENDIMAGESTATUS", "NOSUPPORT");
ast_module_user_remove(u);
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority += 100;
return 0;
}
res = ast_send_image(chan, args.filename);
if (!res)
pbx_builtin_setvar_helper(chan, "SENDIMAGESTATUS", "OK");
ast_module_user_remove(u);
res = ast_send_image(chan, data);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, sendimage_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Image Transmission Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

207
apps/app_intercom.c Normal file
View File

@@ -0,0 +1,207 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Use /dev/dsp as an intercom.
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/frame.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <netinet/in.h>
#if defined(__linux__)
#include <linux/soundcard.h>
#elif defined(__FreeBSD__)
#include <sys/soundcard.h>
#else
#include <soundcard.h>
#endif
#ifdef __OpenBSD__
#define DEV_DSP "/dev/audio"
#else
#define DEV_DSP "/dev/dsp"
#endif
/* Number of 32 byte buffers -- each buffer is 2 ms */
#define BUFFER_SIZE 32
static char *tdesc = "Intercom using /dev/dsp for output";
static char *app = "Intercom";
static char *synopsis = "(Obsolete) Send to Intercom";
static char *descrip =
" Intercom(): Sends the user to the intercom (i.e. /dev/dsp). This program\n"
"is generally considered obselete by the chan_oss module. Returns 0 if the\n"
"user exits with a DTMF tone, or -1 if they hangup.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
AST_MUTEX_DEFINE_STATIC(sound_lock);
static int sound = -1;
static int write_audio(short *data, int len)
{
int res;
struct audio_buf_info info;
ast_mutex_lock(&sound_lock);
if (sound < 0) {
ast_log(LOG_WARNING, "Sound device closed?\n");
ast_mutex_unlock(&sound_lock);
return -1;
}
if (ioctl(sound, SNDCTL_DSP_GETOSPACE, &info)) {
ast_log(LOG_WARNING, "Unable to read output space\n");
ast_mutex_unlock(&sound_lock);
return -1;
}
res = write(sound, data, len);
ast_mutex_unlock(&sound_lock);
return res;
}
static int create_audio(void)
{
int fmt, desired, res, fd;
fd = open(DEV_DSP, O_WRONLY);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
close(fd);
return -1;
}
fmt = AFMT_S16_LE;
res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
close(fd);
return -1;
}
fmt = 0;
res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
close(fd);
return -1;
}
/* 8000 Hz desired */
desired = 8000;
fmt = desired;
res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
close(fd);
return -1;
}
if (fmt != desired) {
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
}
#if 1
/* 2 bytes * 15 units of 2^5 = 32 bytes per buffer */
fmt = ((BUFFER_SIZE) << 16) | (0x0005);
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
}
#endif
sound = fd;
return 0;
}
static int intercom_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct localuser *u;
struct ast_frame *f;
int oreadformat;
LOCAL_USER_ADD(u);
/* Remember original read format */
oreadformat = chan->readformat;
/* Set mode to signed linear */
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
return -1;
}
/* Read packets from the channel */
while(!res) {
res = ast_waitfor(chan, -1);
if (res > 0) {
res = 0;
f = ast_read(chan);
if (f) {
if (f->frametype == AST_FRAME_DTMF) {
ast_frfree(f);
break;
} else {
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass == AST_FORMAT_SLINEAR) {
res = write_audio(f->data, f->datalen);
if (res > 0)
res = 0;
} else
ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
}
}
ast_frfree(f);
} else
res = -1;
}
}
LOCAL_USER_REMOVE(u);
if (!res)
ast_set_read_format(chan, oreadformat);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
if (sound > -1)
close(sound);
return ast_unregister_application(app);
}
int load_module(void)
{
if (create_audio())
return -1;
return ast_register_application(app, intercom_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,132 +0,0 @@
/*
* 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 IVR Demo application
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
static char *tdesc = "IVR Demo Application";
static char *app = "IVRDemo";
static char *synopsis =
" This is a skeleton application that shows you the basic structure to create your\n"
"own asterisk applications and demonstrates the IVR demo.\n";
static int ivr_demo_func(struct ast_channel *chan, void *data)
{
ast_verbose("IVR Demo, data is %s!\n", (char *)data);
return 0;
}
AST_IVR_DECLARE_MENU(ivr_submenu, "IVR Demo Sub Menu", 0,
{
{ "s", AST_ACTION_BACKGROUND, "demo-abouttotry" },
{ "s", AST_ACTION_WAITOPTION },
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
{ "1", AST_ACTION_RESTART },
{ "2", AST_ACTION_PLAYLIST, "digits/2;digits/3" },
{ "3", AST_ACTION_CALLBACK, ivr_demo_func },
{ "4", AST_ACTION_TRANSFER, "demo|s|1" },
{ "*", AST_ACTION_REPEAT },
{ "#", AST_ACTION_UPONE },
{ NULL }
});
AST_IVR_DECLARE_MENU(ivr_demo, "IVR Demo Main Menu", 0,
{
{ "s", AST_ACTION_BACKGROUND, "demo-congrats" },
{ "g", AST_ACTION_BACKGROUND, "demo-instruct" },
{ "g", AST_ACTION_WAITOPTION },
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
{ "1", AST_ACTION_RESTART },
{ "2", AST_ACTION_MENU, &ivr_submenu },
{ "2", AST_ACTION_RESTART },
{ "i", AST_ACTION_PLAYBACK, "invalid" },
{ "i", AST_ACTION_REPEAT, (void *)(unsigned long)2 },
{ "#", AST_ACTION_EXIT },
{ NULL },
});
static int skel_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
/* Do our thing here */
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (!res)
res = ast_ivr_menu_run(chan, &ivr_demo, data);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, skel_exec, tdesc, synopsis);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "IVR Demo Application");

View File

@@ -1,160 +1,114 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to lookup the callerid number, and see if it is blacklisted
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief App to lookup the callerid number, and see if it is blacklisted
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/callerid.h>
#include <asterisk/astdb.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/callerid.h"
#include "asterisk/astdb.h"
#include "asterisk/options.h"
static char *tdesc = "Look up Caller*ID name/number from blacklist database";
static char *app = "LookupBlacklist";
static char *synopsis = "Look up Caller*ID name/number from blacklist database";
static char *descrip =
" LookupBlacklist(options): Looks up the Caller*ID number on the active\n"
"channel in the Asterisk database (family 'blacklist'). \n"
"The option string may contain the following character:\n"
" 'j' -- jump to n+101 priority if the number/name is found in the blacklist\n"
"This application sets the following channel variable upon completion:\n"
" LOOKUPBLSTATUS The status of the Blacklist lookup as a text string, one of\n"
" FOUND | NOTFOUND\n"
"Example: exten => 1234,1,LookupBlacklist()\n\n"
"This application is deprecated and may be removed from a future release.\n"
"Please use the dialplan function BLACKLIST() instead.\n";
" LookupBlacklist: Looks up the Caller*ID number on the active\n"
"channel in the Asterisk database (family 'blacklist'). If the\n"
"number is found, and if there exists a priority n + 101,\n"
"where 'n' is the priority of the current instance, then the\n"
"channel will be setup to continue at that priority level.\n"
"Otherwise, it returns 0. Does nothing if no Caller*ID was received on the\n"
"channel.\n"
"Example: database put blacklist <name/number> 1\n";
STANDARD_LOCAL_USER;
static int blacklist_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
{
char blacklist[1];
int bl = 0;
if (chan->cid.cid_num) {
if (!ast_db_get("blacklist", chan->cid.cid_num, blacklist, sizeof (blacklist)))
bl = 1;
}
if (chan->cid.cid_name) {
if (!ast_db_get("blacklist", chan->cid.cid_name, blacklist, sizeof (blacklist)))
bl = 1;
}
snprintf(buf, len, "%d", bl);
return 0;
}
static struct ast_custom_function blacklist_function = {
.name = "BLACKLIST",
.synopsis = "Check if the callerid is on the blacklist",
.desc = "Uses astdb to check if the Caller*ID is in family 'blacklist'. Returns 1 or 0.\n",
.syntax = "BLACKLIST()",
.read = blacklist_read,
};
LOCAL_USER_DECL;
static int
lookupblacklist_exec (struct ast_channel *chan, void *data)
{
char old_cid[144] = "", *num, *name;
char blacklist[1];
struct ast_module_user *u;
char shrunknum[64] = "";
struct localuser *u;
int bl = 0;
int priority_jump = 0;
static int dep_warning = 0;
u = ast_module_user_add(chan);
if (!dep_warning) {
dep_warning = 1;
ast_log(LOG_WARNING, "LookupBlacklist is deprecated. Please use ${BLACKLIST()} instead.\n");
}
if (!ast_strlen_zero(data)) {
if (strchr(data, 'j'))
priority_jump = 1;
}
if (chan->cid.cid_num) {
if (!ast_db_get("blacklist", chan->cid.cid_num, blacklist, sizeof (blacklist))) {
LOCAL_USER_ADD (u);
if (chan->callerid)
{
strncpy (old_cid, chan->callerid, sizeof (old_cid) - 1);
ast_callerid_parse (old_cid, &name, &num);
if (num)
strncpy (shrunknum, num, sizeof (shrunknum) - 1);
else
num = shrunknum;
ast_shrink_phone_number (shrunknum);
if (!ast_db_get ("blacklist", shrunknum, blacklist, sizeof (blacklist)))
{
if (option_verbose > 2)
ast_log(LOG_NOTICE, "Blacklisted number %s found\n",chan->cid.cid_num);
ast_log(LOG_NOTICE, "Blacklisted number %s found\n",shrunknum);
bl = 1;
}
else if (!ast_db_get ("blacklist", name, blacklist, sizeof (blacklist)))
{
if (option_verbose > 2)
ast_log (LOG_NOTICE,"Blacklisted name \"%s\" found\n",name);
bl = 1;
}
}
if (chan->cid.cid_name) {
if (!ast_db_get("blacklist", chan->cid.cid_name, blacklist, sizeof (blacklist))) {
if (option_verbose > 2)
ast_log (LOG_NOTICE,"Blacklisted name \"%s\" found\n",chan->cid.cid_name);
bl = 1;
}
}
if (bl) {
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "FOUND");
} else
pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "NOTFOUND");
ast_module_user_remove(u);
if (bl && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority+=100;
LOCAL_USER_REMOVE (u);
return 0;
}
static int unload_module(void)
int unload_module (void)
{
int res;
res = ast_unregister_application(app);
res |= ast_custom_function_unregister(&blacklist_function);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application (app);
}
static int load_module(void)
int load_module (void)
{
int res = ast_custom_function_register(&blacklist_function);
res |= ast_register_application (app, lookupblacklist_exec, synopsis,descrip);
return ast_register_application (app, lookupblacklist_exec, synopsis,descrip);
}
char *description (void)
{
return tdesc;
}
int usecount (void)
{
int res;
STANDARD_USECOUNT (res);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Look up Caller*ID name/number from blacklist database");
char *key ()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,49 +1,31 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to set callerid name from database, based on directory number
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief App to set callerid name from database, based on directory number
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/callerid.h>
#include <asterisk/astdb.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/callerid.h"
#include "asterisk/astdb.h"
static char *tdesc = "Look up CallerID Name from local database";
static char *app = "LookupCIDName";
@@ -55,49 +37,75 @@ static char *descrip =
"Caller*ID name. Does nothing if no Caller*ID was received on the\n"
"channel. This is useful if you do not subscribe to Caller*ID\n"
"name delivery, or if you want to change the names on some incoming\n"
"calls.\n\n"
"LookupCIDName is deprecated. Please use ${DB(cidname/${CALLERID(num)})}\n"
"instead.\n";
"calls. Always returns 0.\n";
STANDARD_LOCAL_USER;
static int lookupcidname_exec (struct ast_channel *chan, void *data)
LOCAL_USER_DECL;
static int
lookupcidname_exec (struct ast_channel *chan, void *data)
{
char dbname[64];
struct ast_module_user *u;
static int dep_warning = 0;
char old_cid[144] = "", *num, *name;
char new_cid[144];
char dbname[64];
char shrunknum[64] = "";
struct localuser *u;
u = ast_module_user_add(chan);
if (!dep_warning) {
dep_warning = 1;
ast_log(LOG_WARNING, "LookupCIDName is deprecated. Please use ${DB(cidname/${CALLERID(num)})} instead.\n");
LOCAL_USER_ADD (u);
if (chan->callerid)
{
strncpy (old_cid, chan->callerid, sizeof (old_cid) - 1);
ast_callerid_parse (old_cid, &name, &num); /* this destroys the original string */
if (num) /* It's possible to get an empty number */
strncpy (shrunknum, num, sizeof (shrunknum) - 1);
else
num = shrunknum;
ast_shrink_phone_number (shrunknum);
if (!ast_db_get ("cidname", shrunknum, dbname, sizeof (dbname)))
{
snprintf (new_cid, sizeof (new_cid), "\"%s\" <%s>", dbname, num);
ast_set_callerid (chan, new_cid, 0);
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",
new_cid);
}
if (chan->cid.cid_num) {
if (!ast_db_get ("cidname", chan->cid.cid_num, dbname, sizeof (dbname))) {
ast_set_callerid (chan, NULL, dbname, NULL);
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID name to %s\n",
dbname);
}
}
ast_module_user_remove(u);
return 0;
}
LOCAL_USER_REMOVE (u);
return 0;
}
static int unload_module(void)
int
unload_module (void)
{
int res;
res = ast_unregister_application (app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application (app);
}
static int load_module(void)
int
load_module (void)
{
return ast_register_application (app, lookupcidname_exec, synopsis, descrip);
return ast_register_application (app, lookupcidname_exec, synopsis,
descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Look up CallerID Name from local database");
char *
description (void)
{
return tdesc;
}
int
usecount (void)
{
int res;
STANDARD_USECOUNT (res);
return res;
}
char *
key ()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,615 +1,253 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Macro Implementation
*
* Copyright (C) 2003, Digium
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Dial plan macro Implementation
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/options.h>
#include <asterisk/utils.h>
#include <asterisk/lock.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ARGS 80
/* special result value used to force macro exit */
#define MACRO_EXIT_RESULT 1024
static char *tdesc = "Extension Macros";
static char *descrip =
" Macro(macroname|arg1|arg2...): Executes a macro using the context\n"
"'macro-<macroname>', jumping to the 's' extension of that context and\n"
"executing each step, then returning when the steps end. \n"
"The calling extension, context, and priority are stored in ${MACRO_EXTEN}, \n"
"executing each step, then returning when the steps end. The calling\n"
"extension, context, and priority are stored in ${MACRO_EXTEN}, \n"
"${MACRO_CONTEXT} and ${MACRO_PRIORITY} respectively. Arguments become\n"
"${ARG1}, ${ARG2}, etc in the macro context.\n"
"If you Goto out of the Macro context, the Macro will terminate and control\n"
"will be returned at the location of the Goto.\n"
"If ${MACRO_OFFSET} is set at termination, Macro will attempt to continue\n"
"at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n"
"WARNING: Because of the way Macro is implemented (it executes the priorities\n"
" contained within it via sub-engine), and a fixed per-thread\n"
" memory stack allowance, macros are limited to 7 levels\n"
" of nesting (macro calling macro calling macro, etc.); It\n"
" may be possible that stack-intensive applications in deeply nested\n"
" macros could cause asterisk to crash earlier than this limit.\n"
"NOTE: a bug existed in earlier versions of Asterisk that caused Macro not\n"
"to reset its context and extension correctly upon exit. This meant that\n"
"the 'h' extension within a Macro sometimes would execute, when the dialplan\n"
"exited while that Macro was running. However, since this bug has been in\n"
"Asterisk for so long, users started to depend upon this behavior. Therefore,\n"
"when a channel hangs up when in the midst of executing a Macro, the macro\n"
"context will first be checked for an 'h' extension, followed by the main\n"
"context from which the Macro was originally called. This behavior in 1.4\n"
"exists only for compatibility with earlier versions. You are strongly\n"
"encouraged to make use of the 'h' extension only in the context from which\n"
"Macro was originally called.\n";
static char *if_descrip =
" MacroIf(<expr>?macroname_a[|arg1][:macroname_b[|arg1]])\n"
"Executes macro defined in <macroname_a> if <expr> is true\n"
"(otherwise <macroname_b> if provided)\n"
"Arguments and return values as in application macro()\n";
static char *exclusive_descrip =
" MacroExclusive(macroname|arg1|arg2...):\n"
"Executes macro defined in the context 'macro-macroname'\n"
"Only one call at a time may run the macro.\n"
"(we'll wait if another call is busy executing in the Macro)\n"
"Arguments and return values as in application Macro()\n";
static char *exit_descrip =
" MacroExit():\n"
"Causes the currently running macro to exit as if it had\n"
"ended normally by running out of priorities to execute.\n"
"If used outside a macro, will likely cause unexpected\n"
"behavior.\n";
"${ARG1}, ${ARG2}, etc in the macro context. Macro returns -1 if\n"
"any step in the macro returns -1, and 0 otherwise. If you Goto out\n"
"of the Macro context, the Macro will terminate and control will be return\n"
"at the location of the Goto. Otherwise if ${MACRO_OFFSET} is set at\n"
"termination, Macro will attempt to continue at priority\n"
"MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n";
static char *app = "Macro";
static char *if_app = "MacroIf";
static char *exclusive_app = "MacroExclusive";
static char *exit_app = "MacroExit";
static char *synopsis = "Macro Implementation";
static char *if_synopsis = "Conditional Macro Implementation";
static char *exclusive_synopsis = "Exclusive Macro Implementation";
static char *exit_synopsis = "Exit From Macro";
static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
STANDARD_LOCAL_USER;
struct ast_datastore_info macro_ds_info = {
.type = "MACRO",
.chan_fixup = macro_fixup,
};
LOCAL_USER_DECL;
static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static int macro_exec(struct ast_channel *chan, void *data)
{
int i;
char varname[10];
pbx_builtin_setvar_helper(new_chan, "MACRO_DEPTH", "0");
pbx_builtin_setvar_helper(new_chan, "MACRO_CONTEXT", NULL);
pbx_builtin_setvar_helper(new_chan, "MACRO_EXTEN", NULL);
pbx_builtin_setvar_helper(new_chan, "MACRO_PRIORITY", NULL);
pbx_builtin_setvar_helper(new_chan, "MACRO_OFFSET", NULL);
for (i = 1; i < 100; i++) {
snprintf(varname, sizeof(varname), "ARG%d", i);
while (pbx_builtin_getvar_helper(new_chan, varname)) {
/* Kill all levels of arguments */
pbx_builtin_setvar_helper(new_chan, varname, NULL);
}
}
}
static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
{
struct ast_exten *e;
struct ast_include *i;
struct ast_context *c2;
for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
if (ast_extension_match(ast_get_extension_name(e), exten)) {
int needmatch = ast_get_extension_matchcid(e);
if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
(!needmatch)) {
/* This is the matching extension we want */
struct ast_exten *p;
for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
if (priority != ast_get_extension_priority(p))
continue;
return p;
}
}
}
}
/* No match; run through includes */
for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
e = find_matching_priority(c2, exten, priority, callerid);
if (e)
return e;
}
}
}
return NULL;
}
static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
{
const char *s;
char *tmp;
char *cur, *rest;
char *macro;
char fullmacro[80];
char varname[80];
char runningapp[80], runningdata[1024];
char *oldargs[MAX_ARGS + 1] = { NULL, };
int argc, x;
int res=0;
char oldexten[256]="";
int oldpriority, gosub_level = 0;
char pc[80], depthc[12];
char oldcontext[AST_MAX_CONTEXT] = "";
const char *inhangupc;
int offset, depth = 0, maxdepth = 7;
int setmacrocontext=0;
int autoloopflag, inhangup = 0;
char tmp[256] = "";
char *cur, *rest;
char *macro;
char fullmacro[80];
char varname[80];
char *oldargs[MAX_ARGS + 1] = { NULL, };
int argc, x;
int res=0;
char oldexten[256]="";
int oldpriority;
char pc[80];
char oldcontext[256] = "";
char *offsets;
int offset;
int setmacrocontext=0;
char *save_macro_exten;
char *save_macro_context;
char *save_macro_priority;
char *save_macro_offset;
struct ast_module_user *u;
struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Macro() requires arguments. See \"show application macro\" for help.\n");
return -1;
}
u = ast_module_user_add(chan);
do {
if (macro_store) {
break;
}
if (!(macro_store = ast_channel_datastore_alloc(&macro_ds_info, NULL))) {
ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
break;
}
/* Just the existence of this datastore is enough. */
macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
ast_channel_datastore_add(chan, macro_store);
} while (0);
/* does the user want a deeper rabbit hole? */
s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION");
if (s)
sscanf(s, "%30d", &maxdepth);
/* Count how many levels deep the rabbit hole goes */
s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
if (s)
sscanf(s, "%30d", &depth);
/* Used for detecting whether to return when a Macro is called from another Macro after hangup */
if (strcmp(chan->exten, "h") == 0)
pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP");
if (!ast_strlen_zero(inhangupc))
sscanf(inhangupc, "%30d", &inhangup);
if (depth >= maxdepth) {
ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
ast_module_user_remove(u);
return 0;
}
snprintf(depthc, sizeof(depthc), "%d", depth + 1);
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
tmp = ast_strdupa(data);
rest = tmp;
macro = strsep(&rest, "|");
if (ast_strlen_zero(macro)) {
ast_log(LOG_WARNING, "Invalid macro name specified\n");
ast_module_user_remove(u);
return 0;
}
snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->cid.cid_num)) {
if (!ast_context_find(fullmacro))
ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
else
ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
ast_module_user_remove(u);
return 0;
}
/* If we are to run the macro exclusively, take the mutex */
if (exclusive) {
ast_log(LOG_DEBUG, "Locking macrolock for '%s'\n", fullmacro);
ast_autoservice_start(chan);
if (ast_context_lockmacro(fullmacro)) {
ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
ast_autoservice_stop(chan);
ast_module_user_remove(u);
return 0;
}
ast_autoservice_stop(chan);
}
/* Save old info */
oldpriority = chan->priority;
ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
ast_copy_string(oldcontext, chan->context, sizeof(oldcontext));
if (ast_strlen_zero(chan->macrocontext)) {
ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext));
ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten));
chan->macropriority = chan->priority;
setmacrocontext=1;
}
argc = 1;
/* Save old macro variables */
save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
snprintf(pc, sizeof(pc), "%d", oldpriority);
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
char *save_macro_exten;
char *save_macro_context;
char *save_macro_priority;
char *save_macro_offset;
save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
if (!data || ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Invalid Macro incantation\n");
return 0;
}
strncpy(tmp, data, sizeof(tmp) - 1);
rest = tmp;
macro = strsep(&rest, "|");
if (!macro || ast_strlen_zero(macro)) {
ast_log(LOG_WARNING, "Invalid macro name specified\n");
return 0;
}
snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->callerid)) {
if (!ast_context_find(fullmacro))
ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
else
ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
return 0;
}
/* Save old info */
oldpriority = chan->priority;
strncpy(oldexten, chan->exten, sizeof(oldexten) - 1);
strncpy(oldcontext, chan->context, sizeof(oldcontext) - 1);
if (ast_strlen_zero(chan->macrocontext)) {
strncpy(chan->macrocontext, chan->context, sizeof(chan->macrocontext) - 1);
strncpy(chan->macroexten, chan->exten, sizeof(chan->macroexten) - 1);
chan->macropriority = chan->priority;
setmacrocontext=1;
}
argc = 1;
/* Save old macro variables */
save_macro_exten = pbx_builtin_getvar_helper(chan, "MACRO_EXTEN");
if (save_macro_exten) save_macro_exten = strdup(save_macro_exten);
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
/* Setup environment for new run */
chan->exten[0] = 's';
chan->exten[1] = '\0';
ast_copy_string(chan->context, fullmacro, sizeof(chan->context));
chan->priority = 1;
save_macro_context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT");
if (save_macro_context) save_macro_context = strdup(save_macro_context);
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
const char *s;
/* Save copy of old arguments if we're overwriting some, otherwise
let them pass through to the other macro */
snprintf(varname, sizeof(varname), "ARG%d", argc);
s = pbx_builtin_getvar_helper(chan, varname);
if (s)
oldargs[argc] = ast_strdup(s);
pbx_builtin_setvar_helper(chan, varname, cur);
argc++;
}
autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
struct ast_context *c;
struct ast_exten *e;
runningapp[0] = '\0';
runningdata[0] = '\0';
save_macro_priority = pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY");
if (save_macro_priority) save_macro_priority = strdup(save_macro_priority);
snprintf(pc, sizeof(pc), "%d", oldpriority);
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
save_macro_offset = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET");
if (save_macro_offset) save_macro_offset = strdup(save_macro_offset);
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
/* What application will execute? */
if (ast_rdlock_contexts()) {
ast_log(LOG_WARNING, "Failed to lock contexts list\n");
} else {
for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
if (!strcmp(ast_get_context_name(c), chan->context)) {
if (ast_lock_context(c)) {
ast_log(LOG_WARNING, "Unable to lock context?\n");
} else {
e = find_matching_priority(c, chan->exten, chan->priority, chan->cid.cid_num);
if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
}
ast_unlock_context(c);
}
break;
}
}
}
ast_unlock_contexts();
/* Setup environment for new run */
chan->exten[0] = 's';
chan->exten[1] = '\0';
strncpy(chan->context, fullmacro, sizeof(chan->context) - 1);
chan->priority = 1;
/* Reset the macro depth, if it was changed in the last iteration */
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
/* Something bad happened, or a hangup has been requested. */
if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
(res == '*') || (res == '#')) {
/* Just return result as to the previous application as if it had been dialed */
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
break;
}
switch(res) {
case MACRO_EXIT_RESULT:
res = 0;
goto out;
case AST_PBX_KEEPALIVE:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
goto out;
default:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
goto out;
}
}
ast_log(LOG_DEBUG, "Executed application: %s\n", runningapp);
if (!strcasecmp(runningapp, "GOSUB")) {
gosub_level++;
ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
} else if (!strcasecmp(runningapp, "GOSUBIF")) {
char tmp2[1024] = "", *cond, *app, *app2 = tmp2;
pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
cond = strsep(&app2, "?");
app = strsep(&app2, ":");
if (pbx_checkcondition(cond)) {
if (!ast_strlen_zero(app)) {
gosub_level++;
ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
}
} else {
if (!ast_strlen_zero(app2)) {
gosub_level++;
ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
}
}
} else if (!strcasecmp(runningapp, "RETURN")) {
gosub_level--;
ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
} else if (!strcasecmp(runningapp, "STACKPOP")) {
gosub_level--;
ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
} else if (!strncasecmp(runningapp, "EXEC", 4)) {
/* Must evaluate args to find actual app */
char tmp2[1024] = "", *tmp3 = NULL;
pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
if (!strcasecmp(runningapp, "EXECIF")) {
tmp3 = strchr(tmp2, '|');
if (tmp3)
*tmp3++ = '\0';
if (!pbx_checkcondition(tmp2))
tmp3 = NULL;
} else
tmp3 = tmp2;
if (tmp3)
ast_log(LOG_DEBUG, "Last app: %s\n", tmp3);
if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
gosub_level++;
ast_log(LOG_DEBUG, "Incrementing gosub_level\n");
} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
gosub_level--;
ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
gosub_level--;
ast_log(LOG_DEBUG, "Decrementing gosub_level\n");
}
}
if (gosub_level == 0 && strcasecmp(chan->context, fullmacro)) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
/* Save copy of old arguments if we're overwriting some, otherwise
let them pass through to the other macro */
snprintf(varname, sizeof(varname), "ARG%d", argc);
oldargs[argc] = pbx_builtin_getvar_helper(chan, varname);
if (oldargs[argc])
oldargs[argc] = strdup(oldargs[argc]);
pbx_builtin_setvar_helper(chan, varname, cur);
argc++;
}
while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid))) {
/* Something bad happened, or a hangup has been requested. */
if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
(res == '*') || (res == '#')) {
/* Just return result as to the previous application as if it had been dialed */
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
break;
}
/* don't stop executing extensions when we're in "h" */
if (chan->_softhangup && !inhangup) {
ast_log(LOG_DEBUG, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n",
chan->exten, chan->macroexten, chan->priority);
switch(res) {
case AST_PBX_KEEPALIVE:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
goto out;
break;
default:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
goto out;
}
chan->priority++;
}
out:
/* Don't let the channel change now. */
ast_channel_lock(chan);
/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
snprintf(depthc, sizeof(depthc), "%d", depth);
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
for (x = 1; x < argc; x++) {
/* Restore old arguments and delete ours */
snprintf(varname, sizeof(varname), "ARG%d", x);
if (oldargs[x]) {
pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
free(oldargs[x]);
} else {
pbx_builtin_setvar_helper(chan, varname, NULL);
}
}
/* Restore macro variables */
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
if (save_macro_exten)
free(save_macro_exten);
if (save_macro_context)
free(save_macro_context);
if (save_macro_priority)
free(save_macro_priority);
if (setmacrocontext) {
chan->macrocontext[0] = '\0';
chan->macroexten[0] = '\0';
chan->macropriority = 0;
}
/*!\note
* This section is used to restore a behavior that we mistakenly
* changed in issue #6176, then mistakenly reverted in #13962 and
* #13363. A corresponding change is made in main/pbx.c, where we
* check this variable for existence, then look for the "h" extension
* in that context.
*/
if (ast_check_hangup(chan) || res < 0) {
/* Don't need to lock the channel, as we aren't dereferencing emc.
* The intent here is to grab the deepest context, without overwriting
* in any above context. */
const char *emc = pbx_builtin_getvar_helper(chan, "EXIT_MACRO_CONTEXT");
if (!emc) {
pbx_builtin_setvar_helper(chan, "EXIT_MACRO_CONTEXT", fullmacro);
}
if (strcasecmp(chan->context, fullmacro)) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
break;
}
/* don't stop executing extensions when we're in "h" */
if (chan->_softhangup && strcasecmp(oldexten,"h")) {
ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
chan->exten, chan->priority);
goto out;
}
chan->priority++;
}
out:
for (x=1;x<argc;x++) {
/* Restore old arguments and delete ours */
snprintf(varname, sizeof(varname), "ARG%d", x);
if (oldargs[x]) {
pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
free(oldargs[x]);
} else {
pbx_builtin_setvar_helper(chan, varname, NULL);
}
}
if (!strcasecmp(chan->context, fullmacro)) {
const char *offsets;
/* Restore macro variables */
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
if (save_macro_exten) free(save_macro_exten);
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
if (save_macro_context) free(save_macro_context);
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
if (save_macro_priority) free(save_macro_priority);
if (setmacrocontext) {
chan->macrocontext[0] = '\0';
chan->macroexten[0] = '\0';
chan->macropriority = 0;
}
/* If we're leaving the macro normally, restore original information */
chan->priority = oldpriority;
ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
if (!strcasecmp(chan->context, fullmacro)) {
/* If we're leaving the macro normally, restore original information */
chan->priority = oldpriority;
strncpy(chan->context, oldcontext, sizeof(chan->context) - 1);
if (!(chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO)) {
/* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
strncpy(chan->exten, oldexten, sizeof(chan->exten) - 1);
if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
normally if there is any problem */
if (sscanf(offsets, "%30d", &offset) == 1) {
if (ast_exists_extension(chan, chan->context, chan->exten,
chan->priority + offset + 1,
chan->cid.cid_num)) {
normally if there is any problem */
if (sscanf(offsets, "%d", &offset) == 1) {
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->callerid)) {
chan->priority += offset;
}
}
}
}
}
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
if (save_macro_offset)
free(save_macro_offset);
/* Unlock the macro */
if (exclusive) {
ast_log(LOG_DEBUG, "Unlocking macrolock for '%s'\n", fullmacro);
if (ast_context_unlockmacro(fullmacro)) {
ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
res = 0;
}
}
ast_channel_unlock(chan);
ast_module_user_remove(u);
return res;
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
if (save_macro_offset) free(save_macro_offset);
return res;
}
static int macro_exec(struct ast_channel *chan, void *data)
int unload_module(void)
{
return _macro_exec(chan, data, 0);
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int macroexclusive_exec(struct ast_channel *chan, void *data)
int load_module(void)
{
return _macro_exec(chan, data, 1);
return ast_register_application(app, macro_exec, synopsis, descrip);
}
static int macroif_exec(struct ast_channel *chan, void *data)
char *description(void)
{
char *expr = NULL, *label_a = NULL, *label_b = NULL;
int res = 0;
struct ast_module_user *u;
u = ast_module_user_add(chan);
if (!(expr = ast_strdupa(data))) {
ast_module_user_remove(u);
return -1;
}
if ((label_a = strchr(expr, '?'))) {
*label_a = '\0';
label_a++;
if ((label_b = strchr(label_a, ':'))) {
*label_b = '\0';
label_b++;
}
if (pbx_checkcondition(expr))
res = macro_exec(chan, label_a);
else if (label_b)
res = macro_exec(chan, label_b);
} else
ast_log(LOG_WARNING, "Invalid Syntax.\n");
ast_module_user_remove(u);
return res;
}
static int macro_exit_exec(struct ast_channel *chan, void *data)
{
return MACRO_EXIT_RESULT;
return tdesc;
}
static int unload_module(void)
int usecount(void)
{
int res;
res = ast_unregister_application(if_app);
res |= ast_unregister_application(exit_app);
res |= ast_unregister_application(app);
res |= ast_unregister_application(exclusive_app);
ast_module_user_hangup_all();
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
int res;
res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
res |= ast_register_application(exclusive_app, macroexclusive_exec, exclusive_synopsis, exclusive_descrip);
res |= ast_register_application(app, macro_exec, synopsis, descrip);
return res;
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros");

File diff suppressed because it is too large Load Diff

View File

@@ -1,71 +1,50 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Digital Milliwatt Test
*
* Copyright (C) 2002, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Digital Milliwatt Test
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>res_indications</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/utils.h"
#include "asterisk/indications.h"
static char *tdesc = "Digital Milliwatt (mu-law) Test Application";
static char *app = "Milliwatt";
static char *synopsis = "Generate a Constant 1004Hz tone at 0dbm (mu-law)";
static char *synopsis = "Generate a Constant 1000Hz tone at 0dbm (mu-law)";
static char *descrip =
" Milliwatt([options]): Generate a Constant 1004Hz tone at 0dbm.\n"
"Previous versions of this application generated the tone at 1000Hz. If for\n"
"some reason you would prefer that behavior, supply the 'o' option to get the\n"
"old behavior.\n"
"";
"Milliwatt(): Generate a Constant 1000Hz tone at 0dbm (mu-law)\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static char digital_milliwatt[] = {0x1e,0x0b,0x0b,0x1e,0x9e,0x8b,0x8b,0x9e} ;
static void *milliwatt_alloc(struct ast_channel *chan, void *params)
{
return ast_calloc(1, sizeof(int));
int *indexp;
indexp = malloc(sizeof(int));
if (indexp == NULL) return(NULL);
*indexp = 0;
return(indexp);
}
static void milliwatt_release(struct ast_channel *chan, void *data)
@@ -76,115 +55,94 @@ static void milliwatt_release(struct ast_channel *chan, void *data)
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples)
{
unsigned char buf[AST_FRIENDLY_OFFSET + 640];
const int maxsamples = sizeof (buf) / sizeof (buf[0]);
int i, *indexp = (int *) data;
struct ast_frame wf = {
.frametype = AST_FRAME_VOICE,
.subclass = AST_FORMAT_ULAW,
.offset = AST_FRIENDLY_OFFSET,
.data = buf + AST_FRIENDLY_OFFSET,
.src = __FUNCTION__,
};
struct ast_frame wf;
unsigned char waste[AST_FRIENDLY_OFFSET];
unsigned char buf[640];
int i,*indexp = (int *) data;
/* Instead of len, use samples, because channel.c generator_force
* generate(chan, tmp, 0, 160) ignores len. In any case, len is
* a multiple of samples, given by number of samples times bytes per
* sample. In the case of ulaw, len = samples. for signed linear
* len = 2 * samples */
if (samples > maxsamples) {
ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", maxsamples, samples);
samples = maxsamples;
if (len > sizeof(buf))
{
ast_log(LOG_WARNING,"Only doing %d bytes (%d bytes requested)\n",(int)sizeof(buf),len);
len = sizeof(buf);
}
len = samples * sizeof (buf[0]);
waste[0] = 0; /* make compiler happy */
wf.frametype = AST_FRAME_VOICE;
wf.subclass = AST_FORMAT_ULAW;
wf.offset = AST_FRIENDLY_OFFSET;
wf.mallocd = 0;
wf.data = buf;
wf.datalen = len;
wf.samples = samples;
wf.samples = wf.datalen;
wf.src = "app_milliwatt";
wf.delivery.tv_sec = 0;
wf.delivery.tv_usec = 0;
/* create a buffer containing the digital milliwatt pattern */
for (i = 0; i < len; i++) {
buf[AST_FRIENDLY_OFFSET + i] = digital_milliwatt[(*indexp)++];
for(i = 0; i < len; i++)
{
buf[i] = digital_milliwatt[(*indexp)++];
*indexp &= 7;
}
if (ast_write(chan,&wf) < 0) {
if (ast_write(chan,&wf) < 0)
{
ast_log(LOG_WARNING,"Failed to write frame to '%s': %s\n",chan->name,strerror(errno));
return -1;
}
return 0;
}
static struct ast_generator milliwattgen = {
static struct ast_generator milliwattgen =
{
alloc: milliwatt_alloc,
release: milliwatt_release,
generate: milliwatt_generate,
};
static int old_milliwatt_exec(struct ast_channel *chan)
{
ast_set_write_format(chan, AST_FORMAT_ULAW);
ast_set_read_format(chan, AST_FORMAT_ULAW);
if (chan->_state != AST_STATE_UP) {
ast_answer(chan);
}
if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0) {
ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
return -1;
}
while (!ast_safe_sleep(chan, 10000))
;
ast_deactivate_generator(chan);
return -1;
}
} ;
static int milliwatt_exec(struct ast_channel *chan, void *data)
{
const char *options = data;
struct ast_module_user *u;
int res = -1;
u = ast_module_user_add(chan);
if (!ast_strlen_zero(options) && strchr(options, 'o')) {
res = old_milliwatt_exec(chan);
goto exit_app;
struct localuser *u;
LOCAL_USER_ADD(u);
ast_set_write_format(chan, AST_FORMAT_ULAW);
ast_set_read_format(chan, AST_FORMAT_ULAW);
if (chan->_state != AST_STATE_UP)
{
ast_answer(chan);
}
res = ast_playtones_start(chan, 23255, "1004/1000", 0);
while (!res) {
res = ast_safe_sleep(chan, 10000);
if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0)
{
ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
return -1;
}
res = 0;
exit_app:
ast_module_user_remove(u);
return res;
while(!ast_safe_sleep(chan, 10000));
ast_deactivate_generator(chan);
LOCAL_USER_REMOVE(u);
return -1;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, milliwatt_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Digital Milliwatt (mu-law) Test Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,622 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005, Anthony Minessale II
* Copyright (C) 2005 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
* Kevin P. Fleming <kpfleming@digium.com>
*
* Based on app_muxmon.c provided by
* Anthony Minessale II <anthmct@yahoo.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 MixMonitor() - Record a call and mix the audio during the recording
* \ingroup applications
*
* \author Mark Spencer <markster@digium.com>
* \author Kevin P. Fleming <kpfleming@digium.com>
*
* \note Based on app_muxmon.c provided by
* Anthony Minessale II <anthmct@yahoo.com>
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
static const char *app = "MixMonitor";
static const char *synopsis = "Record a call and mix the audio during the recording";
static const char *desc = ""
" MixMonitor(<file>.<ext>[|<options>[|<command>]])\n\n"
"Records the audio on the current channel to the specified file.\n"
"If the filename is an absolute path, uses that path, otherwise\n"
"creates the file in the configured monitoring directory from\n"
"asterisk.conf. Use of StopMixMonitor is required to guarantee\n"
"the audio file is available for processing during dialplan execution.\n\n"
"Valid options:\n"
" a - Append to the file instead of overwriting it.\n"
" b - Only save audio to the file while the channel is bridged.\n"
" Note: Does not include conferences or sounds played to each bridged\n"
" party.\n"
" Note: If you utilize this option inside a Local channel, you must\n"
" make sure the Local channel is not optimized away. To do this,\n"
" be sure to call your Local channel with the '/n' option.\n"
" For example: Dial(Local/start@mycontext/n)\n"
" v(<x>) - Adjust the heard volume by a factor of <x> (range -4 to 4)\n"
" V(<x>) - Adjust the spoken volume by a factor of <x> (range -4 to 4)\n"
" W(<x>) - Adjust the both heard and spoken volumes by a factor of <x>\n"
" (range -4 to 4)\n\n"
"<command> will be executed when the recording is over\n"
"Any strings matching ^{X} will be unescaped to ${X}.\n"
"All variables will be evaluated at the time MixMonitor is called.\n"
"The variable MIXMONITOR_FILENAME will contain the filename used to record.\n"
"";
static const char *stop_app = "StopMixMonitor";
static const char *stop_synopsis = "Stop recording a call through MixMonitor";
static const char *stop_desc = ""
" StopMixMonitor()\n\n"
"Stop recording a call through MixMonitor, and free the recording's file handle.\n"
"";
struct module_symbols *me;
static const char *mixmonitor_spy_type = "MixMonitor";
struct mixmonitor {
struct ast_audiohook audiohook;
char *filename;
char *post_process;
char *name;
unsigned int flags;
struct mixmonitor_ds *mixmonitor_ds;
};
enum {
MUXFLAG_APPEND = (1 << 1),
MUXFLAG_BRIDGED = (1 << 2),
MUXFLAG_VOLUME = (1 << 3),
MUXFLAG_READVOLUME = (1 << 4),
MUXFLAG_WRITEVOLUME = (1 << 5),
} mixmonitor_flags;
enum {
OPT_ARG_READVOLUME = 0,
OPT_ARG_WRITEVOLUME,
OPT_ARG_VOLUME,
OPT_ARG_ARRAY_SIZE,
} mixmonitor_args;
AST_APP_OPTIONS(mixmonitor_opts, {
AST_APP_OPTION('a', MUXFLAG_APPEND),
AST_APP_OPTION('b', MUXFLAG_BRIDGED),
AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
});
/* This structure is used as a means of making sure that our pointer to
* the channel we are monitoring remains valid. This is very similar to
* what is used in app_chanspy.c.
*/
struct mixmonitor_ds {
struct ast_channel *chan;
/* These condition variables are used to be sure that the channel
* hangup code completes before the mixmonitor thread attempts to
* free this structure. The combination of a bookean flag and a
* ast_cond_t ensure that no matter what order the threads run in,
* we are guaranteed to never have the waiting thread block forever
* in the case that the signaling thread runs first.
*/
unsigned int destruction_ok;
ast_cond_t destruction_condition;
ast_mutex_t lock;
/* The filestream is held in the datastore so it can be stopped
* immediately during stop_mixmonitor or channel destruction. */
int fs_quit;
struct ast_filestream *fs;
struct ast_audiohook *audiohook;
};
/*!
* \internal
* \pre mixmonitor_ds must be locked before calling this function
*/
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
{
if (mixmonitor_ds->fs) {
ast_closestream(mixmonitor_ds->fs);
mixmonitor_ds->fs = NULL;
mixmonitor_ds->fs_quit = 1;
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "MixMonitor close filestream\n");
}
}
static void mixmonitor_ds_destroy(void *data)
{
struct mixmonitor_ds *mixmonitor_ds = data;
ast_mutex_lock(&mixmonitor_ds->lock);
mixmonitor_ds->audiohook = NULL;
mixmonitor_ds->chan = NULL;
mixmonitor_ds->destruction_ok = 1;
ast_cond_signal(&mixmonitor_ds->destruction_condition);
ast_mutex_unlock(&mixmonitor_ds->lock);
}
static void mixmonitor_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
{
struct mixmonitor_ds *mixmonitor_ds = data;
ast_mutex_lock(&mixmonitor_ds->lock);
mixmonitor_ds->chan = new_chan;
ast_mutex_unlock(&mixmonitor_ds->lock);
}
static struct ast_datastore_info mixmonitor_ds_info = {
.type = "mixmonitor",
.destroy = mixmonitor_ds_destroy,
.chan_fixup = mixmonitor_ds_chan_fixup,
};
static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
{
if (mixmonitor->mixmonitor_ds) {
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
mixmonitor->mixmonitor_ds->audiohook = NULL;
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
/* kill the audiohook.*/
ast_audiohook_lock(&mixmonitor->audiohook);
ast_audiohook_detach(&mixmonitor->audiohook);
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_audiohook_destroy(&mixmonitor->audiohook);
}
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
{
struct ast_channel *peer;
int res;
if (!chan)
return -1;
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;
}
#define SAMPLES_PER_FRAME 160
static void mixmonitor_free(struct mixmonitor *mixmonitor)
{
if (mixmonitor) {
if (mixmonitor->mixmonitor_ds) {
ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
ast_free(mixmonitor->mixmonitor_ds);
}
ast_free(mixmonitor);
}
}
static void *mixmonitor_thread(void *obj)
{
struct mixmonitor *mixmonitor = obj;
struct ast_filestream **fs = NULL;
unsigned int oflags;
char *ext;
int errflag = 0;
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
fs = &mixmonitor->mixmonitor_ds->fs;
/* The audiohook must enter and exit the loop locked */
ast_audiohook_lock(&mixmonitor->audiohook);
while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
struct ast_frame *fr = NULL;
if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) {
ast_audiohook_trigger_wait(&mixmonitor->audiohook);
if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
break;
}
continue;
}
/* audiohook lock is not required for the next block.
* Unlock it, but remember to lock it before looping or exiting */
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
/* Initialize the file if not already done so */
if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
oflags = O_CREAT | O_WRONLY;
oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
if ((ext = strrchr(mixmonitor->filename, '.')))
*(ext++) = '\0';
else
ext = "raw";
if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) {
ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
errflag = 1;
}
}
/* Write out the frame(s) */
if (*fs) {
struct ast_frame *cur;
for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
ast_writestream(*fs, cur);
}
}
} else {
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
/* All done! free it. */
ast_frame_free(fr, 0);
ast_audiohook_lock(&mixmonitor->audiohook);
}
ast_audiohook_unlock(&mixmonitor->audiohook);
/* Datastore cleanup. close the filestream and wait for ds destruction */
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
if (!mixmonitor->mixmonitor_ds->destruction_ok) {
ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
}
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
/* kill the audiohook */
destroy_monitor_audiohook(mixmonitor);
if (mixmonitor->post_process) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
ast_safe_system(mixmonitor->post_process);
}
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
mixmonitor_free(mixmonitor);
return NULL;
}
static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
{
struct ast_datastore *datastore = NULL;
struct mixmonitor_ds *mixmonitor_ds;
if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
return -1;
}
ast_mutex_init(&mixmonitor_ds->lock);
ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) {
ast_mutex_destroy(&mixmonitor_ds->lock);
ast_cond_destroy(&mixmonitor_ds->destruction_condition);
ast_free(mixmonitor_ds);
return -1;
}
/* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
mixmonitor_ds->chan = chan;
mixmonitor_ds->audiohook = &mixmonitor->audiohook;
datastore->data = mixmonitor_ds;
ast_channel_lock(chan);
ast_channel_datastore_add(chan, datastore);
ast_channel_unlock(chan);
mixmonitor->mixmonitor_ds = mixmonitor_ds;
return 0;
}
static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
int readvol, int writevol, const char *post_process)
{
pthread_attr_t attr;
pthread_t thread;
struct mixmonitor *mixmonitor;
char postprocess2[1024] = "";
size_t len;
len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
/* If a post process system command is given attach it to the structure */
if (!ast_strlen_zero(post_process)) {
char *p1, *p2;
p1 = ast_strdupa(post_process);
for (p2 = p1; *p2 ; p2++) {
if (*p2 == '^' && *(p2+1) == '{') {
*p2 = '$';
}
}
pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
if (!ast_strlen_zero(postprocess2))
len += strlen(postprocess2) + 1;
}
/* Pre-allocate mixmonitor structure and spy */
if (!(mixmonitor = calloc(1, len))) {
return;
}
/* Setup the actual spy before creating our thread */
if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
mixmonitor_free(mixmonitor);
return;
}
/* Copy over flags and channel name */
mixmonitor->flags = flags;
if (setup_mixmonitor_ds(mixmonitor, chan)) {
mixmonitor_free(mixmonitor);
return;
}
mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
strcpy(mixmonitor->name, chan->name);
if (!ast_strlen_zero(postprocess2)) {
mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
strcpy(mixmonitor->post_process, postprocess2);
}
mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
strcpy(mixmonitor->filename, filename);
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
if (readvol)
mixmonitor->audiohook.options.read_volume = readvol;
if (writevol)
mixmonitor->audiohook.options.write_volume = writevol;
if (startmon(chan, &mixmonitor->audiohook)) {
ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
mixmonitor_spy_type, chan->name);
/* Since we couldn't add ourselves - bail out! */
ast_audiohook_destroy(&mixmonitor->audiohook);
mixmonitor_free(mixmonitor);
return;
}
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
pthread_attr_destroy(&attr);
}
static int mixmonitor_exec(struct ast_channel *chan, void *data)
{
int x, readvol = 0, writevol = 0;
struct ast_module_user *u;
struct ast_flags flags = {0};
char *parse;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filename);
AST_APP_ARG(options);
AST_APP_ARG(post_process);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (ast_strlen_zero(args.filename)) {
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
ast_module_user_remove(u);
return -1;
}
if (args.options) {
char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
} else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
} else {
readvol = get_volfactor(x);
}
}
if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
} else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
} else {
writevol = get_volfactor(x);
}
}
if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
} else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
} else {
readvol = writevol = get_volfactor(x);
}
}
}
/* if not provided an absolute path, use the system-configured monitoring directory */
if (args.filename[0] != '/') {
char *build;
build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
args.filename = build;
}
pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
ast_module_user_remove(u);
return 0;
}
static int stop_mixmonitor_exec(struct ast_channel *chan, void *data)
{
struct ast_datastore *datastore = NULL;
ast_channel_lock(chan);
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
struct mixmonitor_ds *mixmonitor_ds = datastore->data;
ast_mutex_lock(&mixmonitor_ds->lock);
/* closing the filestream here guarantees the file is avaliable to the dialplan
* after calling StopMixMonitor */
mixmonitor_ds_close_fs(mixmonitor_ds);
/* The mixmonitor thread may be waiting on the audiohook trigger.
* In order to exit from the mixmonitor loop before waiting on channel
* destruction, poke the audiohook trigger. */
if (mixmonitor_ds->audiohook) {
ast_audiohook_lock(mixmonitor_ds->audiohook);
ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
ast_audiohook_unlock(mixmonitor_ds->audiohook);
mixmonitor_ds->audiohook = NULL;
}
ast_mutex_unlock(&mixmonitor_ds->lock);
/* Remove the datastore so the monitor thread can exit */
if (!ast_channel_datastore_remove(chan, datastore)) {
ast_channel_datastore_free(datastore);
}
}
ast_channel_unlock(chan);
return 0;
}
static int mixmonitor_cli(int fd, int argc, char **argv)
{
struct ast_channel *chan;
if (argc < 3)
return RESULT_SHOWUSAGE;
if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) {
ast_cli(fd, "No channel matching '%s' found.\n", argv[2]);
return RESULT_SUCCESS;
}
if (!strcasecmp(argv[1], "start"))
mixmonitor_exec(chan, argv[3]);
else if (!strcasecmp(argv[1], "stop"))
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
ast_channel_unlock(chan);
return RESULT_SUCCESS;
}
static char *complete_mixmonitor_cli(const char *line, const char *word, int pos, int state)
{
return ast_complete_channels(line, word, pos, state, 2);
}
static struct ast_cli_entry cli_mixmonitor[] = {
{ { "mixmonitor", NULL, NULL },
mixmonitor_cli, "Execute a MixMonitor command.",
"mixmonitor <start|stop> <chan_name> [args]\n\n"
"The optional arguments are passed to the\n"
"MixMonitor application when the 'start' command is used.\n",
complete_mixmonitor_cli },
};
static int unload_module(void)
{
int res;
ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
res = ast_unregister_application(stop_app);
res |= ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");

View File

@@ -1,179 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2006, Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <app_morsecode__v001@the-tilghman.com>
*
* This code is released by the author with no restrictions on usage.
*
* 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.
*
*/
/*! \file
*
* \brief Morsecode application
*
* \author Tilghman Lesher <app_morsecode__v001@the-tilghman.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/indications.h"
static char *app_morsecode = "Morsecode";
static char *morsecode_synopsis = "Plays morse code";
static char *morsecode_descrip =
"Usage: Morsecode(<string>)\n"
"Plays the Morse code equivalent of the passed string. If the variable\n"
"MORSEDITLEN is set, it will use that value for the length (in ms) of the dit\n"
"(defaults to 80). Additionally, if MORSETONE is set, it will use that tone\n"
"(in Hz). The tone default is 800.\n";
static char *morsecode[] = {
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 0-15 */
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", /* 16-31 */
" ", /* 32 - <space> */
".-.-.-", /* 33 - ! */
".-..-.", /* 34 - " */
"", /* 35 - # */
"", /* 36 - $ */
"", /* 37 - % */
"", /* 38 - & */
".----.", /* 39 - ' */
"-.--.-", /* 40 - ( */
"-.--.-", /* 41 - ) */
"", /* 42 - * */
"", /* 43 - + */
"--..--", /* 44 - , */
"-....-", /* 45 - - */
".-.-.-", /* 46 - . */
"-..-.", /* 47 - / */
"-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", /* 48-57 - 0-9 */
"---...", /* 58 - : */
"-.-.-.", /* 59 - ; */
"", /* 60 - < */
"-...-", /* 61 - = */
"", /* 62 - > */
"..--..", /* 63 - ? */
".--.-.", /* 64 - @ */
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
"-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..",
"-.--.-", /* 91 - [ (really '(') */
"-..-.", /* 92 - \ (really '/') */
"-.--.-", /* 93 - ] (really ')') */
"", /* 94 - ^ */
"..--.-", /* 95 - _ */
".----.", /* 96 - ` */
".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--",
"-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--..",
"-.--.-", /* 123 - { (really '(') */
"", /* 124 - | */
"-.--.-", /* 125 - } (really ')') */
"-..-.", /* 126 - ~ (really bar) */
". . .", /* 127 - <del> (error) */
};
static void playtone(struct ast_channel *chan, int tone, int len)
{
char dtmf[20];
snprintf(dtmf, sizeof(dtmf), "%d/%d", tone, len);
ast_playtones_start(chan, 0, dtmf, 0);
ast_safe_sleep(chan, len);
ast_playtones_stop(chan);
}
static int morsecode_exec(struct ast_channel *chan, void *data)
{
int res=0, ditlen, tone;
char *digit;
const char *ditlenc, *tonec;
struct ast_module_user *u;
u = ast_module_user_add(chan);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Syntax: Morsecode(<string>) - no argument found\n");
ast_module_user_remove(u);
return 0;
}
/* Use variable MORESEDITLEN, if set (else 80) */
ditlenc = pbx_builtin_getvar_helper(chan, "MORSEDITLEN");
if (ast_strlen_zero(ditlenc) || (sscanf(ditlenc, "%30d", &ditlen) != 1)) {
ditlen = 80;
}
/* Use variable MORSETONE, if set (else 800) */
tonec = pbx_builtin_getvar_helper(chan, "MORSETONE");
if (ast_strlen_zero(tonec) || (sscanf(tonec, "%30d", &tone) != 1)) {
tone = 800;
}
for (digit = data; *digit; digit++) {
int digit2 = *digit;
char *dahdit;
if (digit2 < 0) {
continue;
}
for (dahdit = morsecode[digit2]; *dahdit; dahdit++) {
if (*dahdit == '-') {
playtone(chan, tone, 3 * ditlen);
} else if (*dahdit == '.') {
playtone(chan, tone, 1 * ditlen);
} else {
/* Account for ditlen of silence immediately following */
playtone(chan, 0, 2 * ditlen);
}
/* Pause slightly between each dit and dah */
playtone(chan, 0, 1 * ditlen);
}
/* Pause between characters */
playtone(chan, 0, 2 * ditlen);
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_morsecode);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app_morsecode, morsecode_exec, morsecode_synopsis, morsecode_descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Morse code");

View File

@@ -1,38 +1,24 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Silly application to play an MP3 file -- uses mpg123
*
* Copyright (C) 1999-2004, 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 Silly application to play an MP3 file -- uses mpg123
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
/*** MODULEINFO
<depend>working_fork</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/frame.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
@@ -40,69 +26,38 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/frame.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
#define LOCAL_MPG_123 "/usr/local/bin/mpg123"
#define MPG_123 "/usr/bin/mpg123"
static char *tdesc = "Silly MP3 Application";
static char *app = "MP3Player";
static char *synopsis = "Play an MP3 file or stream";
static char *descrip =
" MP3Player(location) Executes mpg123 to play the given location,\n"
"which typically would be a filename or a URL. User can exit by pressing\n"
"any key on the dialpad, or by hanging up.";
" MP3Player(location) Executes mpg123 to play the given location\n"
"which typically would be a filename or a URL. Returns -1 on\n"
"hangup or 0 otherwise. User can exit by pressing any key\n.";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int mp3play(char *filename, int fd)
{
int res;
int x;
sigset_t fullset, oldset;
#ifdef HAVE_CAP
cap_t cap;
#endif
sigfillset(&fullset);
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
res = fork();
if (res < 0)
ast_log(LOG_WARNING, "Fork failed\n");
if (res) {
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
if (res)
return res;
}
#ifdef HAVE_CAP
cap = cap_from_text("cap_net_admin-eip");
if (cap_set_proc(cap)) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
}
cap_free(cap);
#endif
if (ast_opt_high_priority)
ast_set_priority(0);
signal(SIGPIPE, SIG_DFL);
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
dup2(fd, STDOUT_FILENO);
for (x=STDERR_FILENO + 1;x<256;x++) {
close(x);
for (x=0;x<256;x++) {
if (x != STDOUT_FILENO)
close(x);
}
/* Execute mpg123, but buffer if it's a net connection */
if (!strncasecmp(filename, "http://", 7)) {
@@ -122,7 +77,7 @@ static int mp3play(char *filename, int fd)
execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
}
ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
_exit(0);
return -1;
}
static int timed_read(int fd, void *data, int datalen, int timeout)
@@ -131,7 +86,7 @@ static int timed_read(int fd, void *data, int datalen, int timeout)
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
res = ast_poll(fds, 1, timeout);
res = poll(fds, 1, timeout);
if (res < 1) {
ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res);
return -1;
@@ -143,59 +98,66 @@ static int timed_read(int fd, void *data, int datalen, int timeout)
static int mp3_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
struct localuser *u;
int fds[2];
int ms = -1;
int pid = -1;
int owriteformat;
int timeout = 2000;
struct timeval next;
struct timeval now, next;
struct ast_frame *f;
struct myframe {
struct ast_frame f;
char offset[AST_FRIENDLY_OFFSET];
short frdata[160];
} myf = {
.f = { 0, },
};
if (ast_strlen_zero(data)) {
} myf;
if (!data) {
ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
if (pipe(fds)) {
ast_log(LOG_WARNING, "Unable to create pipe\n");
ast_module_user_remove(u);
return -1;
}
LOCAL_USER_ADD(u);
ast_stopstream(chan);
owriteformat = chan->writeformat;
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
ast_module_user_remove(u);
return -1;
}
gettimeofday(&now, NULL);
res = mp3play((char *)data, fds[1]);
if (!strncasecmp((char *)data, "http://", 7)) {
timeout = 10000;
}
/* Wait 1000 ms first */
next = ast_tvnow();
next = now;
next.tv_sec += 1;
if (res >= 0) {
pid = res;
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
user */
for (;;) {
ms = ast_tvdiff_ms(next, ast_tvnow());
gettimeofday(&now, NULL);
ms = (next.tv_sec - now.tv_sec) * 1000;
ms += (next.tv_usec - now.tv_usec) / 1000;
#if 0
printf("ms: %d\n", ms);
#endif
if (ms <= 0) {
#if 0
{
static struct timeval last;
struct timeval tv;
gettimeofday(&tv, NULL);
printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
last = tv;
}
#endif
res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
if (res > 0) {
myf.f.frametype = AST_FRAME_VOICE;
@@ -217,7 +179,14 @@ static int mp3_exec(struct ast_channel *chan, void *data)
res = 0;
break;
}
next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
next.tv_usec += res / 2 * 125;
if (next.tv_usec >= 1000000) {
next.tv_usec -= 1000000;
next.tv_sec++;
}
#if 0
printf("Next: %d\n", ms);
#endif
} else {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
@@ -245,31 +214,38 @@ static int mp3_exec(struct ast_channel *chan, void *data)
}
close(fds[0]);
close(fds[1]);
LOCAL_USER_REMOVE(u);
if (pid > -1)
kill(pid, SIGKILL);
if (!res && owriteformat)
ast_set_write_format(chan, owriteformat);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, mp3_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,38 +1,24 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Silly application to play an NBScat file -- uses nbscat8k
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 Silly application to play an NBScat file -- uses nbscat8k
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
/*** MODULEINFO
<depend>working_fork</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/frame.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
@@ -41,26 +27,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <fcntl.h>
#include <sys/time.h>
#include <sys/socket.h>
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/frame.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
#define LOCAL_NBSCAT "/usr/local/bin/nbscat8k"
#define NBSCAT "/usr/bin/nbscat8k"
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#endif
static char *tdesc = "Silly NBS Stream Application";
static char *app = "NBScat";
@@ -68,45 +39,24 @@ static char *synopsis = "Play an NBS local stream";
static char *descrip =
" NBScat: Executes nbscat to listen to the local NBS stream.\n"
"User can exit by pressing any key\n.";
"Returns -1 on\n hangup or 0 otherwise. User can exit by \n"
"pressing any key\n.";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int NBScatplay(int fd)
{
int res;
int x;
sigset_t fullset, oldset;
#ifdef HAVE_CAP
cap_t cap;
#endif
sigfillset(&fullset);
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
res = fork();
if (res < 0)
ast_log(LOG_WARNING, "Fork failed\n");
if (res) {
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
if (res)
return res;
}
signal(SIGPIPE, SIG_DFL);
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
#ifdef HAVE_CAP
cap = cap_from_text("cap_net_admin-eip");
if (cap_set_proc(cap)) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
}
cap_free(cap);
#endif
if (ast_opt_high_priority)
ast_set_priority(0);
dup2(fd, STDOUT_FILENO);
for (x = STDERR_FILENO + 1; x < 1024; x++) {
for (x=0;x<256;x++) {
if (x != STDOUT_FILENO)
close(x);
}
@@ -114,7 +64,7 @@ static int NBScatplay(int fd)
execl(NBSCAT, "nbscat8k", "-d", (char *)NULL);
execl(LOCAL_NBSCAT, "nbscat8k", "-d", (char *)NULL);
ast_log(LOG_WARNING, "Execute of nbscat8k failed\n");
_exit(0);
return -1;
}
static int timed_read(int fd, void *data, int datalen)
@@ -123,7 +73,7 @@ static int timed_read(int fd, void *data, int datalen)
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
res = ast_poll(fds, 1, 2000);
res = poll(fds, 1, 2000);
if (res < 1) {
ast_log(LOG_NOTICE, "Selected timed out/errored out with %d\n", res);
return -1;
@@ -135,48 +85,57 @@ static int timed_read(int fd, void *data, int datalen)
static int NBScat_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
struct localuser *u;
int fds[2];
int ms = -1;
int pid = -1;
int owriteformat;
struct timeval next;
struct timeval now, next;
struct ast_frame *f;
struct myframe {
struct ast_frame f;
char offset[AST_FRIENDLY_OFFSET];
short frdata[160];
} myf;
u = ast_module_user_add(chan);
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
ast_log(LOG_WARNING, "Unable to create socketpair\n");
ast_module_user_remove(u);
return -1;
}
LOCAL_USER_ADD(u);
ast_stopstream(chan);
owriteformat = chan->writeformat;
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
ast_module_user_remove(u);
return -1;
}
res = NBScatplay(fds[1]);
/* Wait 1000 ms first */
next = ast_tvnow();
next = now;
next.tv_sec += 1;
if (res >= 0) {
pid = res;
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
user */
for (;;) {
ms = ast_tvdiff_ms(next, ast_tvnow());
gettimeofday(&now, NULL);
ms = (next.tv_sec - now.tv_sec) * 1000;
ms += (next.tv_usec - now.tv_usec) / 1000;
#if 0
printf("ms: %d\n", ms);
#endif
if (ms <= 0) {
#if 0
{
static struct timeval last;
struct timeval tv;
gettimeofday(&tv, NULL);
printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
last = tv;
}
#endif
res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
if (res > 0) {
myf.f.frametype = AST_FRAME_VOICE;
@@ -198,7 +157,14 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
res = 0;
break;
}
next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
next.tv_usec += res / 2 * 125;
if (next.tv_usec >= 1000000) {
next.tv_usec -= 1000000;
next.tv_sec++;
}
#if 0
printf("Next: %d\n", ms);
#endif
} else {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
@@ -226,31 +192,38 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
}
close(fds[0]);
close(fds[1]);
LOCAL_USER_REMOVE(u);
if (pid > -1)
kill(pid, SIGKILL);
if (!res && owriteformat)
ast_set_write_format(chan, owriteformat);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, NBScat_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,220 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2004 - 2006 Digium, Inc. All rights reserved.
*
* Mark Spencer <markster@digium.com>
*
* This code is released under the GNU General Public License
* version 2.0. See LICENSE for more information.
*
* 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.
*
*/
/*! \file
*
* \brief page() - Paging application
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>dahdi</depend>
<depend>app_meetme</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "asterisk/options.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/file.h"
#include "asterisk/app.h"
#include "asterisk/chanvars.h"
#include "asterisk/utils.h"
#include "asterisk/dial.h"
#include "asterisk/devicestate.h"
static const char *app_page= "Page";
static const char *page_synopsis = "Pages phones";
static const char *page_descrip =
"Page(Technology/Resource&Technology2/Resource2[|options])\n"
" Places outbound calls to the given technology / resource and dumps\n"
"them into a conference bridge as muted participants. The original\n"
"caller is dumped into the conference as a speaker and the room is\n"
"destroyed when the original caller leaves. Valid options are:\n"
" d - full duplex audio\n"
" q - quiet, do not play beep to caller\n"
" r - record the page into a file (see 'r' for app_meetme)\n";
enum {
PAGE_DUPLEX = (1 << 0),
PAGE_QUIET = (1 << 1),
PAGE_RECORD = (1 << 2),
} page_opt_flags;
AST_APP_OPTIONS(page_opts, {
AST_APP_OPTION('d', PAGE_DUPLEX),
AST_APP_OPTION('q', PAGE_QUIET),
AST_APP_OPTION('r', PAGE_RECORD),
});
static int page_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char *options, *tech, *resource, *tmp, *tmp2;
char meetmeopts[88], originator[AST_CHANNEL_NAME];
struct ast_flags flags = { 0 };
unsigned int confid = ast_random();
struct ast_app *app;
int res = 0, pos = 0, i = 0;
struct ast_dial **dial_list;
unsigned int num_dials;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
return -1;
}
u = ast_module_user_add(chan);
if (!(app = pbx_findapp("MeetMe"))) {
ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
ast_module_user_remove(u);
return -1;
};
options = ast_strdupa(data);
ast_copy_string(originator, chan->name, sizeof(originator));
if ((tmp = strchr(originator, '-')))
*tmp = '\0';
tmp = strsep(&options, "|");
if (options)
ast_app_parse_options(page_opts, &flags, NULL, options);
snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe|%ud|%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"),
(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
/* Count number of extensions in list by number of ampersands + 1 */
num_dials = 1;
tmp2 = tmp;
while (*tmp2) {
if (*tmp2 == '&') {
num_dials++;
}
tmp2++;
}
if (!(dial_list = ast_calloc(num_dials, sizeof(struct ast_dial *)))) {
ast_log(LOG_ERROR, "Can't allocate %ld bytes for dial list\n", (long)(sizeof(struct ast_dial *) * num_dials));
ast_module_user_remove(u);
return -1;
}
/* Go through parsing/calling each device */
while ((tech = strsep(&tmp, "&"))) {
struct ast_dial *dial = NULL;
/* don't call the originating device */
if (!strcasecmp(tech, originator))
continue;
/* If no resource is available, continue on */
if (!(resource = strchr(tech, '/'))) {
ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
continue;
}
*resource++ = '\0';
/* Create a dialing structure */
if (!(dial = ast_dial_create())) {
ast_log(LOG_WARNING, "Failed to create dialing structure.\n");
continue;
}
/* Append technology and resource */
ast_dial_append(dial, tech, resource);
/* Set ANSWER_EXEC as global option */
ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts);
/* Run this dial in async mode */
ast_dial_run(dial, chan, 1);
/* Put in our dialing array */
dial_list[pos++] = dial;
}
if (!ast_test_flag(&flags, PAGE_QUIET)) {
res = ast_streamfile(chan, "beep", chan->language);
if (!res)
res = ast_waitstream(chan, "");
}
if (!res) {
snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"),
(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
pbx_exec(chan, app, meetmeopts);
}
/* Go through each dial attempt cancelling, joining, and destroying */
for (i = 0; i < pos; i++) {
struct ast_dial *dial = dial_list[i];
/* We have to wait for the async thread to exit as it's possible Meetme won't throw them out immediately */
ast_dial_join(dial);
/* Hangup all channels */
ast_dial_hangup(dial);
/* Destroy dialing structure */
ast_dial_destroy(dial);
}
ast_free(dial_list);
ast_module_user_remove(u);
return -1;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_page);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app_page, page_exec, page_synopsis, page_descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Page Multiple Phones");

View File

@@ -1,55 +1,38 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
* Asterisk -- A telephony toolkit for Linux.
*
* ParkAndAnnounce application for Asterisk
* Author: Ben Miller <bgmiller@dccinc.com>
* With TONS of help from Mark!
*
* Asterisk is Copyrighted as follows
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief ParkAndAnnounce application for Asterisk
*
* \author Ben Miller <bgmiller@dccinc.com>
* \arg With TONS of help from Mark!
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/features.h>
#include <asterisk/options.h>
#include <asterisk/logger.h>
#include <asterisk/say.h>
#include <asterisk/lock.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/features.h"
#include "asterisk/options.h"
#include "asterisk/logger.h"
#include "asterisk/say.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
static char *tdesc = "Call Parking and Announce Application";
static char *app = "ParkAndAnnounce";
@@ -57,53 +40,51 @@ static char *synopsis = "Park and Announce";
static char *descrip =
" ParkAndAnnounce(announce:template|timeout|dial|[return_context]):\n"
"Park a call into the parkinglot and announce the call to another channel.\n"
"\n"
"announce template: Colon-separated list of files to announce. The word PARKED\n"
" will be replaced by a say_digits of the extension in which\n"
" the call is parked.\n"
"timeout: Time in seconds before the call returns into the return\n"
" context.\n"
"dial: The app_dial style resource to call to make the\n"
" announcement. Console/dsp calls the console.\n"
"return_context: The goto-style label to jump the call back into after\n"
" timeout. Default <priority+1>.\n"
"\n"
"The variable ${PARKEDAT} will contain the parking extension into which the\n"
"call was placed. Use with the Local channel to allow the dialplan to make\n"
"use of this information.\n";
"Park a call into the parkinglot and announce the call over the console.\n"
"announce template: colon separated list of files to announce, the word PARKED\n"
" will be replaced by a say_digits of the ext the call is parked in\n"
"timeout: time in seconds before the call returns into the return context.\n"
"dial: The app_dial style resource to call to make the announcement. Console/dsp calls the console.\n"
"return_context: the goto style label to jump the call back into after timeout. default=prio+1\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int parkandannounce_exec(struct ast_channel *chan, void *data)
{
int res=0;
char *return_context;
int lot, timeout = 0, dres;
int l, lot, timeout = 0, dres;
char *working, *context, *exten, *priority, *dial, *dialtech, *dialstr;
char *template, *tpl_working, *tpl_current;
char *tmp[100];
char buf[13];
int looptemp = 0,i = 0, res = 0;
char *s;
int looptemp=0,i=0;
char *s,*orig_s;
struct ast_channel *dchan;
struct outgoing_helper oh;
int outstate;
struct ast_module_user *u;
if (ast_strlen_zero(data)) {
struct localuser *u;
if(!data || (data && !strlen(data))) {
ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
return -1;
}
u = ast_module_user_add(chan);
l=strlen(data)+2;
orig_s=malloc(l);
if(!orig_s) {
ast_log(LOG_WARNING, "Out of memory\n");
return -1;
}
s=orig_s;
strncpy(s,data,l);
s = ast_strdupa(data);
template = strsep(&s,"|");
template=strsep(&s,"|");
if(! template) {
ast_log(LOG_WARNING, "PARK: An announce template must be defined\n");
ast_module_user_remove(u);
free(orig_s);
return -1;
}
@@ -111,14 +92,14 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
timeout = atoi(strsep(&s, "|"));
timeout *= 1000;
}
dial = strsep(&s, "|");
if (ast_strlen_zero(dial)) {
dial=strsep(&s, "|");
if(!dial) {
ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or Zap/g1/5551212\n");
ast_module_user_remove(u);
free(orig_s);
return -1;
} else {
dialtech = strsep(&dial, "/");
dialstr = dial;
dialtech=strsep(&dial, "/");
dialstr=dial;
ast_verbose( VERBOSE_PREFIX_3 "Dial Tech,String: (%s,%s)\n", dialtech,dialstr);
}
@@ -146,43 +127,41 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
}
if(atoi(priority) < 0) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
ast_module_user_remove(u);
free(orig_s);
return -1;
}
/* At this point we have a priority and maybe an extension and a context */
chan->priority = atoi(priority);
if (exten)
ast_copy_string(chan->exten, exten, sizeof(chan->exten));
if (context)
ast_copy_string(chan->context, context, sizeof(chan->context));
if(exten && strcasecmp(exten, "BYEXTENSION"))
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
if(context)
strncpy(chan->context, context, sizeof(chan->context)-1);
} else { /* increment the priority by default*/
chan->priority++;
}
if(option_verbose > 2) {
ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->callerid);
if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
}
}
LOCAL_USER_ADD(u);
/* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
res = ast_masq_park_call(chan, NULL, timeout, &lot);
if (res == -1) {
goto finish;
}
ast_masq_park_call(chan, NULL, timeout, &lot);
res=-1;
ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
/* Now place the call to the extention */
snprintf(buf, sizeof(buf), "%d", lot);
memset(&oh, 0, sizeof(oh));
oh.parent_channel = chan;
oh.vars = ast_variable_new("_PARKEDAT", buf);
dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
dchan = ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->callerid);
if(dchan) {
if(dchan->_state == AST_STATE_UP) {
@@ -193,12 +172,14 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", dchan->name);
ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
ast_hangup(dchan);
ast_module_user_remove(u);
free(orig_s);
LOCAL_USER_REMOVE(u);
return -1;
}
} else {
ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
ast_module_user_remove(u);
free(orig_s);
LOCAL_USER_REMOVE(u);
return -1;
}
@@ -209,15 +190,15 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
ast_verbose(VERBOSE_PREFIX_4 "Announce Template:%s\n", template);
tpl_working = template;
tpl_current = strsep(&tpl_working, ":");
tpl_current=strsep(&tpl_working, ":");
while(tpl_current && looptemp < ARRAY_LEN(tmp)) {
while(tpl_current && looptemp < sizeof(tmp)) {
tmp[looptemp]=tpl_current;
looptemp++;
tpl_current = strsep(&tpl_working,":");
tpl_current=strsep(&tpl_working,":");
}
for(i = 0; i < looptemp; i++) {
for(i=0; i<looptemp; i++) {
ast_verbose(VERBOSE_PREFIX_4 "Announce:%s\n", tmp[i]);
if(!strcmp(tmp[i], "PARKED")) {
ast_say_digits(dchan, lot, "", dchan->language);
@@ -235,26 +216,38 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
ast_stopstream(dchan);
ast_hangup(dchan);
finish:
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
free(orig_s);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
/* return ast_register_application(app, park_exec); */
return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,495 +1,118 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Trivial application to playback a sound file
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 playback a sound file
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/cli.h"
#include "asterisk/localtime.h"
#include "asterisk/say.h"
static char *tdesc = "Trivial Playback Application";
static char *app = "Playback";
static char *synopsis = "Play a file";
static char *descrip =
" Playback(filename[&filename2...][|option]): Plays back given filenames (do not put\n"
"extension). Options may also be included following a pipe symbol. The 'skip'\n"
"option causes the playback of the message to be skipped if the channel\n"
"is not in the 'up' state (i.e. it hasn't been answered yet). If 'skip' is \n"
" Playback(filename[|option]): Plays back a given filename (do not put\n"
"extension). Options may also be included following a pipe symbol. The 'skip'\n"
"option causes the playback of the message to be skipped if the channel\n"
"is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
"specified, the application will return immediately should the channel not be\n"
"off hook. Otherwise, unless 'noanswer' is specified, the channel will\n"
"off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
"be answered before the sound is played. Not all channels support playing\n"
"messages while still on hook. If 'j' is specified, the application\n"
"will jump to priority n+101 if present when a file specified to be played\n"
"does not exist.\n"
"This application sets the following channel variable upon completion:\n"
" PLAYBACKSTATUS The status of the playback attempt as a text string, one of\n"
" SUCCESS | FAILED\n"
"See Also: Background (application) -- for playing soundfiles that are interruptible\n"
" WaitExten (application) -- wait for digits from caller, optionally play music on hold\n"
;
"messages while still hook. Returns -1 if the channel was hung up, or if the\n"
"file does not exist. Returns 0 otherwise.\n";
STANDARD_LOCAL_USER;
static struct ast_config *say_cfg = NULL;
/* save the say' api calls.
* The first entry is NULL if we have the standard source,
* otherwise we are sourcing from here.
* 'say load [new|old]' will enable the new or old method, or report status
*/
static const void * say_api_buf[40];
static const char *say_old = "old";
static const char *say_new = "new";
static void save_say_mode(const void *arg)
{
int i = 0;
say_api_buf[i++] = arg;
say_api_buf[i++] = ast_say_number_full;
say_api_buf[i++] = ast_say_enumeration_full;
say_api_buf[i++] = ast_say_digit_str_full;
say_api_buf[i++] = ast_say_character_str_full;
say_api_buf[i++] = ast_say_phonetic_str_full;
say_api_buf[i++] = ast_say_datetime;
say_api_buf[i++] = ast_say_time;
say_api_buf[i++] = ast_say_date;
say_api_buf[i++] = ast_say_datetime_from_now;
say_api_buf[i++] = ast_say_date_with_format;
}
static void restore_say_mode(void *arg)
{
int i = 0;
say_api_buf[i++] = arg;
ast_say_number_full = say_api_buf[i++];
ast_say_enumeration_full = say_api_buf[i++];
ast_say_digit_str_full = say_api_buf[i++];
ast_say_character_str_full = say_api_buf[i++];
ast_say_phonetic_str_full = say_api_buf[i++];
ast_say_datetime = say_api_buf[i++];
ast_say_time = say_api_buf[i++];
ast_say_date = say_api_buf[i++];
ast_say_datetime_from_now = say_api_buf[i++];
ast_say_date_with_format = say_api_buf[i++];
}
/*
* Typical 'say' arguments in addition to the date or number or string
* to say. We do not include 'options' because they may be different
* in recursive calls, and so they are better left as an external
* parameter.
*/
typedef struct {
struct ast_channel *chan;
const char *ints;
const char *language;
int audiofd;
int ctrlfd;
} say_args_t;
static int s_streamwait3(const say_args_t *a, const char *fn)
{
int res = ast_streamfile(a->chan, fn, a->language);
if (res) {
ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
return res;
}
res = (a->audiofd > -1 && a->ctrlfd > -1) ?
ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
ast_waitstream(a->chan, a->ints);
ast_stopstream(a->chan);
return res;
}
/*
* the string is 'prefix:data' or prefix:fmt:data'
* with ':' being invalid in strings.
*/
static int do_say(say_args_t *a, const char *s, const char *options, int depth)
{
struct ast_variable *v;
char *lang, *x, *rule = NULL;
int ret = 0;
struct varshead head = { .first = NULL, .last = NULL };
struct ast_var_t *n;
if (depth++ > 10) {
ast_log(LOG_WARNING, "recursion too deep, exiting\n");
return -1;
} else if (!say_cfg) {
ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
return -1;
}
/* scan languages same as in file.c */
if (a->language == NULL)
a->language = "en"; /* default */
lang = ast_strdupa(a->language);
for (;;) {
for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
if (ast_extension_match(v->name, s)) {
rule = ast_strdupa(v->value);
break;
}
}
if (rule)
break;
if ( (x = strchr(lang, '_')) )
*x = '\0'; /* try without suffix */
else if (strcmp(lang, "en"))
lang = "en"; /* last resort, try 'en' if not done yet */
else
break;
}
if (!rule)
return 0;
/* skip up to two prefixes to get the value */
if ( (x = strchr(s, ':')) )
s = x + 1;
if ( (x = strchr(s, ':')) )
s = x + 1;
n = ast_var_assign("SAY", s);
AST_LIST_INSERT_HEAD(&head, n, entries);
/* scan the body, one piece at a time */
while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
char fn[128];
const char *p, *fmt, *data; /* format and data pointers */
/* prepare a decent file name */
x = ast_skip_blanks(x);
ast_trim_blanks(x);
/* replace variables */
memset(fn, 0, sizeof(fn)); /* XXX why isn't done in pbx_substitute_variables_helper! */
pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
/* locate prefix and data, if any */
fmt = strchr(fn, ':');
if (!fmt || fmt == fn) { /* regular filename */
ret = s_streamwait3(a, fn);
continue;
}
fmt++;
data = strchr(fmt, ':'); /* colon before data */
if (!data || data == fmt) { /* simple prefix-fmt */
ret = do_say(a, fn, options, depth);
continue;
}
/* prefix:fmt:data */
for (p = fmt; p < data && ret <= 0; p++) {
char fn2[sizeof(fn)];
if (*p == ' ' || *p == '\t') /* skip blanks */
continue;
if (*p == '\'') {/* file name - we trim them */
char *y;
strcpy(fn2, ast_skip_blanks(p+1)); /* make a full copy */
y = strchr(fn2, '\'');
if (!y) {
p = data; /* invalid. prepare to end */
break;
}
*y = '\0';
ast_trim_blanks(fn2);
p = strchr(p + 1, '\'');
ret = s_streamwait3(a, fn2);
} else {
int l = fmt-fn;
strcpy(fn2, fn); /* copy everything */
/* after prefix, append the format */
fn2[l++] = *p;
strcpy(fn2 + l, data);
ret = do_say(a, fn2, options, depth);
}
if (ret) {
break;
}
}
}
ast_var_delete(n);
return ret;
}
static int say_full(struct ast_channel *chan, const char *string,
const char *ints, const char *lang, const char *options,
int audiofd, int ctrlfd)
{
say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
return do_say(&a, string, options, 0);
}
static int say_number_full(struct ast_channel *chan, int num,
const char *ints, const char *lang, const char *options,
int audiofd, int ctrlfd)
{
char buf[64];
say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
snprintf(buf, sizeof(buf), "num:%d", num);
return do_say(&a, buf, options, 0);
}
static int say_enumeration_full(struct ast_channel *chan, int num,
const char *ints, const char *lang, const char *options,
int audiofd, int ctrlfd)
{
char buf[64];
say_args_t a = { chan, ints, lang, audiofd, ctrlfd };
snprintf(buf, sizeof(buf), "enum:%d", num);
return do_say(&a, buf, options, 0);
}
static int say_date_generic(struct ast_channel *chan, time_t t,
const char *ints, const char *lang, const char *format, const char *timezone, const char *prefix)
{
char buf[128];
struct tm tm;
say_args_t a = { chan, ints, lang, -1, -1 };
if (format == NULL)
format = "";
ast_localtime(&t, &tm, NULL);
snprintf(buf, sizeof(buf), "%s:%s:%04d%02d%02d%02d%02d.%02d-%d-%3d",
prefix,
format,
tm.tm_year+1900,
tm.tm_mon+1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec,
tm.tm_wday,
tm.tm_yday);
return do_say(&a, buf, NULL, 0);
}
static int say_date_with_format(struct ast_channel *chan, time_t t,
const char *ints, const char *lang, const char *format, const char *timezone)
{
return say_date_generic(chan, t, ints, lang, format, timezone, "datetime");
}
static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
{
return say_date_generic(chan, t, ints, lang, "", NULL, "date");
}
static int say_time(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
{
return say_date_generic(chan, t, ints, lang, "", NULL, "time");
}
static int say_datetime(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
{
return say_date_generic(chan, t, ints, lang, "", NULL, "datetime");
}
/*
* remap the 'say' functions to use those in this file
*/
static int __say_init(int fd, int argc, char *argv[])
{
const char *old_mode = say_api_buf[0] ? say_new : say_old;
char *mode;
if (argc == 2) {
ast_cli(fd, "say mode is [%s]\n", old_mode);
return RESULT_SUCCESS;
} else if (argc != 3)
return RESULT_SHOWUSAGE;
mode = argv[2];
ast_log(LOG_WARNING, "init say.c from %s to %s\n", old_mode, mode);
if (!strcmp(mode, old_mode)) {
ast_log(LOG_WARNING, "say mode is %s already\n", mode);
} else if (!strcmp(mode, say_new)) {
if (say_cfg == NULL)
say_cfg = ast_config_load("say.conf");
save_say_mode(say_new);
ast_say_number_full = say_number_full;
ast_say_enumeration_full = say_enumeration_full;
#if 0
ast_say_digits_full = say_digits_full;
ast_say_digit_str_full = say_digit_str_full;
ast_say_character_str_full = say_character_str_full;
ast_say_phonetic_str_full = say_phonetic_str_full;
ast_say_datetime_from_now = say_datetime_from_now;
#endif
ast_say_datetime = say_datetime;
ast_say_time = say_time;
ast_say_date = say_date;
ast_say_date_with_format = say_date_with_format;
} else if (!strcmp(mode, say_old) && say_api_buf[0] == say_new) {
restore_say_mode(NULL);
} else {
ast_log(LOG_WARNING, "unrecognized mode %s\n", mode);
}
return RESULT_SUCCESS;
}
static struct ast_cli_entry cli_playback[] = {
{ { "say", "load", NULL },
__say_init, "set/show the say mode",
"Usage: say load [new|old]\n Set/show the say mode\n" },
};
LOCAL_USER_DECL;
static int playback_exec(struct ast_channel *chan, void *data)
{
int res = 0;
int mres = 0;
struct ast_module_user *u;
char *tmp;
struct localuser *u;
char tmp[256];
char *options;
int option_skip=0;
int option_say=0;
int option_noanswer = 0;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(filenames);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
char *stringp;
if (!data || ast_strlen_zero((char *)data)) {
ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
return -1;
}
tmp = ast_strdupa(data);
u = ast_module_user_add(chan);
AST_STANDARD_APP_ARGS(args, tmp);
if (args.options) {
if (strcasestr(args.options, "skip"))
option_skip = 1;
if (strcasestr(args.options, "say"))
option_say = 1;
if (strcasestr(args.options, "noanswer"))
option_noanswer = 1;
if (strchr(args.options, 'j'))
priority_jump = 1;
}
strncpy(tmp, (char *)data, sizeof(tmp)-1);
stringp=tmp;
strsep(&stringp, "|");
options = strsep(&stringp, "|");
if (options && !strcasecmp(options, "skip"))
option_skip = 1;
if (options && !strcasecmp(options, "noanswer"))
option_noanswer = 1;
LOCAL_USER_ADD(u);
if (chan->_state != AST_STATE_UP) {
if (option_skip) {
/* At the user's option, skip if the line is not up */
goto done;
} else if (!option_noanswer) {
LOCAL_USER_REMOVE(u);
return 0;
} else if (!option_noanswer)
/* Otherwise answer unless we're supposed to send this while on-hook */
res = ast_answer(chan);
}
}
if (!res) {
char *back = args.filenames;
char *front;
ast_stopstream(chan);
while (!res && (front = strsep(&back, "&"))) {
if (option_say)
res = say_full(chan, front, "", chan->language, NULL, -1, -1);
else
res = ast_streamfile(chan, front, chan->language);
if (!res) {
res = ast_waitstream(chan, "");
ast_stopstream(chan);
} else {
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
res = 0;
mres = 1;
}
res = ast_streamfile(chan, tmp, chan->language);
if (!res)
res = ast_waitstream(chan, "");
else {
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
res = 0;
}
ast_stopstream(chan);
}
done:
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int reload(void)
int unload_module(void)
{
if (say_cfg) {
ast_config_destroy(say_cfg);
ast_log(LOG_NOTICE, "Reloading say.conf\n");
}
say_cfg = ast_config_load("say.conf");
/*
* XXX here we should sort rules according to the same order
* we have in pbx.c so we have the same matching behaviour.
*/
return 0;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int unload_module(void)
int load_module(void)
{
int res;
res = ast_unregister_application(app);
ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
ast_module_user_hangup_all();
if (say_cfg)
ast_config_destroy(say_cfg);
return res;
}
static int load_module(void)
{
say_cfg = ast_config_load("say.conf");
ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
return ast_register_application(app, playback_exec, synopsis, descrip);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
.load = load_module,
.unload = unload_module,
.reload = reload,
);
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,156 +1,85 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Block all calls without Caller*ID, require phone # to be entered
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Block all calls without Caller*ID, require phone # to be entered
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/callerid.h>
#include <asterisk/app.h>
#include <asterisk/config.h>
#include <string.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/utils.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/callerid.h"
#include "asterisk/app.h"
#include "asterisk/config.h"
#include <stdlib.h>
#define PRIV_CONFIG "privacy.conf"
static char *tdesc = "Require phone number to be entered, if no CallerID sent";
static char *app = "PrivacyManager";
static char *synopsis = "Require phone number to be entered, if no CallerID sent";
static char *descrip =
" PrivacyManager([maxretries[|minlength[|options]]]): If no Caller*ID \n"
"is sent, PrivacyManager answers the channel and asks the caller to\n"
"enter their phone number. The caller is given 3 attempts to do so.\n"
"The application does nothing if Caller*ID was received on the channel.\n"
" Configuration file privacy.conf contains two variables:\n"
" maxretries default 3 -maximum number of attempts the caller is allowed \n"
" to input a callerid.\n"
" minlength default 10 -minimum allowable digits in the input callerid number.\n"
"If you don't want to use the config file and have an i/o operation with\n"
"every call, you can also specify maxretries and minlength as application\n"
"parameters. Doing so supercedes any values set in privacy.conf.\n"
"The option string may contain the following character: \n"
" 'j' -- jump to n+101 priority after <maxretries> failed attempts to collect\n"
" the minlength number of digits.\n"
"The application sets the following channel variable upon completion: \n"
"PRIVACYMGRSTATUS The status of the privacy manager's attempt to collect \n"
" a phone number from the user. A text string that is either:\n"
" SUCCESS | FAILED \n"
;
" PrivacyManager: If no Caller*ID is sent, PrivacyManager answers the\n"
"channel and asks the caller to enter their 10 digit phone number.\n"
"The caller is given 3 attempts. If after 3 attempts, they do not enter\n"
"their 10 digit phone number, and if there exists a priority n + 101,\n"
"where 'n' is the priority of the current instance, then the\n"
"channel will be setup to continue at that priority level.\n"
"Otherwise, it returns 0. Does nothing if Caller*ID was received on the\n"
"channel.\n";
STANDARD_LOCAL_USER;
static int privacy_exec (struct ast_channel *chan, void *data)
LOCAL_USER_DECL;
static int
privacy_exec (struct ast_channel *chan, void *data)
{
int res=0;
int retries;
int maxretries = 3;
int minlength = 10;
int x = 0;
const char *s;
char phone[30];
struct ast_module_user *u;
struct ast_config *cfg = NULL;
char *parse = NULL;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(maxretries);
AST_APP_ARG(minlength);
AST_APP_ARG(options);
);
int x;
char *s;
char phone[10];
char new_cid[144];
struct localuser *u;
struct ast_config *cfg;
u = ast_module_user_add(chan);
if (!ast_strlen_zero(chan->cid.cid_num)) {
LOCAL_USER_ADD (u);
if (chan->callerid)
{
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
} else {
}
else
{
/*Answer the channel if it is not already*/
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
if (res) {
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return -1;
}
}
if (!ast_strlen_zero(data)) {
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.maxretries) {
if (sscanf(args.maxretries, "%30d", &x) == 1)
maxretries = x;
else
ast_log(LOG_WARNING, "Invalid max retries argument\n");
}
if (args.minlength) {
if (sscanf(args.minlength, "%30d", &x) == 1)
minlength = x;
else
ast_log(LOG_WARNING, "Invalid min length argument\n");
}
if (args.options)
if (strchr(args.options, 'j'))
priority_jump = 1;
}
if (!x)
{
/*Read in the config file*/
cfg = ast_config_load(PRIV_CONFIG);
/*Read in the config file*/
cfg = ast_load(PRIV_CONFIG);
if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
if (sscanf(s, "%30d", &x) == 1)
maxretries = x;
else
ast_log(LOG_WARNING, "Invalid max retries argument\n");
}
if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
if (sscanf(s, "%30d", &x) == 1)
minlength = x;
else
ast_log(LOG_WARNING, "Invalid min length argument\n");
}
}
/*Play unidentified call*/
res = ast_safe_sleep(chan, 1000);
@@ -159,21 +88,23 @@ static int privacy_exec (struct ast_channel *chan, void *data)
if (!res)
res = ast_waitstream(chan, "");
if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
if (sscanf(s, "%d", &x) == 1) {
maxretries = x;
} else {
ast_log(LOG_WARNING, "Invalid max retries argument\n");
}
}
/*Ask for 10 digit number, give 3 attempts*/
for (retries = 0; retries < maxretries; retries++) {
if (!res)
res = ast_streamfile(chan, "privacy-prompt", chan->language);
if (!res)
res = ast_waitstream(chan, "");
if (!res )
res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
res = ast_app_getdata(chan, "privacy-prompt", phone, sizeof(phone), 0);
if (res < 0)
break;
/*Make sure we get at least digits*/
if (strlen(phone) >= minlength )
/*Make sure we get 10 digits*/
if (strlen(phone) == 10)
break;
else {
res = ast_streamfile(chan, "privacy-incorrect", chan->language);
@@ -183,50 +114,57 @@ static int privacy_exec (struct ast_channel *chan, void *data)
}
/*Got a number, play sounds and send them on their way*/
if ((retries < maxretries) && res >= 0 ) {
if ((retries < maxretries) && !res) {
res = ast_streamfile(chan, "privacy-thankyou", chan->language);
if (!res)
res = ast_waitstream(chan, "");
ast_set_callerid (chan, phone, "Privacy Manager", NULL);
/* Clear the unavailable presence bit so if it came in on PRI
* the caller id will now be passed out to other channels
*/
chan->cid.cid_pres &= (AST_PRES_UNAVAILABLE ^ 0xFF);
if (option_verbose > 2) {
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s, callerpres to %d\n",phone,chan->cid.cid_pres);
}
pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
snprintf (new_cid, sizeof (new_cid), "\"%s\" <%s>", "Privacy Manager", phone);
ast_set_callerid (chan, new_cid, 0);
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",new_cid);
} else {
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
/*Send the call to n+101 priority, where n is the current priority*/
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority+=100;
}
if (cfg)
ast_config_destroy(cfg);
ast_destroy(cfg);
}
ast_module_user_remove(u);
return 0;
LOCAL_USER_REMOVE (u);
return 0;
}
static int unload_module(void)
int
unload_module (void)
{
int res;
res = ast_unregister_application (app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application (app);
}
static int load_module(void)
int
load_module (void)
{
return ast_register_application (app, privacy_exec, synopsis, descrip);
return ast_register_application (app, privacy_exec, synopsis,
descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");
char *
description (void)
{
return tdesc;
}
int
usecount (void)
{
int res;
STANDARD_USECOUNT (res);
return res;
}
char *
key ()
{
return ASTERISK_GPL_KEY;
}

394
apps/app_qcall.c Normal file
View File

@@ -0,0 +1,394 @@
/** @file app_qcall.c
*
* Asterisk -- A telephony toolkit for Linux.
*
* Call back a party and connect them to a running pbx thread
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*
* Call a user from a file contained within a queue (/var/spool/asterisk/qcall)
*
* The queue is a directory containing files with the call request information
* as a single line of text as follows:
*
* Dialstring Caller-ID Extension Maxsecs [Identifier] [Required-response]
*
* Dialstring -- A Dial String (The number to be called) in the
* format Technology/Number, such IAX/mysys/1234 or Zap/g1/1234
*
* Caller-ID -- A Standard nomalized representation of the Caller-ID of
* the number being dialed (generally 10 digits in the US). Leave as
* "asreceived" to use the default Caller*ID
*
* Extension -- The Extension (optionally Extension@context) that the
* user should be "transferred" to after acceptance of the call.
*
* Maxsecs -- The Maximum time of the call in seconds. Specify 0 for infinite.
*
* Identifier -- The "Identifier" of the request. This is used to determine
* the names of the audio prompt files played. The first prompt, the one that
* asks for the input, is just the exact string specified as the identifier.
* The second prompt, the one that is played after the correct input is given,
* (generally a "thank you" recording), is the specified string with "-ok"
* added to the end. So, if you specify "foo" as the identifier, your first
* prompt file that will be played will be "foo" and the second one will be
* "foo-ok". If omitted no prompt is given
*
* Required-Response (Optional) -- Specify a digit string to be used as the
* acceptance "code" if you desire it to be something other then "1". This
* can be used to implement some sort of PIN or security system. It may be
* more then a single character.
*
* NOTE: It is important to remember that the process that creates these
* files needs keep and maintain a write lock (using flock with the LOCK_EX
* option) when writing these files.
*
*/
#include <asterisk/lock.h>
#include <asterisk/utils.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/options.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/file.h>
#include "../astconf.h"
static char qdir[255];
static char *tdesc = "Call from Queue";
static pthread_t qcall_thread;
static int debug = 0;
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
#define OLDESTOK 14400 /* not any more then this number of secs old */
#define INITIALONE 1 /* initial wait before the first one in secs */
#define NEXTONE 600 /* wait before trying it again in secs */
#define MAXWAITFORANSWER 45000 /* max call time before answer */
/* define either one or both of these two if your application requires it */
#if 0
#define ACCTCODE "SOMETHING" /* Account code */
#define AMAFLAGS AST_CDR_BILLING /* AMA flags */
#endif
/* define this if you want to have a particular CLID display on the user's
phone when they receive the call */
#if 0
#define OURCLID "2564286275" /* The callerid to be displayed when calling */
#endif
static void *qcall_do(void *arg);
static void *qcall(void *ignore)
{
pthread_t dialer_thread;
DIR *dirp;
FILE *fp;
struct dirent *dp;
char fname[80];
struct stat mystat;
time_t t;
void *arg;
pthread_attr_t attr;
time(&t);
if (debug) printf("@@@@ qcall starting at %s",ctime(&t));
for(;;)
{
time(&t);
dirp = opendir(qdir);
if (!dirp)
{
perror("app_qcall:Cannot open queue directory");
break;
}
while((dp = readdir(dirp)) != NULL)
{
if (dp->d_name[0] == '.') continue;
snprintf(fname, sizeof(fname), "%s/%s", qdir, dp->d_name);
if (stat(fname,&mystat) == -1)
{
perror("app_qcall:stat");
fprintf(stderr,"%s\n",fname);
continue;
}
/* if not a regular file, skip it */
if ((mystat.st_mode & S_IFMT) != S_IFREG) continue;
/* if not yet .... */
if (mystat.st_atime == mystat.st_mtime)
{ /* first time */
if ((mystat.st_atime + INITIALONE) > t)
continue;
}
else
{ /* already looked at once */
if ((mystat.st_atime + NEXTONE) > t) continue;
}
/* if too old */
if (mystat.st_mtime < (t - OLDESTOK))
{
/* kill it, its too old */
unlink(fname);
continue;
}
/* "touch" file's access time */
fp = fopen(fname,"r");
if (fp) fclose(fp);
/* make a copy of the filename string, so that we
may go on and use the buffer */
arg = (void *) strdup(fname);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ast_pthread_create(&dialer_thread,&attr,qcall_do,arg) == -1)
{
perror("qcall: Cannot create thread");
continue;
}
}
closedir(dirp);
sleep(1);
}
pthread_exit(NULL);
}
/* single thread with one file (request) to dial */
static void *qcall_do(void *arg)
{
char fname[300] = "";
char dialstr[300];
char extstr[300];
char ident[300] = "";
char reqinp[300] = "";
char buf[300];
char clid[300],*tele,*context;
FILE *fp;
int ms = MAXWAITFORANSWER,maxsecs;
struct ast_channel *channel;
time_t t;
/* get the filename from the arg */
strncpy(fname,(char *)arg, sizeof(fname) - 1);
free(arg);
time(&t);
fp = fopen(fname,"r");
if (!fp) /* if cannot open request file */
{
perror("qcall_do:fopen");
fprintf(stderr,"%s\n",fname);
unlink(fname);
pthread_exit(NULL);
}
/* lock the file */
if (flock(fileno(fp),LOCK_EX) == -1)
{
perror("qcall_do:flock");
fprintf(stderr,"%s\n",fname);
pthread_exit(NULL);
}
/* default required input for acknowledgement */
reqinp[0] = '1';
reqinp[1] = '\0';
/* default no ident */
ident[0] = '\0'; /* default no ident */
if (fscanf(fp,"%s %s %s %d %s %s",dialstr,clid,
extstr,&maxsecs,ident,reqinp) < 4)
{
fprintf(stderr,"qcall_do:file line invalid in file %s:\n",fname);
pthread_exit(NULL);
}
flock(fileno(fp),LOCK_UN);
fclose(fp);
tele = strchr(dialstr,'/');
if (!tele)
{
fprintf(stderr,"qcall_do:Dial number must be in format tech/number\n");
unlink(fname);
pthread_exit(NULL);
}
*tele++ = 0;
channel = ast_request(dialstr,AST_FORMAT_SLINEAR,tele);
if (channel)
{
ast_set_read_format(channel,AST_FORMAT_SLINEAR);
ast_set_write_format(channel,AST_FORMAT_SLINEAR);
#ifdef OURCLID
if (channel->callerid)
free(channel->callerid);
channel->callerid = strdup(OURCLID);
if (channel->ani)
free(channel->ani);
channel->ani = strdup(OURCLID);
#endif
channel->whentohangup = 0;
channel->appl = "AppQcall";
channel->data = "(Outgoing Line)";
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Qcall initiating call to %s/%s on %s (%s)\n",
dialstr,tele,channel->name,fname);
ast_call(channel,tele,MAXWAITFORANSWER);
}
else
{
fprintf(stderr,"qcall_do:Sorry unable to obtain channel\n");
pthread_exit(NULL);
}
if (strcasecmp(clid, "asreceived")) {
if (channel->callerid) free(channel->callerid);
channel->callerid = NULL;
if (channel->ani) free(channel->ani);
channel->ani = NULL;
}
if (channel->_state == AST_STATE_UP)
if (debug) printf("@@@@ Autodial:Line is Up\n");
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Qcall waiting for answer on %s\n",
channel->name);
while(ms > 0){
struct ast_frame *f;
ms = ast_waitfor(channel,ms);
f = ast_read(channel);
if (!f)
{
if (debug) printf("@@@@ qcall_do:Hung Up\n");
unlink(fname);
break;
}
if (f->frametype == AST_FRAME_CONTROL)
{
if (f->subclass == AST_CONTROL_HANGUP)
{
if (debug) printf("@@@@ qcall_do:Hung Up\n");
unlink(fname);
ast_frfree(f);
break;
}
if (f->subclass == AST_CONTROL_ANSWER)
{
if (debug) printf("@@@@ qcall_do:Phone Answered\n");
if (channel->_state == AST_STATE_UP)
{
unlink(fname);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Qcall got answer on %s\n",
channel->name);
usleep(1500000);
if (strlen(ident)) {
ast_streamfile(channel,ident,0);
if (ast_readstring(channel,buf,strlen(reqinp),10000,5000,"#"))
{
ast_stopstream(channel);
if (debug) printf("@@@@ qcall_do: timeout or hangup in dtmf read\n");
ast_frfree(f);
break;
}
ast_stopstream(channel);
if (strcmp(buf,reqinp)) /* if not match */
{
if (debug) printf("@@@@ qcall_do: response (%s) does not match required (%s)\n",buf,reqinp);
ast_frfree(f);
break;
}
ast_frfree(f);
}
/* okay, now we go for it */
context = strchr(extstr,'@');
if (!context) context = "default";
else *context++ = 0;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Qcall got accept, now putting through to %s@%s on %s\n",
extstr,context,channel->name);
if (strlen(ident)) {
strncat(ident,"-ok", sizeof(ident) - strlen(ident) - 1);
/* if file existent, play it */
if (!ast_streamfile(channel,ident,0))
{
ast_waitstream(channel,"");
ast_stopstream(channel);
}
}
if (strcasecmp(clid, "asreceived")) {
channel->callerid = strdup(clid);
channel->ani = strdup(clid);
}
channel->language[0] = 0;
channel->dnid = strdup(extstr);
#ifdef AMAFLAGS
channel->amaflags = AMAFLAGS;
#endif
#ifdef ACCTCODE
strncpy(channel->accountcode, ACCTCODE, sizeof(chan->accountcode) - 1);
#else
channel->accountcode[0] = 0;
#endif
if (maxsecs) /* if finite length call */
{
time(&channel->whentohangup);
channel->whentohangup += maxsecs;
}
strncpy(channel->exten, extstr, sizeof(channel->exten) - 1);
strncpy(channel->context, context, sizeof(channel->context) - 1);
channel->priority = 1;
if(debug) printf("Caller ID is %s\n", channel->callerid);
ast_pbx_run(channel);
pthread_exit(NULL);
}
}
else if(f->subclass==AST_CONTROL_RINGING)
if (debug) printf("@@@@ qcall_do:Phone Ringing end\n");
}
ast_frfree(f);
}
ast_hangup(channel);
if (debug) printf("@@@@ qcall_do:Hung up channel\n");
pthread_exit(NULL);
return NULL;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return 0;
}
int load_module(void)
{
snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "qcall");
mkdir(qdir,0760);
ast_pthread_create(&qcall_thread,NULL,qcall,NULL);
return 0;
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +1,29 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (c) 2003 - 2005 Tilghman Lesher. All rights reserved.
* Random application
*
* Copyright (c) 2003-2004 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <asterisk__app_random__200508@the-tilghman.com>
* Tilghman Lesher <asterisk__app_random__20040111@the-tilghman.com>
*
* This code is released by the author with no restrictions on usage or distribution.
*
* 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.
*
*/
/*! \file
*
* \brief Random application
*
* \author Tilghman Lesher <asterisk__app_random__200508@the-tilghman.com>
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
/*! \todo The Random() app should be removed from trunk following the release of 1.4 */
static char *tdesc = "Random goto";
static char *app_random = "Random";
@@ -47,62 +31,97 @@ static char *random_synopsis = "Conditionally branches, based upon a probability
static char *random_descrip =
"Random([probability]:[[context|]extension|]priority)\n"
" probability := INTEGER in the range 1 to 100\n"
"DEPRECATED: Use GotoIf($[${RAND(1,100)} > <number>]?<label>)\n";
" probability := INTEGER in the range 1 to 100\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int random_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
struct localuser *u;
char *s;
char *exten, *pri, *context;
char *prob;
int probint;
static int deprecated = 0;
int probint, priorityint;
if (ast_strlen_zero(data)) {
if (!data) {
ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n");
return -1;
}
u = ast_module_user_add(chan);
s = ast_strdupa(data);
LOCAL_USER_ADD(u);
s = ast_strdupa((void *) data);
prob = strsep(&s,":");
if ((!prob) || (sscanf(prob, "%30d", &probint) != 1))
if ((!prob) || (sscanf(prob, "%d", &probint) != 1))
probint = 0;
if (!deprecated) {
deprecated = 1;
ast_log(LOG_WARNING, "Random is deprecated in Asterisk 1.4. Replace with GotoIf($[${RAND(0,99)} + %d >= 100]?%s)\n", probint, s);
}
if ((ast_random() % 100) + probint >= 100) {
res = ast_parseable_goto(chan, s);
if ((random() % 100) + probint > 100) {
context = strsep(&s, "|");
exten = strsep(&s, "|");
if (!exten) {
/* Only a priority */
pri = context;
exten = NULL;
context = NULL;
} else {
pri = strsep(&s, "|");
if (!pri) {
pri = exten;
exten = context;
context = NULL;
}
}
if (!pri) {
ast_log(LOG_WARNING, "No label specified\n");
LOCAL_USER_REMOVE(u);
return -1;
} else if (sscanf(pri, "%d", &priorityint) != 1) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
LOCAL_USER_REMOVE(u);
return -1;
}
/* At this point we have a priority and */
/* maybe an extension and a context */
chan->priority = priorityint - 1;
if (exten && strcasecmp(exten, "BYEXTENSION"))
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
if (context)
strncpy(chan->context, context, sizeof(chan->context)-1);
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n",
chan->context,chan->exten, chan->priority+1);
LOCAL_USER_REMOVE(u);
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app_random);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app_random);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app_random, random_exec, random_synopsis, random_descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Random goto");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,234 +1,144 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Trivial application to read a variable
*
* Copyright (C) 2003, Digium
*
* 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 read a variable
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/app.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/options.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/indications.h"
enum {
OPT_SKIP = (1 << 0),
OPT_INDICATION = (1 << 1),
OPT_NOANSWER = (1 << 2),
} read_option_flags;
AST_APP_OPTIONS(read_app_options, {
AST_APP_OPTION('s', OPT_SKIP),
AST_APP_OPTION('i', OPT_INDICATION),
AST_APP_OPTION('n', OPT_NOANSWER),
});
static char *tdesc = "Read Variable Application";
static char *app = "Read";
static char *synopsis = "Read a variable";
static char *descrip =
" Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n"
"Reads a #-terminated string of digits a certain number of times from the\n"
"user in to the given variable.\n"
" filename -- file to play before reading digits or tone with option i\n"
" Read(variable[|filename][|maxdigits][|option])\n\n"
"Reads a #-terminated string of digits from the user in to the given variable,\n"
"optionally playing a given filename first.\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"
" Any value below 0 means the same. Max accepted value is 255.\n"
" option -- options are 's' , 'i', 'n'\n"
" 's' to return immediately if the line is not up,\n"
" 'i' to play filename as an indication tone from your indications.conf\n"
" 'n' to read digits even if the line is not up.\n"
" attempts -- if greater than 1, that many attempts will be made in the \n"
" event no data is entered.\n"
" timeout -- An integer number of seconds to wait for a digit response. If greater\n"
" than 0, that value will override the default timeout.\n\n"
"Read should disconnect if the function fails or errors out.\n";
" option -- may be 'skip' to return immediately if the line is not up,\n"
" or 'noanswer' to read digits even if the line is not up.\n\n"
"Returns -1 on hangup or error and 0 otherwise.\n";
STANDARD_LOCAL_USER;
#define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
LOCAL_USER_DECL;
static int read_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char tmp[256] = "";
int maxdigits = 255;
int tries = 1, to = 0, x = 0;
char *argcopy = NULL;
struct tone_zone_sound *ts;
struct ast_flags flags = {0};
AST_DECLARE_APP_ARGS(arglist,
AST_APP_ARG(variable);
AST_APP_ARG(filename);
AST_APP_ARG(maxdigits);
AST_APP_ARG(options);
AST_APP_ARG(attempts);
AST_APP_ARG(timeout);
);
if (ast_strlen_zero(data)) {
struct localuser *u;
char tmp[256];
char argdata[256] = "";
char *varname;
char *filename;
char *stringp;
char *maxdigitstr;
char *options;
int option_skip = 0;
int option_noanswer = 0;
int maxdigits=255;
if (!data || ast_strlen_zero((char *)data)) {
ast_log(LOG_WARNING, "Read requires an argument (variable)\n");
return -1;
}
u = ast_module_user_add(chan);
argcopy = ast_strdupa(data);
AST_STANDARD_APP_ARGS(arglist, argcopy);
if (!ast_strlen_zero(arglist.options)) {
ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
}
if (!ast_strlen_zero(arglist.attempts)) {
tries = atoi(arglist.attempts);
if (tries <= 0)
tries = 1;
}
if (!ast_strlen_zero(arglist.timeout)) {
to = atoi(arglist.timeout);
if (to <= 0)
to = 0;
else
to *= 1000;
}
if (ast_strlen_zero(arglist.filename)) {
arglist.filename = NULL;
}
if (!ast_strlen_zero(arglist.maxdigits)) {
maxdigits = atoi(arglist.maxdigits);
if ((maxdigits<1) || (maxdigits>255)) {
maxdigits = 255;
} else if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %d digits.\n", maxdigits);
}
if (ast_strlen_zero(arglist.variable)) {
ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n");
ast_module_user_remove(u);
strncpy(argdata, (char *)data, sizeof(argdata)-1);
stringp=argdata;
varname = strsep(&stringp, "|");
filename = strsep(&stringp, "|");
maxdigitstr = strsep(&stringp,"|");
options = strsep(&stringp, "|");
if (options && !strcasecmp(options, "skip"))
option_skip = 1;
if (options && !strcasecmp(options, "noanswer"))
option_noanswer = 1;
if (!(filename) || ast_strlen_zero(filename))
filename = NULL;
if (maxdigitstr) {
maxdigits = atoi(maxdigitstr);
if ((maxdigits<1) || (maxdigits>255)) {
maxdigits = 255;
} else
ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %i digits.\n", maxdigits);
}
if (!(varname) || ast_strlen_zero(varname)) {
ast_log(LOG_WARNING, "Read requires an variable name\n");
return -1;
}
ts=NULL;
if (ast_test_flag(&flags,OPT_INDICATION)) {
if (!ast_strlen_zero(arglist.filename)) {
ts = ast_get_indication_tone(chan->zone,arglist.filename);
}
}
LOCAL_USER_ADD(u);
if (chan->_state != AST_STATE_UP) {
if (ast_test_flag(&flags,OPT_SKIP)) {
if (option_skip) {
/* At the user's option, skip if the line is not up */
pbx_builtin_setvar_helper(chan, arglist.variable, "\0");
ast_module_user_remove(u);
pbx_builtin_setvar_helper(chan, varname, "\0");
LOCAL_USER_REMOVE(u);
return 0;
} else if (!ast_test_flag(&flags,OPT_NOANSWER)) {
} else if (!option_noanswer) {
/* Otherwise answer unless we're supposed to read while on-hook */
res = ast_answer(chan);
}
}
if (!res) {
while (tries && !res) {
ast_stopstream(chan);
if (ts && ts->data[0]) {
if (!to)
to = chan->pbx ? chan->pbx->rtimeout * 1000 : 6000;
res = ast_playtones_start(chan, 0, ts->data, 0);
for (x = 0; x < maxdigits; ) {
res = ast_waitfordigit(chan, to);
ast_playtones_stop(chan);
if (res < 1) {
tmp[x]='\0';
break;
}
tmp[x++] = res;
if (tmp[x-1] == '#') {
tmp[x-1] = '\0';
break;
}
}
} else {
res = ast_app_getdata(chan, arglist.filename, tmp, maxdigits, to);
}
if (res > -1) {
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
if (!ast_strlen_zero(tmp)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
tries = 0;
} else {
tries--;
if (option_verbose > 2) {
if (tries)
ast_verbose(VERBOSE_PREFIX_3 "User entered nothing, %d chance%s left\n", tries, (tries != 1) ? "s" : "");
else
ast_verbose(VERBOSE_PREFIX_3 "User entered nothing.\n");
}
}
res = 0;
} else {
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
}
ast_stopstream(chan);
res = ast_app_getdata(chan, filename, tmp, maxdigits, 0);
if (res > -1) {
pbx_builtin_setvar_helper(chan, varname, tmp);
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
res = 0;
} else {
ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
}
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, read_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read Variable Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,120 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Matt O'Gorman <mogorman@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 ReadFile application -- Reads in a File for you.
*
* \author Matt O'Gorman <mogorman@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
static char *app_readfile = "ReadFile";
static char *readfile_synopsis = "ReadFile(varname=file,length)";
static char *readfile_descrip =
"ReadFile(varname=file,length)\n"
" Varname - Result stored here.\n"
" File - The name of the file to read.\n"
" Length - Maximum number of characters to capture.\n";
static int readfile_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL;
int len=0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "ReadFile require an argument!\n");
return -1;
}
u = ast_module_user_add(chan);
s = ast_strdupa(data);
varname = strsep(&s, "=");
file = strsep(&s, "|");
length = s;
if (!varname || !file) {
ast_log(LOG_ERROR, "No file or variable specified!\n");
ast_module_user_remove(u);
return -1;
}
if (length) {
if ((sscanf(length, "%30d", &len) != 1) || (len < 0)) {
ast_log(LOG_WARNING, "%s is not a positive number, defaulting length to max\n", length);
len = 0;
}
}
if ((returnvar = ast_read_textfile(file))) {
if (len > 0) {
if (len < strlen(returnvar))
returnvar[len]='\0';
else
ast_log(LOG_WARNING, "%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar));
}
pbx_builtin_setvar_helper(chan, varname, returnvar);
free(returnvar);
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_readfile);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app_readfile, readfile_exec, readfile_synopsis, readfile_descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stores output of file into a variable");

View File

@@ -1,263 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Anthony Minessale <anthmct@yahoo.com>
* 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 RealTime App
*
* \author Anthony Minessale <anthmct@yahoo.com>
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/options.h"
#include "asterisk/pbx.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#define next_one(var) var = var->next
#define crop_data(str) { *(str) = '\0' ; (str)++; }
static char *app = "RealTime";
static char *uapp = "RealTimeUpdate";
static char *synopsis = "Realtime Data Lookup";
static char *usynopsis = "Realtime Data Rewrite";
static char *USAGE = "RealTime(<family>|<colmatch>|<value>[|<prefix>])";
static char *UUSAGE = "RealTimeUpdate(<family>|<colmatch>|<value>|<newcol>|<newval>)";
static char *desc =
"Use the RealTime config handler system to read data into channel variables.\n"
"RealTime(<family>|<colmatch>|<value>[|<prefix>])\n\n"
"All unique column names will be set as channel variables with optional prefix\n"
"to the name. For example, a prefix of 'var_' would make the column 'name'\n"
"become the variable ${var_name}. REALTIMECOUNT will be set with the number\n"
"of values read.\n";
static char *udesc = "Use the RealTime config handler system to update a value\n"
"RealTimeUpdate(<family>|<colmatch>|<value>|<newcol>|<newval>)\n\n"
"The column <newcol> in 'family' matching column <colmatch>=<value> will be\n"
"updated to <newval>. REALTIMECOUNT will be set with the number of rows\n"
"updated or -1 if an error occurs.\n";
static int cli_realtime_load(int fd, int argc, char **argv)
{
char *header_format = "%30s %-30s\n";
struct ast_variable *var = NULL, *save = NULL;
if (argc < 5) {
ast_cli(fd, "You must supply a family name, a column to match on, and a value to match to.\n");
return RESULT_FAILURE;
}
var = ast_load_realtime(argv[2], argv[3], argv[4], NULL);
if (var) {
save = var;
ast_cli(fd, header_format, "Column Name", "Column Value");
ast_cli(fd, header_format, "--------------------", "--------------------");
while (var) {
ast_cli(fd, header_format, var->name, var->value);
var = var->next;
}
ast_variables_destroy(save);
} else {
ast_cli(fd, "No rows found matching search criteria.\n");
}
return RESULT_SUCCESS;
}
static int cli_realtime_update(int fd, int argc, char **argv) {
int res = 0;
if(argc<7) {
ast_cli(fd, "You must supply a family name, a column to update on, a new value, column to match, and value to to match.\n");
ast_cli(fd, "Ex: realtime update sipfriends name bobsphone port 4343\n will execute SQL as UPDATE sipfriends SET port = 4343 WHERE name = bobsphone\n");
return RESULT_FAILURE;
}
res = ast_update_realtime(argv[2], argv[3], argv[4], argv[5], argv[6], NULL);
if(res < 0) {
ast_cli(fd, "Failed to update. Check the debug log for possible SQL related entries.\n");
return RESULT_SUCCESS;
}
ast_cli(fd, "Updated %d RealTime record%s.\n", res, (res != 1) ? "s" : "");
return RESULT_SUCCESS;
}
static char cli_realtime_load_usage[] =
"Usage: realtime load <family> <colmatch> <value>\n"
" Prints out a list of variables using the RealTime driver.\n";
static char cli_realtime_update_usage[] =
"Usage: realtime update <family> <colmatch> <value>\n"
" Update a single variable using the RealTime driver.\n";
static struct ast_cli_entry cli_realtime[] = {
{ { "realtime", "load", NULL, NULL },
cli_realtime_load, "Used to print out RealTime variables.",
cli_realtime_load_usage, NULL },
{ { "realtime", "update", NULL, NULL },
cli_realtime_update, "Used to update RealTime variables.",
cli_realtime_update_usage, NULL },
};
static int realtime_update_exec(struct ast_channel *chan, void *data)
{
char *family=NULL, *colmatch=NULL, *value=NULL, *newcol=NULL, *newval=NULL;
struct ast_module_user *u;
int res = 0, count = 0;
char countc[13];
ast_log(LOG_WARNING, "The RealTimeUpdate application has been deprecated in favor of the REALTIME dialplan function.\n");
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
return -1;
}
u = ast_module_user_add(chan);
family = ast_strdupa(data);
if ((colmatch = strchr(family,'|'))) {
crop_data(colmatch);
if ((value = strchr(colmatch,'|'))) {
crop_data(value);
if ((newcol = strchr(value,'|'))) {
crop_data(newcol);
if ((newval = strchr(newcol,'|')))
crop_data(newval);
}
}
}
if (! (family && value && colmatch && newcol && newval) ) {
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
res = -1;
} else {
count = ast_update_realtime(family,colmatch,value,newcol,newval,NULL);
}
snprintf(countc, sizeof(countc), "%d", count);
pbx_builtin_setvar_helper(chan, "REALTIMECOUNT", countc);
ast_module_user_remove(u);
return res;
}
static int realtime_exec(struct ast_channel *chan, void *data)
{
int res=0, count=0;
struct ast_module_user *u;
struct ast_variable *var, *itt;
char *family=NULL, *colmatch=NULL, *value=NULL, *prefix=NULL, *vname=NULL;
char countc[13];
size_t len;
ast_log(LOG_WARNING, "The RealTime application has been deprecated in favor of the REALTIME dialplan function.\n");
if (ast_strlen_zero(data)) {
ast_log(LOG_ERROR,"Invalid input: usage %s\n",USAGE);
return -1;
}
u = ast_module_user_add(chan);
family = ast_strdupa(data);
if ((colmatch = strchr(family,'|'))) {
crop_data(colmatch);
if ((value = strchr(colmatch,'|'))) {
crop_data(value);
if ((prefix = strchr(value,'|')))
crop_data(prefix);
}
}
if (! (family && value && colmatch) ) {
ast_log(LOG_ERROR,"Invalid input: usage %s\n",USAGE);
res = -1;
} else {
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4"Realtime Lookup: family:'%s' colmatch:'%s' value:'%s'\n",family,colmatch,value);
if ((var = ast_load_realtime(family, colmatch, value, NULL))) {
for (itt = var; itt; itt = itt->next) {
if(prefix) {
len = strlen(prefix) + strlen(itt->name) + 2;
vname = alloca(len);
snprintf(vname,len,"%s%s",prefix,itt->name);
} else
vname = itt->name;
pbx_builtin_setvar_helper(chan, vname, itt->value);
count++;
}
ast_variables_destroy(var);
} else if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4"No Realtime Matches Found.\n");
}
snprintf(countc, sizeof(countc), "%d", count);
pbx_builtin_setvar_helper(chan, "REALTIMECOUNT", countc);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
res = ast_unregister_application(uapp);
res |= ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
res = ast_register_application(uapp, realtime_update_exec, usynopsis, udesc);
res |= ast_register_application(app, realtime_exec, synopsis, desc);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Data Lookup/Rewrite");

View File

@@ -1,92 +1,67 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Trivial application to record a sound file
*
* Copyright (C) 2001, Linux Support Services, Inc.
*
* Matthew Fredrickson <creslin@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.
* Matthew Fredrickson <creslin@linux-support.net>
*
* 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 record a sound file
*
* \author Matthew Fredrickson <creslin@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/dsp.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/dsp.h"
#include "asterisk/utils.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
static char *tdesc = "Trivial Record Application";
static char *app = "Record";
static char *synopsis = "Record to a file";
static char *descrip =
" Record(filename.format|silence[|maxduration][|options])\n\n"
" Record(filename:format|silence[|maxduration][|option])\n\n"
"Records from the channel into a given filename. If the file exists it will\n"
"be overwritten.\n"
"- 'format' is the format of the file type to be recorded (wav, gsm, etc).\n"
"- 'silence' is the number of seconds of silence to allow before returning.\n"
"- 'maxduration' is the maximum recording duration in seconds. If missing\n"
"or 0 there is no maximum.\n"
"- 'options' may contain any of the following letters:\n"
" 'a' : append to existing recording rather than replacing\n"
" 'n' : do not answer, but record anyway if line not yet answered\n"
" 'q' : quiet (do not play a beep tone)\n"
" 's' : skip recording if the line is not yet answered\n"
" 't' : use alternate '*' terminator key (DTMF) instead of default '#'\n"
" 'x' : ignore all terminator keys (DTMF) and keep recording until hangup\n"
"\n"
"- 'option' may be 'skip' to return immediately if the line is not up,\n"
"or 'noanswer' to attempt to record even if the line is not up.\n\n"
"If filename contains '%d', these characters will be replaced with a number\n"
"incremented by one each time the file is recorded. A channel variable\n"
"named RECORDED_FILE will also be set, which contains the final filemname.\n\n"
"Use 'core show file formats' to see the available formats on your system\n\n"
"incremented by one each time the file is recorded. \n\n"
"Formats: g723, g729, gsm, h263, ulaw, alaw, vox, wav, WAV\n\n"
"User can press '#' to terminate the recording and continue to the next priority.\n\n"
"If the user should hangup during a recording, all data will be lost and the\n"
"application will teminate. \n";
"Returns -1 when the user hangs up.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int record_exec(struct ast_channel *chan, void *data)
{
int res = 0;
int count = 0;
int percentflag = 0;
char *filename, *ext = NULL, *silstr, *maxstr, *options;
char *vdata, *p;
int i = 0;
char fil[256];
char tmp[256];
char ext[10];
char *vdata;
int i = 0;
int j = 0;
struct ast_filestream *s = '\0';
struct ast_module_user *u;
struct localuser *u;
struct ast_frame *f = NULL;
struct ast_dsp *sildet = NULL; /* silence detector dsp */
@@ -94,134 +69,124 @@ static int record_exec(struct ast_channel *chan, void *data)
int dspsilence = 0;
int silence = 0; /* amount of silence to allow */
int gotsilence = 0; /* did we timeout for silence? */
int maxduration = 0; /* max duration of recording in milliseconds */
char silencestr[5];
char durationstr[8];
int maxduration = 0; /* max duration of recording */
int gottimeout = 0; /* did we timeout for maxduration exceeded? */
time_t timeout = 0;
char option[16];
int option_skip = 0;
int option_noanswer = 0;
int option_append = 0;
int terminator = '#';
int option_quiet = 0;
int rfmt = 0;
int flags;
int waitres;
struct ast_silence_generator *silgen = NULL;
char *end=NULL;
char *p=NULL;
/* The next few lines of code parse out the filename and header from the input string */
if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
if (!data) { /* no data implies no filename or anything is present */
ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
/* Yay for strsep being easy */
vdata = ast_strdupa(data);
p = vdata;
filename = strsep(&p, "|");
silstr = strsep(&p, "|");
maxstr = strsep(&p, "|");
options = strsep(&p, "|");
if (filename) {
if (strstr(filename, "%d"))
percentflag = 1;
ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */
if (!ext)
ext = strchr(filename, ':');
if (ext) {
*ext = '\0';
ext++;
p = vdata;
while(p && (p=strchr(p,':'))) {
end=p;
if(!strcasecmp(end,":end")) {
*end='\0';
end++;
break;
}
p++;
end=NULL;
}
if (!ext) {
ast_log(LOG_WARNING, "No extension specified to filename!\n");
ast_module_user_remove(u);
for (; vdata[i] && (vdata[i] != ':') && (vdata[i] != '|'); i++ ) {
if ((vdata[i] == '%') && (vdata[i+1] == 'd')) {
percentflag = 1; /* the wildcard is used */
}
if (j < sizeof(fil) - 1)
fil[j++] = vdata[i];
}
fil[j] = '\0';
if (vdata[i] != ':') {
ast_log(LOG_WARNING, "No extension found\n");
return -1;
}
if (silstr) {
if ((sscanf(silstr, "%30d", &i) == 1) && (i > -1)) {
silence = i * 1000;
} else if (!ast_strlen_zero(silstr)) {
ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr);
}
i++;
j = 0;
for (; vdata[i] && (vdata[i] != '|'); i++)
if (j < sizeof(ext) - 1)
ext[j++] = vdata[i];
ext[j] = '\0';
if (vdata[i] == '|')
i++;
j = 0;
for (; vdata[i] && (vdata[i] != '|'); i++)
if (j < sizeof(silencestr) - 1)
silencestr[j++] = vdata[i];
silencestr[j] = '\0';
if (j > 0) {
silence = atoi(silencestr);
if (silence > 0)
silence *= 1000;
}
if (maxstr) {
if ((sscanf(maxstr, "%30d", &i) == 1) && (i > -1))
/* Convert duration to milliseconds */
maxduration = i * 1000;
else if (!ast_strlen_zero(maxstr))
ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr);
}
if (options) {
/* Retain backwards compatibility with old style options */
if (!strcasecmp(options, "skip"))
option_skip = 1;
else if (!strcasecmp(options, "noanswer"))
option_noanswer = 1;
else {
if (strchr(options, 's'))
option_skip = 1;
if (strchr(options, 'n'))
option_noanswer = 1;
if (strchr(options, 'a'))
option_append = 1;
if (strchr(options, 't'))
terminator = '*';
if (strchr(options, 'x'))
terminator = 0;
if (strchr(options, 'q'))
option_quiet = 1;
}
}
if (vdata[i] == '|')
i++;
j = 0;
for (; vdata[i] && (vdata[i] != '|'); i++)
if (j < sizeof(durationstr) - 1)
durationstr[j++] = vdata[i];
durationstr[j] = '\0';
if (j > 0)
maxduration = atoi(durationstr);
if (vdata[i] == '|')
i++;
j = 0;
for (; vdata[i] && (vdata[i] != '|'); i++)
if (j < sizeof(option) - 1)
option[j++] = vdata[i];
option[j] = '\0';
if (!strcasecmp(option, "skip"))
option_skip = 1;
if (!strcasecmp(option, "noanswer"))
option_noanswer = 1;
/* done parsing */
/* these are to allow the use of the %d in the config file for a wild card of sort to
create a new file with the inputed name scheme */
if (percentflag) {
AST_DECLARE_APP_ARGS(fname,
AST_APP_ARG(piece)[100];
);
char *tmp2 = ast_strdupa(filename);
char countstring[15];
int i;
/* Separate each piece out by the format specifier */
AST_NONSTANDARD_APP_ARGS(fname, tmp2, '%');
do {
int tmplen;
/* First piece has no leading percent, so it's copied verbatim */
ast_copy_string(tmp, fname.piece[0], sizeof(tmp));
tmplen = strlen(tmp);
for (i = 1; i < fname.argc; i++) {
if (fname.piece[i][0] == 'd') {
/* Substitute the count */
snprintf(countstring, sizeof(countstring), "%d", count);
ast_copy_string(tmp + tmplen, countstring, sizeof(tmp) - tmplen);
tmplen += strlen(countstring);
} else if (tmplen + 2 < sizeof(tmp)) {
/* Unknown format specifier - just copy it verbatim */
tmp[tmplen++] = '%';
tmp[tmplen++] = fname.piece[i][0];
}
/* Copy the remaining portion of the piece */
ast_copy_string(tmp + tmplen, &(fname.piece[i][1]), sizeof(tmp) - tmplen);
}
snprintf(tmp, sizeof(tmp), fil, count);
count++;
} while (ast_fileexists(tmp, ext, chan->language) > 0);
} while ( ast_fileexists(tmp, ext, chan->language) != -1 );
pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
} else
ast_copy_string(tmp, filename, sizeof(tmp));
strncpy(tmp, fil, sizeof(tmp)-1);
/* end of routine mentioned */
LOCAL_USER_ADD(u);
if (chan->_state != AST_STATE_UP) {
if (option_skip) {
/* At the user's option, skip if the line is not up */
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return 0;
} else if (!option_noanswer) {
/* Otherwise answer unless we're supposed to record while on-hook */
@@ -229,12 +194,7 @@ static int record_exec(struct ast_channel *chan, void *data)
}
}
if (res) {
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
goto out;
}
if (!option_quiet) {
if (!res) {
/* Some code to play a nice little beep to signify the start of the record operation */
res = ast_streamfile(chan, "beep", chan->language);
if (!res) {
@@ -243,144 +203,138 @@ static int record_exec(struct ast_channel *chan, void *data)
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
}
ast_stopstream(chan);
}
/* The end of beep code. Now the recording starts */
if (silence > 0) {
rfmt = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
ast_module_user_remove(u);
return -1;
}
sildet = ast_dsp_new();
if (!sildet) {
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
ast_module_user_remove(u);
return -1;
}
ast_dsp_set_threshold(sildet, 256);
}
flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
if (!s) {
ast_log(LOG_WARNING, "Could not create file %s\n", filename);
goto out;
}
if (ast_opt_transmit_silence)
silgen = ast_channel_start_silence_generator(chan);
/* Request a video update */
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
if (maxduration <= 0)
maxduration = -1;
while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
if (maxduration > 0) {
if (waitres == 0) {
gottimeout = 1;
break;
}
maxduration = waitres;
/* The end of beep code. Now the recording starts */
if (silence > 0) {
rfmt = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
return -1;
}
sildet = ast_dsp_new();
if (!sildet) {
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
return -1;
}
ast_dsp_set_threshold(sildet, 256);
}
f = ast_read(chan);
if (!f) {
res = -1;
break;
}
if (f->frametype == AST_FRAME_VOICE) {
res = ast_writestream(s, f);
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
ast_frfree(f);
break;
}
if (silence > 0) {
dspsilence = 0;
ast_dsp_silence(sildet, f, &dspsilence);
if (dspsilence) {
totalsilence = dspsilence;
} else {
totalsilence = 0;
}
if (totalsilence > silence) {
/* Ended happily with silence */
ast_frfree(f);
gotsilence = 1;
flags = end ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
if (s) {
if (maxduration > 0)
timeout = time(NULL) + (time_t)maxduration;
while (ast_waitfor(chan, -1) > -1) {
if (maxduration > 0 && time(NULL) > timeout) {
gottimeout = 1;
break;
}
}
} else if (f->frametype == AST_FRAME_VIDEO) {
res = ast_writestream(s, f);
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
ast_frfree(f);
break;
}
} else if ((f->frametype == AST_FRAME_DTMF) &&
(f->subclass == terminator)) {
ast_frfree(f);
break;
}
ast_frfree(f);
}
if (!f) {
ast_log(LOG_DEBUG, "Got hangup\n");
res = -1;
}
if (gotsilence) {
ast_stream_rewind(s, silence-1000);
ast_truncstream(s);
} else if (!gottimeout) {
/* Strip off the last 1/4 second of it */
ast_stream_rewind(s, 250);
ast_truncstream(s);
}
ast_closestream(s);
if (silgen)
ast_channel_stop_silence_generator(chan, silgen);
out:
f = ast_read(chan);
if (!f) {
res = -1;
break;
}
if (f->frametype == AST_FRAME_VOICE) {
res = ast_writestream(s, f);
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
break;
}
if (silence > 0) {
dspsilence = 0;
ast_dsp_silence(sildet, f, &dspsilence);
if (dspsilence) {
totalsilence = dspsilence;
} else {
totalsilence = 0;
}
if (totalsilence > silence) {
/* Ended happily with silence */
ast_frfree(f);
gotsilence = 1;
break;
}
}
}
if (f->frametype == AST_FRAME_VIDEO) {
res = ast_writestream(s, f);
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
break;
}
}
if ((f->frametype == AST_FRAME_DTMF) &&
(f->subclass == '#')) {
ast_frfree(f);
break;
}
ast_frfree(f);
}
if (!f) {
ast_log(LOG_DEBUG, "Got hangup\n");
res = -1;
}
if (gotsilence) {
ast_stream_rewind(s, silence-1000);
ast_truncstream(s);
} else if (!gottimeout) {
/* Strip off the last 1/4 second of it */
ast_stream_rewind(s, 250);
ast_truncstream(s);
}
ast_closestream(s);
} else
ast_log(LOG_WARNING, "Could not create file %s\n", fil);
} else
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
LOCAL_USER_REMOVE(u);
if ((silence > 0) && rfmt) {
res = ast_set_read_format(chan, rfmt);
if (res)
ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
res = ast_set_read_format(chan, rfmt);
if (res)
ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
if (sildet)
ast_dsp_free(sildet);
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, record_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,30 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (c) 2003, 2006 Tilghman Lesher. All rights reserved.
* Copyright (c) 2006 Digium, Inc.
* SayUnixTime application
*
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <app_sayunixtime__200309@the-tilghman.com>
*
* This code is released by the author with no restrictions on usage.
*
* 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.
*
*/
/*! \file
*
* \brief SayUnixTime application
*
* \author Tilghman Lesher <app_sayunixtime__200309@the-tilghman.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/say.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/say.h"
#include "asterisk/app.h"
static char *tdesc = "Say time";
static char *app_sayunixtime = "SayUnixTime";
static char *app_datetime = "DateTime";
@@ -55,7 +38,8 @@ static char *sayunixtime_descrip =
" timezone: timezone, see /usr/share/zoneinfo for a list.\n"
" defaults to machine default.\n"
" format: a format the time is to be said in. See voicemail.conf.\n"
" defaults to \"ABdY 'digits/at' IMp\"\n";
" defaults to \"ABdY 'digits/at' IMp\"\n"
" Returns 0 or -1 on hangup.\n";
static char *datetime_descrip =
"DateTime([unixtime][|[timezone][|format]])\n"
" unixtime: time, in seconds since Jan 1, 1970. May be negative.\n"
@@ -63,64 +47,95 @@ static char *datetime_descrip =
" timezone: timezone, see /usr/share/zoneinfo for a list.\n"
" defaults to machine default.\n"
" format: a format the time is to be said in. See voicemail.conf.\n"
" defaults to \"ABdY 'digits/at' IMp\"\n";
" defaults to \"ABdY 'digits/at' IMp\"\n"
" Returns 0 or -1 on hangup.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int sayunixtime_exec(struct ast_channel *chan, void *data)
{
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(timeval);
AST_APP_ARG(timezone);
AST_APP_ARG(format);
);
char *parse;
int res = 0;
struct ast_module_user *u;
int res=0;
struct localuser *u;
char *s,*zone=NULL,*timec;
time_t unixtime;
if (!data)
return 0;
char *format = "ABdY 'digits/at' IMp";
struct timeval tv;
parse = ast_strdupa(data);
LOCAL_USER_ADD(u);
u = ast_module_user_add(chan);
gettimeofday(&tv,NULL);
unixtime = (time_t)tv.tv_sec;
AST_STANDARD_APP_ARGS(args, parse);
if (data) {
s = data;
s = ast_strdupa(s);
if (s) {
timec = strsep(&s,"|");
if ((timec) && (*timec != '\0')) {
long timein;
if (sscanf(timec,"%ld",&timein) == 1) {
unixtime = (time_t)timein;
}
}
if (s) {
zone = strsep(&s,"|");
if (zone && (*zone == '\0'))
zone = NULL;
if (s) {
format = s;
}
}
} else {
ast_log(LOG_ERROR, "Out of memory error\n");
}
}
ast_get_time_t(args.timeval, &unixtime, time(NULL), NULL);
if (chan->_state != AST_STATE_UP)
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
}
if (!res)
res = ast_say_date_with_format(chan, unixtime, AST_DIGIT_ANY,
chan->language, args.format, args.timezone);
ast_module_user_remove(u);
res = ast_say_date_with_format(chan, unixtime, AST_DIGIT_ANY, chan->language, format, zone);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
STANDARD_HANGUP_LOCALUSERS;
res = ast_unregister_application(app_sayunixtime);
res |= ast_unregister_application(app_datetime);
ast_module_user_hangup_all();
return res;
if (! res)
return ast_unregister_application(app_datetime);
else
return res;
}
static int load_module(void)
int load_module(void)
{
int res;
res = ast_register_application(app_sayunixtime, sayunixtime_exec, sayunixtime_synopsis, sayunixtime_descrip);
res |= ast_register_application(app_datetime, sayunixtime_exec, sayunixtime_synopsis, datetime_descrip);
if (! res)
return ast_register_application(app_datetime, sayunixtime_exec, sayunixtime_synopsis, datetime_descrip);
else
return res;
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say time");
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,143 +1,84 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to send DTMF digits
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 App to send DTMF digits
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/options.h>
#include <asterisk/utils.h>
#include <asterisk/app.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
static char *tdesc = "Send DTMF digits Application";
static char *app = "SendDTMF";
static char *synopsis = "Sends arbitrary DTMF digits";
static char *descrip =
" SendDTMF(digits[|timeout_ms]): Sends DTMF digits on a channel. \n"
" Accepted digits: 0-9, *#abcd, w (.5s pause)\n"
" The application will either pass the assigned digits or terminate if it\n"
" encounters an error.\n";
" SendDTMF(digits): Sends DTMF digits on a channel. \n"
" Accepted digits: 0-9, *#abcd\n"
" Returns 0 on success or -1 on a hangup.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int senddtmf_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *digits = NULL, *to = NULL;
int timeout = 250;
struct localuser *u;
char *digits = data;
if (ast_strlen_zero(data)) {
if (!digits || ast_strlen_zero(digits)) {
ast_log(LOG_WARNING, "SendDTMF requires an argument (digits or *#aAbBcCdD)\n");
return 0;
return -1;
}
u = ast_module_user_add(chan);
digits = ast_strdupa(data);
if ((to = strchr(digits,'|'))) {
*to = '\0';
to++;
timeout = atoi(to);
}
if (timeout <= 0)
timeout = 250;
res = ast_dtmf_stream(chan,NULL,digits,timeout);
ast_module_user_remove(u);
LOCAL_USER_ADD(u);
res = ast_dtmf_stream(chan,NULL,digits,250);
LOCAL_USER_REMOVE(u);
return res;
}
static char mandescr_playdtmf[] =
"Description: Plays a dtmf digit on the specified channel.\n"
"Variables: (all are required)\n"
" Channel: Channel name to send digit to\n"
" Digit: The dtmf digit to play\n";
static int manager_play_dtmf(struct mansession *s, const struct message *m)
int unload_module(void)
{
const char *channel = astman_get_header(m, "Channel");
const char *digit = astman_get_header(m, "Digit");
struct ast_channel *chan = ast_get_channel_by_name_locked(channel);
if (!chan) {
astman_send_error(s, m, "Channel not specified");
return 0;
}
if (ast_strlen_zero(digit)) {
astman_send_error(s, m, "No digit specified");
ast_mutex_unlock(&chan->lock);
return 0;
}
ast_senddigit(chan, *digit);
ast_mutex_unlock(&chan->lock);
astman_send_ack(s, m, "DTMF successfully queued");
return 0;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int unload_module(void)
int load_module(void)
{
int res;
res = ast_unregister_application(app);
res |= ast_manager_unregister("PlayDTMF");
ast_module_user_hangup_all();
return res;
return ast_register_application(app, senddtmf_exec, synopsis, descrip);
}
static int load_module(void)
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_manager_register2( "PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf, "Play DTMF signal on a specific channel.", mandescr_playdtmf );
res |= ast_register_application(app, senddtmf_exec, synopsis, descrip);
STANDARD_USECOUNT(res);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send DTMF digits Application");
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,133 +1,94 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to transmit a text message
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 App to transmit a text message
*
* \author Mark Spencer <markster@digium.com>
*
* \note Requires support of sending text messages from channel driver
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <string.h>
#include <stdlib.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
static char *tdesc = "Send Text Applications";
static const char *app = "SendText";
static char *app = "SendText";
static const char *synopsis = "Send a Text Message";
static char *synopsis = "Send a Text Message";
static const char *descrip =
" SendText(text[|options]): Sends text to current channel (callee).\n"
"Result of transmission will be stored in the SENDTEXTSTATUS\n"
"channel variable:\n"
" SUCCESS Transmission succeeded\n"
" FAILURE Transmission failed\n"
" UNSUPPORTED Text transmission not supported by channel\n"
"\n"
"At this moment, text is supposed to be 7 bit ASCII in most channels.\n"
"The option string many contain the following character:\n"
"'j' -- jump to n+101 priority if the channel doesn't support\n"
" text transport\n";
static char *descrip =
" SendText(text): Sends text to client. If the client\n"
"does not support text transport, and there exists a step with\n"
"priority n + 101, then execution will continue at that step.\n"
"Otherwise, execution will continue at the next priority level.\n"
"SendText only returns 0 if the text was sent correctly or if\n"
"the channel does not support text transport, and -1 otherwise.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int sendtext_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *status = "UNSUPPORTED";
char *parse = NULL;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(text);
AST_APP_ARG(options);
);
u = ast_module_user_add(chan);
/* NOT ast_strlen_zero, because some protocols (e.g. SIP) MUST be able to
* send a zero-length message. */
if (!data) {
ast_log(LOG_WARNING, "SendText requires an argument (text[|options])\n");
ast_module_user_remove(u);
struct localuser *u;
if (!data || !strlen((char *)data)) {
ast_log(LOG_WARNING, "SendText requires an argument (text)\n");
return -1;
} else
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
ast_channel_lock(chan);
if (!chan->tech->send_text) {
ast_channel_unlock(chan);
pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
LOCAL_USER_ADD(u);
ast_mutex_lock(&chan->lock);
if (!chan->pvt->send_text) {
ast_mutex_unlock(&chan->lock);
/* Does not support transport */
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
ast_module_user_remove(u);
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority += 100;
LOCAL_USER_REMOVE(u);
return 0;
}
status = "FAILURE";
res = ast_sendtext(chan, args.text);
if (!res)
status = "SUCCESS";
ast_channel_unlock(chan);
pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
ast_module_user_remove(u);
return 0;
ast_mutex_unlock(&chan->lock);
res = ast_sendtext(chan, (char *)data);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, sendtext_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send Text Applications");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,56 +1,55 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to set callerid
*
* Copyright (C) 1999, Mark Spencer
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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 App to set callerid
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/callerid.h>
#include <string.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/image.h"
#include "asterisk/callerid.h"
#include <stdlib.h>
static char *app2 = "SetCallerPres";
static char *synopsis2 = "Set CallerID Presentation";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static struct {
int val;
char *name;
} preses[] = {
{ AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened" },
{ AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen" },
{ AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen" },
{ AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed" },
{ AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED , "prohib_not_screened" },
{ AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen" },
{ AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen" },
{ AST_PRES_PROHIB_NETWORK_NUMBER, "prohib" },
{ AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable" },
};
static char *descrip2 =
" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n"
" Valid presentations are:\n"
" SetCallerPres(presentation): Set Caller*ID presentation on\n"
"a call to a new value. Sets ANI as well if a flag is used.\n"
"Always returns 0. Valid presentations are:\n"
"\n"
" allowed_not_screened : Presentation Allowed, Not Screened\n"
" allowed_passed_screen : Presentation Allowed, Passed Screen\n"
@@ -66,61 +65,56 @@ static char *descrip2 =
static int setcallerid_pres_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
int res = 0;
char tmp[256] = "";
struct localuser *u;
int x;
char *opts;
int pres = -1;
u = ast_module_user_add(chan);
/* For interface consistency, permit the argument to be specified as a number */
if (sscanf(data, "%30d", &pres) != 1 || pres < 0 || pres > 255 || (pres & 0x9c)) {
pres = ast_parse_caller_presentation(data);
if (data)
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
opts = strchr(tmp, '|');
if (opts) {
*opts = '\0';
opts++;
}
for (x=0;x<sizeof(preses) / sizeof(preses[0]);x++) {
if (!strcasecmp(preses[x].name, tmp)) {
pres = preses[x].val;
break;
}
}
if (pres < 0) {
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show application SetCallerPres')\n",
(char *) data);
ast_module_user_remove(u);
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show application SetCallerPres')\n", tmp);
return 0;
}
chan->cid.cid_pres = pres;
ast_module_user_remove(u);
return 0;
LOCAL_USER_ADD(u);
chan->callingpres = pres;
LOCAL_USER_REMOVE(u);
return res;
}
static char *tdesc = "Set CallerID Application";
static char *app = "SetCallerID";
static char *synopsis = "Set CallerID";
static char *descrip =
" SetCallerID(clid[|a]): Set Caller*ID on a call to a new\n"
"value. Sets ANI as well if a flag is used. \n";
"value. Sets ANI as well if a flag is used. Always returns 0\n";
static int setcallerid_exec(struct ast_channel *chan, void *data)
{
int res = 0;
char *tmp = NULL;
char name[256];
char num[256];
struct ast_module_user *u;
char tmp[256] = "";
struct localuser *u;
char *opt;
int anitoo = 0;
static int dep_warning = 0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SetCallerID requires an argument!\n");
return 0;
}
u = ast_module_user_add(chan);
if (!dep_warning) {
dep_warning = 1;
ast_log(LOG_WARNING, "SetCallerID is deprecated. Please use Set(CALLERID(all)=...) or Set(CALLERID(ani)=...) instead.\n");
}
tmp = ast_strdupa(data);
if (data)
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
opt = strchr(tmp, '|');
if (opt) {
*opt = '\0';
@@ -128,35 +122,38 @@ static int setcallerid_exec(struct ast_channel *chan, void *data)
if (*opt == 'a')
anitoo = 1;
}
ast_callerid_split(tmp, name, sizeof(name), num, sizeof(num));
ast_set_callerid(chan, num, name, anitoo ? num : NULL);
ast_module_user_remove(u);
LOCAL_USER_ADD(u);
ast_set_callerid(chan, strlen(tmp) ? tmp : NULL, anitoo);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
ast_unregister_application(app2);
return ast_unregister_application(app);
}
int load_module(void)
{
ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2);
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_unregister_application(app2);
res |= ast_unregister_application(app);
ast_module_user_hangup_all();
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
int res;
res = ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2);
res |= ast_register_application(app, setcallerid_exec, synopsis, descrip);
return res;
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Application");

View File

@@ -1,47 +1,30 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Applictions connected with CDR engine
*
* Copyright (C) 2003, Digium
*
* Justin Huff <jjhuff@mspin.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.
* the GNU General Public License
*/
/*! \file
*
* \brief Applictions connected with CDR engine
*
* \author Justin Huff <jjhuff@mspin.net>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
#include <asterisk/channel.h>
#include <asterisk/cdr.h>
#include <asterisk/module.h>
#include <asterisk/pbx.h>
#include <asterisk/logger.h>
#include <asterisk/config.h>
#include <asterisk/manager.h>
#include <asterisk/utils.h>
#include <stdlib.h>
#include <string.h>
#include "asterisk/channel.h"
#include "asterisk/cdr.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/logger.h"
#include "asterisk/config.h"
#include "asterisk/manager.h"
#include "asterisk/utils.h"
static char *tdesc = "CDR user field apps";
static char *setcdruserfield_descrip =
"[Synopsis]\n"
@@ -53,7 +36,7 @@ static char *setcdruserfield_descrip =
" CDR records can be used for billing or storing other arbitrary data\n"
" (I.E. telephone survey responses)\n"
" Also see AppendCDRUserField().\n"
"\nThis application is deprecated in favor of Set(CDR(userfield)=...)\n";
" Always returns 0\n";
static char *setcdruserfield_app = "SetCDRUserField";
@@ -69,18 +52,21 @@ static char *appendcdruserfield_descrip =
" CDR records can be used for billing or storing other arbitrary data\n"
" (I.E. telephone survey responses)\n"
" Also see SetCDRUserField().\n"
"\nThis application is deprecated in favor of Set(CDR(userfield)=...)\n";
" Always returns 0\n";
static char *appendcdruserfield_app = "AppendCDRUserField";
static char *appendcdruserfield_synopsis = "Append to the CDR user field";
STANDARD_LOCAL_USER;
static int action_setcdruserfield(struct mansession *s, const struct message *m)
LOCAL_USER_DECL;
static int action_setcdruserfield(struct mansession *s, struct message *m)
{
struct ast_channel *c = NULL;
const char *userfield = astman_get_header(m, "UserField");
const char *channel = astman_get_header(m, "Channel");
const char *append = astman_get_header(m, "Append");
char *userfield = astman_get_header(m, "UserField");
char *channel = astman_get_header(m, "Channel");
char *append = astman_get_header(m, "Append");
if (ast_strlen_zero(channel)) {
astman_send_error(s, m, "No Channel specified");
@@ -90,7 +76,13 @@ static int action_setcdruserfield(struct mansession *s, const struct message *m)
astman_send_error(s, m, "No UserField specified");
return 0;
}
c = ast_get_channel_by_name_locked(channel);
c = ast_channel_walk_locked(NULL);
while (c) {
if (!strcasecmp(c->name, channel))
break;
ast_mutex_unlock(&c->lock);
c = ast_channel_walk_locked(c);
}
if (!c) {
astman_send_error(s, m, "No such channel");
return 0;
@@ -106,70 +98,68 @@ static int action_setcdruserfield(struct mansession *s, const struct message *m)
static int setcdruserfield_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
struct localuser *u;
int res = 0;
static int dep_warning = 0;
u = ast_module_user_add(chan);
if (chan->cdr && data) {
LOCAL_USER_ADD(u)
if (chan->cdr && data)
{
ast_cdr_setuserfield(chan, (char*)data);
}
if (!dep_warning) {
dep_warning = 1;
ast_log(LOG_WARNING, "SetCDRUserField is deprecated. Please use CDR(userfield) instead.\n");
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int appendcdruserfield_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
struct localuser *u;
int res = 0;
static int dep_warning = 0;
u = ast_module_user_add(chan);
if (chan->cdr && data) {
LOCAL_USER_ADD(u)
if (chan->cdr && data)
{
ast_cdr_appenduserfield(chan, (char*)data);
}
if (!dep_warning) {
dep_warning = 1;
ast_log(LOG_WARNING, "AppendCDRUserField is deprecated. Please use CDR(userfield) instead.\n");
}
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
STANDARD_HANGUP_LOCALUSERS;
res = ast_unregister_application(setcdruserfield_app);
res |= ast_unregister_application(appendcdruserfield_app);
res |= ast_manager_unregister("SetCDRUserField");
ast_module_user_hangup_all();
ast_manager_unregister("SetCDRUserField");
return res;
}
static int load_module(void)
int load_module(void)
{
int res;
res = ast_register_application(setcdruserfield_app, setcdruserfield_exec, setcdruserfield_synopsis, setcdruserfield_descrip);
res |= ast_register_application(appendcdruserfield_app, appendcdruserfield_exec, appendcdruserfield_synopsis, appendcdruserfield_descrip);
res |= ast_manager_register("SetCDRUserField", EVENT_FLAG_CALL, action_setcdruserfield, "Set the CDR UserField");
ast_manager_register("SetCDRUserField", EVENT_FLAG_CALL, action_setcdruserfield, "Set the CDR UserField");
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CDR user field apps");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

107
apps/app_setcidname.c Normal file
View File

@@ -0,0 +1,107 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* App to set callerid
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/callerid.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
static char *tdesc = "Set CallerID Name";
static char *app = "SetCIDName";
static char *synopsis = "Set CallerID Name";
static char *descrip =
" SetCIDName(cname[|a]): Set Caller*ID Name on a call to a new\n"
"value, while preserving the original Caller*ID number. This is\n"
"useful for providing additional information to the called\n"
"party. Sets ANI as well if a flag is used. Always returns 0\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int setcallerid_exec(struct ast_channel *chan, void *data)
{
int res = 0;
char tmp[256] = "";
char oldcid[256] = "", *l, *n;
char newcid[256] = "";
struct localuser *u;
char *opt;
int anitoo = 0;
if (data)
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
opt = strchr(tmp, '|');
if (opt) {
*opt = '\0';
opt++;
if (*opt == 'a')
anitoo = 1;
}
LOCAL_USER_ADD(u);
if (chan->callerid) {
strncpy(oldcid, chan->callerid, sizeof(oldcid) - 1);
ast_callerid_parse(oldcid, &n, &l);
n = tmp;
if (!ast_strlen_zero(n)) {
if (l && !ast_strlen_zero(l))
snprintf(newcid, sizeof(newcid), "\"%s\" <%s>", n, l);
else
strncpy(newcid, tmp, sizeof(newcid) - 1);
} else if (l && !ast_strlen_zero(l)) {
strncpy(newcid, l, sizeof(newcid) - 1);
}
} else
strncpy(newcid, tmp, sizeof(newcid) - 1);
ast_set_callerid(chan, !ast_strlen_zero(newcid) ? newcid : NULL, anitoo);
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

108
apps/app_setcidnum.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* App to set callerid
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
* Oliver Daudey <traveler@xs4all.nl>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/lock.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/image.h>
#include <asterisk/callerid.h>
#include <asterisk/utils.h>
#include <string.h>
#include <stdlib.h>
static char *tdesc = "Set CallerID Number";
static char *app = "SetCIDNum";
static char *synopsis = "Set CallerID Number";
static char *descrip =
" SetCIDNum(cnum[|a]): Set Caller*ID Number on a call to a new\n"
"value, while preserving the original Caller*ID name. This is\n"
"useful for providing additional information to the called\n"
"party. Sets ANI as well if a flag is used. Always returns 0\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int setcallerid_exec(struct ast_channel *chan, void *data)
{
int res = 0;
char tmp[256] = "";
char oldcid[256] = "", *l, *n;
char newcid[256] = "";
struct localuser *u;
char *opt;
int anitoo = 0;
if (data)
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
opt = strchr(tmp, '|');
if (opt) {
*opt = '\0';
opt++;
if (*opt == 'a')
anitoo = 1;
}
LOCAL_USER_ADD(u);
if (chan->callerid) {
strncpy(oldcid, chan->callerid, sizeof(oldcid) - 1);
ast_callerid_parse(oldcid, &n, &l);
l = tmp;
if (!ast_strlen_zero(l)) {
if (n && !ast_strlen_zero(n))
snprintf(newcid, sizeof(newcid), "\"%s\" <%s>", n, l);
else
strncpy(newcid, tmp, sizeof(newcid) - 1);
} else if (n && !ast_strlen_zero(n)) {
strncpy(newcid, n, sizeof(newcid) - 1);
}
} else
strncpy(newcid, tmp, sizeof(newcid) - 1);
ast_set_callerid(chan, !ast_strlen_zero(newcid) ? newcid : NULL, anitoo);
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,136 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005, Frank Sautter, levigo holding gmbh, www.levigo.de
*
* Frank Sautter - asterisk+at+sautter+dot+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 App to set the ISDN Transfer Capability
*
* \author Frank Sautter - asterisk+at+sautter+dot+com
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <string.h>
#include <stdlib.h>
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/options.h"
#include "asterisk/transcap.h"
static char *app = "SetTransferCapability";
static char *synopsis = "Set ISDN Transfer Capability";
static struct { int val; char *name; } transcaps[] = {
{ AST_TRANS_CAP_SPEECH, "SPEECH" },
{ AST_TRANS_CAP_DIGITAL, "DIGITAL" },
{ AST_TRANS_CAP_RESTRICTED_DIGITAL, "RESTRICTED_DIGITAL" },
{ AST_TRANS_CAP_3_1K_AUDIO, "3K1AUDIO" },
{ AST_TRANS_CAP_DIGITAL_W_TONES, "DIGITAL_W_TONES" },
{ AST_TRANS_CAP_VIDEO, "VIDEO" },
};
static char *descrip =
" SetTransferCapability(transfercapability): Set the ISDN Transfer \n"
"Capability of a call to a new value.\n"
"Valid Transfer Capabilities are:\n"
"\n"
" SPEECH : 0x00 - Speech (default, voice calls)\n"
" DIGITAL : 0x08 - Unrestricted digital information (data calls)\n"
" RESTRICTED_DIGITAL : 0x09 - Restricted digital information\n"
" 3K1AUDIO : 0x10 - 3.1kHz Audio (fax calls)\n"
" DIGITAL_W_TONES : 0x11 - Unrestricted digital information with tones/announcements\n"
" VIDEO : 0x18 - Video\n"
"\n"
"This application is deprecated in favor of Set(CHANNEL(transfercapability)=...)\n"
;
static int settransfercapability_exec(struct ast_channel *chan, void *data)
{
char *tmp = NULL;
struct ast_module_user *u;
int x;
char *opts;
int transfercapability = -1;
static int dep_warning = 0;
u = ast_module_user_add(chan);
if (!dep_warning) {
dep_warning = 1;
ast_log(LOG_WARNING, "SetTransferCapability is deprecated. Please use CHANNEL(transfercapability) instead.\n");
}
if (data)
tmp = ast_strdupa(data);
else
tmp = "";
opts = strchr(tmp, '|');
if (opts)
*opts = '\0';
for (x = 0; x < (sizeof(transcaps) / sizeof(transcaps[0])); x++) {
if (!strcasecmp(transcaps[x].name, tmp)) {
transfercapability = transcaps[x].val;
break;
}
}
if (transfercapability < 0) {
ast_log(LOG_WARNING, "'%s' is not a valid transfer capability (see 'show application SetTransferCapability')\n", tmp);
ast_module_user_remove(u);
return 0;
}
chan->transfercapability = (unsigned short)transfercapability;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Setting transfer capability to: 0x%.2x - %s.\n", transfercapability, tmp);
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, settransfercapability_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set ISDN Transfer Capability");

View File

@@ -1,133 +1,74 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) <Year>, <Your Name Here>
* Skeleton application
*
* Copyright (C) 1999, Mark Spencer
*
* <Your Name Here> <<Your Email Here>>
*
* 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.
* Mark Spencer <markster@linux-support.net>
*
* 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.
* the GNU General Public License
*/
/*! \file
*
* \brief Skeleton application
*
* \author <Your Name Here> <<Your Email Here>>
*
* This is a skeleton for development of an Asterisk application
* \ingroup applications
*/
/*** MODULEINFO
<defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/lock.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
static char *app = "Skel";
static char *tdesc = "Trivial skeleton Application";
static char *app = "skel";
static char *synopsis =
"Skeleton application.";
static char *descrip = "This application is a template to build other applications from.\n"
" It shows you the basic structure to create your own Asterisk applications.\n";
" This is a skeleton application that shows you the basic structure to create your\n"
"own asterisk applications.\n";
enum {
OPTION_A = (1 << 0),
OPTION_B = (1 << 1),
OPTION_C = (1 << 2),
} option_flags;
STANDARD_LOCAL_USER;
enum {
OPTION_ARG_B = 0,
OPTION_ARG_C = 1,
/* This *must* be the last value in this enum! */
OPTION_ARG_ARRAY_SIZE = 2,
} option_args;
LOCAL_USER_DECL;
AST_APP_OPTIONS(app_opts,{
AST_APP_OPTION('a', OPTION_A),
AST_APP_OPTION_ARG('b', OPTION_B, OPTION_ARG_B),
AST_APP_OPTION_ARG('c', OPTION_C, OPTION_ARG_C),
});
static int app_exec(struct ast_channel *chan, void *data)
static int skel_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_flags flags;
struct ast_module_user *u;
char *parse, *opts[OPTION_ARG_ARRAY_SIZE];
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(dummy);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n", app);
int res=0;
struct localuser *u;
if (!data) {
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
LOCAL_USER_ADD(u);
/* Do our thing here */
/* We need to make a copy of the input string if we are going to modify it! */
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.argc == 2)
ast_app_parse_options(app_opts, &flags, opts, args.options);
if (!ast_strlen_zero(args.dummy))
ast_log(LOG_NOTICE, "Dummy value is : %s\n", args.dummy);
if (ast_test_flag(&flags, OPTION_A))
ast_log(LOG_NOTICE, "Option A is set\n");
if (ast_test_flag(&flags, OPTION_B))
ast_log(LOG_NOTICE, "Option B is set with : %s\n", opts[OPTION_ARG_B] ? opts[OPTION_ARG_B] : "<unspecified>");
if (ast_test_flag(&flags, OPTION_C))
ast_log(LOG_NOTICE, "Option C is set with : %s\n", opts[OPTION_ARG_C] ? opts[OPTION_ARG_C] : "<unspecified>");
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, skel_exec, synopsis, tdesc);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_unregister_application(app);
return res;
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
return ast_register_application(app, app_exec, synopsis, descrip);
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Application");

Some files were not shown because too many files have changed in this diff Show More