mirror of
https://github.com/asterisk/asterisk.git
synced 2026-03-23 22:33:34 +00:00
Compare commits
374 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c00fa343f | ||
|
|
c22cac6853 | ||
|
|
f295815c45 | ||
|
|
829bf52765 | ||
|
|
b224ed93ca | ||
|
|
c3d195a2b3 | ||
|
|
aea2d73afa | ||
|
|
5bc6b3b6fd | ||
|
|
58c3bdc8f1 | ||
|
|
6f7efa99d5 | ||
|
|
fb912bc629 | ||
|
|
95dc3bba01 | ||
|
|
83b525e2cb | ||
|
|
4a40420978 | ||
|
|
08cc142495 | ||
|
|
48d13f84a5 | ||
|
|
7b12d67e50 | ||
|
|
d98317c7ad | ||
|
|
ce8275960e | ||
|
|
a6e5c98723 | ||
|
|
60df6b45d2 | ||
|
|
235212182e | ||
|
|
831a96aac1 | ||
|
|
bdea273046 | ||
|
|
f08096e951 | ||
|
|
d5a3b59ccf | ||
|
|
457bdd22bb | ||
|
|
43fde6acce | ||
|
|
adf51ade80 | ||
|
|
65f95fee51 | ||
|
|
bca4868578 | ||
|
|
9a729f7aff | ||
|
|
d125a1a278 | ||
|
|
6c0ac0721e | ||
|
|
65acfca5af | ||
|
|
3585625b40 | ||
|
|
c43f01c211 | ||
|
|
52aa07e2b2 | ||
|
|
b97c1529fc | ||
|
|
0a48c19845 | ||
|
|
8aa27f2c5c | ||
|
|
0bb7b71572 | ||
|
|
ac1e4d72dd | ||
|
|
ecf158b51e | ||
|
|
8d417967ce | ||
|
|
8d1c316519 | ||
|
|
70bd3bebc5 | ||
|
|
8c63eaec22 | ||
|
|
35ea822831 | ||
|
|
420f3d12aa | ||
|
|
469e6d539a | ||
|
|
09bf0c3032 | ||
|
|
3db3883d3d | ||
|
|
b85f9ea8fb | ||
|
|
84b4d40f79 | ||
|
|
ea4baa91d0 | ||
|
|
eb76fca6a3 | ||
|
|
677ed9a31a | ||
|
|
dea7edda6b | ||
|
|
da3df5ec26 | ||
|
|
0a0470ad00 | ||
|
|
b89b296584 | ||
|
|
41feb1c7ff | ||
|
|
9884c9637a | ||
|
|
b0f4874196 | ||
|
|
3667b25224 | ||
|
|
dcccda229d | ||
|
|
d31a0d9e7b | ||
|
|
674425a343 | ||
|
|
efd60d1d1f | ||
|
|
0cfcb22bbc | ||
|
|
9925080ca6 | ||
|
|
e34983cde0 | ||
|
|
17187101f6 | ||
|
|
747495fc0e | ||
|
|
d564b81083 | ||
|
|
50249c732b | ||
|
|
108275cf6c | ||
|
|
13b57f8255 | ||
|
|
6b8f2a96f1 | ||
|
|
b21dc2c0c2 | ||
|
|
f096152b20 | ||
|
|
3b776cdfdc | ||
|
|
9593aa0aa1 | ||
|
|
4edd97a713 | ||
|
|
eb1b6f313e | ||
|
|
38ca23948d | ||
|
|
e6ae8990bc | ||
|
|
14e8c4c5a3 | ||
|
|
b2bd6c27db | ||
|
|
d3080cc1ae | ||
|
|
023a312f65 | ||
|
|
89995395d9 | ||
|
|
fbe6931218 | ||
|
|
8545a6d4c0 | ||
|
|
3388661f38 | ||
|
|
1d58eff4a7 | ||
|
|
cc4595f85e | ||
|
|
ac9f562712 | ||
|
|
b3af62dc4f | ||
|
|
a70900ccd0 | ||
|
|
782eb432ab | ||
|
|
4e3b9d6389 | ||
|
|
dbc0f5d2e2 | ||
|
|
ea27f3c186 | ||
|
|
2dc23188a2 | ||
|
|
a4725e9c73 | ||
|
|
575c2bccd5 | ||
|
|
2d5cc8be5c | ||
|
|
10191fe126 | ||
|
|
4a391da1bd | ||
|
|
86406e8ba0 | ||
|
|
536dcc2058 | ||
|
|
c4c44af8e3 | ||
|
|
b26f150b75 | ||
|
|
271ccecaf2 | ||
|
|
0742e08800 | ||
|
|
34a135da3b | ||
|
|
39139b2802 | ||
|
|
799247b4d5 | ||
|
|
677a22c209 | ||
|
|
973a1dec88 | ||
|
|
dfc0e65f4b | ||
|
|
1e94621214 | ||
|
|
5fbe407b98 | ||
|
|
a3ce65e5cd | ||
|
|
fcf8040825 | ||
|
|
842e9246a6 | ||
|
|
6b682d34ff | ||
|
|
1ef0003131 | ||
|
|
4e884dbd28 | ||
|
|
0a1d8918d8 | ||
|
|
3da520e492 | ||
|
|
0a0cf51877 | ||
|
|
cab988b595 | ||
|
|
507c47ffa4 | ||
|
|
7c92ffe150 | ||
|
|
f522e07cbd | ||
|
|
df18b234b1 | ||
|
|
7652fdda20 | ||
|
|
bab77bbab1 | ||
|
|
ce008d40a1 | ||
|
|
710445b5b1 | ||
|
|
ba001a7d15 | ||
|
|
4f144aa5e3 | ||
|
|
8d66f50877 | ||
|
|
e0db36550e | ||
|
|
13f4e66b14 | ||
|
|
ae8fe3738b | ||
|
|
b5111fb985 | ||
|
|
671cde62de | ||
|
|
0ea76a52a9 | ||
|
|
db467378b4 | ||
|
|
e27d844918 | ||
|
|
3b0edd5cfe | ||
|
|
74eef60486 | ||
|
|
b3a8fbf495 | ||
|
|
bae6e7b617 | ||
|
|
cf015dbefc | ||
|
|
32cc1bedc1 | ||
|
|
a96ecb64a6 | ||
|
|
d1757b3b49 | ||
|
|
917259bcd3 | ||
|
|
eb177856db | ||
|
|
9849ad993d | ||
|
|
bb886dd488 | ||
|
|
48fb967c05 | ||
|
|
e74a7116e5 | ||
|
|
fd25b81993 | ||
|
|
dcd9d8d58f | ||
|
|
1d9b2a9df1 | ||
|
|
659da47b95 | ||
|
|
e83bfee678 | ||
|
|
ab209c7d92 | ||
|
|
dc08bd8501 | ||
|
|
aca3c1f79d | ||
|
|
e07c977f18 | ||
|
|
2ae21cc5c3 | ||
|
|
05fed23d06 | ||
|
|
2f43722570 | ||
|
|
7ea315539c | ||
|
|
10d527906a | ||
|
|
2f1d118537 | ||
|
|
696922defe | ||
|
|
cea50c9247 | ||
|
|
636f956bf0 | ||
|
|
64b1d91701 | ||
|
|
ff83f7c6ed | ||
|
|
87c0cd2667 | ||
|
|
366c8a99ef | ||
|
|
30f2aff526 | ||
|
|
962cffffc7 | ||
|
|
f196484187 | ||
|
|
c40fe2f71a | ||
|
|
74c149e891 | ||
|
|
57c82eb66f | ||
|
|
5460606cff | ||
|
|
1a509417a4 | ||
|
|
898cd20ceb | ||
|
|
792b78b317 | ||
|
|
4efe647169 | ||
|
|
4fbba55f14 | ||
|
|
2efc5a9e83 | ||
|
|
57144d5102 | ||
|
|
555bbffec3 | ||
|
|
e22510658b | ||
|
|
cb08e49303 | ||
|
|
dee03d2b80 | ||
|
|
b5ec3e47fa | ||
|
|
ffb11fb950 | ||
|
|
fbee1f0ed7 | ||
|
|
131ada1116 | ||
|
|
b0609b29aa | ||
|
|
bbb59b8c5e | ||
|
|
72deed0c37 | ||
|
|
b9f8c60fa7 | ||
|
|
87b36e1ff1 | ||
|
|
d8c5d338cb | ||
|
|
417438fea0 | ||
|
|
5488ffb6d4 | ||
|
|
e8725ce940 | ||
|
|
0e734920e8 | ||
|
|
ad598a2060 | ||
|
|
bb47f95262 | ||
|
|
a7a2115b9c | ||
|
|
18429f2a69 | ||
|
|
7e6430787c | ||
|
|
dc3ba8c223 | ||
|
|
2fd6520a7e | ||
|
|
7a61b36104 | ||
|
|
2f4783a770 | ||
|
|
6056391a78 | ||
|
|
213b3575ce | ||
|
|
3821e18d08 | ||
|
|
224c6e3f7c | ||
|
|
18ab6f429c | ||
|
|
07f8542ce7 | ||
|
|
cf293c224d | ||
|
|
e234ad0011 | ||
|
|
229b778b0b | ||
|
|
66f484defe | ||
|
|
ed523e248a | ||
|
|
3c49f27bf4 | ||
|
|
226d146b25 | ||
|
|
1892289329 | ||
|
|
5529fc0355 | ||
|
|
73ef559240 | ||
|
|
b59a63c8cd | ||
|
|
c36927137f | ||
|
|
649aaad100 | ||
|
|
ea4c262482 | ||
|
|
89de6c9df6 | ||
|
|
4578bc3b0c | ||
|
|
8df1e4866a | ||
|
|
9f92220a9c | ||
|
|
09a9e7bcb7 | ||
|
|
a434f8877a | ||
|
|
ef891dc0a7 | ||
|
|
3ebe29c983 | ||
|
|
1028e43464 | ||
|
|
4979f66f28 | ||
|
|
a5e9fe97c8 | ||
|
|
2293cfaf84 | ||
|
|
d252dde933 | ||
|
|
37a49a5992 | ||
|
|
2783801610 | ||
|
|
82f19c9a91 | ||
|
|
71d9531e45 | ||
|
|
3bbeaefa57 | ||
|
|
4611be805a | ||
|
|
587493fdfc | ||
|
|
50079144e3 | ||
|
|
2ca80e76a0 | ||
|
|
68e6502484 | ||
|
|
1e91dfa5df | ||
|
|
e4e5f7c65b | ||
|
|
8ef66261f1 | ||
|
|
90812b536c | ||
|
|
2b880d3ef8 | ||
|
|
6ab729aeb3 | ||
|
|
c9f97f49c5 | ||
|
|
8b352fcb94 | ||
|
|
5a06af4d57 | ||
|
|
2ede900bfd | ||
|
|
fb0ffc7784 | ||
|
|
e69171dc06 | ||
|
|
8452f6b494 | ||
|
|
f9bc6f8afc | ||
|
|
f9f44d7d9b | ||
|
|
86bb1472cc | ||
|
|
ef09c506c8 | ||
|
|
af7b3b420e | ||
|
|
3b80a35a66 | ||
|
|
f59b27258c | ||
|
|
d38fff38f9 | ||
|
|
91c5b12f25 | ||
|
|
894bdd5cda | ||
|
|
d8c58ca6c8 | ||
|
|
43f7956422 | ||
|
|
96fcc02900 | ||
|
|
2e8b6e7f20 | ||
|
|
3ed93398e9 | ||
|
|
d84e0caea8 | ||
|
|
5c1da58b90 | ||
|
|
018c617199 | ||
|
|
a49f954f6a | ||
|
|
03a8791440 | ||
|
|
78ad17381e | ||
|
|
5b03803e2f | ||
|
|
ee1e461a57 | ||
|
|
a543725311 | ||
|
|
8c701a0861 | ||
|
|
5fbe566524 | ||
|
|
e14cf31bc9 | ||
|
|
0042c03c7e | ||
|
|
41023ecb9c | ||
|
|
fb8d0a544d | ||
|
|
acaf8c9cc9 | ||
|
|
0d3fc8d103 | ||
|
|
9bbfbacacc | ||
|
|
8e301c629f | ||
|
|
9576d8a081 | ||
|
|
7db96672bf | ||
|
|
0d8f099ca2 | ||
|
|
0a4d7e5068 | ||
|
|
a32f75b800 | ||
|
|
78f37c51ef | ||
|
|
d6e5eb75ee | ||
|
|
6f433a7e7b | ||
|
|
ce2ecb5582 | ||
|
|
45c15e8561 | ||
|
|
5e3f4186da | ||
|
|
d03694df19 | ||
|
|
d52e8fa7d2 | ||
|
|
77c6cd0bff | ||
|
|
463ebe8b4b | ||
|
|
a563eab49a | ||
|
|
bf9d4b103d | ||
|
|
7dc2449f3a | ||
|
|
27cc20db11 | ||
|
|
4e04f5f731 | ||
|
|
5ec3844077 | ||
|
|
f641c7cd0d | ||
|
|
49aa54cafc | ||
|
|
e3b81e66a1 | ||
|
|
7bb6b928b5 | ||
|
|
ad4dc7c4a9 | ||
|
|
feb9764721 | ||
|
|
8c74501001 | ||
|
|
5861d3fd64 | ||
|
|
08acdc6a86 | ||
|
|
3b50570c9b | ||
|
|
00d7e962a7 | ||
|
|
192f7413c2 | ||
|
|
5bdb8074aa | ||
|
|
6abe5e1b23 | ||
|
|
4612b4ccca | ||
|
|
3245bf61a1 | ||
|
|
9ee13167bb | ||
|
|
ca9633ca9b | ||
|
|
e04884545c | ||
|
|
aa2239a050 | ||
|
|
40a1b60cbd | ||
|
|
cccb11916f | ||
|
|
49641825eb | ||
|
|
c14c078405 | ||
|
|
f2af073588 | ||
|
|
b9a5eddb6d | ||
|
|
bffc815375 | ||
|
|
5c3f322364 | ||
|
|
3a6fae817c | ||
|
|
d8f74ecb94 | ||
|
|
f7f2b1b033 | ||
|
|
601ab7ff82 |
@@ -1 +1 @@
|
||||
33
|
||||
8
|
||||
|
||||
@@ -1 +1 @@
|
||||
33
|
||||
8
|
||||
|
||||
4
BUGS
4
BUGS
@@ -7,10 +7,10 @@ the official Asterisk Bug Tracker at:
|
||||
http://bugs.digium.com
|
||||
|
||||
For more information on using the bug tracker, or to
|
||||
learn how you can contribute by acting as a bug marshal
|
||||
learn how you can contribute by acting as a bug marshall
|
||||
please see:
|
||||
|
||||
http://www.asterisk.org/developers/bug-guidelines
|
||||
http://www.digium.com/index.php?menu=bugguidelines
|
||||
|
||||
If you would like to submit a feature request, please
|
||||
resist the temptation to post it to the bug tracker.
|
||||
|
||||
499
CHANGES
499
CHANGES
@@ -1,374 +1,127 @@
|
||||
Changes since Asterisk 1.2:
|
||||
Changes since Asterisk 1.2.0-beta2:
|
||||
|
||||
* 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).
|
||||
* Cygwin build system portability
|
||||
* Optional generation of outbound silence during channel recording
|
||||
|
||||
Changes since Asterisk 1.2.0-beta1:
|
||||
|
||||
* Many, many bug fixes
|
||||
* Documentation and sample configuration updates
|
||||
* Vastly improved presence/subscription support in the SIP channel driver
|
||||
* A new (experimental) mISDN channel driver
|
||||
* A new monitoring application (MixMonitor)
|
||||
* More portability fixes for non-Linux platforms
|
||||
* New dialplan functions replacing old applications
|
||||
* Significant deadlock and performance upgrades for the Manager interface
|
||||
* An upgrade to the 'new' dialplan expression parser for all users
|
||||
* New Zaptel echo cancellers with improved performance
|
||||
* Support for the latest OSP toolkit from TransNexus
|
||||
* Support user-controlled volume adjustment in MeetMe application
|
||||
* More dialplan applications now return status variables instead of priority jumping
|
||||
* Much more powerful ENUM support in the dialplan
|
||||
* SIP domain support for authentication and virtual hosting
|
||||
* Many PRI protocol updates and fixes, including more complete Q.SIG support
|
||||
* New applications: Pickup() and Page()
|
||||
|
||||
Changes since Asterisk 1.0:
|
||||
|
||||
This list currently only containts changes made from the end of November until
|
||||
March 26, 2005.
|
||||
|
||||
* Add new applications:
|
||||
-- AgentMonitorOutgoing
|
||||
-- Curl
|
||||
-- ExecIf
|
||||
-- ExecIfTime
|
||||
-- IAX2Provision
|
||||
-- MacroExit
|
||||
-- MacroIf
|
||||
-- PauseQueueMember
|
||||
-- ReadFile
|
||||
-- SetRDNIS
|
||||
-- SIPAddHeader
|
||||
-- SIPGetHeader
|
||||
-- StartMusicOnHold
|
||||
-- StopMusicOnHold
|
||||
-- UnpauseQueueMember
|
||||
-- WaitForSilence
|
||||
-- While / EndWhile
|
||||
* app Answer
|
||||
-- added delay option
|
||||
* app ChanIsAvail
|
||||
-- added 's' option
|
||||
* app Dial
|
||||
-- add option to specify the class for musiconhold with m option
|
||||
* app EnumLookup
|
||||
-- added "reload enum" for configuration
|
||||
* app Goto
|
||||
-- added relative priorities
|
||||
* app GotoIf
|
||||
-- added relative priorities
|
||||
* app MeetMe
|
||||
-- added 'i' option
|
||||
-- added 'r' option
|
||||
-- added 'T' option
|
||||
-- added 'P' option
|
||||
-- added 'c' option
|
||||
-- added adminpin to meetme.conf
|
||||
-- added reload command
|
||||
* app PrivacyManager
|
||||
-- add config file privacy.conf
|
||||
* app queue
|
||||
-- queues.conf
|
||||
-- added persistentmembers option to queues.conf
|
||||
-- changed music option to musiconhold
|
||||
-- added weight option
|
||||
-- added note about why agent groups probably shouldn't be used
|
||||
-- added timeoutrestart option
|
||||
* app Read
|
||||
-- added attempts parameter
|
||||
-- added timeout parameter
|
||||
* app Record
|
||||
-- added 'q' option
|
||||
* app SendDTMF
|
||||
-- add timeout option
|
||||
* app SMS
|
||||
-- document alternative syntax for queueing messages
|
||||
* app Voicemail
|
||||
-- add info about VM_CATEGORY
|
||||
-- voicemail.conf
|
||||
-- added usedirectory option
|
||||
-- added VM_CIDNUM and VM_CIDNAME in message config
|
||||
* chan IAX2
|
||||
-- new jitterbuffer
|
||||
-- added setvar option
|
||||
-- added regex to iax2 show peers/users
|
||||
-- allow multiple bindaddr lines in iax.conf
|
||||
-- added reload command
|
||||
-- added forcejitterbuffer option
|
||||
-- added note about specifying bindport before bindaddr
|
||||
-- added trunktimestamps option
|
||||
* chan Agent
|
||||
-- added agent logoff CLI command
|
||||
* chan OSS
|
||||
-- added Flash CLI command
|
||||
* chan SIP
|
||||
-- added setvar option
|
||||
-- added compactheaders option
|
||||
-- added usereqphone option
|
||||
-- added registertimeout option
|
||||
-- added externhost option
|
||||
-- added sip notify CLI command
|
||||
-- added sip_notify.conf
|
||||
-- added allowguest option
|
||||
* chan Zap
|
||||
-- added hanguponplarityswitch option
|
||||
-- added sendcalleridafter option
|
||||
-- added priresetinterval option
|
||||
-- added TON/NPI config options (the ones right above the resetinterval option)
|
||||
-- added answeronpolarityswitch option
|
||||
-- added "never" for resetinterval
|
||||
* extensions
|
||||
-- allow '*' when including files (#include "sip-*.conf")
|
||||
-- added eswitch
|
||||
* General
|
||||
-- added #exec syntax for including output from a command
|
||||
-- added show features CLI command
|
||||
-- added configuration templates for category inheritance
|
||||
|
||||
88
CREDITS
88
CREDITS
@@ -27,149 +27,69 @@ 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
|
||||
|
||||
James Golovich - Innumerable contributions
|
||||
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/
|
||||
|
||||
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
|
||||
wjordan@vonage.com
|
||||
|
||||
Jac Kersing - Various fixes
|
||||
|
||||
Steven Critchfield - Seek and Trunc functions for playback and recording
|
||||
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
|
||||
|
||||
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/
|
||||
|
||||
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
|
||||
|
||||
Steve Murphy - privacy support
|
||||
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.freeplaymusic.com
|
||||
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
|
||||
GSM source:
|
||||
|
||||
@@ -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
|
||||
|
||||
26
LICENSE
26
LICENSE
@@ -5,18 +5,6 @@ applies to all loadable Asterisk modules used on your system as well,
|
||||
except as defined below. The GPL (version 2) is included in this
|
||||
source tree in the file COPYING.
|
||||
|
||||
This package also includes various components that are not part of
|
||||
Asterisk itself; these components are in the 'contrib' directory
|
||||
and its subdirectories. Most of these components are also
|
||||
distributed under the GPL version 2 as well, except for the following:
|
||||
|
||||
contrib/firmware/iax/iaxy.bin:
|
||||
This file is Copyright (C) Digium, Inc. and is licensed for
|
||||
use with Digium IAXy hardware devices only. It can be
|
||||
distributed freely as long as the distribution is in the
|
||||
original form present in this package (not reformatted or
|
||||
modified).
|
||||
|
||||
Digium, Inc. (formerly Linux Support Services) holds copyright
|
||||
and/or sufficient licenses to all components of the Asterisk
|
||||
package, and therefore can grant, at its sole discretion, the ability
|
||||
@@ -31,8 +19,8 @@ there is no requirement that you provide the same exception in your
|
||||
GPL'd products (although if you've written a module for Asterisk we
|
||||
would strongly encourage you to make the same exception that we do).
|
||||
|
||||
Specific permission is also granted to link Asterisk with OpenSSL, OpenH323
|
||||
and/or the UW IMAP Toolkit and distribute the resulting binary files.
|
||||
Specific permission is also granted to link Asterisk with OpenSSL and
|
||||
OpenH323.
|
||||
|
||||
In addition, Asterisk implements two management/control protocols: the
|
||||
Asterisk Manager Interface (AMI) and the Asterisk Gateway Interface
|
||||
@@ -50,19 +38,19 @@ 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
|
||||
steps you must take.
|
||||
|
||||
If you have any questions regarding our licensing policy, please
|
||||
contact us:
|
||||
|
||||
+1.877.344.4861 (via telephone in the USA)
|
||||
+1.877.546.8963 (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)
|
||||
IAX2/misery.digium.com/6000 (via IAX2)
|
||||
licensing@digium.com (via email)
|
||||
|
||||
Digium, Inc.
|
||||
445 Jan Davis Drive
|
||||
150 West Park Loop
|
||||
Suite 100
|
||||
Huntsville, AL 35806
|
||||
USA
|
||||
|
||||
@@ -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
|
||||
129
Makefile.rules
129
Makefile.rules
@@ -1,129 +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
|
||||
|
||||
ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),)
|
||||
# More GSM codec optimization
|
||||
# Uncomment to enable MMXTM optimizations for x86 architecture CPU's
|
||||
# which support MMX instructions. This should be newer pentiums,
|
||||
# ppro's, etc, as well as the AMD K6 and K7.
|
||||
#K6OPT=-DK6OPT
|
||||
|
||||
ASTCFLAGS+=$(OPTIMIZE)
|
||||
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)
|
||||
CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(ASTCFLAGS))
|
||||
CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
|
||||
CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
|
||||
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 $< $(CC_CFLAGS) $(OPTIMIZE)
|
||||
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 $< $(CC_CFLAGS) $(OPTIMIZE)
|
||||
endif
|
||||
$(CMD_PREFIX) $(CC) -o $@ -c $< $(CC_CFLAGS)
|
||||
|
||||
ifneq ($(COMPILE_DOUBLE),yes)
|
||||
%.o: %.c
|
||||
$(ECHO_PREFIX) echo " [CC] $< -> $@"
|
||||
$(CMD_PREFIX) $(CC) -o $@ -c $< $(CC_CFLAGS) $(MAKE_DEPS)
|
||||
endif
|
||||
|
||||
%.i: %.c
|
||||
$(ECHO_PREFIX) echo " [CPP] $< -> $@"
|
||||
$(CMD_PREFIX) $(CC) -o $@ -E $< $(CC_CFLAGS) $(MAKE_DEPS)
|
||||
|
||||
%.oo: %.ii
|
||||
$(ECHO_PREFIX) echo " [CXXi] $< -> $@"
|
||||
ifeq ($(COMPILE_DOUBLE),yes)
|
||||
$(CMD_PREFIX) $(CXX) -o /dev/null -c $< $(CXX_CFLAGS) $(OPTIMIZE)
|
||||
endif
|
||||
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(CXX_CFLAGS)
|
||||
|
||||
ifneq ($(COMPILE_DOUBLE),yes)
|
||||
%.oo: %.cc
|
||||
$(ECHO_PREFIX) echo " [CXX] $< -> $@"
|
||||
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(CXX_CFLAGS) $(MAKE_DEPS)
|
||||
endif
|
||||
|
||||
%.ii: %.cc
|
||||
$(ECHO_PREFIX) echo " [CPP] $< -> $@"
|
||||
$(CMD_PREFIX) $(CXX) -o $@ -E $< $(CXX_CFLAGS) $(MAKE_DEPS)
|
||||
|
||||
%.c: %.y
|
||||
$(ECHO_PREFIX) echo " [BISON] $< -> $@"
|
||||
$(CMD_PREFIX) bison -o $@ -d --name-prefix=ast_yy $<
|
||||
|
||||
%.c: %.fl
|
||||
$(ECHO_PREFIX) echo " [FLEX] $< -> $@"
|
||||
$(CMD_PREFIX) flex -o $@ --full $<
|
||||
|
||||
%.so: %.o
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(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)
|
||||
|
||||
dist-clean:: clean
|
||||
48
README
48
README
@@ -1,17 +1,17 @@
|
||||
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.
|
||||
Copyright (C) 2001-2005 Digium, Inc.
|
||||
and other copyright holders.
|
||||
================================================================
|
||||
|
||||
* SECURITY
|
||||
It is imperative that you read and fully understand the contents of
|
||||
the security information file (doc/security.txt) before you attempt
|
||||
to configure and run an Asterisk server.
|
||||
the SECURITY file before you attempt to configure and run 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
|
||||
@@ -51,15 +51,13 @@ ANY special hardware, not even a soundcard) to install and run Asterisk.
|
||||
* All Wildcard (tm) products from Digium (www.digium.com)
|
||||
* QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net)
|
||||
* any full duplex sound card supported by ALSA or OSS
|
||||
* any ISDN card supported by mISDN on Linux (BRI)
|
||||
* The Xorcom AstriBank channel bank
|
||||
* VoiceTronix OpenLine products
|
||||
|
||||
The are several drivers for ISDN BRI cards available from third party sources.
|
||||
Check the voip-info.org wiki for more information on chan_capi and
|
||||
Check the voip-info.org wiki for more information on chan_capi, chan_misdn and
|
||||
zaphfc.
|
||||
|
||||
* UPGRADING FROM AN EARLIER VERSION
|
||||
* UPGRADING FROM VERSION 1.0
|
||||
|
||||
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
|
||||
@@ -84,31 +82,14 @@ On many distributions, these files are installed by packages with names like
|
||||
|
||||
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"
|
||||
1) Run "make"
|
||||
|
||||
Assuming the build completes successfully:
|
||||
|
||||
5) Run "make install"
|
||||
2) 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
|
||||
Each time you update or checkout from CVS, 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.
|
||||
@@ -116,7 +97,7 @@ is required, and the file .lastclean, which contains the last .cleancount used.
|
||||
If this is your first time working with Asterisk, you may wish to install
|
||||
the sample PBX, with demonstration extensions, etc. If so, run:
|
||||
|
||||
6) "make samples"
|
||||
3) "make samples"
|
||||
|
||||
Doing so will overwrite any existing config files you have.
|
||||
|
||||
@@ -159,7 +140,7 @@ 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:
|
||||
asterisk. For example, in zapata.conf, one might specify:
|
||||
|
||||
switchtype=national
|
||||
|
||||
@@ -257,6 +238,3 @@ you're interested in getting more information.
|
||||
Welcome to the growing worldwide community of Asterisk users!
|
||||
|
||||
Mark Spencer
|
||||
|
||||
----
|
||||
Asterisk is a trademark belonging to Digium, inc
|
||||
|
||||
22
README.opsound
Normal file
22
README.opsound
Normal 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
|
||||
@@ -28,13 +28,6 @@ The IAX2 protocol supports strong RSA key authentication as well as
|
||||
AES encryption of voice and signalling. The SIP channel does not
|
||||
support encryption in this version of Asterisk.
|
||||
|
||||
By default, if you have libcap available, Asterisk will try to retain the
|
||||
CAP_NET_ADMIN capability when running as a non-root user. If you do not need
|
||||
that capability you may want to configure Asterisk with --without-cap; however,
|
||||
this will prevent Asterisk from being able to mark high ToS bits under Linux.
|
||||
More information on CAP_NET_ADMIN is available at:
|
||||
http://www.lids.org/lids-howto/node48.html
|
||||
|
||||
* DIALPLAN SECURITY
|
||||
|
||||
First and foremost remember this:
|
||||
@@ -72,9 +65,3 @@ 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.
|
||||
|
||||
* LOG SECURITY
|
||||
|
||||
Please note that the Asterisk log files, as well as information printed to the
|
||||
Asterisk CLI, may contain sensitive information such as passwords and call
|
||||
history. Keep this in mind when providing access to these resources.
|
||||
210
UPGRADE-1.2.txt
210
UPGRADE-1.2.txt
@@ -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
|
||||
665
UPGRADE.txt
665
UPGRADE.txt
@@ -1,500 +1,205 @@
|
||||
=========================================================
|
||||
=== 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
|
||||
Information for Upgrading From Previous Asterisk Releases
|
||||
=========================================================
|
||||
|
||||
Build Process (configure script):
|
||||
Compiling:
|
||||
|
||||
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:
|
||||
* 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.
|
||||
|
||||
$ ./configure --help
|
||||
Dialplan Expressions:
|
||||
|
||||
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.
|
||||
* 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.
|
||||
|
||||
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.
|
||||
Agents:
|
||||
|
||||
Build Process (module selection):
|
||||
* 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 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 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.
|
||||
|
||||
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.
|
||||
Parking:
|
||||
|
||||
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'.
|
||||
* 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.
|
||||
|
||||
Build Process (Makefile targets):
|
||||
Dialing:
|
||||
|
||||
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.
|
||||
* 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.
|
||||
|
||||
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'.
|
||||
IAX:
|
||||
|
||||
Sound (prompt) and Music On Hold files:
|
||||
* 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.
|
||||
|
||||
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 FreePlay Music are now available
|
||||
in the same five formats, but no longer available in MP3 format.
|
||||
SIP:
|
||||
|
||||
The Asterisk 1.4 tarball packages will only include English prompts in GSM format,
|
||||
(as were supplied with previous releases) and the FreePlay 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.
|
||||
* 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.
|
||||
|
||||
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.
|
||||
|
||||
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 '!'.
|
||||
* The "Registry" event now uses "Username" rather than "User" for
|
||||
consistency with IAX.
|
||||
|
||||
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).
|
||||
|
||||
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.
|
||||
* 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
|
||||
|
||||
@@ -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.
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2006, Digium, Inc.
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
@@ -19,14 +19,9 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Various sorts of access control
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -39,20 +34,18 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#include <fcntl.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#include <sys/sockio.h>
|
||||
#include <net/if.h>
|
||||
#elif defined(HAVE_GETIFADDRS)
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
/* netinet/ip.h may not define the following (See RFCs 791 and 1349) */
|
||||
@@ -64,6 +57,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#define IPTOS_MINCOST IPTOS_LOWCOST
|
||||
#endif
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/acl.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -71,6 +68,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/srv.h"
|
||||
#include "asterisk/compat.h"
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
AST_MUTEX_DEFINE_STATIC(routeseq_lock);
|
||||
#endif
|
||||
|
||||
struct ast_ha {
|
||||
/* Host access rule */
|
||||
@@ -81,179 +83,18 @@ struct ast_ha {
|
||||
};
|
||||
|
||||
/* Default IP - if not otherwise set, don't breathe garbage */
|
||||
static struct in_addr __ourip = { .s_addr = 0x00000000, };
|
||||
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;
|
||||
};
|
||||
|
||||
#if (!defined(SOLARIS) && !defined(HAVE_GETIFADDRS))
|
||||
static int get_local_address(struct in_addr *ourip)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
static void score_address(const struct sockaddr_in *sin, struct in_addr *best_addr, int *best_score)
|
||||
{
|
||||
const char *address;
|
||||
int score;
|
||||
|
||||
address = ast_inet_ntoa(sin->sin_addr);
|
||||
|
||||
/* RFC 1700 alias for the local network */
|
||||
if (address[0] == '0')
|
||||
score = -25;
|
||||
/* RFC 1700 localnet */
|
||||
else if (strncmp(address, "127", 3) == 0)
|
||||
score = -20;
|
||||
/* RFC 1918 non-public address space */
|
||||
else if (strncmp(address, "10.", 3) == 0)
|
||||
score = -5;
|
||||
/* RFC 1918 non-public address space */
|
||||
else if (strncmp(address, "172", 3) == 0) {
|
||||
/* 172.16.0.0 - 172.19.255.255, but not 172.160.0.0 - 172.169.255.255 */
|
||||
if (address[4] == '1' && address[5] >= '6' && address[6] == '.')
|
||||
score = -5;
|
||||
/* 172.20.0.0 - 172.29.255.255, but not 172.200.0.0 - 172.255.255.255 nor 172.2.0.0 - 172.2.255.255 */
|
||||
else if (address[4] == '2' && address[6] == '.')
|
||||
score = -5;
|
||||
/* 172.30.0.0 - 172.31.255.255 */
|
||||
else if (address[4] == '3' && address[5] <= '1')
|
||||
score = -5;
|
||||
/* All other 172 addresses are public */
|
||||
else
|
||||
score = 0;
|
||||
/* RFC 2544 Benchmark test range */
|
||||
} else if (strncmp(address, "198.1", 5) == 0 && address[5] >= '8' && address[6] == '.')
|
||||
score = -10;
|
||||
/* RFC 1918 non-public address space */
|
||||
else if (strncmp(address, "192.168", 7) == 0)
|
||||
score = -5;
|
||||
/* RFC 3330 Zeroconf network */
|
||||
else if (strncmp(address, "169.254", 7) == 0)
|
||||
/*!\note Better score than a test network, but not quite as good as RFC 1918
|
||||
* address space. The reason is that some Linux distributions automatically
|
||||
* configure a Zeroconf address before trying DHCP, so we want to prefer a
|
||||
* DHCP lease to a Zeroconf address.
|
||||
*/
|
||||
score = -10;
|
||||
/* RFC 3330 Test network */
|
||||
else if (strncmp(address, "192.0.2.", 8) == 0)
|
||||
score = -15;
|
||||
/* Every other address should be publically routable */
|
||||
else
|
||||
score = 0;
|
||||
|
||||
if (score > *best_score) {
|
||||
*best_score = score;
|
||||
memcpy(best_addr, &sin->sin_addr, sizeof(*best_addr));
|
||||
}
|
||||
}
|
||||
|
||||
static int get_local_address(struct in_addr *ourip)
|
||||
{
|
||||
int s, res = -1;
|
||||
#ifdef SOLARIS
|
||||
struct lifreq *ifr = NULL;
|
||||
struct lifnum ifn;
|
||||
struct lifconf ifc;
|
||||
struct sockaddr_in *sa;
|
||||
char *buf = NULL;
|
||||
int bufsz, x;
|
||||
#endif /* SOLARIS */
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
|
||||
struct ifaddrs *ifap, *ifaphead;
|
||||
int rtnerr;
|
||||
const struct sockaddr_in *sin;
|
||||
#endif /* BSD_OR_LINUX */
|
||||
struct in_addr best_addr;
|
||||
int best_score = -100;
|
||||
memset(&best_addr, 0, sizeof(best_addr));
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
|
||||
rtnerr = getifaddrs(&ifaphead);
|
||||
if (rtnerr) {
|
||||
perror(NULL);
|
||||
return -1;
|
||||
}
|
||||
#endif /* BSD_OR_LINUX */
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (s > 0) {
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
|
||||
for (ifap = ifaphead; ifap; ifap = ifap->ifa_next) {
|
||||
|
||||
if (ifap->ifa_addr && ifap->ifa_addr->sa_family == AF_INET) {
|
||||
sin = (const struct sockaddr_in *) ifap->ifa_addr;
|
||||
score_address(sin, &best_addr, &best_score);
|
||||
res = 0;
|
||||
|
||||
if (best_score == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* BSD_OR_LINUX */
|
||||
|
||||
/* There is no reason whatsoever that this shouldn't work on Linux or BSD also. */
|
||||
#ifdef SOLARIS
|
||||
/* Get a count of interfaces on the machine */
|
||||
ifn.lifn_family = AF_INET;
|
||||
ifn.lifn_flags = 0;
|
||||
ifn.lifn_count = 0;
|
||||
if (ioctl(s, SIOCGLIFNUM, &ifn) < 0) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bufsz = ifn.lifn_count * sizeof(struct lifreq);
|
||||
if (!(buf = malloc(bufsz))) {
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
memset(buf, 0, bufsz);
|
||||
|
||||
/* Get a list of interfaces on the machine */
|
||||
ifc.lifc_len = bufsz;
|
||||
ifc.lifc_buf = buf;
|
||||
ifc.lifc_family = AF_INET;
|
||||
ifc.lifc_flags = 0;
|
||||
if (ioctl(s, SIOCGLIFCONF, &ifc) < 0) {
|
||||
close(s);
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ifr = ifc.lifc_req, x = 0; x < ifn.lifn_count; ifr++, x++) {
|
||||
sa = (struct sockaddr_in *)&(ifr->lifr_addr);
|
||||
score_address(sa, &best_addr, &best_score);
|
||||
res = 0;
|
||||
|
||||
if (best_score == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
#endif /* SOLARIS */
|
||||
|
||||
close(s);
|
||||
}
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
|
||||
freeifaddrs(ifaphead);
|
||||
#endif /* BSD_OR_LINUX */
|
||||
|
||||
if (res == 0 && ourip)
|
||||
memcpy(ourip, &best_addr, sizeof(*ourip));
|
||||
return res;
|
||||
}
|
||||
#endif /* HAVE_GETIFADDRS */
|
||||
|
||||
/* Free HA structure */
|
||||
void ast_free_ha(struct ast_ha *ha)
|
||||
{
|
||||
struct ast_ha *hal;
|
||||
while (ha) {
|
||||
while(ha) {
|
||||
hal = ha;
|
||||
ha = ha->next;
|
||||
free(hal);
|
||||
@@ -271,12 +112,9 @@ static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
|
||||
/* Create duplicate of ha structure */
|
||||
static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
|
||||
{
|
||||
struct ast_ha *new_ha;
|
||||
|
||||
if ((new_ha = ast_malloc(sizeof(*new_ha)))) {
|
||||
/* Copy from original to new object */
|
||||
ast_copy_ha(original, new_ha);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -285,16 +123,16 @@ static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
|
||||
/* Used in chan_sip2 templates */
|
||||
struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
|
||||
{
|
||||
struct ast_ha *start = original;
|
||||
struct ast_ha *start=original;
|
||||
struct ast_ha *ret = NULL;
|
||||
struct ast_ha *link, *prev = 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)
|
||||
if (!ret)
|
||||
ret = link; /* Save starting point */
|
||||
|
||||
start = start->next; /* Go to next object */
|
||||
@@ -305,20 +143,19 @@ struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
|
||||
|
||||
struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
|
||||
{
|
||||
struct ast_ha *ha;
|
||||
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 = ast_malloc(sizeof(*ha)))) {
|
||||
if (ha) {
|
||||
ast_copy_string(tmp, stuff, sizeof(tmp));
|
||||
nm = strchr(tmp, '/');
|
||||
if (!nm) {
|
||||
@@ -330,7 +167,7 @@ struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
|
||||
if (!strchr(nm, '.')) {
|
||||
if ((sscanf(nm, "%d", &x) == 1) && (x >= 0) && (x <= 32)) {
|
||||
y = 0;
|
||||
for (z = 0; z < x; z++) {
|
||||
for (z=0;z<x;z++) {
|
||||
y >>= 1;
|
||||
y |= 0x80000000;
|
||||
}
|
||||
@@ -339,12 +176,12 @@ struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
|
||||
} else if (!inet_aton(nm, &ha->netmask)) {
|
||||
ast_log(LOG_WARNING, "%s is not a valid netmask\n", nm);
|
||||
free(ha);
|
||||
return ret;
|
||||
return path;
|
||||
}
|
||||
if (!inet_aton(tmp, &ha->netaddr)) {
|
||||
ast_log(LOG_WARNING, "%s is not a valid IP\n", tmp);
|
||||
free(ha);
|
||||
return ret;
|
||||
return path;
|
||||
}
|
||||
ha->netaddr.s_addr &= ha->netmask.s_addr;
|
||||
if (!strncasecmp(sense, "p", 1)) {
|
||||
@@ -359,8 +196,7 @@ struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
|
||||
ret = ha;
|
||||
}
|
||||
}
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n", stuff, nm);
|
||||
ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n", stuff, nm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -372,10 +208,10 @@ int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
char iabuf2[INET_ADDRSTRLEN];
|
||||
/* DEBUG */
|
||||
ast_copy_string(iabuf, ast_inet_ntoa(sin->sin_addr), sizeof(iabuf));
|
||||
ast_copy_string(iabuf2, ast_inet_ntoa(ha->netaddr), sizeof(iabuf2));
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "##### Testing %s with %s\n", iabuf, iabuf2);
|
||||
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)
|
||||
@@ -411,55 +247,12 @@ int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *se
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dscp_codepoint {
|
||||
char *name;
|
||||
unsigned int space;
|
||||
};
|
||||
|
||||
/* IANA registered DSCP codepoints */
|
||||
|
||||
static const struct dscp_codepoint dscp_pool1[] = {
|
||||
{ "CS0", 0x00 },
|
||||
{ "CS1", 0x08 },
|
||||
{ "CS2", 0x10 },
|
||||
{ "CS3", 0x18 },
|
||||
{ "CS4", 0x20 },
|
||||
{ "CS5", 0x28 },
|
||||
{ "CS6", 0x30 },
|
||||
{ "CS7", 0x38 },
|
||||
{ "AF11", 0x0A },
|
||||
{ "AF12", 0x0C },
|
||||
{ "AF13", 0x0E },
|
||||
{ "AF21", 0x12 },
|
||||
{ "AF22", 0x14 },
|
||||
{ "AF23", 0x16 },
|
||||
{ "AF31", 0x1A },
|
||||
{ "AF32", 0x1C },
|
||||
{ "AF33", 0x1E },
|
||||
{ "AF41", 0x22 },
|
||||
{ "AF42", 0x24 },
|
||||
{ "AF43", 0x26 },
|
||||
{ "EF", 0x2E },
|
||||
};
|
||||
|
||||
int ast_str2tos(const char *value, unsigned int *tos)
|
||||
int ast_str2tos(const char *value, int *tos)
|
||||
{
|
||||
int fval;
|
||||
unsigned int x;
|
||||
|
||||
if (sscanf(value, "%i", &fval) == 1) {
|
||||
*tos = fval & 0xFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (x = 0; x < sizeof(dscp_pool1) / sizeof(dscp_pool1[0]); x++) {
|
||||
if (!strcasecmp(value, dscp_pool1[x].name)) {
|
||||
*tos = dscp_pool1[x].space << 2;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcasecmp(value, "lowdelay"))
|
||||
if (sscanf(value, "%i", &fval) == 1)
|
||||
*tos = fval & 0xff;
|
||||
else if (!strcasecmp(value, "lowdelay"))
|
||||
*tos = IPTOS_LOWDELAY;
|
||||
else if (!strcasecmp(value, "throughput"))
|
||||
*tos = IPTOS_THROUGHPUT;
|
||||
@@ -471,44 +264,16 @@ int ast_str2tos(const char *value, unsigned int *tos)
|
||||
*tos = 0;
|
||||
else
|
||||
return -1;
|
||||
|
||||
ast_log(LOG_WARNING, "TOS value %s is deprecated. Please see doc/ip-tos.txt for more information.\n", value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *ast_tos2str(unsigned int tos)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
switch (tos) {
|
||||
case 0:
|
||||
return "none";
|
||||
case IPTOS_LOWDELAY:
|
||||
return "lowdelay";
|
||||
case IPTOS_THROUGHPUT:
|
||||
return "throughput";
|
||||
case IPTOS_RELIABILITY:
|
||||
return "reliability";
|
||||
case IPTOS_MINCOST:
|
||||
return "mincost";
|
||||
default:
|
||||
for (x = 0; x < sizeof(dscp_pool1) / sizeof(dscp_pool1[0]); x++) {
|
||||
if (dscp_pool1[x].space == (tos >> 2))
|
||||
return dscp_pool1[x].name;
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
int ast_get_ip(struct sockaddr_in *sin, const char *value)
|
||||
{
|
||||
return ast_get_ip_or_srv(sin, value, NULL);
|
||||
}
|
||||
|
||||
/* iface is the interface (e.g. eth0); address is the return value */
|
||||
int ast_lookup_iface(char *iface, struct in_addr *address)
|
||||
int ast_lookup_iface(char *iface, struct in_addr *address)
|
||||
{
|
||||
int mysock, res = 0;
|
||||
struct my_ifreq ifreq;
|
||||
@@ -585,6 +350,6 @@ int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
|
||||
/* A.ROOT-SERVERS.NET. */
|
||||
if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
|
||||
return 0;
|
||||
return get_local_address(ourip);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -31,16 +31,12 @@
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
*/
|
||||
|
||||
/*! \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>
|
||||
*/
|
||||
\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
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
@@ -31,15 +31,11 @@
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
*/
|
||||
|
||||
/*! \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>
|
||||
*/
|
||||
\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.
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
45
agi/Makefile
45
agi/Makefile
@@ -3,7 +3,7 @@
|
||||
#
|
||||
# Makefile for AGI-related stuff
|
||||
#
|
||||
# Copyright (C) 1999-2006, Digium
|
||||
# Copyright (C) 1999-2005, Digium
|
||||
#
|
||||
# Mark Spencer <markster@digium.com>
|
||||
#
|
||||
@@ -11,37 +11,42 @@
|
||||
# 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+=-DNO_AST_MM
|
||||
|
||||
LIBS=
|
||||
ifeq ($(OSARCH),SunOS)
|
||||
LIBS+=-lsocket -lnsl
|
||||
LIBS=-lsocket -lnsl ../strcompat.o
|
||||
endif
|
||||
|
||||
include $(ASTTOPDIR)/Makefile.rules
|
||||
ifeq ($(findstring BSD,${OSARCH}),BSD)
|
||||
CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
|
||||
endif
|
||||
|
||||
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 $(LIBS)
|
||||
|
||||
eagi-sphinx-test: eagi-sphinx-test.o
|
||||
$(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o $(LIBS)
|
||||
|
||||
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:
|
||||
../build_tools/mkdep $(CFLAGS) `ls *.c`
|
||||
|
||||
@@ -17,10 +17,7 @@
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/compat.h"
|
||||
#include <asterisk/compat.h>
|
||||
|
||||
#define AUDIO_FILENO (STDERR_FILENO + 1)
|
||||
|
||||
@@ -70,9 +67,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 +118,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 +129,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)) {
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/compat.h"
|
||||
#include <asterisk/compat.h>
|
||||
|
||||
#define AUDIO_FILENO (STDERR_FILENO + 1)
|
||||
|
||||
@@ -24,9 +21,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 +65,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;
|
||||
|
||||
488
agi/jukebox.agi
488
agi/jukebox.agi
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,7 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief u-Law to Signed linear conversion
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
@@ -71,7 +70,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);
|
||||
1058
main/app.c → app.c
1058
main/app.c → app.c
File diff suppressed because it is too large
Load Diff
137
apps/Makefile
137
apps/Makefile
@@ -3,40 +3,131 @@
|
||||
#
|
||||
# Makefile for PBX applications
|
||||
#
|
||||
# Copyright (C) 1999-2006, Digium, Inc.
|
||||
# Copyright (C) 1999-2005, Digium
|
||||
#
|
||||
# Mark Spencer <markster@digium.com>
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License
|
||||
#
|
||||
|
||||
-include ../menuselect.makeopts ../menuselect.makedeps
|
||||
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_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_setcidname.so app_lookupcidname.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_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 app_math.so app_realtime.so \
|
||||
app_dumpchan.so app_waitforsilence.so app_while.so app_setrdnis.so \
|
||||
app_md5.so app_readfile.so app_chanspy.so app_settransfercapability.so \
|
||||
app_dictate.so app_externalivr.so app_directed_pickup.so \
|
||||
app_mixmonitor.so app_stack.so
|
||||
|
||||
MENUSELECT_CATEGORY=APPS
|
||||
MENUSELECT_DESCRIPTION=Applications
|
||||
#
|
||||
# Obsolete things...
|
||||
#
|
||||
#APPS+=app_sql_postgres.so
|
||||
#APPS+=app_sql_odbc.so
|
||||
|
||||
ALL_C_MODS:=$(patsubst %.c,%,$(wildcard app_*.c))
|
||||
ALL_CC_MODS:=$(patsubst %.cc,%,$(wildcard app_*.cc))
|
||||
#
|
||||
# Experimental things
|
||||
#
|
||||
#APPS+=app_ivrdemo.so
|
||||
#APPS+=app_skel.so
|
||||
#APPS+=app_rpt.so
|
||||
|
||||
C_MODS:=$(filter-out $(MENUSELECT_APPS),$(ALL_C_MODS))
|
||||
CC_MODS:=$(filter-out $(MENUSELECT_APPS),$(ALL_CC_MODS))
|
||||
ifndef WITHOUT_ZAPTEL
|
||||
ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),)
|
||||
APPS+=app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so app_page.so
|
||||
endif
|
||||
endif # WITHOUT_ZAPTEL
|
||||
|
||||
LOADABLE_MODS:=$(C_MODS) $(CC_MODS)
|
||||
|
||||
ifneq ($(findstring apps,$(MENUSELECT_EMBED)),)
|
||||
EMBEDDED_MODS:=$(LOADABLE_MODS)
|
||||
LOADABLE_MODS:=
|
||||
ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/osp/osp.h $(CROSS_COMPILE_TARGET)/usr/include/osp/osp.h),)
|
||||
APPS+=app_osplookup.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)
|
||||
ifeq ($(findstring BSD,${OSARCH}),BSD)
|
||||
CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
|
||||
endif
|
||||
|
||||
all: _all
|
||||
CURLLIBS=$(shell $(CROSS_COMPILE_BIN)curl-config --libs)
|
||||
ifneq ($(shell if [[ 0x`$(CROSS_COMPILE_BIN)curl-config --vernum` -ge 0x70907 ]]; then echo "OK" ; fi),)
|
||||
ifneq (${CURLLIBS},)
|
||||
APPS+=app_curl.so
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(ASTTOPDIR)/Makefile.moddir_rules
|
||||
ifeq (${OSARCH},CYGWIN)
|
||||
CYGSOLINK=-Wl,--out-implib=lib$@.a -Wl,--export-all-symbols
|
||||
CYGSOLIB=-L.. -L. -L../res -lasterisk.dll -lres_features.so -lres_adsi.so -lres_monitor.so
|
||||
else
|
||||
CFLAGS+=-fPIC
|
||||
APPS+=app_sms.so
|
||||
endif
|
||||
|
||||
#
|
||||
# If you have UnixODBC you can use ODBC voicemail
|
||||
# storage
|
||||
#
|
||||
# Uncomment to use ODBC storage
|
||||
#CFLAGS+=-DUSE_ODBC_STORAGE
|
||||
# Uncomment for extended ODBC voicemail storage
|
||||
#CFLAGS+=-DEXTENDED_ODBC_STORAGE
|
||||
# See doc/README.odbcstorage for more information
|
||||
|
||||
all: $(APPS)
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o look .depend
|
||||
|
||||
%.so : %.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB}
|
||||
|
||||
app_rpt.so : app_rpt.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -ltonezone
|
||||
|
||||
install: all
|
||||
for x in $(APPS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done
|
||||
rm -f $(DESTDIR)$(MODULES_DIR)/app_datetime.so
|
||||
rm -f $(DESTDIR)$(MODULES_DIR)/app_qcall.so
|
||||
|
||||
app_curl.so: app_curl.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CURLLIBS)
|
||||
|
||||
app_sql_postgres.o: app_sql_postgres.c
|
||||
$(CC) -pipe -I$(CROSS_COMPILE_TARGET)/usr/local/pgsql/include -I$(CROSS_COMPILE_TARGET)/usr/include/postgresql $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
|
||||
|
||||
app_sql_postgres.so: app_sql_postgres.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -L/usr/local/pgsql/lib -lpq
|
||||
|
||||
app_sql_odbc.so: app_sql_odbc.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lodbc
|
||||
|
||||
look: look.c
|
||||
$(CC) -pipe -O6 -g look.c -o look -lncurses
|
||||
|
||||
ifeq (SunOS,$(shell uname))
|
||||
app_chanspy.so: app_chanspy.o
|
||||
$(CC) $(SOLINK) -o $@ $< -lrt
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
depend: .depend
|
||||
|
||||
.depend:
|
||||
../build_tools/mkdep $(CFLAGS) `ls *.c`
|
||||
|
||||
env:
|
||||
env
|
||||
|
||||
@@ -17,22 +17,11 @@
|
||||
*/
|
||||
|
||||
/*! \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 <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
@@ -43,6 +32,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -53,6 +46,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
|
||||
static char *tdesc = "Asterisk ADSI Programming Application";
|
||||
|
||||
static char *app = "ADSIProg";
|
||||
|
||||
static char *synopsis = "Load Asterisk ADSI Scripts into phone";
|
||||
@@ -63,6 +58,10 @@ 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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct adsi_event {
|
||||
int id;
|
||||
char *name;
|
||||
@@ -1357,16 +1356,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 */
|
||||
@@ -1444,11 +1444,11 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
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 +1462,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 +1475,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 +1486,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 +1499,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 +1510,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 +1523,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 +1531,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 +1544,21 @@ 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;
|
||||
struct localuser *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (ast_strlen_zero(data))
|
||||
data = "asterisk.adsi";
|
||||
|
||||
if (!ast_adsi_available(chan)) {
|
||||
if (!adsi_available(chan)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "ADSI Unavailable on CPE. Not bothering to try.\n");
|
||||
} else {
|
||||
@@ -1567,26 +1567,40 @@ static int adsi_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -22,17 +22,13 @@
|
||||
*
|
||||
* *** 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -41,6 +37,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -56,7 +56,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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,9 +67,11 @@ 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"
|
||||
@@ -93,10 +94,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
|
||||
@@ -136,7 +145,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 +215,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 +222,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;
|
||||
}
|
||||
}
|
||||
@@ -549,9 +556,9 @@ 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;
|
||||
@@ -571,11 +578,17 @@ 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));
|
||||
@@ -626,13 +639,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,13 +654,13 @@ 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);
|
||||
LOCAL_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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -666,7 +679,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;
|
||||
}
|
||||
}
|
||||
@@ -721,7 +734,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -733,7 +746,7 @@ 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 */
|
||||
|
||||
@@ -743,7 +756,6 @@ static int load_config(void)
|
||||
|
||||
if(option_verbose >= 4)
|
||||
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
|
||||
@@ -810,7 +822,7 @@ static int load_config(void)
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -819,23 +831,36 @@ static int load_config(void)
|
||||
*/
|
||||
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
if(load_config())
|
||||
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
|
||||
else
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
load_config();
|
||||
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
430
apps/app_amd.c
430
apps/app_amd.c
@@ -1,430 +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");
|
||||
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,
|
||||
);
|
||||
@@ -17,24 +17,21 @@
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Execute arbitrary authenticate commands
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -44,33 +41,17 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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"
|
||||
" Authenticate(password[|options]): This application asks the caller to enter a\n"
|
||||
"given password in order to continue dialplan execution. If the password begins\n"
|
||||
"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"
|
||||
@@ -85,96 +66,79 @@ static char *descrip =
|
||||
" 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"
|
||||
;
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int auth_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int jump = 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)) {
|
||||
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 = "";
|
||||
if (strchr(opts, 'j'))
|
||||
jump = 1;
|
||||
/* 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)) {
|
||||
fgets(buf, sizeof(buf), f);
|
||||
if (!feof(f) && !ast_strlen_zero(buf)) {
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
if (strchr(opts, 'm')) {
|
||||
md5secret = strchr(buf, ':');
|
||||
if (md5secret == NULL)
|
||||
continue;
|
||||
@@ -182,13 +146,13 @@ static int auth_exec(struct ast_channel *chan, void *data)
|
||||
md5secret++;
|
||||
ast_md5_hash(md5passwd, passwd);
|
||||
if (!strcmp(md5passwd, md5secret)) {
|
||||
if (ast_test_flag(&flags,OPT_ACCOUNT))
|
||||
if (strchr(opts, 'a'))
|
||||
ast_cdr_setaccount(chan, buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(passwd, buf)) {
|
||||
if (ast_test_flag(&flags,OPT_ACCOUNT))
|
||||
if (strchr(opts, 'a'))
|
||||
ast_cdr_setaccount(chan, buf);
|
||||
break;
|
||||
}
|
||||
@@ -197,7 +161,7 @@ static int auth_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
fclose(f);
|
||||
if (!ast_strlen_zero(buf)) {
|
||||
if (ast_test_flag(&flags,OPT_MULTIPLE)) {
|
||||
if (strchr(opts, 'm')) {
|
||||
if (md5secret && !strcmp(md5passwd, md5secret))
|
||||
break;
|
||||
} else {
|
||||
@@ -206,23 +170,23 @@ static int auth_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
}
|
||||
} 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') && !strchr(opts, 'm'))
|
||||
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) {
|
||||
if (jump && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
|
||||
res = 0;
|
||||
} else {
|
||||
if (!ast_streamfile(chan, "vm-goodbye", chan->language))
|
||||
@@ -230,25 +194,39 @@ static int auth_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -17,25 +17,25 @@
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Applications connected with CDR engine
|
||||
*
|
||||
* Martin Pycko <martinp@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/pbx.h"
|
||||
|
||||
|
||||
static char *tdesc = "Tell Asterisk to not maintain a CDR for the current call";
|
||||
|
||||
static char *nocdr_descrip =
|
||||
" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n"
|
||||
"current call.\n";
|
||||
@@ -43,36 +43,55 @@ static char *nocdr_descrip =
|
||||
static char *nocdr_app = "NoCDR";
|
||||
static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int nocdr_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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);
|
||||
LOCAL_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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -18,19 +18,11 @@
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Check if Channel is Available
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
* \author James Golovich <james@gnuinter.net>
|
||||
|
||||
* \brief Check if Channel is Available
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -38,6 +30,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -48,6 +44,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/devicestate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Check channel availability";
|
||||
|
||||
static char *app = "ChanIsAvail";
|
||||
|
||||
static char *synopsis = "Check channel availability";
|
||||
@@ -63,37 +61,36 @@ static char *descrip =
|
||||
" 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";
|
||||
|
||||
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;
|
||||
struct localuser *u;
|
||||
char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur, *options, *stringp;
|
||||
struct ast_channel *tempchan;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(reqchans);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
info = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, info);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 's'))
|
||||
stringp = info;
|
||||
strsep(&stringp, "|");
|
||||
options = strsep(&stringp, "|");
|
||||
if (options) {
|
||||
if (strchr(options, 's'))
|
||||
option_state = 1;
|
||||
if (strchr(args.options, 'j'))
|
||||
if (strchr(options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
peers = args.reqchans;
|
||||
peers = info;
|
||||
if (peers) {
|
||||
cur = peers;
|
||||
do {
|
||||
@@ -107,7 +104,7 @@ 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
*number = '\0';
|
||||
@@ -142,32 +139,47 @@ static int chanavail_exec(struct ast_channel *chan, void *data)
|
||||
if (res < 1) {
|
||||
pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
|
||||
pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
|
||||
if (priority_jump || ast_opt_priority_jumping) {
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
1041
apps/app_chanspy.c
1041
apps/app_chanspy.c
File diff suppressed because it is too large
Load Diff
@@ -17,22 +17,19 @@
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to control playback of a sound file
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -44,6 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static const char *tdesc = "Control Playback Application";
|
||||
|
||||
static const char *app = "ControlPlayback";
|
||||
|
||||
static const char *synopsis = "Play a file with fast forward and rewind";
|
||||
@@ -66,6 +65,9 @@ static const char *descrip =
|
||||
" CPLAYBACKSTATUS - This variable contains the status of the attempt as a text\n"
|
||||
" string, one of: SUCCESS | USERSTOPPED | ERROR\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int is_on_phonepad(char key)
|
||||
{
|
||||
@@ -76,7 +78,7 @@ static int controlplayback_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0, priority_jump = 0;
|
||||
int skipms = 0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
char *tmp;
|
||||
int argc;
|
||||
char *argv[8];
|
||||
@@ -96,7 +98,7 @@ static int controlplayback_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
memset(argv, 0, sizeof(argv));
|
||||
@@ -105,7 +107,7 @@ static int controlplayback_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
if (argc < 1) {
|
||||
ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -132,12 +134,12 @@ static int controlplayback_exec(struct ast_channel *chan, void *data)
|
||||
res = ast_control_streamfile(chan, argv[arg_file], argv[arg_fwd], argv[arg_rev], argv[arg_stop], argv[arg_pause], argv[arg_restart], skipms);
|
||||
|
||||
/* If we stopped on one of our stop keys, return 0 */
|
||||
if (res > 0 && argv[arg_stop] && strchr(argv[arg_stop], res)) {
|
||||
if (argv[arg_stop] && strchr(argv[arg_stop], res)) {
|
||||
res = 0;
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
|
||||
} else {
|
||||
if (res < 0) {
|
||||
if (priority_jump || ast_opt_priority_jumping) {
|
||||
if (priority_jump || option_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");
|
||||
}
|
||||
@@ -148,21 +150,41 @@ static int controlplayback_exec(struct ast_channel *chan, void *data)
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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 (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
256
apps/app_curl.c
Normal file
256
apps/app_curl.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2004 - 2005, Tilghman Lesher
|
||||
*
|
||||
* Tilghman Lesher <curl-20050919@the-tilghman.com>
|
||||
* and Brian Wilkins <bwilkins@cfl.rr.com> (Added POST option)
|
||||
*
|
||||
* app_curl.c is distributed with no restrictions on usage or
|
||||
* redistribution.
|
||||
*
|
||||
* 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 Curl - App to load a URL
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#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/cli.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Load external URL";
|
||||
|
||||
static char *app = "Curl";
|
||||
|
||||
static char *synopsis = "Load an external URL";
|
||||
|
||||
static char *descrip =
|
||||
" Curl(URL[|postdata]): This application will request the specified URL.\n"
|
||||
"It is mainly used for signalling external applications of an event.\n"
|
||||
"Parameters:\n"
|
||||
" URL - This is the external URL to request.\n"
|
||||
" postdata - This information will be treated as POST data.\n"
|
||||
"This application will set the following variable:\n"
|
||||
" CURL - This variable will contain the resulting page.\n"
|
||||
"This application has been deprecated in favor of the CURL function.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static void *myrealloc(void *ptr, size_t size)
|
||||
{
|
||||
/* There might be a realloc() out there that doesn't like reallocing
|
||||
NULL pointers, so we take care of it here */
|
||||
if (ptr)
|
||||
return realloc(ptr, size);
|
||||
else
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
{
|
||||
register int realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)data;
|
||||
|
||||
mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1);
|
||||
if (mem->memory) {
|
||||
memcpy(&(mem->memory[mem->size]), ptr, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
}
|
||||
return realsize;
|
||||
}
|
||||
|
||||
static int curl_internal(struct MemoryStruct *chunk, char *url, char *post)
|
||||
{
|
||||
CURL *curl;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "asterisk-libcurl-agent/1.0");
|
||||
|
||||
if (post) {
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);
|
||||
}
|
||||
|
||||
curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int curl_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *info, *post_data=NULL, *url;
|
||||
struct MemoryStruct chunk = { NULL, 0 };
|
||||
static int dep_warning = 0;
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application Curl is deprecated. Please use the CURL() function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Curl requires an argument (URL)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if ((info = ast_strdupa(data))) {
|
||||
url = strsep(&info, "|");
|
||||
post_data = info;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! curl_internal(&chunk, url, post_data)) {
|
||||
if (chunk.memory) {
|
||||
chunk.memory[chunk.size] = '\0';
|
||||
if (chunk.memory[chunk.size - 1] == 10)
|
||||
chunk.memory[chunk.size - 1] = '\0';
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "CURL", chunk.memory);
|
||||
|
||||
free(chunk.memory);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *acf_curl_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
struct localuser *u;
|
||||
char *info, *post_data=NULL, *url;
|
||||
struct MemoryStruct chunk = { NULL, 0 };
|
||||
|
||||
*buf = '\0';
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
|
||||
return buf;
|
||||
}
|
||||
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
info = ast_strdupa(data);
|
||||
if (!info) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
url = strsep(&info, "|");
|
||||
post_data = info;
|
||||
|
||||
if (! curl_internal(&chunk, url, post_data)) {
|
||||
if (chunk.memory) {
|
||||
chunk.memory[chunk.size] = '\0';
|
||||
if (chunk.memory[chunk.size - 1] == 10)
|
||||
chunk.memory[chunk.size - 1] = '\0';
|
||||
|
||||
ast_copy_string(buf, chunk.memory, len);
|
||||
free(chunk.memory);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ast_custom_function acf_curl = {
|
||||
.name = "CURL",
|
||||
.synopsis = "Retrieves the contents of a URL",
|
||||
.syntax = "CURL(url[|post-data])",
|
||||
.desc =
|
||||
" url - URL to retrieve\n"
|
||||
" post-data - Optional data to send as a POST (GET is default action)\n",
|
||||
.read = acf_curl_exec,
|
||||
};
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_unregister(&acf_curl);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_register(&acf_curl);
|
||||
res |= ast_register_application(app, curl_exec, synopsis, descrip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2003-2006 Tilghman Lesher. All rights reserved.
|
||||
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_cut__v003@the-tilghman.com>
|
||||
*
|
||||
@@ -16,23 +16,20 @@
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief CUT function
|
||||
* \brief Cut application
|
||||
*
|
||||
* \author Tilghman Lesher <app_cut__v003@the-tilghman.com>
|
||||
*
|
||||
* \ingroup functions
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
@@ -44,6 +41,37 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
static char *tdesc = "Cut out information from a string";
|
||||
|
||||
static char *app_cut = "Cut";
|
||||
|
||||
static char *cut_synopsis = "Splits a variable's contents using the specified delimiter";
|
||||
|
||||
static char *cut_descrip =
|
||||
" Cut(newvar=varname,delimiter,fieldspec): This applicaiton will split the\n"
|
||||
"contents of a variable based on the given delimeter and store the result in\n"
|
||||
"a new variable.\n"
|
||||
"Parameters:\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"
|
||||
"This application has been deprecated in favor of the CUT function.\n";
|
||||
|
||||
static char *app_sort = "Sort";
|
||||
static char *app_sort_synopsis = "Sorts a list of keywords and values";
|
||||
static char *app_sort_descrip =
|
||||
" Sort(newvar=key1:val1[,key2:val2[[...],keyN:valN]]): This application will\n"
|
||||
"sort the list provided in ascending order. The result will be stored in the\n"
|
||||
"specified variable name.\n"
|
||||
" This applicaiton has been deprecated in favor of the SORT function.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct sortable_keys {
|
||||
char *key;
|
||||
float value;
|
||||
@@ -52,12 +80,13 @@ struct sortable_keys {
|
||||
static int sort_subroutine(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct sortable_keys *one=arg1, *two=arg2;
|
||||
if (one->value < two->value)
|
||||
if (one->value < two->value) {
|
||||
return -1;
|
||||
else if (one->value == two->value)
|
||||
} else if (one->value == two->value) {
|
||||
return 0;
|
||||
else
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define ERROR_NOARG (-1)
|
||||
@@ -72,17 +101,25 @@ static int sort_internal(struct ast_channel *chan, char *data, char *buffer, siz
|
||||
|
||||
memset(buffer, 0, buflen);
|
||||
|
||||
if (!data)
|
||||
if (!data) {
|
||||
return ERROR_NOARG;
|
||||
}
|
||||
|
||||
strings = ast_strdupa(data);
|
||||
strings = ast_strdupa((char *)data);
|
||||
if (!strings) {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
|
||||
for (ptrkey = strings; *ptrkey; ptrkey++) {
|
||||
if (*ptrkey == '|')
|
||||
if (*ptrkey == '|') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
sortable_keys = alloca(count * sizeof(struct sortable_keys));
|
||||
if (!sortable_keys) {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
|
||||
memset(sortable_keys, 0, count * sizeof(struct sortable_keys));
|
||||
|
||||
@@ -94,7 +131,8 @@ static int sort_internal(struct ast_channel *chan, char *data, char *buffer, siz
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
*ptrvalue++ = '\0';
|
||||
*ptrvalue = '\0';
|
||||
ptrvalue++;
|
||||
sortable_keys[count2].key = ptrkey;
|
||||
sscanf(ptrvalue, "%f", &sortable_keys[count2].value);
|
||||
count2++;
|
||||
@@ -117,47 +155,42 @@ static int sort_internal(struct ast_channel *chan, char *data, char *buffer, siz
|
||||
|
||||
static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
|
||||
{
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(varname);
|
||||
AST_APP_ARG(delimiter);
|
||||
AST_APP_ARG(field);
|
||||
);
|
||||
char *s, *args[3], *varname=NULL, *delimiter=NULL, *field=NULL;
|
||||
int args_okay = 0;
|
||||
|
||||
memset(buffer, 0, buflen);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
memset(buffer, 0, buflen);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if(args.argc < 3){
|
||||
return ERROR_NOARG;
|
||||
} else {
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
ast_app_separate_args(s, '|', args, 3);
|
||||
varname = args[0];
|
||||
delimiter = args[1];
|
||||
field = args[2];
|
||||
|
||||
if (field) {
|
||||
args_okay = 1;
|
||||
}
|
||||
} else {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (args_okay) {
|
||||
char d, ds[2];
|
||||
char *tmp = alloca(strlen(args.varname) + 4);
|
||||
char *tmp = alloca(strlen(varname) + 4);
|
||||
char varvalue[MAXRESULT], *tmp2=varvalue;
|
||||
|
||||
if (tmp) {
|
||||
snprintf(tmp, strlen(args.varname) + 4, "${%s}", args.varname);
|
||||
snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
|
||||
memset(varvalue, 0, sizeof(varvalue));
|
||||
} else {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
|
||||
if (args.delimiter[0] == '\\') {
|
||||
if (args.delimiter[1] == 'n')
|
||||
d = '\n';
|
||||
else if (args.delimiter[1] == 't')
|
||||
d = '\t';
|
||||
else if (args.delimiter[1] == 'r')
|
||||
d = '\r';
|
||||
else if (args.delimiter[1])
|
||||
d = args.delimiter[1];
|
||||
else
|
||||
d = '-';
|
||||
} else if (args.delimiter[0])
|
||||
d = args.delimiter[0];
|
||||
if (delimiter[0])
|
||||
d = delimiter[0];
|
||||
else
|
||||
d = '-';
|
||||
|
||||
@@ -168,8 +201,8 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size
|
||||
|
||||
if (tmp2) {
|
||||
int curfieldnum = 1;
|
||||
while (tmp2 != NULL && args.field != NULL) {
|
||||
char *nextgroup = strsep(&(args.field), "&");
|
||||
while ((tmp2 != NULL) && (field != NULL)) {
|
||||
char *nextgroup = strsep(&field, "&");
|
||||
int num1 = 0, num2 = MAXRESULT;
|
||||
char trashchar;
|
||||
|
||||
@@ -190,44 +223,146 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size
|
||||
|
||||
/* Get to start, if any */
|
||||
if (num1 > 0) {
|
||||
while (tmp2 != (char *)NULL + 1 && curfieldnum < num1) {
|
||||
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))
|
||||
if ((num1 > 0) && (curfieldnum > num1)) {
|
||||
ast_log(LOG_WARNING, "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) {
|
||||
while ((tmp2 != NULL) && (curfieldnum <= num2)) {
|
||||
char *tmp3 = strsep(&tmp2, ds);
|
||||
int curlen = strlen(buffer);
|
||||
|
||||
if (curlen)
|
||||
if (curlen) {
|
||||
snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3);
|
||||
else
|
||||
} else {
|
||||
snprintf(buffer, buflen, "%s", tmp3);
|
||||
}
|
||||
|
||||
curfieldnum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ERROR_NOARG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
static int sort_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
int ret = -1;
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *varname, *strings, result[512] = "";
|
||||
static int dep_warning=0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application Sort is deprecated. Please use the SORT() function instead.\n");
|
||||
dep_warning=1;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
ast_log(LOG_ERROR, "Sort() requires an argument\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
strings = ast_strdupa((char *)data);
|
||||
if (!strings) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
varname = strsep(&strings, "=");
|
||||
switch (sort_internal(chan, strings, result, sizeof(result))) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "Sort() requires an argument\n");
|
||||
res = 0;
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
break;
|
||||
case 0:
|
||||
pbx_builtin_setvar_helper(chan, varname, result);
|
||||
res = 0;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
res = -1;
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cut_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s, *newvar=NULL, result[512];
|
||||
static int dep_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application Cut is deprecated. Please use the CUT() function instead.\n");
|
||||
dep_warning=1;
|
||||
}
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
newvar = strsep(&s, "=");
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cut_internal(chan, s, result, sizeof(result))) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "Cut() requires an argument\n");
|
||||
res = 0;
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
break;
|
||||
case ERROR_USAGE:
|
||||
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
|
||||
res = 0;
|
||||
break;
|
||||
case 0:
|
||||
pbx_builtin_setvar_helper(chan, newvar, result);
|
||||
res = 0;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
res = -1;
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
switch (sort_internal(chan, data, buf, len)) {
|
||||
case ERROR_NOARG:
|
||||
@@ -237,48 +372,37 @@ static int acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
break;
|
||||
case 0:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return ret;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int acf_cut_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
static char *acf_cut_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
int ret = -1;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct localuser *u;
|
||||
|
||||
if (chan) {
|
||||
u = ast_module_user_add(chan);
|
||||
}
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
switch (cut_internal(chan, data, buf, len)) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
|
||||
ast_log(LOG_ERROR, "CUT() requires an argument\n");
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
break;
|
||||
case ERROR_USAGE:
|
||||
ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n");
|
||||
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
|
||||
break;
|
||||
case 0:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
}
|
||||
|
||||
if (chan) {
|
||||
ast_module_user_remove(u);
|
||||
}
|
||||
|
||||
return ret;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ast_custom_function acf_sort = {
|
||||
@@ -305,26 +429,45 @@ struct ast_custom_function acf_cut = {
|
||||
.read = acf_cut_exec,
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
int res;
|
||||
|
||||
res |= ast_custom_function_unregister(&acf_cut);
|
||||
res = ast_custom_function_unregister(&acf_cut);
|
||||
res |= ast_custom_function_unregister(&acf_sort);
|
||||
res |= ast_unregister_application(app_sort);
|
||||
res |= ast_unregister_application(app_cut);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
int res;
|
||||
|
||||
res |= ast_custom_function_register(&acf_cut);
|
||||
res = ast_custom_function_register(&acf_cut);
|
||||
res |= ast_custom_function_register(&acf_sort);
|
||||
res |= ast_register_application(app_sort, sort_exec, app_sort_synopsis, app_sort_descrip);
|
||||
res |= ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Cut out information from a string");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
101
apps/app_datetime.c
Normal file
101
apps/app_datetime.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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 Time of day - Report the time of day
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#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/say.h"
|
||||
|
||||
static char *tdesc = "Date and Time";
|
||||
|
||||
static char *app = "DateTime";
|
||||
|
||||
static char *synopsis = "Say the date and time";
|
||||
|
||||
static char *descrip =
|
||||
" DateTime(): This application will say the current date and time.\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)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
214
apps/app_db.c
214
apps/app_db.c
@@ -22,22 +22,19 @@
|
||||
*
|
||||
* \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -48,38 +45,65 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
/*! \todo XXX Remove this application after 1.4 is relased */
|
||||
static char *tdesc = "Database Access Functions";
|
||||
|
||||
static char *g_descrip =
|
||||
" DBget(varname=family/key[|options]): This application will retrieve a value\n"
|
||||
"from the Asterisk database and store it in the given variable.\n"
|
||||
" Options:\n"
|
||||
" j - Jump to priority n+101 if the requested family/key isn't found.\n"
|
||||
" This application sets the following channel variable upon completion:\n"
|
||||
" DBGETSTATUS - This variable will contain the status of the attempt\n"
|
||||
" FOUND | NOTFOUND \n"
|
||||
" This application has been deprecated in favor of the DB function.\n";
|
||||
|
||||
static char *p_descrip =
|
||||
" DBput(family/key=value): This application will store the given value in the\n"
|
||||
"specified location in the Asterisk database.\n"
|
||||
" This application has been deprecated in favor of the DB function.\n";
|
||||
|
||||
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): This applicaiton will delete a key from the Asterisk\n"
|
||||
"database.\n";
|
||||
|
||||
static char *dt_descrip =
|
||||
" DBdeltree(family[/keytree]): This application will delete a family or keytree\n"
|
||||
"from the Asterisk database\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;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int deltree_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *family, *keytree;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log(LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
if (ast_strlen_zero(keytree))
|
||||
@@ -101,7 +125,7 @@ static int deltree_exec(struct ast_channel *chan, void *data)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: Error deleting key from database.\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -109,24 +133,23 @@ static int deltree_exec(struct ast_channel *chan, void *data)
|
||||
static int del_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *family, *key;
|
||||
struct ast_module_user *u;
|
||||
static int deprecation_warning = 0;
|
||||
struct localuser *u;
|
||||
|
||||
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");
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log (LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
if (option_verbose > 2)
|
||||
@@ -139,29 +162,162 @@ static int del_exec(struct ast_channel *chan, void *data)
|
||||
ast_log(LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
static int put_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *value, *family, *key;
|
||||
static int dep_warning = 0;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the ${DB(family/key)} function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log(LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
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");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *varname, *family, *key, *options = NULL;
|
||||
char dbresult[256];
|
||||
static int dep_warning = 0;
|
||||
int priority_jump = 0;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the ${DB(family/key)} function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log(LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(argv, '=') && strchr(argv, '/')) {
|
||||
varname = strsep(&argv, "=");
|
||||
family = strsep(&argv, "/");
|
||||
if (strchr((void *)&argv, '|')) {
|
||||
key = strsep(&argv, "|");
|
||||
options = strsep(&argv, "\0");
|
||||
} else
|
||||
key = strsep(&argv, "\0");
|
||||
|
||||
if (!varname || !family || !key) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
if (strchr(options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
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);
|
||||
pbx_builtin_setvar_helper(chan, "DBGETSTATUS", "FOUND");
|
||||
} else {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBget: Value not found in database.\n");
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
/* Send the call to n+101 priority, where n is the current priority */
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "DBGETSTATUS", "NOTFOUND");
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = ast_unregister_application(dt_app);
|
||||
retval |= ast_unregister_application(d_app);
|
||||
retval |= ast_unregister_application(p_app);
|
||||
retval |= ast_unregister_application(g_app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
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(g_app, get_exec, g_synopsis, g_descrip);
|
||||
retval |= ast_register_application(p_app, put_exec, p_synopsis, p_descrip);
|
||||
retval |= ast_register_application(d_app, del_exec, d_synopsis, d_descrip);
|
||||
retval |= ast_register_application(dt_app, deltree_exec, dt_synopsis, dt_descrip);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database Access Functions");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
1802
apps/app_dial.c
1802
apps/app_dial.c
File diff suppressed because it is too large
Load Diff
@@ -22,20 +22,18 @@
|
||||
*
|
||||
* \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 <sys/stat.h> /* for mkdir */
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -46,12 +44,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Virtual Dictation Machine";
|
||||
static char *app = "Dictate";
|
||||
static char *synopsis = "Virtual Dictation Machine";
|
||||
static char *desc = " Dictate([<base_dir>[|<filename>]])\n"
|
||||
static char *desc = " Dictate([<base_dir>])\n"
|
||||
"Start dictation machine using optional base dir for files.\n";
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
typedef enum {
|
||||
DFLAG_RECORD = (1 << 0),
|
||||
DFLAG_PLAY = (1 << 1),
|
||||
@@ -78,20 +80,16 @@ static int play_and_wait(struct ast_channel *chan, char *file, char *digits)
|
||||
|
||||
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 *mydata, *argv[2], *path = NULL, filein[256];
|
||||
char dftbase[256];
|
||||
char *base;
|
||||
struct ast_flags flags = {0};
|
||||
struct ast_filestream *fs;
|
||||
struct ast_frame *f = NULL;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
int ffactor = 320 * 80,
|
||||
res = 0,
|
||||
argc = 0,
|
||||
done = 0,
|
||||
oldr = 0,
|
||||
lastop = 0,
|
||||
@@ -102,43 +100,35 @@ static int dictate_exec(struct ast_channel *chan, void *data)
|
||||
maxlen = 0,
|
||||
mode = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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 (!ast_strlen_zero(data) && (mydata = ast_strdupa(data))) {
|
||||
argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
}
|
||||
|
||||
if (args.argc && !ast_strlen_zero(args.base)) {
|
||||
base = args.base;
|
||||
if (argc) {
|
||||
base = argv[0];
|
||||
} 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);
|
||||
LOCAL_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 = "";
|
||||
for(res = 0; !res;) {
|
||||
if (ast_app_getdata(chan, "dictate/enter_filename", filein, sizeof(filein), 0) ||
|
||||
ast_strlen_zero(filein)) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
mkdir(base, 0755);
|
||||
len = strlen(base) + strlen(filein) + 2;
|
||||
if (!path || len > maxlen) {
|
||||
@@ -267,8 +257,7 @@ static int dictate_exec(struct ast_channel *chan, void *data)
|
||||
if (lastop != DFLAG_PLAY) {
|
||||
lastop = DFLAG_PLAY;
|
||||
ast_closestream(fs);
|
||||
if (!(fs = ast_openstream(chan, path, chan->language)))
|
||||
break;
|
||||
fs = ast_openstream(chan, path, chan->language);
|
||||
ast_seekstream(fs, samples, SEEK_SET);
|
||||
chan->stream = NULL;
|
||||
}
|
||||
@@ -330,20 +319,40 @@ static int dictate_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, dictate_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,20 +20,18 @@
|
||||
*
|
||||
* \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -41,141 +39,131 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define PICKUPMARK "PICKUPMARK"
|
||||
|
||||
static const char *tdesc = "Directed Call Pickup Application";
|
||||
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"
|
||||
" Pickup(extension[@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\".";
|
||||
"context will be used.\n";
|
||||
|
||||
/* Perform actual pickup between two channels */
|
||||
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
|
||||
{
|
||||
int res = 0;
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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) &&
|
||||
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;
|
||||
struct localuser *u = NULL;
|
||||
struct ast_channel *origin = NULL, *target = NULL;
|
||||
char *tmp = NULL, *exten = NULL, *context = NULL;
|
||||
char workspace[256] = "";
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Pickup requires an argument (extension)!\n");
|
||||
ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* 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);
|
||||
/* Get the extension and context if present */
|
||||
exten = data;
|
||||
context = strchr(data, '@');
|
||||
if (context) {
|
||||
*context = '\0';
|
||||
context++;
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
/* Find a channel to pickup */
|
||||
origin = ast_get_channel_by_exten_locked(exten, context);
|
||||
if (origin && origin->cdr) {
|
||||
ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace,
|
||||
sizeof(workspace), 0);
|
||||
if (tmp) {
|
||||
/* We have a possible channel... now we need to find it! */
|
||||
target = ast_get_channel_by_name_locked(tmp);
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No target channel found.\n");
|
||||
res = -1;
|
||||
}
|
||||
ast_mutex_unlock(&origin->lock);
|
||||
} else {
|
||||
if (origin)
|
||||
ast_mutex_unlock(&origin->lock);
|
||||
ast_log(LOG_DEBUG, "No originating channel found.\n");
|
||||
}
|
||||
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING))) {
|
||||
ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name,
|
||||
chan->name);
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
res = ast_queue_control(chan, AST_CONTROL_ANSWER);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n",
|
||||
chan->name);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
res = ast_channel_masquerade(target, chan);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No call pickup possible...\n");
|
||||
res = -1;
|
||||
}
|
||||
/* Done */
|
||||
out:
|
||||
if (target)
|
||||
ast_mutex_unlock(&target->lock);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, pickup_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -19,21 +19,19 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Provide a directory of extensions
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -43,18 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
@@ -63,7 +51,7 @@ static char *descrip =
|
||||
"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"
|
||||
" This applicaiton will immediate 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"
|
||||
@@ -74,10 +62,8 @@ static char *descrip =
|
||||
" 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";
|
||||
" instead of using the last name.\n";
|
||||
|
||||
/* For simplicity, I'm keeping the format compatible with the voicemail config,
|
||||
but i'm open to suggestions for isolating it */
|
||||
@@ -87,127 +73,15 @@ static char *descrip =
|
||||
/* 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,79 +151,80 @@ 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 == '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 > -1) {
|
||||
switch (res) {
|
||||
case '1':
|
||||
/* Name selected */
|
||||
loop = 0;
|
||||
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;
|
||||
|
||||
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 == '*') /* Skip to next match in list */
|
||||
break;
|
||||
|
||||
/* Not '1', or '*', so decrement number of tries */
|
||||
res = 0;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
return(res);
|
||||
}
|
||||
@@ -361,8 +236,8 @@ static struct ast_config *realtime_directory(char *context)
|
||||
struct ast_category *cat;
|
||||
struct ast_variable *var;
|
||||
char *mailbox;
|
||||
const char *fullname;
|
||||
const char *hidefromdir;
|
||||
char *fullname;
|
||||
char *hidefromdir;
|
||||
char tmp[100];
|
||||
|
||||
/* Load flat file config. */
|
||||
@@ -389,16 +264,13 @@ static struct ast_config *realtime_directory(char *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)) ) {
|
||||
mailbox = ast_category_browse(rtdata, NULL);
|
||||
while (mailbox) {
|
||||
fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
|
||||
hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
|
||||
snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
|
||||
@@ -409,24 +281,23 @@ static struct ast_config *realtime_directory(char *context)
|
||||
ast_variable_append(cat, var);
|
||||
else
|
||||
ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
|
||||
mailbox = ast_category_browse(rtdata, 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)) {
|
||||
ast_log(LOG_WARNING,
|
||||
@@ -435,7 +306,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
return -1;
|
||||
}
|
||||
if (digit == '0') {
|
||||
if (!ast_goto_if_exists(chan, dialcontext, "o", 1) ||
|
||||
if (!ast_goto_if_exists(chan, chan->context, "o", 1) ||
|
||||
(!ast_strlen_zero(chan->macrocontext) &&
|
||||
!ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
|
||||
return 0;
|
||||
@@ -446,7 +317,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
}
|
||||
}
|
||||
if (digit == '*') {
|
||||
if (!ast_goto_if_exists(chan, dialcontext, "a", 1) ||
|
||||
if (!ast_goto_if_exists(chan, chan->context, "a", 1) ||
|
||||
(!ast_strlen_zero(chan->macrocontext) &&
|
||||
!ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) {
|
||||
return 0;
|
||||
@@ -479,7 +350,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
pos = strrchr(pos, ' ') + 1;
|
||||
conv = convert(pos);
|
||||
if (conv) {
|
||||
if (!strncmp(conv, ext, strlen(ext))) {
|
||||
if (!strcmp(conv, ext)) {
|
||||
/* Match! */
|
||||
found++;
|
||||
free(conv);
|
||||
@@ -496,7 +367,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
|
||||
@@ -523,66 +394,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;
|
||||
@@ -595,113 +411,106 @@ 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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
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;
|
||||
|
||||
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 = realtime_directory(context);
|
||||
if (!cfg) {
|
||||
ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ucfg = ast_config_load("users.conf");
|
||||
|
||||
dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
|
||||
dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
|
||||
if (ast_strlen_zero(dirintro))
|
||||
dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
|
||||
if (ast_strlen_zero(dirintro))
|
||||
dirintro = last ? "dir-intro" : "dir-intro-fn";
|
||||
if (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);
|
||||
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, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm);
|
||||
res = do_directory(chan, cfg, context, dialcontext, res, last);
|
||||
if (res > 0) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
ast_stopstream(chan);
|
||||
if (res >= 0)
|
||||
if (res >= 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ucfg)
|
||||
ast_config_destroy(ucfg);
|
||||
ast_config_destroy(cfg);
|
||||
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);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
185
apps/app_disa.c
185
apps/app_disa.c
@@ -26,16 +26,16 @@
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -47,14 +47,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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"
|
||||
"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"
|
||||
@@ -70,7 +71,7 @@ static char *descrip =
|
||||
"Be aware that using this compromises the security of your PBX.\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"
|
||||
"individual passcodes 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"
|
||||
@@ -92,9 +93,11 @@ static char *descrip =
|
||||
"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";
|
||||
"exists in the context, it will be used.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static void play_dialtone(struct ast_channel *chan, char *mailbox)
|
||||
{
|
||||
@@ -111,10 +114,10 @@ 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 i,j,k,x,did_ignore;
|
||||
int firstdigittimeout = 20000;
|
||||
int digittimeout = 10000;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
char *tmp, exten[AST_MAX_EXTENSION],acctcode[20]="";
|
||||
char pwline[256];
|
||||
char ourcidname[256],ourcidnum[256];
|
||||
@@ -128,15 +131,14 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
AST_APP_ARG(context);
|
||||
AST_APP_ARG(cid);
|
||||
AST_APP_ARG(mailbox);
|
||||
AST_APP_ARG(noanswer);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
|
||||
ast_log(LOG_WARNING, "disa requires an argument (passcode/passcode file)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (chan->pbx) {
|
||||
firstdigittimeout = chan->pbx->rtimeout*1000;
|
||||
@@ -144,13 +146,13 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
|
||||
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);
|
||||
ast_log(LOG_WARNING, "Unable to set write format to Mu-law on %s\n",chan->name);
|
||||
LOCAL_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);
|
||||
ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n",chan->name);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -158,6 +160,11 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
ast_log(LOG_DEBUG, "Responsetimeout: %d\n", firstdigittimeout);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, tmp);
|
||||
|
||||
@@ -168,15 +175,10 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
|
||||
|
||||
|
||||
special_noanswer = 0;
|
||||
if ((!args.noanswer) || strcmp(args.noanswer,"NOANSWER"))
|
||||
{
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
/* answer */
|
||||
ast_answer(chan);
|
||||
}
|
||||
} else special_noanswer = 1;
|
||||
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;
|
||||
@@ -196,7 +198,8 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
for (;;) {
|
||||
/* if outa time, give em reorder */
|
||||
if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
|
||||
((k&2) ? digittimeout : firstdigittimeout)) {
|
||||
((k&2) ? digittimeout : firstdigittimeout))
|
||||
{
|
||||
ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
|
||||
((k&1) ? "extension" : "password"),chan->name);
|
||||
break;
|
||||
@@ -207,68 +210,72 @@ 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();
|
||||
/* 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,"%d",&j) < 1) { /* nope, it must be a filename */
|
||||
if (sscanf(args.passcode,"%d",&j) < 1)
|
||||
{ /* nope, it must be a filename */
|
||||
fp = fopen(args.passcode,"r");
|
||||
if (!fp) {
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
pwline[0] = 0;
|
||||
while(fgets(pwline,sizeof(pwline) - 1,fp)) {
|
||||
if (!pwline[0])
|
||||
continue;
|
||||
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;
|
||||
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,"%d", &j) < 1)
|
||||
continue;
|
||||
/* if we got it */
|
||||
/* password must be in valid format (numeric) */
|
||||
if (sscanf(args.passcode,"%d",&j) < 1) continue;
|
||||
/* if we got it */
|
||||
if (!strcmp(exten,args.passcode)) {
|
||||
if (ast_strlen_zero(args.context))
|
||||
args.context = "disa";
|
||||
@@ -276,11 +283,12 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
args.mailbox = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
/* compare the two */
|
||||
if (strcmp(exten,args.passcode)) {
|
||||
}
|
||||
/* compare the two */
|
||||
if (strcmp(exten,args.passcode))
|
||||
{
|
||||
ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
|
||||
goto reorder;
|
||||
|
||||
@@ -294,26 +302,15 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
exten[sizeof(acctcode)] = 0;
|
||||
ast_copy_string(acctcode, exten, sizeof(acctcode));
|
||||
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, "");
|
||||
@@ -324,7 +321,7 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
did_ignore = 0;
|
||||
}
|
||||
|
||||
/* if can do some more, do it */
|
||||
/* if can do some more, do it */
|
||||
if (!ast_matchmore_extension(chan,args.context,exten,1, chan->cid.cid_num)) {
|
||||
break;
|
||||
}
|
||||
@@ -344,18 +341,18 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
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)) {
|
||||
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);
|
||||
ast_copy_string(chan->accountcode, acctcode, sizeof(chan->accountcode));
|
||||
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -367,7 +364,8 @@ 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 +374,39 @@ 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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
*
|
||||
* Anthony Minessale <anthmct@yahoo.com>
|
||||
*
|
||||
* A license has been granted to Digium (via disclaimer) for the use of
|
||||
* this code.
|
||||
* disclaimed to Digium
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
@@ -22,21 +21,19 @@
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -47,27 +44,30 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Dump Info About The Calling Channel";
|
||||
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";
|
||||
" 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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int ast_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];
|
||||
long elapsed_seconds=0;
|
||||
int hour=0, min=0, sec=0;
|
||||
char cgrp[256];
|
||||
char pgrp[256];
|
||||
|
||||
now = ast_tvnow();
|
||||
memset(buf, 0, size);
|
||||
memset(buf,0,size);
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
@@ -85,12 +85,11 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
"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"
|
||||
"NativeFormat= %d\n"
|
||||
"WriteFormat= %d\n"
|
||||
"ReadFormat= %d\n"
|
||||
"1stFileDescriptor= %d\n"
|
||||
"Framesin= %d %s\n"
|
||||
"Framesout= %d %s\n"
|
||||
@@ -105,20 +104,19 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
"Data= %s\n"
|
||||
"Blocking_in= %s\n",
|
||||
c->name,
|
||||
c->tech->type,
|
||||
c->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)"),
|
||||
(c->cid.cid_num ? c->cid.cid_num : "(N/A)"),
|
||||
(c->cid.cid_name ? c->cid.cid_name : "(N/A)"),
|
||||
(c->cid.cid_dnid ? c->cid.cid_dnid : "(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,
|
||||
c->nativeformats,
|
||||
c->writeformat,
|
||||
c->readformat,
|
||||
c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ? " (DEBUGGED)" : "",
|
||||
c->fout & 0x7fffffff, (c->fout & 0x80000000) ? " (DEBUGGED)" : "", (long)c->whentohangup,
|
||||
hour,
|
||||
min,
|
||||
sec,
|
||||
@@ -128,7 +126,7 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
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)"),
|
||||
( c-> data ? (!ast_strlen_zero(c->data) ? c->data : "(Empty)") : "(None)"),
|
||||
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
|
||||
|
||||
return 0;
|
||||
@@ -136,41 +134,59 @@ static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
|
||||
static int dumpchan_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char vars[BUFSIZ * 4];
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char vars[1024];
|
||||
char info[1024];
|
||||
int level = 0;
|
||||
static char *line = "================================================================================";
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!ast_strlen_zero(data))
|
||||
if (!ast_strlen_zero(data)) {
|
||||
level = atoi(data);
|
||||
}
|
||||
|
||||
pbx_builtin_serialize_variables(chan, vars, sizeof(vars));
|
||||
serialize_showchan(chan, info, sizeof(info));
|
||||
ast_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_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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
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");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,21 +19,19 @@
|
||||
/*! \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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -41,64 +39,85 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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. \n"
|
||||
"User can exit the application by either pressing the '#' key, \n"
|
||||
"or hanging 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);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
270
apps/app_enumlookup.c
Normal file
270
apps/app_enumlookup.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* 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 Enumlookup - lookup entry in ENUM
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#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/options.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/enum.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "ENUM Lookup";
|
||||
|
||||
static char *app = "EnumLookup";
|
||||
|
||||
static char *synopsis = "Lookup number in ENUM";
|
||||
|
||||
static char *descrip =
|
||||
" EnumLookup(exten[|option]): 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"
|
||||
"Currently, the enumservices SIP, H323, IAX, IAX2 and TEL are recognized. \n"
|
||||
"\nReturns status in the ENUMSTATUS channel variable:\n"
|
||||
" ERROR Failed to do a lookup\n"
|
||||
" <tech> Technology of the successful lookup: SIP, H323, IAX, IAX2 or TEL\n"
|
||||
" BADURI Got URI Asterisk does not understand.\n"
|
||||
" The option string may contain zero or the following character:\n"
|
||||
" 'j' -- jump to +101 priority if the lookup isn't successful.\n"
|
||||
" and jump to +51 priority on a TEL entry.\n";
|
||||
|
||||
#define ENUM_CONFIG "enum.conf"
|
||||
|
||||
static char h323driver[80] = "";
|
||||
#define H323DRIVERDEFAULT "H323"
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/*--- enumlookup_exec: Look up number in ENUM and return result */
|
||||
static int enumlookup_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0,priority_jump=0;
|
||||
char tech[80];
|
||||
char dest[80];
|
||||
char tmp[256];
|
||||
char *c,*t = NULL;
|
||||
static int dep_warning=0;
|
||||
struct localuser *u;
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(d);
|
||||
AST_APP_ARG(o);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application EnumLookup is deprecated. Please use the ENUMLOOKUP() function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
if (!parse) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
tech[0] = '\0';
|
||||
dest[0] = '\0';
|
||||
|
||||
if (args.o) {
|
||||
if (strchr(args.o, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
res = ast_get_enum(chan, args.d, dest, sizeof(dest), tech, sizeof(tech), NULL, NULL);
|
||||
|
||||
if (!res) { /* Failed to do a lookup */
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
/* Look for a "busy" place */
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "ENUMSTATUS", "ERROR");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "ENUMSTATUS", tech);
|
||||
/* 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 (priority_jump || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 51))
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
} else if (!ast_strlen_zero(tech)) {
|
||||
ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
|
||||
pbx_builtin_setvar_helper(chan, "ENUMSTATUS", "BADURI");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--- load_config: Load enum.conf and find out how to handle H.323 */
|
||||
static int load_config(void)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
char *s;
|
||||
|
||||
cfg = ast_config_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_config_destroy(cfg);
|
||||
return 0;
|
||||
}
|
||||
ast_log(LOG_NOTICE, "No ENUM Config file, using defaults\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*--- unload_module: Unload this application from PBX */
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--- load_module: Load this application into PBX */
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app, enumlookup_exec, synopsis, descrip);
|
||||
|
||||
if (!res)
|
||||
res = load_config();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--- reload: Reload configuration file */
|
||||
int reload(void)
|
||||
{
|
||||
return load_config();
|
||||
}
|
||||
|
||||
|
||||
/*--- description: Describe module */
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
127
apps/app_eval.c
Normal file
127
apps/app_eval.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_eval__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 Eval application
|
||||
*
|
||||
* \author Tilghman Lesher <app_eval__v001@the-tilghman.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#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"
|
||||
|
||||
/* 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];
|
||||
static int dep_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated in favor of the dialplan function, EVAL\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_eval);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
204
apps/app_exec.c
204
apps/app_exec.c
@@ -2,9 +2,8 @@
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
|
||||
* Portions copyright (c) 2006, Philipp Dunkel.
|
||||
*
|
||||
* Tilghman Lesher <app_exec__v002@the-tilghman.com>
|
||||
* Tilghman Lesher <app_exec__v001@the-tilghman.com>
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
@@ -20,21 +19,20 @@
|
||||
*
|
||||
* \brief Exec application
|
||||
*
|
||||
* \author Tilghman Lesher <app_exec__v002@the-tilghman.com>
|
||||
* \author Philipp Dunkel <philipp.dunkel@ebox.at>
|
||||
* \author Tilghman Lesher <app_exec__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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
@@ -45,177 +43,93 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
/* 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 = "Executes internal application";
|
||||
|
||||
static char *exec_descrip =
|
||||
"Usage: 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";
|
||||
|
||||
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";
|
||||
"see the application System. Returns whatever value the\n"
|
||||
"app returns or a non-zero value if the app cannot be found.\n";
|
||||
|
||||
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";
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
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 = -1;
|
||||
}
|
||||
}
|
||||
} 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 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;
|
||||
}
|
||||
|
||||
static int execif_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(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_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
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 ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Executes dialplan applications");
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -22,32 +22,19 @@
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
@@ -57,22 +44,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static const char *tdesc = "External IVR Interface Application";
|
||||
|
||||
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"
|
||||
" ExternalIVR(command[|arg[|arg...]]): Forks an 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";
|
||||
"See doc/README.externalivr 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__)
|
||||
@@ -82,8 +69,9 @@ struct playlist_entry {
|
||||
char filename[1];
|
||||
};
|
||||
|
||||
struct ivr_localuser {
|
||||
struct localuser {
|
||||
struct ast_channel *chan;
|
||||
struct localuser *next;
|
||||
AST_LIST_HEAD(playlist, playlist_entry) playlist;
|
||||
AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
|
||||
int abort_current_sound;
|
||||
@@ -91,9 +79,10 @@ struct ivr_localuser {
|
||||
int option_autoclear;
|
||||
};
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct gen_state {
|
||||
struct ivr_localuser *u;
|
||||
struct localuser *u;
|
||||
struct ast_filestream *stream;
|
||||
struct playlist_entry *current;
|
||||
int sample_queue;
|
||||
@@ -116,10 +105,12 @@ static void send_child_event(FILE *handle, const char event, const char *data,
|
||||
|
||||
static void *gen_alloc(struct ast_channel *chan, void *params)
|
||||
{
|
||||
struct ivr_localuser *u = params;
|
||||
struct localuser *u = params;
|
||||
struct gen_state *state;
|
||||
|
||||
if (!(state = ast_calloc(1, sizeof(*state))))
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
state->u = u;
|
||||
@@ -148,7 +139,7 @@ static void gen_release(struct ast_channel *chan, void *data)
|
||||
/* caller has the playlist locked */
|
||||
static int gen_nextfile(struct gen_state *state)
|
||||
{
|
||||
struct ivr_localuser *u = state->u;
|
||||
struct localuser *u = state->u;
|
||||
char *file_to_stream;
|
||||
|
||||
u->abort_current_sound = 0;
|
||||
@@ -160,7 +151,7 @@ static int gen_nextfile(struct gen_state *state)
|
||||
if (state->current) {
|
||||
file_to_stream = state->current->filename;
|
||||
} else {
|
||||
file_to_stream = "silence/10";
|
||||
file_to_stream = "silence-10";
|
||||
u->playing_silence = 1;
|
||||
}
|
||||
|
||||
@@ -180,7 +171,7 @@ static int gen_nextfile(struct gen_state *state)
|
||||
static struct ast_frame *gen_readframe(struct gen_state *state)
|
||||
{
|
||||
struct ast_frame *f = NULL;
|
||||
struct ivr_localuser *u = state->u;
|
||||
struct localuser *u = state->u;
|
||||
|
||||
if (u->abort_current_sound ||
|
||||
(u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
|
||||
@@ -238,8 +229,10 @@ static struct ast_generator gen =
|
||||
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 ? */
|
||||
|
||||
entry = calloc(1, sizeof(*entry) + strlen(filename) + 10);
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
strcpy(entry->filename, filename);
|
||||
@@ -249,14 +242,13 @@ static struct playlist_entry *make_entry(const char *filename)
|
||||
|
||||
static int app_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *lu;
|
||||
struct localuser *u = NULL;
|
||||
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];
|
||||
@@ -265,28 +257,24 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
AST_LIST_HEAD_INIT(&u->playlist);
|
||||
AST_LIST_HEAD_INIT(&u->finishlist);
|
||||
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;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
buf = ast_strdupa(data);
|
||||
if (!buf) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
@@ -324,21 +312,6 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
@@ -347,7 +320,7 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
close(i);
|
||||
execv(argv[0], argv);
|
||||
fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
|
||||
_exit(1);
|
||||
exit(1);
|
||||
} else {
|
||||
/* parent process */
|
||||
int child_events_fd = child_stdin[1];
|
||||
@@ -360,8 +333,6 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
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]);
|
||||
@@ -384,8 +355,6 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
@@ -474,7 +443,7 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
continue;
|
||||
|
||||
if (input[0] == 'S') {
|
||||
if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
|
||||
if (ast_fileexists(&input[2], NULL, NULL) == -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");
|
||||
@@ -493,7 +462,7 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
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) {
|
||||
if (ast_fileexists(&input[2], NULL, NULL) == -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");
|
||||
@@ -519,7 +488,7 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
} else if (ready_fd == child_errors_fd) {
|
||||
char input[1024];
|
||||
|
||||
if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) {
|
||||
if (exception || feof(child_errors)) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
|
||||
res = -1;
|
||||
break;
|
||||
@@ -552,10 +521,6 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
if (child_errors)
|
||||
fclose(child_errors);
|
||||
|
||||
if (test_available_fd > -1) {
|
||||
close(test_available_fd);
|
||||
}
|
||||
|
||||
if (child_stdin[0])
|
||||
close(child_stdin[0]);
|
||||
|
||||
@@ -577,25 +542,42 @@ static int app_exec(struct ast_channel *chan, void *data)
|
||||
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
|
||||
free(entry);
|
||||
|
||||
ast_module_user_remove(lu);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, app_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,10 @@
|
||||
/*! \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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -49,10 +39,10 @@ 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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -63,10 +53,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 +67,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 +84,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 +94,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,38 +126,16 @@ 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);
|
||||
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 +146,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 +164,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");
|
||||
@@ -262,18 +224,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 */
|
||||
ast_log(LOG_DEBUG, "Last frame\n");
|
||||
res=0;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -304,16 +265,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];
|
||||
@@ -336,19 +297,18 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
char *data;
|
||||
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);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
cfg = ast_config_load(FESTIVAL_CONFIG);
|
||||
if (!cfg) {
|
||||
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (!(host = ast_variable_retrieve(cfg, "general", "host"))) {
|
||||
@@ -369,25 +329,15 @@ 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);
|
||||
if (!data) {
|
||||
ast_log(LOG_ERROR, "Out of memery\n");
|
||||
ast_config_destroy(cfg);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intstr = strchr(data, '|');
|
||||
if (intstr) {
|
||||
@@ -405,7 +355,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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
@@ -415,7 +365,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
if (serverhost == (struct hostent *)0) {
|
||||
ast_log(LOG_WARNING,"festival_client: gethostbyname failed\n");
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
|
||||
@@ -426,7 +376,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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -453,25 +403,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 +442,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);
|
||||
@@ -525,10 +465,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
* */
|
||||
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);
|
||||
ast_log(LOG_WARNING,"Unable to read from cache/festival fd");
|
||||
return -1;
|
||||
}
|
||||
n += read_data;
|
||||
@@ -555,31 +492,41 @@ 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);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -18,26 +18,25 @@
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to flash a DAHDI trunk
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
* \brief App to flash a zap trunk
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>dahdi</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/zaptel.h>
|
||||
#else
|
||||
#include <zaptel.h>
|
||||
#endif /* __linux__ */
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
@@ -49,33 +48,28 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 oths application will only work on Zap trunks.\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 +77,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 +102,40 @@ 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)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
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 ast_register_application(app, flash_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Flash channel application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
1138
apps/app_followme.c
1138
apps/app_followme.c
File diff suppressed because it is too large
Load Diff
@@ -18,148 +18,42 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Fork CDR application
|
||||
*
|
||||
* \author Anthony Minessale anthmct@yahoo.com
|
||||
*
|
||||
* \note Development of this app Sponsored/Funded by TAAN Softworks Corp
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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/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";
|
||||
"cdr record starting from the time of the fork call\n"
|
||||
"If the option 'v' is passed all cdr variables will be passed along also.\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)
|
||||
static void ast_cdr_fork(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_cdr *cdr;
|
||||
struct ast_cdr *newcdr;
|
||||
@@ -174,94 +68,64 @@ static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, ch
|
||||
return;
|
||||
|
||||
ast_cdr_append(cdr, newcdr);
|
||||
|
||||
if (!ast_test_flag(&optflags, OPT_NORESET))
|
||||
ast_cdr_reset(newcdr, &flags);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
);
|
||||
struct localuser *u;
|
||||
|
||||
if (!chan->cdr) {
|
||||
ast_log(LOG_WARNING, "Channel does not have a CDR\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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_set2_flag(chan->cdr, strchr(data, 'v'), AST_CDR_FLAG_KEEP_VARS);
|
||||
|
||||
ast_cdr_fork(chan, flags, opts[OPT_ARG_VARSET]);
|
||||
ast_cdr_fork(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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,21 +19,19 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Get ADSI CPE ID
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -43,14 +41,19 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/adsi.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Get ADSI CPE ID";
|
||||
|
||||
static char *app = "GetCPEID";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice)
|
||||
{
|
||||
@@ -60,42 +63,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 +108,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 +126,42 @@ 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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
340
apps/app_groupcount.c
Normal file
340
apps/app_groupcount.c
Normal file
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* 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 Group Manipulation Applications
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
|
||||
#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 "asterisk/utils.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int group_count_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int count;
|
||||
struct localuser *u;
|
||||
char group[80] = "";
|
||||
char category[80] = "";
|
||||
char ret[80] = "";
|
||||
char *grp;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The GetGroupCount application has been deprecated, please use the GROUP_COUNT function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
|
||||
|
||||
if (ast_strlen_zero(group)) {
|
||||
grp = pbx_builtin_getvar_helper(chan, category);
|
||||
strncpy(group, grp, sizeof(group) - 1);
|
||||
}
|
||||
|
||||
count = ast_app_group_get_count(group, category);
|
||||
snprintf(ret, sizeof(ret), "%d", count);
|
||||
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_match_count_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int count;
|
||||
struct localuser *u;
|
||||
char group[80] = "";
|
||||
char category[80] = "";
|
||||
char ret[80] = "";
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The GetGroupMatchCount application has been deprecated, please use the GROUP_MATCH_COUNT function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
|
||||
|
||||
if (!ast_strlen_zero(group)) {
|
||||
count = ast_app_group_match_get_count(group, category);
|
||||
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;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The SetGroup application has been deprecated, please use the GROUP() function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_app_group_set_channel(chan, data))
|
||||
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 limit[80]="";
|
||||
char category[80]="";
|
||||
static int deprecation_warning = 0;
|
||||
char *parse;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(max);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The CheckGroup application has been deprecated, please use a combination of the GotoIf application and the GROUP_COUNT() function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (!(parse = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.max)) {
|
||||
ast_log(LOG_WARNING, "CheckGroup requires an argument(max[@category][|options])\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
ast_app_group_split_group(args.max, limit, sizeof(limit), category, sizeof(category));
|
||||
|
||||
if ((sscanf(limit, "%d", &max) == 1) && (max > -1)) {
|
||||
count = ast_app_group_get_count(pbx_builtin_getvar_helper(chan, category), category);
|
||||
if (count > max) {
|
||||
pbx_builtin_setvar_helper(chan, "CHECKGROUPSTATUS", "OVERMAX");
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
res = -1;
|
||||
}
|
||||
} else
|
||||
pbx_builtin_setvar_helper(chan, "CHECKGROUPSTATUS", "OK");
|
||||
} else
|
||||
ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_show_channels(int fd, int argc, char *argv[])
|
||||
{
|
||||
#define FORMAT_STRING "%-25s %-20s %-20s\n"
|
||||
|
||||
struct ast_channel *c = NULL;
|
||||
int numchans = 0;
|
||||
struct ast_var_t *current;
|
||||
struct varshead *headp;
|
||||
regex_t regexbuf;
|
||||
int havepattern = 0;
|
||||
|
||||
if (argc < 3 || argc > 4)
|
||||
return RESULT_SHOWUSAGE;
|
||||
|
||||
if (argc == 4) {
|
||||
if (regcomp(®exbuf, argv[3], REG_EXTENDED | REG_NOSUB))
|
||||
return RESULT_SHOWUSAGE;
|
||||
havepattern = 1;
|
||||
}
|
||||
|
||||
ast_cli(fd, FORMAT_STRING, "Channel", "Group", "Category");
|
||||
while ( (c = ast_channel_walk_locked(c)) != NULL) {
|
||||
headp=&c->varshead;
|
||||
AST_LIST_TRAVERSE(headp,current,entries) {
|
||||
if (!strncmp(ast_var_name(current), GROUP_CATEGORY_PREFIX "_", strlen(GROUP_CATEGORY_PREFIX) + 1)) {
|
||||
if (!havepattern || !regexec(®exbuf, ast_var_value(current), 0, NULL, 0)) {
|
||||
ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current),
|
||||
(ast_var_name(current) + strlen(GROUP_CATEGORY_PREFIX) + 1));
|
||||
numchans++;
|
||||
}
|
||||
} else if (!strcmp(ast_var_name(current), GROUP_CATEGORY_PREFIX)) {
|
||||
if (!havepattern || !regexec(®exbuf, ast_var_value(current), 0, NULL, 0)) {
|
||||
ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current), "(default)");
|
||||
numchans++;
|
||||
}
|
||||
}
|
||||
}
|
||||
numchans++;
|
||||
ast_mutex_unlock(&c->lock);
|
||||
}
|
||||
|
||||
if (havepattern)
|
||||
regfree(®exbuf);
|
||||
|
||||
ast_cli(fd, "%d active channel%s\n", numchans, (numchans != 1) ? "s" : "");
|
||||
return RESULT_SUCCESS;
|
||||
#undef FORMAT_STRING
|
||||
}
|
||||
|
||||
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 *app_group_match_count = "GetGroupMatchCount";
|
||||
|
||||
static char *group_count_synopsis = "Get the channel count of a group";
|
||||
static char *group_set_synopsis = "Set the channel's group";
|
||||
static char *group_check_synopsis = "Check the channel count of a group against a limit";
|
||||
static char *group_match_count_synopsis = "Get the channel count of all groups that match a pattern";
|
||||
|
||||
static char *group_count_descrip =
|
||||
"Usage: GetGroupCount([groupname][@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. \n"
|
||||
"Note: This application has been deprecated, please use the function\n"
|
||||
"GROUP_COUNT.\n";
|
||||
|
||||
static char *group_set_descrip =
|
||||
"Usage: SetGroup(groupname[@category])\n"
|
||||
" Sets the channel group to the specified value. Equivalent to\n"
|
||||
"Set(GROUP=group). Always returns 0.\n";
|
||||
|
||||
static char *group_check_descrip =
|
||||
"Usage: CheckGroup(max[@category][|options])\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. \n"
|
||||
" The option string may contain zero of the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the number does in fact exceed max,\n"
|
||||
" and priority n+101 exists. Execuation then continues at that\n"
|
||||
" step, otherwise -1 is returned.\n"
|
||||
" This application sets the following channel variable upon successful completion:\n"
|
||||
" CHECKGROUPSTATUS The status of the check that the current channel's\n"
|
||||
" group does not exceed 'max'. It's value is one of\n"
|
||||
" OK | OVERMAX \n";
|
||||
|
||||
static char *group_match_count_descrip =
|
||||
"Usage: GetGroupMatchCount(groupmatch[@category])\n"
|
||||
" Calculates the group count for all groups that match the specified\n"
|
||||
"pattern. Uses standard regular expression matching (see regex(7)).\n"
|
||||
"Stores result in GROUPCOUNT. Always returns 0.\n"
|
||||
"Note: This application has been deprecated, please use the function\n"
|
||||
"GROUP_MATCH_COUNT.\n";
|
||||
|
||||
static char show_channels_usage[] =
|
||||
"Usage: group show channels [pattern]\n"
|
||||
" Lists all currently active channels with channel group(s) specified.\n Optional regular expression pattern is matched to group names for each channel.\n";
|
||||
|
||||
static struct ast_cli_entry cli_show_channels =
|
||||
{ { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", show_channels_usage};
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_cli_unregister(&cli_show_channels);
|
||||
res |= ast_unregister_application(app_group_count);
|
||||
res |= ast_unregister_application(app_group_set);
|
||||
res |= ast_unregister_application(app_group_check);
|
||||
res |= ast_unregister_application(app_group_match_count);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
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);
|
||||
res |= ast_register_application(app_group_match_count, group_match_count_exec, group_match_count_synopsis, group_match_count_descrip);
|
||||
res |= ast_cli_register(&cli_show_channels);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Changes Copyright (c) 2004 - 2006 Todd Freeman <freeman@andrews.edu>
|
||||
* Changes Copyright (c) 2004 - 2005 Todd Freeman <freeman@andrews.edu>
|
||||
*
|
||||
* 95% based on HasNewVoicemail by:
|
||||
*
|
||||
@@ -24,18 +24,9 @@
|
||||
*
|
||||
* \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>
|
||||
@@ -43,6 +34,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -53,6 +48,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.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_descrip =
|
||||
@@ -63,8 +59,7 @@ static char *hasvoicemail_descrip =
|
||||
" '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";
|
||||
" <# of messages in the folder, 0 for NONE>\n";
|
||||
|
||||
static char *app_hasnewvoicemail = "HasNewVoicemail";
|
||||
static char *hasnewvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
|
||||
@@ -76,13 +71,35 @@ static char *hasnewvoicemail_descrip =
|
||||
" '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";
|
||||
" <# of messages in the folder, 0 for NONE>\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int hasvoicemail_internal(char *context, char *box, char *folder)
|
||||
{
|
||||
char vmpath[256];
|
||||
DIR *vmdir;
|
||||
struct dirent *vment;
|
||||
int count=0;
|
||||
|
||||
snprintf(vmpath,sizeof(vmpath), "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR, context, box, folder);
|
||||
if ((vmdir = opendir(vmpath))) {
|
||||
/* 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)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
closedir(vmdir);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
char *input, *varname = NULL, *vmbox, *context = "default";
|
||||
char *vmfolder;
|
||||
int vmcount = 0;
|
||||
@@ -105,16 +122,22 @@ static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
input = ast_strdupa(data);
|
||||
input = ast_strdupa((char *)data);
|
||||
if (! input) {
|
||||
ast_log(LOG_ERROR, "Out of memory error\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, input);
|
||||
|
||||
vmbox = strsep(&args.vmbox, "@");
|
||||
|
||||
if (!ast_strlen_zero(args.vmbox))
|
||||
context = args.vmbox;
|
||||
if ((vmbox = strsep(&args.vmbox, "@")))
|
||||
if (!ast_strlen_zero(args.vmbox))
|
||||
context = args.vmbox;
|
||||
if (!vmbox)
|
||||
vmbox = args.vmbox;
|
||||
|
||||
vmfolder = strchr(vmbox, '/');
|
||||
if (vmfolder) {
|
||||
@@ -129,7 +152,7 @@ static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
vmcount = ast_app_messagecount(context, vmbox, vmfolder);
|
||||
vmcount = hasvoicemail_internal(context, vmbox, vmfolder);
|
||||
/* Set the count in the channel variable */
|
||||
if (varname) {
|
||||
snprintf(tmp, sizeof(tmp), "%d", vmcount);
|
||||
@@ -138,7 +161,7 @@ static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
if (vmcount > 0) {
|
||||
/* Branch to the next extension */
|
||||
if (priority_jump || ast_opt_priority_jumping) {
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
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);
|
||||
}
|
||||
@@ -147,45 +170,46 @@ static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
snprintf(tmp, sizeof(tmp), "%d", vmcount);
|
||||
pbx_builtin_setvar_helper(chan, "HASVMSTATUS", tmp);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acf_vmcount_exec(struct ast_channel *chan, char *cmd, char *argsstr, char *buf, size_t len)
|
||||
static char *acf_vmcount_exec(struct ast_channel *chan, char *cmd, char *data, 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);
|
||||
);
|
||||
struct localuser *u;
|
||||
char *args, *context, *box, *folder;
|
||||
|
||||
if (ast_strlen_zero(argsstr))
|
||||
return -1;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, argsstr);
|
||||
args = ast_strdupa(data);
|
||||
if (!args) {
|
||||
ast_log(LOG_ERROR, "Out of memory");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (strchr(args.vmbox, '@')) {
|
||||
context = args.vmbox;
|
||||
args.vmbox = strsep(&context, "@");
|
||||
box = strsep(&args, "|");
|
||||
if (strchr(box, '@')) {
|
||||
context = box;
|
||||
box = strsep(&context, "@");
|
||||
} else {
|
||||
context = "default";
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.folder)) {
|
||||
args.folder = "INBOX";
|
||||
if (args) {
|
||||
folder = args;
|
||||
} else {
|
||||
folder = "INBOX";
|
||||
}
|
||||
|
||||
snprintf(buf, len, "%d", ast_app_messagecount(context, args.vmbox, args.folder));
|
||||
snprintf(buf, len, "%d", hasvoicemail_internal(context, box, folder));
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ast_custom_function acf_vmcount = {
|
||||
@@ -198,7 +222,7 @@ struct ast_custom_function acf_vmcount = {
|
||||
.read = acf_vmcount_exec,
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -206,12 +230,12 @@ static int unload_module(void)
|
||||
res |= ast_unregister_application(app_hasvoicemail);
|
||||
res |= ast_unregister_application(app_hasnewvoicemail);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -222,4 +246,19 @@ static int load_module(void)
|
||||
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;
|
||||
}
|
||||
|
||||
126
apps/app_ices.c
126
apps/app_ices.c
@@ -19,20 +19,10 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>working_fork</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -41,9 +31,10 @@ 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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
@@ -53,10 +44,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define path_BIN "/usr/bin/"
|
||||
#define path_LOCAL "/usr/local/bin/"
|
||||
#define ICES "/usr/bin/ices"
|
||||
#define LOCAL_ICES "/usr/local/bin/ices"
|
||||
|
||||
static char *tdesc = "Encode and Stream via icecast and ices";
|
||||
|
||||
static char *app = "ICES";
|
||||
|
||||
@@ -65,74 +57,40 @@ 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). \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;
|
||||
@@ -148,13 +106,13 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
last = ast_tv(0, 0);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
flags = fcntl(fds[1], F_GETFL);
|
||||
@@ -169,7 +127,7 @@ 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -179,11 +137,11 @@ 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);
|
||||
LOCAL_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 +149,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 +172,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,7 +179,6 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
ast_frfree(f);
|
||||
}
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
if (pid > -1)
|
||||
@@ -229,25 +186,40 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
if (!res && oreadformat)
|
||||
ast_set_read_format(chan, oreadformat);
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to transmit an image
|
||||
*
|
||||
* \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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -44,6 +42,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
@@ -59,11 +59,14 @@ static char *descrip =
|
||||
" SENDIMAGESTATUS The status is the result of the attempt as a text string, one of\n"
|
||||
" OK | NOSUPPORT \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;
|
||||
struct localuser *u;
|
||||
char *parse;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
@@ -71,9 +74,13 @@ static int sendimage_exec(struct ast_channel *chan, void *data)
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
if (!(parse = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
@@ -89,10 +96,10 @@ static int sendimage_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
if (!ast_supports_images(chan)) {
|
||||
/* Does not support transport */
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
if (priority_jump || option_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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -101,25 +108,40 @@ static int sendimage_exec(struct ast_channel *chan, void *data)
|
||||
if (!res)
|
||||
pbx_builtin_setvar_helper(chan, "SENDIMAGESTATUS", "OK");
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
234
apps/app_intercom.c
Normal file
234
apps/app_intercom.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 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 Use /dev/dsp as an intercom.
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.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
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#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"
|
||||
|
||||
#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. User can terminate\n"with a DTMF tone, or by 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!res)
|
||||
ast_set_read_format(chan, oreadformat);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (sound > -1)
|
||||
close(sound);
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -19,25 +19,19 @@
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -88,18 +82,21 @@ AST_IVR_DECLARE_MENU(ivr_demo, "IVR Demo Main Menu", 0,
|
||||
{ NULL },
|
||||
});
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
|
||||
if (ast_strlen_zero(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 */
|
||||
|
||||
@@ -108,25 +105,40 @@ static int skel_exec(struct ast_channel *chan, void *data)
|
||||
if (!res)
|
||||
res = ast_ivr_menu_run(chan, &ivr_demo, data);
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, skel_exec, tdesc, synopsis);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "IVR Demo Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -20,20 +20,18 @@
|
||||
*
|
||||
* \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 <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -47,6 +45,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
@@ -59,52 +59,21 @@ static char *descrip =
|
||||
"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";
|
||||
"Example: exten => 1234,1,LookupBlacklist()\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 blacklist[1];
|
||||
struct ast_module_user *u;
|
||||
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");
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!ast_strlen_zero(data)) {
|
||||
if (strchr(data, 'j'))
|
||||
@@ -127,34 +96,46 @@ lookupblacklist_exec (struct ast_channel *chan, void *data)
|
||||
}
|
||||
|
||||
if (bl) {
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
if (priority_jump || option_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);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \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 <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -45,6 +43,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
|
||||
static char *tdesc = "Look up CallerID Name from local database";
|
||||
|
||||
static char *app = "LookupCIDName";
|
||||
|
||||
static char *synopsis = "Look up CallerID Name from local database";
|
||||
@@ -55,49 +55,66 @@ 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.\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 dbname[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->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);
|
||||
}
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
405
apps/app_macro.c
405
apps/app_macro.c
@@ -19,22 +19,20 @@
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -50,6 +48,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
/* 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"
|
||||
@@ -60,18 +60,7 @@ static char *descrip =
|
||||
"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"
|
||||
"Extensions: While a macro is being executed, it becomes the current context.\n"
|
||||
" This means that if a hangup occurs, for instance, that the macro\n"
|
||||
" will be searched for an 'h' extension, NOT the context from which\n"
|
||||
" the macro was called. So, make sure to define all appropriate\n"
|
||||
" extensions in your macro! (you can use 'catch' in AEL) \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 macros\n"
|
||||
" could cause asterisk to crash earlier than this limit.\n";
|
||||
"at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n";
|
||||
|
||||
static char *if_descrip =
|
||||
" MacroIf(<expr>?macroname_a[|arg1][:macroname_b[|arg1]])\n"
|
||||
@@ -79,13 +68,6 @@ static char *if_descrip =
|
||||
"(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"
|
||||
@@ -95,141 +77,59 @@ static char *exit_descrip =
|
||||
|
||||
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;
|
||||
int oldpriority;
|
||||
char pc[80], depthc[12];
|
||||
char oldcontext[AST_MAX_CONTEXT] = "";
|
||||
const char *inhangupc;
|
||||
int offset, depth = 0, maxdepth = 7;
|
||||
char *offsets;
|
||||
int offset, depth;
|
||||
int setmacrocontext=0;
|
||||
int autoloopflag, inhangup = 0;
|
||||
int autoloopflag, dead = 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, ¯o_ds_info, NULL);
|
||||
struct localuser *u;
|
||||
|
||||
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(¯o_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, "%d", &maxdepth);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Count how many levels deep the rabbit hole goes */
|
||||
s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
|
||||
if (s)
|
||||
sscanf(s, "%d", &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, "%d", &inhangup);
|
||||
tmp = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
|
||||
if (tmp) {
|
||||
sscanf(tmp, "%d", &depth);
|
||||
} else {
|
||||
depth = 0;
|
||||
}
|
||||
|
||||
if (depth >= maxdepth) {
|
||||
if (depth >= 7) {
|
||||
ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
snprintf(depthc, sizeof(depthc), "%d", depth + 1);
|
||||
@@ -240,33 +140,18 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
macro = strsep(&rest, "|");
|
||||
if (ast_strlen_zero(macro)) {
|
||||
ast_log(LOG_WARNING, "Invalid macro name specified\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_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))
|
||||
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);
|
||||
ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
|
||||
LOCAL_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;
|
||||
@@ -280,17 +165,25 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
}
|
||||
argc = 1;
|
||||
/* Save old macro variables */
|
||||
save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
|
||||
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);
|
||||
|
||||
save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
|
||||
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);
|
||||
|
||||
save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
|
||||
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 = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
|
||||
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);
|
||||
|
||||
/* Setup environment for new run */
|
||||
@@ -300,49 +193,20 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
chan->priority = 1;
|
||||
|
||||
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);
|
||||
oldargs[argc] = pbx_builtin_getvar_helper(chan, varname);
|
||||
if (oldargs[argc])
|
||||
oldargs[argc] = strdup(oldargs[argc]);
|
||||
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';
|
||||
|
||||
/* 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();
|
||||
|
||||
/* 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')) ||
|
||||
@@ -361,109 +225,56 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
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);
|
||||
dead = 1;
|
||||
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 (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 && !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);
|
||||
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:
|
||||
|
||||
/* 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);
|
||||
if (!dead) {
|
||||
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]);
|
||||
if (!dead)
|
||||
pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
|
||||
free(oldargs[x]);
|
||||
} else {
|
||||
} else if (!dead) {
|
||||
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 (!dead) {
|
||||
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)
|
||||
@@ -471,36 +282,18 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
if (save_macro_priority)
|
||||
free(save_macro_priority);
|
||||
|
||||
if (setmacrocontext) {
|
||||
if (!dead && 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 (!dead && !strcasecmp(chan->context, fullmacro)) {
|
||||
/* If we're leaving the macro normally, restore original information */
|
||||
chan->priority = oldpriority;
|
||||
ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
|
||||
if (!(chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO)) {
|
||||
/* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
|
||||
const char *offsets;
|
||||
ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
|
||||
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
|
||||
@@ -514,45 +307,26 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
}
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
|
||||
if (!dead)
|
||||
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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int macro_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return _macro_exec(chan, data, 0);
|
||||
}
|
||||
|
||||
static int macroexclusive_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return _macro_exec(chan, data, 1);
|
||||
}
|
||||
|
||||
static int macroif_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *expr = NULL, *label_a = NULL, *label_b = NULL;
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(expr = ast_strdupa(data))) {
|
||||
ast_module_user_remove(u);
|
||||
expr = ast_strdupa(data);
|
||||
if (!expr) {
|
||||
ast_log(LOG_ERROR, "Out of Memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -563,14 +337,14 @@ static int macroif_exec(struct ast_channel *chan, void *data)
|
||||
*label_b = '\0';
|
||||
label_b++;
|
||||
}
|
||||
if (pbx_checkcondition(expr))
|
||||
res = macro_exec(chan, label_a);
|
||||
if (ast_true(expr))
|
||||
macro_exec(chan, label_a);
|
||||
else if (label_b)
|
||||
res = macro_exec(chan, label_b);
|
||||
macro_exec(chan, label_b);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Invalid Syntax.\n");
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -580,30 +354,43 @@ static int macro_exit_exec(struct ast_channel *chan, void *data)
|
||||
return MACRO_EXIT_RESULT;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(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_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
297
apps/app_math.c
Normal file
297
apps/app_math.c
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2004 - 2005, Andy Powell
|
||||
*
|
||||
* Updated 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 A simple math application
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#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/options.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/manager.h"
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
|
||||
static char *tdesc = "Basic Math Functions";
|
||||
|
||||
static char *app_math = "Math";
|
||||
|
||||
static char *math_synopsis = "Performs Mathematical Functions";
|
||||
|
||||
static char *math_descrip =
|
||||
"Math(returnvar,<number1><op><number 2>\n\n"
|
||||
"Perform floating point calculation on number 1 to number 2 and \n"
|
||||
"store the result in returnvar. Valid ops are: \n"
|
||||
" +,-,/,*,%,<,>,>=,<=,==\n"
|
||||
"and behave as their C equivalents.\n";
|
||||
|
||||
#define ADDFUNCTION 0
|
||||
#define DIVIDEFUNCTION 1
|
||||
#define MULTIPLYFUNCTION 2
|
||||
#define SUBTRACTFUNCTION 3
|
||||
#define MODULUSFUNCTION 4
|
||||
|
||||
#define GTFUNCTION 5
|
||||
#define LTFUNCTION 6
|
||||
#define GTEFUNCTION 7
|
||||
#define LTEFUNCTION 8
|
||||
#define EQFUNCTION 9
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int math_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
float fnum1;
|
||||
float fnum2;
|
||||
float ftmp = 0;
|
||||
char *op;
|
||||
int iaction=-1;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
/* dunno, big calulations :D */
|
||||
char user_result[30];
|
||||
|
||||
char *s;
|
||||
char *mvar, *mvalue1, *mvalue2=NULL;
|
||||
|
||||
struct localuser *u;
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "Math() is deprecated, please use Set(var=${MATH(...)} instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "No parameters passed. !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
if (!s) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mvar = strsep(&s, "|");
|
||||
mvalue1 = strsep(&s, "|");
|
||||
|
||||
if ((op = strchr(mvalue1, '+'))) {
|
||||
iaction = ADDFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '-'))) {
|
||||
iaction = SUBTRACTFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '*'))) {
|
||||
iaction = MULTIPLYFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '/'))) {
|
||||
iaction = DIVIDEFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '>'))) {
|
||||
iaction = GTFUNCTION;
|
||||
*op = '\0';
|
||||
if (*(op+1) == '=') {
|
||||
op++;
|
||||
*op = '\0';
|
||||
iaction = GTEFUNCTION;
|
||||
}
|
||||
} else if ((op = strchr(mvalue1, '<'))) {
|
||||
iaction = LTFUNCTION;
|
||||
*op = '\0';
|
||||
if (*(op+1) == '=') {
|
||||
op++;
|
||||
*op = '\0';
|
||||
iaction = LTEFUNCTION;
|
||||
}
|
||||
} else if ((op = strchr(mvalue1, '='))) {
|
||||
iaction = GTFUNCTION;
|
||||
*op = '\0';
|
||||
if (*(op+1) == '=') {
|
||||
op++;
|
||||
*op = '\0';
|
||||
iaction = EQFUNCTION;
|
||||
} else
|
||||
op = NULL;
|
||||
}
|
||||
|
||||
if (op)
|
||||
mvalue2 = op + 1;
|
||||
|
||||
if (!mvar || !mvalue1 || !mvalue2) {
|
||||
ast_log(LOG_WARNING, "Supply all the parameters - just this once, please\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp(mvar,"")) {
|
||||
ast_log(LOG_WARNING, "No return variable set.\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(mvalue1, "%f", &fnum1) != 1) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue1);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(mvalue2, "%f", &fnum2) != 1) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue2);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (iaction) {
|
||||
case ADDFUNCTION :
|
||||
ftmp = fnum1 + fnum2;
|
||||
break;
|
||||
case DIVIDEFUNCTION :
|
||||
if (fnum2 <=0)
|
||||
ftmp = 0; /* can't do a divide by 0 */
|
||||
else
|
||||
ftmp = (fnum1 / fnum2);
|
||||
break;
|
||||
case MULTIPLYFUNCTION :
|
||||
ftmp = (fnum1 * fnum2);
|
||||
break;
|
||||
case SUBTRACTFUNCTION :
|
||||
ftmp = (fnum1 - fnum2);
|
||||
break;
|
||||
case MODULUSFUNCTION : {
|
||||
int inum1 = fnum1;
|
||||
int inum2 = fnum2;
|
||||
|
||||
ftmp = (inum1 % inum2);
|
||||
|
||||
break;
|
||||
}
|
||||
case GTFUNCTION :
|
||||
if (fnum1 > fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case LTFUNCTION :
|
||||
if (fnum1 < fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case GTEFUNCTION :
|
||||
if (fnum1 >= fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case LTEFUNCTION :
|
||||
if (fnum1 <= fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case EQFUNCTION :
|
||||
if (fnum1 == fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
default :
|
||||
ast_log(LOG_WARNING, "Something happened that neither of us should be proud of %d\n", iaction);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iaction < GTFUNCTION || iaction > EQFUNCTION)
|
||||
snprintf(user_result,sizeof(user_result),"%f",ftmp);
|
||||
|
||||
pbx_builtin_setvar_helper(chan, mvar, user_result);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_math);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_math, math_exec, math_synopsis, math_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
/* Fading everything to black and blue... */
|
||||
205
apps/app_md5.c
Normal file
205
apps/app_md5.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Olle E. Johansson, Edvina.net
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief MD5 checksum application
|
||||
*
|
||||
* \todo Remove this deprecated application in 1.3dev
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc_md5 = "MD5 checksum applications";
|
||||
static char *app_md5 = "MD5";
|
||||
static char *desc_md5 = "Calculate MD5 checksum";
|
||||
static char *synopsis_md5 =
|
||||
" MD5(<var>=<string>): Calculates a MD5 checksum on <string>.\n"
|
||||
"Returns hash value in a channel variable. \n";
|
||||
|
||||
static char *app_md5check = "MD5Check";
|
||||
static char *desc_md5check = "Check MD5 checksum";
|
||||
static char *synopsis_md5check =
|
||||
" MD5Check(<md5hash>|<string>[|options]): Calculates a MD5 checksum on <string>\n"
|
||||
"and compares it with the hash. Returns 0 if <md5hash> is correct for <string>.\n"
|
||||
"The option string may contain zero or more of the following characters:\n"
|
||||
" 'j' -- jump to priority n+101 if the hash and string do not match \n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" CHECKMD5STATUS The status of the MD5 check, one of the following\n"
|
||||
" MATCH | NOMATCH\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/*--- md5_exec: Calculate MD5 checksum (hash) on given string and
|
||||
return it in channel variable ---*/
|
||||
static int md5_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *varname= NULL; /* Variable to set */
|
||||
char *string = NULL; /* String to calculate on */
|
||||
char retvar[50]; /* Return value */
|
||||
static int dep_warning = 0;
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the MD5 function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Syntax: md5(<varname>=<string>) - missing argument!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
memset(retvar,0, sizeof(retvar));
|
||||
string = ast_strdupa(data);
|
||||
varname = strsep(&string,"=");
|
||||
if (ast_strlen_zero(varname)) {
|
||||
ast_log(LOG_WARNING, "Syntax: md5(<varname>=<string>) - missing argument!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
ast_md5_hash(retvar, string);
|
||||
pbx_builtin_setvar_helper(chan, varname, retvar);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--- md5check_exec: Calculate MD5 checksum and compare it with
|
||||
existing checksum. ---*/
|
||||
static int md5check_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *string = NULL; /* String to calculate on */
|
||||
char newhash[50]; /* Return value */
|
||||
static int dep_warning = 0;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(md5hash);
|
||||
AST_APP_ARG(string);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the CHECK_MD5 function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(string = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, string);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.md5hash) || ast_strlen_zero(args.string)) {
|
||||
ast_log(LOG_WARNING, "Syntax: MD5Check(<md5hash>|<string>[|options]) - missing argument!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(newhash,0, sizeof(newhash));
|
||||
|
||||
ast_md5_hash(newhash, args.string);
|
||||
if (!strcmp(newhash, args.md5hash)) { /* Verification ok */
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "MD5 verified ok: %s -- %s\n", args.md5hash, args.string);
|
||||
pbx_builtin_setvar_helper(chan, "CHECKMD5STATUS", "MATCH");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "ERROR: MD5 not verified: %s -- %s\n", args.md5hash, args.string);
|
||||
pbx_builtin_setvar_helper(chan, "CHECKMD5STATUS", "NOMATCH");
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "Can't jump to exten+101 (e%s,p%d), sorry\n", chan->exten,chan->priority+101);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_md5);
|
||||
res |= ast_unregister_application(app_md5check);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app_md5check, md5check_exec, desc_md5check, synopsis_md5check);
|
||||
res |= ast_register_application(app_md5, md5_exec, desc_md5, synopsis_md5);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc_md5;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
4514
apps/app_meetme.c
4514
apps/app_meetme.c
File diff suppressed because it is too large
Load Diff
@@ -19,51 +19,49 @@
|
||||
/*! \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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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/utils.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)
|
||||
@@ -74,121 +72,99 @@ static void milliwatt_release(struct ast_channel *chan, void *data)
|
||||
|
||||
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct ast_frame wf;
|
||||
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__,
|
||||
};
|
||||
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 + AST_FRIENDLY_OFFSET > sizeof(buf))
|
||||
{
|
||||
ast_log(LOG_WARNING,"Only doing %d bytes (%d bytes requested)\n",(int)(sizeof(buf) - AST_FRIENDLY_OFFSET),len);
|
||||
len = sizeof(buf) - AST_FRIENDLY_OFFSET;
|
||||
}
|
||||
|
||||
len = samples * sizeof (buf[0]);
|
||||
wf.frametype = AST_FRAME_VOICE;
|
||||
wf.subclass = AST_FORMAT_ULAW;
|
||||
wf.offset = AST_FRIENDLY_OFFSET;
|
||||
wf.mallocd = 0;
|
||||
wf.data = buf + AST_FRIENDLY_OFFSET;
|
||||
wf.datalen = len;
|
||||
wf.samples = samples;
|
||||
|
||||
wf.samples = wf.datalen;
|
||||
wf.src = "app_milliwatt";
|
||||
wf.delivery.tv_sec = 0;
|
||||
wf.delivery.tv_usec = 0;
|
||||
wf.prev = wf.next = NULL;
|
||||
/* create a buffer containing the digital milliwatt pattern */
|
||||
for (i = 0; i < len; i++) {
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
buf[AST_FRIENDLY_OFFSET + 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_app *playtones_app;
|
||||
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);
|
||||
}
|
||||
|
||||
if (!(playtones_app = pbx_findapp("Playtones"))) {
|
||||
ast_log(LOG_ERROR, "The Playtones application is required to run Milliwatt()\n");
|
||||
goto exit_app;
|
||||
if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0)
|
||||
{
|
||||
ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = pbx_exec(chan, playtones_app, "1004/1000");
|
||||
|
||||
while (!res) {
|
||||
res = ast_safe_sleep(chan, 10000);
|
||||
}
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Anthony Minessale II
|
||||
* Copyright (C) 2005 - 2006, Digium, Inc.
|
||||
* Copyright (C) 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Kevin P. Fleming <kpfleming@digium.com>
|
||||
@@ -22,30 +22,23 @@
|
||||
*/
|
||||
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/chanspy.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
@@ -53,10 +46,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 *tdesc = "Mixed Audio Monitoring Application";
|
||||
static const char *app = "MixMonitor";
|
||||
static const char *synopsis = "Record a call and mix the audio during the recording";
|
||||
static const char *desc = ""
|
||||
@@ -68,37 +61,30 @@ static const char *desc = ""
|
||||
"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: does not include conferences.\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"
|
||||
"Any strings matching ^{X} will be unescaped to ${X} and \n"
|
||||
"all variables will be evaluated at that time.\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"
|
||||
"Stops the audio recording that was started with a call to MixMonitor()\n"
|
||||
"on the current channel.\n"
|
||||
"";
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
struct module_symbols *me;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static const char *mixmonitor_spy_type = "MixMonitor";
|
||||
|
||||
struct mixmonitor {
|
||||
struct ast_audiohook audiohook;
|
||||
struct ast_channel *chan;
|
||||
char *filename;
|
||||
char *post_process;
|
||||
char *name;
|
||||
unsigned int flags;
|
||||
struct mixmonitor_ds *mixmonitor_ds;
|
||||
int readvol;
|
||||
int writevol;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -124,51 +110,22 @@ AST_APP_OPTIONS(mixmonitor_opts, {
|
||||
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;
|
||||
};
|
||||
|
||||
static void mixmonitor_ds_destroy(void *data)
|
||||
static void stopmon(struct ast_channel *chan, struct ast_channel_spy *spy)
|
||||
{
|
||||
struct mixmonitor_ds *mixmonitor_ds = data;
|
||||
/* If our status has changed to DONE, then the channel we're spying on is gone....
|
||||
DON'T TOUCH IT!!! RUN AWAY!!! */
|
||||
if (spy->status == CHANSPY_DONE)
|
||||
return;
|
||||
|
||||
ast_mutex_lock(&mixmonitor_ds->lock);
|
||||
mixmonitor_ds->chan = NULL;
|
||||
mixmonitor_ds->destruction_ok = 1;
|
||||
ast_cond_signal(&mixmonitor_ds->destruction_condition);
|
||||
ast_mutex_unlock(&mixmonitor_ds->lock);
|
||||
if (!chan)
|
||||
return;
|
||||
|
||||
ast_mutex_lock(&chan->lock);
|
||||
ast_channel_spy_remove(chan, spy);
|
||||
ast_mutex_unlock(&chan->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 int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
|
||||
static int startmon(struct ast_channel *chan, struct ast_channel_spy *spy)
|
||||
{
|
||||
struct ast_channel *peer;
|
||||
int res;
|
||||
@@ -176,8 +133,10 @@ static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
|
||||
if (!chan)
|
||||
return -1;
|
||||
|
||||
res = ast_audiohook_attach(chan, audiohook);
|
||||
|
||||
ast_mutex_lock(&chan->lock);
|
||||
res = ast_channel_spy_add(chan, spy);
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
|
||||
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
|
||||
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
|
||||
|
||||
@@ -189,194 +148,169 @@ static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
|
||||
static void *mixmonitor_thread(void *obj)
|
||||
{
|
||||
struct mixmonitor *mixmonitor = obj;
|
||||
struct ast_channel_spy spy;
|
||||
struct ast_filestream *fs = NULL;
|
||||
char *ext, *name;
|
||||
unsigned int oflags;
|
||||
char *ext;
|
||||
int errflag = 0;
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
|
||||
struct ast_frame *f;
|
||||
char post_process[1024] = "";
|
||||
|
||||
ast_audiohook_lock(&mixmonitor->audiohook);
|
||||
STANDARD_INCREMENT_USECOUNT;
|
||||
|
||||
while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
struct ast_frame *fr = NULL;
|
||||
name = ast_strdupa(mixmonitor->chan->name);
|
||||
|
||||
oflags = O_CREAT|O_WRONLY;
|
||||
oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
|
||||
|
||||
ast_audiohook_trigger_wait(&mixmonitor->audiohook);
|
||||
|
||||
if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
|
||||
break;
|
||||
|
||||
if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
|
||||
continue;
|
||||
|
||||
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) {
|
||||
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 */
|
||||
if (fs)
|
||||
ast_writestream(fs, fr);
|
||||
} else {
|
||||
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
|
||||
}
|
||||
|
||||
/* All done! free it. */
|
||||
ast_frame_free(fr, 0);
|
||||
if ((ext = strrchr(mixmonitor->filename, '.'))) {
|
||||
*(ext++) = '\0';
|
||||
} else {
|
||||
ext = "raw";
|
||||
}
|
||||
|
||||
ast_audiohook_detach(&mixmonitor->audiohook);
|
||||
ast_audiohook_unlock(&mixmonitor->audiohook);
|
||||
ast_audiohook_destroy(&mixmonitor->audiohook);
|
||||
fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644);
|
||||
if (!fs) {
|
||||
ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ast_test_flag(mixmonitor, MUXFLAG_APPEND))
|
||||
ast_seekstream(fs, 0, SEEK_END);
|
||||
|
||||
memset(&spy, 0, sizeof(spy));
|
||||
ast_set_flag(&spy, CHANSPY_FORMAT_AUDIO);
|
||||
ast_set_flag(&spy, CHANSPY_MIXAUDIO);
|
||||
spy.type = mixmonitor_spy_type;
|
||||
spy.status = CHANSPY_RUNNING;
|
||||
spy.read_queue.format = AST_FORMAT_SLINEAR;
|
||||
spy.write_queue.format = AST_FORMAT_SLINEAR;
|
||||
if (mixmonitor->readvol) {
|
||||
ast_set_flag(&spy, CHANSPY_READ_VOLADJUST);
|
||||
spy.read_vol_adjustment = mixmonitor->readvol;
|
||||
}
|
||||
if (mixmonitor->writevol) {
|
||||
ast_set_flag(&spy, CHANSPY_WRITE_VOLADJUST);
|
||||
spy.write_vol_adjustment = mixmonitor->writevol;
|
||||
}
|
||||
ast_mutex_init(&spy.lock);
|
||||
|
||||
if (startmon(mixmonitor->chan, &spy)) {
|
||||
ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
|
||||
spy.type, mixmonitor->chan->name);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", name);
|
||||
|
||||
if (mixmonitor->post_process) {
|
||||
char *p;
|
||||
|
||||
for (p = mixmonitor->post_process; *p ; p++) {
|
||||
if (*p == '^' && *(p+1) == '{') {
|
||||
*p = '$';
|
||||
}
|
||||
}
|
||||
pbx_substitute_variables_helper(mixmonitor->chan, mixmonitor->post_process, post_process, sizeof(post_process) - 1);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
struct ast_frame *next;
|
||||
int write;
|
||||
|
||||
ast_mutex_lock(&spy.lock);
|
||||
|
||||
ast_channel_spy_trigger_wait(&spy);
|
||||
|
||||
if (ast_check_hangup(mixmonitor->chan) || spy.status != CHANSPY_RUNNING) {
|
||||
ast_mutex_unlock(&spy.lock);
|
||||
break;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (!(f = ast_channel_spy_read_frame(&spy, SAMPLES_PER_FRAME)))
|
||||
break;
|
||||
|
||||
write = (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) ||
|
||||
ast_bridged_channel(mixmonitor->chan));
|
||||
|
||||
/* it is possible for ast_channel_spy_read_frame() to return a chain
|
||||
of frames if a queue flush was necessary, so process them
|
||||
*/
|
||||
for (; f; f = next) {
|
||||
next = f->next;
|
||||
if (write)
|
||||
ast_writestream(fs, f);
|
||||
ast_frfree(f);
|
||||
}
|
||||
}
|
||||
|
||||
ast_mutex_unlock(&spy.lock);
|
||||
}
|
||||
|
||||
stopmon(mixmonitor->chan, &spy);
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", name);
|
||||
|
||||
if (!ast_strlen_zero(post_process)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", post_process);
|
||||
ast_safe_system(post_process);
|
||||
}
|
||||
|
||||
out2:
|
||||
ast_mutex_destroy(&spy.lock);
|
||||
|
||||
if (fs)
|
||||
ast_closestream(fs);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
|
||||
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);
|
||||
ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
|
||||
ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
|
||||
ast_free(mixmonitor->mixmonitor_ds);
|
||||
out:
|
||||
free(mixmonitor);
|
||||
|
||||
STANDARD_DECREMENT_USECOUNT;
|
||||
|
||||
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_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;
|
||||
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;
|
||||
int len;
|
||||
|
||||
len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
|
||||
len = sizeof(*mixmonitor) + strlen(filename) + 1;
|
||||
if (!ast_strlen_zero(post_process))
|
||||
len += strlen(post_process) + 1;
|
||||
|
||||
/* 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))) {
|
||||
ast_log(LOG_ERROR, "Memory Error!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy over flags and channel name */
|
||||
mixmonitor->flags = flags;
|
||||
if (setup_mixmonitor_ds(mixmonitor, chan)) {
|
||||
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;
|
||||
mixmonitor->chan = chan;
|
||||
mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor);
|
||||
strcpy(mixmonitor->filename, filename);
|
||||
|
||||
/* Setup the actual spy before creating our thread */
|
||||
if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
|
||||
free(mixmonitor);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
free(mixmonitor);
|
||||
return;
|
||||
if (!ast_strlen_zero(post_process)) {
|
||||
mixmonitor->post_process = mixmonitor->filename + strlen(filename) + 1;
|
||||
strcpy(mixmonitor->post_process, post_process);
|
||||
}
|
||||
mixmonitor->readvol = readvol;
|
||||
mixmonitor->writevol = writevol;
|
||||
mixmonitor->flags = flags;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
|
||||
ast_pthread_create(&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 localuser *u;
|
||||
struct ast_flags flags = {0};
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
@@ -390,15 +324,19 @@ static int mixmonitor_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
if (!(parse = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -450,20 +388,7 @@ static int mixmonitor_exec(struct ast_channel *chan, void *data)
|
||||
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_module_user *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -483,49 +408,59 @@ static int mixmonitor_cli(int fd, int argc, char **argv)
|
||||
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_spy_stop_by_type(chan, mixmonitor_spy_type);
|
||||
|
||||
ast_channel_unlock(chan);
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
|
||||
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 struct ast_cli_entry cli_mixmonitor = {
|
||||
{ "mixmonitor", NULL, NULL },
|
||||
mixmonitor_cli,
|
||||
"Execute a MixMonitor command",
|
||||
"mixmonitor <start|stop> <chan_name> [<args>]\n"
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
|
||||
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_cli_unregister(&cli_mixmonitor);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
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);
|
||||
res = ast_cli_register(&cli_mixmonitor);
|
||||
res |= ast_register_application(app, mixmonitor_exec, synopsis, desc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -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, "%d", &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, "%d", &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");
|
||||
@@ -19,20 +19,10 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Silly application to play an MP3 file -- uses mpg123
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>working_fork</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -40,9 +30,10 @@ 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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
@@ -52,11 +43,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
@@ -66,43 +58,23 @@ static char *descrip =
|
||||
"which typically would be a filename or a URL. User can exit by pressing\n"
|
||||
"any key on the dialpad, or by hanging up.";
|
||||
|
||||
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 +94,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)
|
||||
@@ -143,7 +115,7 @@ 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;
|
||||
@@ -162,11 +134,11 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -176,7 +148,7 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -249,25 +221,40 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
if (!res && owriteformat)
|
||||
ast_set_write_format(chan, owriteformat);
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,10 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Silly application to play an NBScat file -- uses nbscat8k
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>working_fork</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -41,9 +31,10 @@ 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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
@@ -53,7 +44,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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"
|
||||
@@ -62,6 +52,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#define AF_LOCAL AF_UNIX
|
||||
#endif
|
||||
|
||||
static char *tdesc = "Silly NBS Stream Application";
|
||||
|
||||
static char *app = "NBScat";
|
||||
|
||||
static char *synopsis = "Play an NBS local stream";
|
||||
@@ -70,43 +62,21 @@ static char *descrip =
|
||||
" NBScat: Executes nbscat to listen to the local NBS stream.\n"
|
||||
"User can exit by 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 +84,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)
|
||||
@@ -135,7 +105,7 @@ 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;
|
||||
@@ -148,11 +118,11 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
|
||||
short frdata[160];
|
||||
} myf;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create socketpair\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -162,7 +132,7 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -232,25 +202,40 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
|
||||
if (!res && owriteformat)
|
||||
ast_set_write_format(chan, owriteformat);
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
1888
apps/app_osplookup.c
1888
apps/app_osplookup.c
File diff suppressed because it is too large
Load Diff
221
apps/app_page.c
221
apps/app_page.c
@@ -20,26 +20,19 @@
|
||||
*
|
||||
* \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -48,9 +41,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 *tdesc = "Page Multiple Phones";
|
||||
|
||||
static const char *app_page= "Page";
|
||||
|
||||
@@ -63,109 +56,142 @@ static const char *page_descrip =
|
||||
"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";
|
||||
" q - quiet, do not play beep to caller\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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),
|
||||
});
|
||||
|
||||
struct calloutdata {
|
||||
char cidnum[64];
|
||||
char cidname[64];
|
||||
char tech[64];
|
||||
char resource[256];
|
||||
char meetmeopts[64];
|
||||
struct ast_variable *variables;
|
||||
};
|
||||
|
||||
static void *page_thread(void *data)
|
||||
{
|
||||
struct calloutdata *cd = data;
|
||||
ast_pbx_outgoing_app(cd->tech, AST_FORMAT_SLINEAR, cd->resource, 30000,
|
||||
"MeetMe", cd->meetmeopts, NULL, 0, cd->cidnum, cd->cidname, cd->variables, NULL, NULL);
|
||||
free(cd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void launch_page(struct ast_channel *chan, const char *meetmeopts, const char *tech, const char *resource)
|
||||
{
|
||||
struct calloutdata *cd;
|
||||
const char *varname;
|
||||
struct ast_variable *lastvar = NULL;
|
||||
struct ast_var_t *varptr;
|
||||
pthread_t t;
|
||||
pthread_attr_t attr;
|
||||
cd = malloc(sizeof(struct calloutdata));
|
||||
if (cd) {
|
||||
memset(cd, 0, sizeof(struct calloutdata));
|
||||
ast_copy_string(cd->cidnum, chan->cid.cid_num ? chan->cid.cid_num : "", sizeof(cd->cidnum));
|
||||
ast_copy_string(cd->cidname, chan->cid.cid_name ? chan->cid.cid_name : "", sizeof(cd->cidname));
|
||||
ast_copy_string(cd->tech, tech, sizeof(cd->tech));
|
||||
ast_copy_string(cd->resource, resource, sizeof(cd->resource));
|
||||
ast_copy_string(cd->meetmeopts, meetmeopts, sizeof(cd->meetmeopts));
|
||||
|
||||
AST_LIST_TRAVERSE(&chan->varshead, varptr, entries) {
|
||||
if (!(varname = ast_var_full_name(varptr)))
|
||||
continue;
|
||||
if (varname[0] == '_') {
|
||||
struct ast_variable *newvar = NULL;
|
||||
|
||||
if (varname[1] == '_') {
|
||||
newvar = ast_variable_new(varname, ast_var_value(varptr));
|
||||
} else {
|
||||
newvar = ast_variable_new(&varname[1], ast_var_value(varptr));
|
||||
}
|
||||
|
||||
if (newvar) {
|
||||
if (lastvar)
|
||||
lastvar->next = newvar;
|
||||
else
|
||||
cd->variables = newvar;
|
||||
lastvar = newvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (ast_pthread_create(&t, &attr, page_thread, cd)) {
|
||||
ast_log(LOG_WARNING, "Unable to create paging thread: %s\n", strerror(errno));
|
||||
free(cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 localuser *u;
|
||||
char *options;
|
||||
char *tech, *resource;
|
||||
char meetmeopts[80];
|
||||
struct ast_flags flags = { 0 };
|
||||
unsigned int confid = ast_random();
|
||||
unsigned int confid = rand();
|
||||
struct ast_app *app;
|
||||
int res = 0, pos = 0, i = 0;
|
||||
struct ast_dial **dial_list;
|
||||
unsigned int num_dials;
|
||||
char *tmp;
|
||||
int res=0;
|
||||
char originator[AST_CHANNEL_NAME];
|
||||
|
||||
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);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(app = pbx_findapp("MeetMe"))) {
|
||||
ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
};
|
||||
|
||||
options = ast_strdupa(data);
|
||||
|
||||
ast_copy_string(originator, chan->name, sizeof(originator));
|
||||
if ((tmp = strchr(originator, '-')))
|
||||
*tmp = '\0';
|
||||
if (!options) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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" : "") );
|
||||
snprintf(meetmeopts, sizeof(meetmeopts), "%ud|%sqxdw", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m");
|
||||
|
||||
/* Count number of extensions in list by number of ampersands + 1 */
|
||||
num_dials = 1;
|
||||
tmp2 = tmp;
|
||||
while (*tmp2) {
|
||||
if (*tmp2 == '&') {
|
||||
num_dials++;
|
||||
}
|
||||
tmp2++;
|
||||
}
|
||||
ast_copy_string(originator, chan->name, sizeof(originator));
|
||||
if ((tmp = strchr(originator, '-')))
|
||||
*tmp = '\0';
|
||||
|
||||
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, '/'))) {
|
||||
if ((resource = strchr(tech, '/'))) {
|
||||
*resource++ = '\0';
|
||||
launch_page(chan, meetmeopts, tech, resource);
|
||||
} else {
|
||||
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)) {
|
||||
@@ -173,48 +199,47 @@ static int page_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%sqxd", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t");
|
||||
pbx_exec(chan, app, meetmeopts, 1);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_page);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
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");
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2006, Digium, Inc.
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
@@ -22,23 +22,20 @@
|
||||
/*! \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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -49,7 +46,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 +55,57 @@ 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;
|
||||
struct localuser *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
l=strlen(data)+2;
|
||||
orig_s=malloc(l);
|
||||
if(!orig_s) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
s=orig_s;
|
||||
strncpy(s,data,l);
|
||||
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -111,14 +113,15 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
timeout = atoi(strsep(&s, "|"));
|
||||
timeout *= 1000;
|
||||
}
|
||||
dial = strsep(&s, "|");
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
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,15 +149,16 @@ 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
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++;
|
||||
}
|
||||
@@ -169,19 +173,16 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
/* 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);
|
||||
|
||||
if(dchan) {
|
||||
@@ -193,12 +194,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 +212,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);
|
||||
@@ -234,27 +237,45 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
ast_stopstream(dchan);
|
||||
ast_hangup(dchan);
|
||||
|
||||
finish:
|
||||
ast_module_user_remove(u);
|
||||
free(orig_s);
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to playback a sound file
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -43,9 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 = "Sound File Playback Application";
|
||||
|
||||
static char *app = "Playback";
|
||||
|
||||
@@ -65,329 +62,21 @@ static char *descrip =
|
||||
"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"
|
||||
;
|
||||
|
||||
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 = index(fn, ':');
|
||||
if (!fmt || fmt == fn) { /* regular filename */
|
||||
ret = s_streamwait3(a, fn);
|
||||
continue;
|
||||
}
|
||||
fmt++;
|
||||
data = index(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 = index(fn2, '\'');
|
||||
if (!y) {
|
||||
p = data; /* invalid. prepare to end */
|
||||
break;
|
||||
}
|
||||
*y = '\0';
|
||||
ast_trim_blanks(fn2);
|
||||
p = index(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;
|
||||
int res = 0, mres = 0;
|
||||
struct localuser *u;
|
||||
char *tmp = NULL;
|
||||
int option_skip=0;
|
||||
int option_say=0;
|
||||
int option_noanswer = 0;
|
||||
char *front = NULL, *back = NULL;
|
||||
int priority_jump = 0;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(filenames);
|
||||
AST_APP_ARG(options);
|
||||
@@ -398,16 +87,20 @@ static int playback_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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'))
|
||||
@@ -417,78 +110,71 @@ static int playback_exec(struct ast_channel *chan, void *data)
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
if (option_skip) {
|
||||
/* At the user's option, skip if the line is not up */
|
||||
goto done;
|
||||
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);
|
||||
front = tmp;
|
||||
while (!res && front) {
|
||||
if ((back = strchr(front, '&'))) {
|
||||
*back = '\0';
|
||||
back++;
|
||||
}
|
||||
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)
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
res = 0;
|
||||
mres = 1;
|
||||
}
|
||||
front = back;
|
||||
}
|
||||
if (mres)
|
||||
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "FAILED");
|
||||
else
|
||||
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "SUCCESS");
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_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);
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \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 <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/utils.h"
|
||||
@@ -49,6 +47,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#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";
|
||||
@@ -74,6 +74,11 @@ static char *descrip =
|
||||
" SUCCESS | FAILED \n"
|
||||
;
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
|
||||
|
||||
static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
@@ -82,9 +87,9 @@ static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
int maxretries = 3;
|
||||
int minlength = 10;
|
||||
int x = 0;
|
||||
const char *s;
|
||||
char *s;
|
||||
char phone[30];
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
struct ast_config *cfg = NULL;
|
||||
char *parse = NULL;
|
||||
int priority_jump = 0;
|
||||
@@ -94,8 +99,7 @@ static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
LOCAL_USER_ADD (u);
|
||||
if (!ast_strlen_zero(chan->cid.cid_num)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
|
||||
@@ -104,13 +108,19 @@ static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
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)) {
|
||||
if (!ast_strlen_zero((char *)data))
|
||||
{
|
||||
parse = ast_strdupa(data);
|
||||
if (!parse) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
@@ -183,24 +193,16 @@ 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);
|
||||
}
|
||||
ast_set_callerid (chan, phone, "Privacy Manager", NULL);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",phone);
|
||||
pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
|
||||
} else {
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
|
||||
}
|
||||
@@ -208,25 +210,45 @@ static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
ast_config_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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
4220
apps/app_queue.c
4220
apps/app_queue.c
File diff suppressed because it is too large
Load Diff
@@ -23,15 +23,15 @@
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
@@ -39,7 +39,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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 +47,81 @@ 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 char random_state[256];
|
||||
|
||||
static int random_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
|
||||
char *s;
|
||||
char *prob;
|
||||
int probint;
|
||||
static int deprecated = 0;
|
||||
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
if (!s) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
prob = strsep(&s,":");
|
||||
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) {
|
||||
if ((random() % 100) + probint > 100) {
|
||||
res = ast_parseable_goto(chan, s);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n",
|
||||
chan->context,chan->exten, chan->priority+1);
|
||||
}
|
||||
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_random);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
initstate((getppid() * 65535 + getpid()) % RAND_MAX, random_state, 256);
|
||||
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;
|
||||
}
|
||||
|
||||
193
apps/app_read.c
193
apps/app_read.c
@@ -19,20 +19,18 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to read a variable
|
||||
*
|
||||
* \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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -43,19 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
|
||||
@@ -65,131 +52,131 @@ 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"
|
||||
" filename -- file to play before reading digits.\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"
|
||||
" 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"
|
||||
" 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"
|
||||
" timeout -- if greater than 0, that value will override the default timeout.\n\n"
|
||||
"Read should disconnect if the function fails or errors out.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
|
||||
|
||||
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;
|
||||
struct localuser *u;
|
||||
char tmp[256];
|
||||
char *timeout = NULL;
|
||||
char *varname = NULL;
|
||||
char *filename = NULL;
|
||||
char *loops;
|
||||
char *maxdigitstr=NULL;
|
||||
char *options=NULL;
|
||||
int option_skip = 0;
|
||||
int option_noanswer = 0;
|
||||
int maxdigits=255;
|
||||
int tries = 1;
|
||||
int to = 0;
|
||||
int x = 0;
|
||||
char *argcopy = NULL;
|
||||
struct tone_zone_sound *ts;
|
||||
struct ast_flags flags = {0};
|
||||
char *args[8];
|
||||
|
||||
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)) {
|
||||
ast_log(LOG_WARNING, "Read requires an argument (variable)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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 (!argcopy) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_app_separate_args(argcopy, '|', args, sizeof(args) / sizeof(args[0])) < 1) {
|
||||
ast_log(LOG_WARNING, "Cannot Parse Arguments.\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
varname = args[x++];
|
||||
filename = args[x++];
|
||||
maxdigitstr = args[x++];
|
||||
options = args[x++];
|
||||
loops = args[x++];
|
||||
timeout = args[x++];
|
||||
|
||||
if (!ast_strlen_zero(arglist.attempts)) {
|
||||
tries = atoi(arglist.attempts);
|
||||
if (tries <= 0)
|
||||
if (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(loops) {
|
||||
tries = atoi(loops);
|
||||
if(tries <= 0)
|
||||
tries = 1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(arglist.timeout)) {
|
||||
to = atoi(arglist.timeout);
|
||||
if(timeout) {
|
||||
to = atoi(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 (ast_strlen_zero(filename))
|
||||
filename = NULL;
|
||||
if (maxdigitstr) {
|
||||
maxdigits = atoi(maxdigitstr);
|
||||
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)) {
|
||||
if (ast_strlen_zero(varname)) {
|
||||
ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
res = ast_app_getdata(chan, filename, tmp, maxdigits, to);
|
||||
if (res > -1) {
|
||||
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
|
||||
pbx_builtin_setvar_helper(chan, varname, tmp);
|
||||
if (!ast_strlen_zero(tmp)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
|
||||
@@ -205,30 +192,44 @@ static int read_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
res = 0;
|
||||
} else {
|
||||
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
|
||||
if (option_verbose > 2)
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -20,20 +20,18 @@
|
||||
*
|
||||
* \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
@@ -42,6 +40,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Stores output of file into a variable";
|
||||
|
||||
static char *app_readfile = "ReadFile";
|
||||
|
||||
static char *readfile_synopsis = "ReadFile(varname=file,length)";
|
||||
@@ -52,11 +52,15 @@ static char *readfile_descrip =
|
||||
" File - The name of the file to read.\n"
|
||||
" Length - Maximum number of characters to capture.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
|
||||
static int readfile_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL;
|
||||
int len=0;
|
||||
|
||||
@@ -65,9 +69,14 @@ static int readfile_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
if (!s) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
varname = strsep(&s, "=");
|
||||
file = strsep(&s, "|");
|
||||
@@ -75,7 +84,7 @@ static int readfile_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
if (!varname || !file) {
|
||||
ast_log(LOG_ERROR, "No file or variable specified!\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -96,25 +105,40 @@ static int readfile_exec(struct ast_channel *chan, void *data)
|
||||
pbx_builtin_setvar_helper(chan, varname, returnvar);
|
||||
free(returnvar);
|
||||
}
|
||||
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_readfile);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
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");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -20,22 +20,19 @@
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -49,54 +46,50 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#define next_one(var) var = var->next
|
||||
#define crop_data(str) { *(str) = '\0' ; (str)++; }
|
||||
|
||||
static char *tdesc = "Realtime Data Lookup/Rewrite";
|
||||
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"
|
||||
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";
|
||||
"All unique column names will be set as channel variables with optional prefix to the name.\n"
|
||||
"e.g. prefix of 'var_' would make the column 'name' become the variable ${var_name}\n\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";
|
||||
"The column <newcol> in 'family' matching column <colmatch>=<value> will be updated to <newval>\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int cli_realtime_load(int fd, int argc, char **argv)
|
||||
static int cli_load_realtime(int fd, int argc, char **argv)
|
||||
{
|
||||
char *header_format = "%30s %-30s\n";
|
||||
struct ast_variable *var = NULL, *save = NULL;
|
||||
struct ast_variable *var=NULL;
|
||||
|
||||
if (argc < 5) {
|
||||
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;
|
||||
if(var) {
|
||||
ast_cli(fd, header_format, "Column Name", "Column Value");
|
||||
ast_cli(fd, header_format, "--------------------", "--------------------");
|
||||
while (var) {
|
||||
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) {
|
||||
static int cli_update_realtime(int fd, int argc, char **argv) {
|
||||
int res = 0;
|
||||
|
||||
if(argc<7) {
|
||||
@@ -117,49 +110,45 @@ static int cli_realtime_update(int fd, int argc, char **argv) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static char cli_realtime_load_usage[] =
|
||||
static char cli_load_realtime_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[] =
|
||||
static struct ast_cli_entry cli_load_realtime_cmd = {
|
||||
{ "realtime", "load", NULL, NULL }, cli_load_realtime,
|
||||
"Used to print out RealTime variables.", cli_load_realtime_usage, NULL };
|
||||
|
||||
static char cli_update_realtime_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 struct ast_cli_entry cli_update_realtime_cmd = {
|
||||
{ "realtime", "update", NULL, NULL }, cli_update_realtime,
|
||||
"Used to update RealTime variables.", cli_update_realtime_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");
|
||||
struct localuser *u;
|
||||
int res = 0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,13 +156,10 @@ static int realtime_update_exec(struct ast_channel *chan, void *data)
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
|
||||
res = -1;
|
||||
} else {
|
||||
count = ast_update_realtime(family,colmatch,value,newcol,newval,NULL);
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -181,29 +167,27 @@ static int realtime_update_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
static int realtime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0, count=0;
|
||||
struct ast_module_user *u;
|
||||
int res=0;
|
||||
struct localuser *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);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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 = 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) ) {
|
||||
@@ -223,41 +207,56 @@ static int realtime_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
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_cli_unregister(&cli_load_realtime_cmd);
|
||||
res |= ast_cli_unregister(&cli_update_realtime_cmd);
|
||||
res |= ast_unregister_application(uapp);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
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_cli_register(&cli_load_realtime_cmd);
|
||||
res |= ast_cli_register(&cli_update_realtime_cmd);
|
||||
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");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,19 +20,17 @@
|
||||
*
|
||||
* \brief Trivial application to record a sound file
|
||||
*
|
||||
* \author Matthew Fredrickson <creslin@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -43,8 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
|
||||
@@ -63,17 +61,18 @@ static char *descrip =
|
||||
" '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"
|
||||
" 't' : use alternate '*' terminator key instead of default '#'\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"
|
||||
"Use 'show file formats' to see the available formats on your system\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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int record_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
@@ -86,7 +85,7 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
char tmp[256];
|
||||
|
||||
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 */
|
||||
@@ -112,10 +111,15 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Yay for strsep being easy */
|
||||
vdata = ast_strdupa(data);
|
||||
if (!vdata) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = vdata;
|
||||
filename = strsep(&p, "|");
|
||||
@@ -136,7 +140,7 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
if (!ext) {
|
||||
ast_log(LOG_WARNING, "No extension specified to filename!\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (silstr) {
|
||||
@@ -169,8 +173,6 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
option_append = 1;
|
||||
if (strchr(options, 't'))
|
||||
terminator = '*';
|
||||
if (strchr(options, 'x'))
|
||||
terminator = 0;
|
||||
if (strchr(options, 'q'))
|
||||
option_quiet = 1;
|
||||
}
|
||||
@@ -181,39 +183,13 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
/* 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), filename, 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, filename, sizeof(tmp)-1);
|
||||
/* end of routine mentioned */
|
||||
|
||||
|
||||
@@ -221,7 +197,7 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
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 */
|
||||
@@ -252,13 +228,13 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
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);
|
||||
LOCAL_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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
ast_dsp_set_threshold(sildet, 256);
|
||||
@@ -273,7 +249,7 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ast_opt_transmit_silence)
|
||||
if (option_transmit_silence_during_record)
|
||||
silgen = ast_channel_start_silence_generator(chan);
|
||||
|
||||
/* Request a video update */
|
||||
@@ -362,25 +338,40 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
ast_dsp_free(sildet);
|
||||
}
|
||||
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
8787
apps/app_rpt.c
8787
apps/app_rpt.c
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2003, 2006 Tilghman Lesher. All rights reserved.
|
||||
* Copyright (c) 2006 Digium, Inc.
|
||||
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_sayunixtime__200309@the-tilghman.com>
|
||||
*
|
||||
@@ -19,21 +18,19 @@
|
||||
/*! \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
@@ -41,7 +38,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
@@ -65,55 +64,78 @@ static char *datetime_descrip =
|
||||
" format: a format the time is to be said in. See voicemail.conf.\n"
|
||||
" defaults to \"ABdY 'digits/at' IMp\"\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,*format;
|
||||
time_t unixtime;
|
||||
struct timeval tv;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
tv = ast_tvnow();
|
||||
unixtime = (time_t)tv.tv_sec;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
if( !strcasecmp(chan->language, "da" ) ) {
|
||||
format = "A dBY HMS";
|
||||
} else if ( !strcasecmp(chan->language, "de" ) ) {
|
||||
format = "A dBY HMS";
|
||||
} else {
|
||||
format = "ABdY 'digits/at' IMp";
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
res = ast_unregister_application(app_sayunixtime);
|
||||
res |= ast_unregister_application(app_datetime);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -123,4 +145,19 @@ static int load_module(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say time");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to send DTMF digits
|
||||
*
|
||||
* \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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -43,7 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#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";
|
||||
|
||||
@@ -55,11 +54,14 @@ static char *descrip =
|
||||
" The application will either pass the assigned digits or terminate if it\n"
|
||||
" encounters an error.\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;
|
||||
struct localuser *u;
|
||||
char *digits = NULL, *to = NULL;
|
||||
int timeout = 250;
|
||||
|
||||
@@ -68,9 +70,14 @@ static int senddtmf_exec(struct ast_channel *chan, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
digits = ast_strdupa(data);
|
||||
if (!digits) {
|
||||
ast_log(LOG_ERROR, "Out of Memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((to = strchr(digits,'|'))) {
|
||||
*to = '\0';
|
||||
@@ -78,66 +85,45 @@ static int senddtmf_exec(struct ast_channel *chan, void *data)
|
||||
timeout = atoi(to);
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
if(timeout <= 0)
|
||||
timeout = 250;
|
||||
|
||||
res = ast_dtmf_stream(chan,NULL,digits,timeout);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
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)
|
||||
{
|
||||
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 (!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;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
res |= ast_manager_unregister("PlayDTMF");
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, senddtmf_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -19,22 +19,20 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to transmit a text message
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \note Requires support of sending text messages from channel driver
|
||||
* Requires support of sending text messages from channel driver
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -46,6 +44,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static const char *tdesc = "Send Text Applications";
|
||||
|
||||
static const char *app = "SendText";
|
||||
|
||||
static const char *synopsis = "Send a Text Message";
|
||||
@@ -63,11 +63,14 @@ static const char *descrip =
|
||||
"'j' -- jump to n+101 priority if the channel doesn't support\n"
|
||||
" text transport\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;
|
||||
struct localuser *u;
|
||||
char *status = "UNSUPPORTED";
|
||||
char *parse = NULL;
|
||||
int priority_jump = 0;
|
||||
@@ -76,14 +79,20 @@ static int sendtext_exec(struct ast_channel *chan, void *data)
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "SendText requires an argument (text[|options])\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
} else
|
||||
} else {
|
||||
parse = ast_strdupa(data);
|
||||
if (!parse) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
@@ -92,40 +101,56 @@ static int sendtext_exec(struct ast_channel *chan, void *data)
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
ast_channel_lock(chan);
|
||||
ast_mutex_lock(&chan->lock);
|
||||
if (!chan->tech->send_text) {
|
||||
ast_channel_unlock(chan);
|
||||
pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
/* Does not support transport */
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
status = "FAILURE";
|
||||
ast_channel_unlock(chan);
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
res = ast_sendtext(chan, args.text);
|
||||
if (!res)
|
||||
status = "SUCCESS";
|
||||
pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
|
||||
ast_module_user_remove(u);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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 (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set callerid
|
||||
*
|
||||
* \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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -47,6 +45,9 @@ static char *app2 = "SetCallerPres";
|
||||
|
||||
static char *synopsis2 = "Set CallerID Presentation";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static char *descrip2 =
|
||||
" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n"
|
||||
@@ -66,28 +67,29 @@ static char *descrip2 =
|
||||
|
||||
static int setcallerid_pres_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
int pres = -1;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* For interface consistency, permit the argument to be specified as a number */
|
||||
if (sscanf(data, "%d", &pres) != 1 || pres < 0 || pres > 255 || (pres & 0x9c)) {
|
||||
pres = ast_parse_caller_presentation(data);
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
pres = ast_parse_caller_presentation(data);
|
||||
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
chan->cid.cid_pres = pres;
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *tdesc = "Set CallerID Application";
|
||||
|
||||
static char *app = "SetCallerID";
|
||||
|
||||
static char *synopsis = "Set CallerID";
|
||||
@@ -102,24 +104,23 @@ static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
char *tmp = NULL;
|
||||
char name[256];
|
||||
char num[256];
|
||||
struct ast_module_user *u;
|
||||
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");
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
@@ -132,24 +133,24 @@ static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
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_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app2);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -159,4 +160,19 @@ static int load_module(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
/*! \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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/cdr.h"
|
||||
#include "asterisk/module.h"
|
||||
@@ -43,6 +41,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
|
||||
static char *tdesc = "CDR user field apps";
|
||||
|
||||
static char *setcdruserfield_descrip =
|
||||
"[Synopsis]\n"
|
||||
"SetCDRUserField(value)\n\n"
|
||||
@@ -52,8 +52,7 @@ static char *setcdruserfield_descrip =
|
||||
" can use for data not stored anywhere else in the record.\n"
|
||||
" 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";
|
||||
" Also see AppendCDRUserField().\n";
|
||||
|
||||
|
||||
static char *setcdruserfield_app = "SetCDRUserField";
|
||||
@@ -68,19 +67,21 @@ static char *appendcdruserfield_descrip =
|
||||
" can use for data not stored anywhere else in the record.\n"
|
||||
" 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";
|
||||
" Also see SetCDRUserField().\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");
|
||||
@@ -106,49 +107,37 @@ 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);
|
||||
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);
|
||||
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;
|
||||
|
||||
@@ -156,12 +145,12 @@ static int unload_module(void)
|
||||
res |= ast_unregister_application(appendcdruserfield_app);
|
||||
res |= ast_manager_unregister("SetCDRUserField");
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -172,4 +161,19 @@ static int load_module(void)
|
||||
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;
|
||||
}
|
||||
|
||||
132
apps/app_setcidname.c
Normal file
132
apps/app_setcidname.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 App to set callerid
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/utils.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. \n"
|
||||
"SetCIDName has been deprecated in favor of the function\n"
|
||||
"CALLERID(name)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *tmp = NULL;
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "SetCIDName is deprecated, please use Set(CALLERID(name)=value) instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR, "SetCIDName requires an argument!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
}
|
||||
|
||||
ast_set_callerid(chan, NULL, tmp, NULL);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
131
apps/app_setcidnum.c
Normal file
131
apps/app_setcidnum.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Oliver Daudey <traveler@xs4all.nl>
|
||||
*
|
||||
* 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 callerid number
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/utils.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.\n"
|
||||
"SetCIDNum has been deprecated in favor of the function\n"
|
||||
"CALLERID(number)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
int anitoo = 0;
|
||||
char *tmp = NULL;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "SetCIDNum is deprecated, please use Set(CALLERID(number)=value) instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (data)
|
||||
tmp = ast_strdupa(data);
|
||||
else
|
||||
tmp = "";
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
opt++;
|
||||
if (*opt == 'a')
|
||||
anitoo = 1;
|
||||
}
|
||||
|
||||
ast_set_callerid(chan, tmp, NULL, anitoo ? tmp : NULL);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
132
apps/app_setrdnis.c
Normal file
132
apps/app_setrdnis.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Oliver Daudey <traveler@xs4all.nl>
|
||||
*
|
||||
* 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 rdnis
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Set RDNIS Number";
|
||||
|
||||
static char *app = "SetRDNIS";
|
||||
|
||||
static char *synopsis = "Set RDNIS Number";
|
||||
|
||||
static char *descrip =
|
||||
" SetRDNIS(cnum): Set RDNIS Number on a call to a new\n"
|
||||
"value.\n"
|
||||
"SetRDNIS has been deprecated in favor of the function\n"
|
||||
"CALLERID(rdnis)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setrdnis_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
char *opt, *n, *l;
|
||||
char *tmp = NULL;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "SetRDNIS is deprecated, please use Set(CALLERID(rdnis)=value) instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (data)
|
||||
tmp = ast_strdupa(data);
|
||||
else
|
||||
tmp = "";
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt)
|
||||
*opt = '\0';
|
||||
|
||||
n = l = NULL;
|
||||
ast_callerid_parse(tmp, &n, &l);
|
||||
if (l) {
|
||||
ast_shrink_phone_number(l);
|
||||
ast_mutex_lock(&chan->lock);
|
||||
if (chan->cid.cid_rdnis)
|
||||
free(chan->cid.cid_rdnis);
|
||||
chan->cid.cid_rdnis = (l[0]) ? strdup(l) : NULL;
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, setrdnis_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -19,19 +19,17 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set the ISDN Transfer Capability
|
||||
*
|
||||
* \author Frank Sautter - asterisk+at+sautter+dot+com
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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"
|
||||
@@ -44,6 +42,9 @@ static char *app = "SetTransferCapability";
|
||||
|
||||
static char *synopsis = "Set ISDN Transfer Capability";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static struct { int val; char *name; } transcaps[] = {
|
||||
{ AST_TRANS_CAP_SPEECH, "SPEECH" },
|
||||
@@ -64,27 +65,20 @@ static char *descrip =
|
||||
" 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"
|
||||
" 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;
|
||||
struct localuser *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");
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (data)
|
||||
tmp = ast_strdupa(data);
|
||||
else
|
||||
@@ -102,7 +96,7 @@ static int settransfercapability_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,26 +105,41 @@ static int settransfercapability_exec(struct ast_channel *chan, void *data)
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Setting transfer capability to: 0x%.2x - %s.\n", transfercapability, tmp);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, settransfercapability_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set ISDN Transfer Capability");
|
||||
char *description(void)
|
||||
{
|
||||
return synopsis;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
118
apps/app_skel.c
118
apps/app_skel.c
@@ -19,26 +19,20 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief Skeleton application
|
||||
*
|
||||
* \author <Your Name Here> <<Your Email Here>>
|
||||
*
|
||||
* This is a skeleton for development of an Asterisk application
|
||||
* 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 <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -47,87 +41,109 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
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";
|
||||
|
||||
enum {
|
||||
OPTION_A = (1 << 0),
|
||||
OPTION_B = (1 << 1),
|
||||
OPTION_C = (1 << 2),
|
||||
} option_flags;
|
||||
#define OPTION_A (1 << 0) /* Option A */
|
||||
#define OPTION_B (1 << 1) /* Option B(n) */
|
||||
#define OPTION_C (1 << 2) /* Option C(str) */
|
||||
#define OPTION_NULL (1 << 3) /* Dummy Termination */
|
||||
|
||||
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;
|
||||
|
||||
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),
|
||||
AST_DECLARE_OPTIONS(app_opts,{
|
||||
['a'] = { OPTION_A },
|
||||
['b'] = { OPTION_B, 1 },
|
||||
['c'] = { OPTION_C, 2 }
|
||||
});
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int app_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);
|
||||
);
|
||||
struct localuser *u;
|
||||
char *options=NULL;
|
||||
char *dummy = NULL;
|
||||
char *args;
|
||||
int argc = 0;
|
||||
char *opts[2];
|
||||
char *argv[2];
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n", app);
|
||||
ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n",app);
|
||||
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);
|
||||
args = ast_strdupa(data);
|
||||
if (!args) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
|
||||
dummy = argv[0];
|
||||
options = argv[1];
|
||||
ast_parseoptions(app_opts, &flags, opts, options);
|
||||
}
|
||||
|
||||
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_strlen_zero(dummy))
|
||||
ast_log(LOG_NOTICE, "Dummy value is : %s\n", 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>");
|
||||
ast_log(LOG_NOTICE,"Option B is set with : %s\n", opts[0] ? opts[0] : "<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);
|
||||
ast_log(LOG_NOTICE,"Option C is set with : %s\n", opts[1] ? opts[1] : "<unspecified>");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, app_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
155
apps/app_sms.c
155
apps/app_sms.c
@@ -18,14 +18,9 @@
|
||||
*
|
||||
* \brief SMS application - ETSI ES 201 912 protocol 1 implimentation
|
||||
* \ingroup applications
|
||||
*
|
||||
* \author Adrian Kennard
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -36,6 +31,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
@@ -61,6 +60,8 @@ static volatile unsigned int seq; /* arbitrary message sequence number for
|
||||
static char log_file[255];
|
||||
static char spool_dir[255];
|
||||
|
||||
static char *tdesc = "SMS/PSTN handler";
|
||||
|
||||
static char *app = "SMS";
|
||||
|
||||
static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
|
||||
@@ -93,6 +94,9 @@ static signed short wave[] = {
|
||||
static unsigned char wavea[80];
|
||||
#endif
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/* SMS 7 bit character mapping to UCS-2 */
|
||||
static const unsigned short defaultalphabet[] = {
|
||||
@@ -193,7 +197,7 @@ static void sms_release (struct ast_channel *chan, void *data)
|
||||
|
||||
static void sms_messagetx (sms_t * h);
|
||||
|
||||
/*! \brief copy number, skipping non digits apart from leading + */
|
||||
/*--- numcpy: copy number, skipping non digits apart from leading + */
|
||||
static void numcpy (char *d, char *s)
|
||||
{
|
||||
if (*s == '+')
|
||||
@@ -206,7 +210,7 @@ static void numcpy (char *d, char *s)
|
||||
*d = 0;
|
||||
}
|
||||
|
||||
/*! \brief static, return a date/time in ISO format */
|
||||
/*--- isodate: static, return a date/time in ISO format */
|
||||
static char * isodate (time_t t)
|
||||
{
|
||||
static char date[20];
|
||||
@@ -214,7 +218,7 @@ static char * isodate (time_t t)
|
||||
return date;
|
||||
}
|
||||
|
||||
/*! \brief reads next UCS character from null terminated UTF-8 string and advanced pointer */
|
||||
/*--- utf8decode: reads next UCS character from null terminated UTF-8 string and advanced pointer */
|
||||
/* for non valid UTF-8 sequences, returns character as is */
|
||||
/* Does not advance pointer for null termination */
|
||||
static long utf8decode (unsigned char **pp)
|
||||
@@ -260,7 +264,7 @@ static long utf8decode (unsigned char **pp)
|
||||
return *p; /* not sensible */
|
||||
}
|
||||
|
||||
/*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes */
|
||||
/*--- packsms7: takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes */
|
||||
/* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
|
||||
/* o can be null, in which case this is used to validate or count only */
|
||||
/* if the input contains invalid characters then the return value is -1 */
|
||||
@@ -330,7 +334,7 @@ static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, un
|
||||
return n;
|
||||
}
|
||||
|
||||
/*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes */
|
||||
/*--- packsms8: takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes */
|
||||
/* The return value is the number of bytes packed in to o, which is internally limited to 140 */
|
||||
/* o can be null, in which case this is used to validate or count only */
|
||||
/* if the input contains invalid characters then the return value is -1 */
|
||||
@@ -362,7 +366,7 @@ static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, un
|
||||
return p;
|
||||
}
|
||||
|
||||
/*! \brief takes a binary header (udhl bytes at udh) and UCS-2
|
||||
/*--- packsms16: takes a binary header (udhl bytes at udh) and UCS-2
|
||||
message (udl characters at ud) and packs in to o using 16 bit
|
||||
UCS-2 character codes
|
||||
The return value is the number of bytes packed in to o, which is
|
||||
@@ -399,7 +403,7 @@ static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, u
|
||||
return p;
|
||||
}
|
||||
|
||||
/*! \brief general pack, with length and data,
|
||||
/*--- packsms: general pack, with length and data,
|
||||
returns number of bytes of target used */
|
||||
static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
|
||||
{
|
||||
@@ -431,7 +435,7 @@ static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, u
|
||||
}
|
||||
|
||||
|
||||
/*! \brief pack a date and return */
|
||||
/*--- packdate: pack a date and return */
|
||||
static void packdate (unsigned char *o, time_t w)
|
||||
{
|
||||
struct tm *t = localtime (&w);
|
||||
@@ -452,7 +456,7 @@ static void packdate (unsigned char *o, time_t w)
|
||||
*o++ = ((z % 10) << 4) + z / 10;
|
||||
}
|
||||
|
||||
/*! \brief unpack a date and return */
|
||||
/*--- unpackdate: unpack a date and return */
|
||||
static time_t unpackdate (unsigned char *i)
|
||||
{
|
||||
struct tm t;
|
||||
@@ -467,10 +471,10 @@ static time_t unpackdate (unsigned char *i)
|
||||
t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
|
||||
else
|
||||
t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
|
||||
return ast_mktime(&t, NULL);
|
||||
return mktime (&t);
|
||||
}
|
||||
|
||||
/*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
|
||||
/*--- unpacksms7: unpacks bytes (7 bit encoding) at i, len l septets,
|
||||
and places in udh and ud setting udhl and udl. udh not used
|
||||
if udhi not set */
|
||||
static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
|
||||
@@ -521,7 +525,7 @@ static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, i
|
||||
*udl = (o - ud);
|
||||
}
|
||||
|
||||
/*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
|
||||
/*--- unpacksms8: unpacks bytes (8 bit encoding) at i, len l septets,
|
||||
and places in udh and ud setting udhl and udl. udh not used
|
||||
if udhi not set */
|
||||
static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
|
||||
@@ -546,7 +550,7 @@ static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, i
|
||||
*udl = (o - ud);
|
||||
}
|
||||
|
||||
/*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
|
||||
/*--- unpacksms16: unpacks bytes (16 bit encoding) at i, len l septets,
|
||||
and places in udh and ud setting udhl and udl.
|
||||
udh not used if udhi not set */
|
||||
static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
|
||||
@@ -575,7 +579,7 @@ static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh,
|
||||
*udl = (o - ud);
|
||||
}
|
||||
|
||||
/*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
|
||||
/*--- unpacksms: general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
|
||||
static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
|
||||
{
|
||||
int l = *i++;
|
||||
@@ -589,7 +593,7 @@ static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, i
|
||||
return l + 1;
|
||||
}
|
||||
|
||||
/*! \brief unpack an address from i, return byte length, unpack to o */
|
||||
/*--- unpackaddress: unpack an address from i, return byte length, unpack to o */
|
||||
static unsigned char unpackaddress (char *o, unsigned char *i)
|
||||
{
|
||||
unsigned char l = i[0],
|
||||
@@ -606,7 +610,7 @@ static unsigned char unpackaddress (char *o, unsigned char *i)
|
||||
return (l + 5) / 2;
|
||||
}
|
||||
|
||||
/*! \brief store an address at o, and return number of bytes used */
|
||||
/*--- packaddress: store an address at o, and return number of bytes used */
|
||||
static unsigned char packaddress (unsigned char *o, char *i)
|
||||
{
|
||||
unsigned char p = 2;
|
||||
@@ -631,7 +635,7 @@ static unsigned char packaddress (unsigned char *o, char *i)
|
||||
return p;
|
||||
}
|
||||
|
||||
/*! \brief Log the output, and remove file */
|
||||
/*--- sms_log: Log the output, and remove file */
|
||||
static void sms_log (sms_t * h, char status)
|
||||
{
|
||||
if (*h->oa || *h->da) {
|
||||
@@ -662,16 +666,14 @@ static void sms_log (sms_t * h, char status)
|
||||
*p++ = h->ud[n];
|
||||
*p++ = '\n';
|
||||
*p = 0;
|
||||
if (write (o, line, strlen (line)) < 0) {
|
||||
ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
|
||||
}
|
||||
write (o, line, strlen (line));
|
||||
close (o);
|
||||
}
|
||||
*h->oa = *h->da = h->udl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief parse and delete a file */
|
||||
/*--- sms_readfile: parse and delete a file */
|
||||
static void sms_readfile (sms_t * h, char *fn)
|
||||
{
|
||||
char line[1000];
|
||||
@@ -692,8 +694,7 @@ static void sms_readfile (sms_t * h, char *fn)
|
||||
}
|
||||
while (fgets (line, sizeof (line), s))
|
||||
{ /* process line in file */
|
||||
char *p;
|
||||
void *pp = &p;
|
||||
unsigned char *p;
|
||||
for (p = line; *p && *p != '\n' && *p != '\r'; p++);
|
||||
*p = 0; /* strip eoln */
|
||||
p = line;
|
||||
@@ -713,7 +714,7 @@ static void sms_readfile (sms_t * h, char *fn)
|
||||
{ /* parse message (UTF-8) */
|
||||
unsigned char o = 0;
|
||||
while (*p && o < SMSLEN)
|
||||
h->ud[o++] = utf8decode(pp);
|
||||
h->ud[o++] = utf8decode((unsigned char **)&p);
|
||||
h->udl = o;
|
||||
if (*p)
|
||||
ast_log (LOG_WARNING, "UD too long in %s\n", fn);
|
||||
@@ -757,7 +758,7 @@ static void sms_readfile (sms_t * h, char *fn)
|
||||
t.tm_min = M;
|
||||
t.tm_sec = S;
|
||||
t.tm_isdst = -1;
|
||||
h->scts = ast_mktime(&t, NULL);
|
||||
h->scts = mktime (&t);
|
||||
if (h->scts == (time_t) - 1)
|
||||
ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
|
||||
}
|
||||
@@ -854,7 +855,7 @@ static void sms_readfile (sms_t * h, char *fn)
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief white a received text message to a file */
|
||||
/*--- sms_writefile: white a received text message to a file */
|
||||
static void sms_writefile (sms_t * h)
|
||||
{
|
||||
char fn[200] = "", fn2[200] = "";
|
||||
@@ -941,7 +942,7 @@ static void sms_writefile (sms_t * h)
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief read dir skipping dot files... */
|
||||
/*--- readdirqueue: read dir skipping dot files... */
|
||||
static struct dirent *readdirqueue (DIR * d, char *queue)
|
||||
{
|
||||
struct dirent *f;
|
||||
@@ -951,7 +952,7 @@ static struct dirent *readdirqueue (DIR * d, char *queue)
|
||||
return f;
|
||||
}
|
||||
|
||||
/*! \brief handle the incoming message */
|
||||
/*--- sms_handleincoming: handle the incoming message */
|
||||
static unsigned char sms_handleincoming (sms_t * h)
|
||||
{
|
||||
unsigned char p = 3;
|
||||
@@ -1022,7 +1023,8 @@ static unsigned char sms_handleincoming (sms_t * h)
|
||||
#define NAME_MAX 1024
|
||||
#endif
|
||||
|
||||
/*! \brief find and fill in next message, or send a REL if none waiting */
|
||||
/*--- sms_nextoutgoing: find and fill in next message,
|
||||
or send a REL if none waiting */
|
||||
static void sms_nextoutgoing (sms_t * h)
|
||||
{
|
||||
char fn[100 + NAME_MAX] = "";
|
||||
@@ -1048,7 +1050,7 @@ static void sms_nextoutgoing (sms_t * h)
|
||||
unsigned char p = 2;
|
||||
h->omsg[0] = 0x91; /* SMS_DATA */
|
||||
if (h->smsc) { /* deliver */
|
||||
h->omsg[p++] = (more ? 4 : 0) + ((h->udhl > 0) ? 0x40 : 0);
|
||||
h->omsg[p++] = (more ? 4 : 0);
|
||||
p += packaddress (h->omsg + p, h->oa);
|
||||
h->omsg[p++] = h->pid;
|
||||
h->omsg[p++] = h->dcs;
|
||||
@@ -1176,31 +1178,33 @@ static void sms_messagetx(sms_t * h)
|
||||
static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct ast_frame f = { 0 };
|
||||
#define MAXSAMPLES (800)
|
||||
unsigned char waste[AST_FRIENDLY_OFFSET];
|
||||
#ifdef OUTALAW
|
||||
unsigned char *buf;
|
||||
unsigned char buf[800];
|
||||
#else
|
||||
short *buf;
|
||||
signed short buf[800];
|
||||
#endif
|
||||
#define SAMPLE2LEN sizeof(*buf)
|
||||
sms_t *h = data;
|
||||
int i;
|
||||
|
||||
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) / sizeof (signed short)), len);
|
||||
len = sizeof (buf);
|
||||
#ifdef OUTALAW
|
||||
samples = len;
|
||||
#else
|
||||
samples = len / 2;
|
||||
#endif
|
||||
}
|
||||
len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
|
||||
buf = alloca(len);
|
||||
|
||||
waste[0] = 0; /* make compiler happy */
|
||||
f.frametype = AST_FRAME_VOICE;
|
||||
#ifdef OUTALAW
|
||||
f.subclass = AST_FORMAT_ALAW;
|
||||
f.datalen = samples;
|
||||
#else
|
||||
f.subclass = AST_FORMAT_SLINEAR;
|
||||
f.datalen = samples * 2;
|
||||
#endif
|
||||
f.datalen = samples * SAMPLE2LEN;
|
||||
f.offset = AST_FRIENDLY_OFFSET;
|
||||
f.mallocd = 0;
|
||||
f.data = buf;
|
||||
@@ -1252,8 +1256,6 @@ static int sms_generate (struct ast_channel *chan, void *data, int len, int samp
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#undef SAMPLE2LEN
|
||||
#undef MAXSAMPLES
|
||||
}
|
||||
|
||||
static void sms_process (sms_t * h, int samples, signed short *data)
|
||||
@@ -1359,17 +1361,17 @@ static struct ast_generator smsgen = {
|
||||
static int sms_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = -1;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
struct ast_frame *f;
|
||||
sms_t h = { 0 };
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
h.ipc0 = h.ipc1 = 20; /* phase for cosine */
|
||||
h.dcs = 0xF1; /* default */
|
||||
if (!data) {
|
||||
ast_log (LOG_ERROR, "Requires queue name at least\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1382,20 +1384,20 @@ static int sms_exec (struct ast_channel *chan, void *data)
|
||||
answer = 0;
|
||||
if (!*d || *d == '|') {
|
||||
ast_log (LOG_ERROR, "Requires queue name\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
for (p = d; *p && *p != '|'; p++);
|
||||
if (p - d >= sizeof (h.queue)) {
|
||||
ast_log (LOG_ERROR, "Queue name too long\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
strncpy(h.queue, (char *)d, p - d);
|
||||
strncpy (h.queue, d, p - d);
|
||||
if (*p == '|')
|
||||
p++;
|
||||
d = p;
|
||||
for (p = (unsigned char *)h.queue; *p; p++)
|
||||
for (p = h.queue; *p; p++)
|
||||
if (!isalnum (*p))
|
||||
*p = '-'; /* make very safe for filenames */
|
||||
while (*d && *d != '|') {
|
||||
@@ -1427,20 +1429,20 @@ static int sms_exec (struct ast_channel *chan, void *data)
|
||||
}
|
||||
if (*d == '|') {
|
||||
/* submitting a message, not taking call. */
|
||||
/* deprecated, use smsq instead */
|
||||
/* depricated, use smsq instead */
|
||||
d++;
|
||||
h.scts = time (0);
|
||||
for (p = d; *p && *p != '|'; p++);
|
||||
if (*p)
|
||||
*p++ = 0;
|
||||
if (strlen ((char *)d) >= sizeof (h.oa)) {
|
||||
if (strlen (d) >= sizeof (h.oa)) {
|
||||
ast_log (LOG_ERROR, "Address too long %s\n", d);
|
||||
return 0;
|
||||
}
|
||||
if (h.smsc) {
|
||||
ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
|
||||
ast_copy_string (h.oa, d, sizeof (h.oa));
|
||||
} else {
|
||||
ast_copy_string (h.da, (char *)d, sizeof (h.da));
|
||||
ast_copy_string (h.da, d, sizeof (h.da));
|
||||
}
|
||||
if (!h.smsc)
|
||||
ast_copy_string (h.oa, h.cli, sizeof (h.oa));
|
||||
@@ -1457,7 +1459,7 @@ static int sms_exec (struct ast_channel *chan, void *data)
|
||||
h.rx = 0; /* sent message */
|
||||
h.mr = -1;
|
||||
sms_writefile (&h);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1481,13 +1483,13 @@ static int sms_exec (struct ast_channel *chan, void *data)
|
||||
res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_activate_generator (chan, &smsgen, &h) < 0) {
|
||||
ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1506,22 +1508,22 @@ static int sms_exec (struct ast_channel *chan, void *data)
|
||||
|
||||
sms_log (&h, '?'); /* log incomplete message */
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return (h.err);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application (app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module (void)
|
||||
{
|
||||
#ifdef OUTALAW
|
||||
{
|
||||
@@ -1535,4 +1537,19 @@ static int load_module(void)
|
||||
return ast_register_application (app, sms_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");
|
||||
char *description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -19,22 +19,20 @@
|
||||
/*! \file
|
||||
*
|
||||
* \brief SoftHangup application
|
||||
*
|
||||
* \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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
@@ -44,6 +42,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
static char *synopsis = "Soft Hangup Application";
|
||||
|
||||
static char *tdesc = "Hangs up the requested channel";
|
||||
|
||||
static char *desc = " SoftHangup(Technology/resource|options)\n"
|
||||
"Hangs up the requested channel. If there are no channels to hangup,\n"
|
||||
"the application will report it.\n"
|
||||
@@ -52,10 +52,13 @@ static char *desc = " SoftHangup(Technology/resource|options)\n"
|
||||
|
||||
static char *app = "SoftHangup";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int softhangup_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
struct ast_channel *c=NULL;
|
||||
char *options, *cut, *cdata, *match;
|
||||
char name[AST_CHANNEL_NAME] = "";
|
||||
@@ -66,7 +69,7 @@ static int softhangup_exec(struct ast_channel *chan, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
cdata = ast_strdupa(data);
|
||||
match = strsep(&cdata, "|");
|
||||
@@ -74,12 +77,12 @@ static int softhangup_exec(struct ast_channel *chan, void *data)
|
||||
all = options && strchr(options,'a');
|
||||
c = ast_channel_walk_locked(NULL);
|
||||
while (c) {
|
||||
ast_copy_string(name, c->name, sizeof(name));
|
||||
strncpy(name, c->name, sizeof(name)-1);
|
||||
ast_mutex_unlock(&c->lock);
|
||||
/* XXX watch out, i think it is wrong to access c-> after unlocking! */
|
||||
if (all) {
|
||||
/* CAPI is set up like CAPI[foo/bar]/clcnt */
|
||||
if (!strcmp(c->tech->type, "CAPI"))
|
||||
if (!strcmp(c->type,"CAPI"))
|
||||
cut = strrchr(name,'/');
|
||||
/* Basically everything else is Foo/Bar-Z */
|
||||
else
|
||||
@@ -97,25 +100,40 @@ static int softhangup_exec(struct ast_channel *chan, void *data)
|
||||
c = ast_channel_walk_locked(c);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
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();
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, softhangup_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hangs up the requested channel");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user