mirror of
https://github.com/asterisk/asterisk.git
synced 2026-03-27 16:23:30 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9727f66369 | ||
|
|
a1f2dc6595 | ||
|
|
236129e011 | ||
|
|
d790490af0 | ||
|
|
4eeba77ef7 |
@@ -1 +0,0 @@
|
||||
32
|
||||
@@ -1 +0,0 @@
|
||||
32
|
||||
21
BUGS
21
BUGS
@@ -1,8 +1,14 @@
|
||||
Asterisk 1.0-RC-1 Known Major Bugs
|
||||
==================================
|
||||
* Some people still have issues with H.323
|
||||
* QuickNet driver still not entirely stable
|
||||
|
||||
Asterisk Bug Tracking Information
|
||||
=================================
|
||||
|
||||
To learn about and report Asterisk bugs, please visit
|
||||
the official Asterisk Bug Tracker at:
|
||||
To learn about and report Asterisk bugs or make feature
|
||||
requests, please visit the official Asterisk Bug Tracker
|
||||
at:
|
||||
|
||||
http://bugs.digium.com
|
||||
|
||||
@@ -10,13 +16,8 @@ For more information on using the bug tracker, or to
|
||||
learn how you can contribute by acting as a bug marshal
|
||||
please see:
|
||||
|
||||
http://www.asterisk.org/developers/bug-guidelines
|
||||
|
||||
If you would like to submit a feature request, please
|
||||
resist the temptation to post it to the bug tracker.
|
||||
Feature requests should be posted to the asterisk-dev
|
||||
mailing list, located at:
|
||||
|
||||
http://lists.digium.com
|
||||
http://www.digium.com/bugtracker.html
|
||||
|
||||
Thank you!
|
||||
|
||||
Mark
|
||||
|
||||
916
CHANGES
916
CHANGES
@@ -1,345 +1,573 @@
|
||||
Changes since Asterisk 1.2:
|
||||
NOTE: Corrections or additions to the ChangeLog may be submitted
|
||||
to http://bugs.digium.com. Documentation and formatting
|
||||
fixes are not listed here. A complete listing of changes
|
||||
is available through the Asterisk-CVS mailing list hosted
|
||||
at http://lists.digium.com.
|
||||
|
||||
* 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()
|
||||
* 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. 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
|
||||
8. 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
|
||||
9. OSPFinish() : now also can return ERROR result.
|
||||
10. OSPLookup() : Sets more variables, also now returns ERROR result.
|
||||
11. Page() -- New option: r - record the page into a file (see 'r' for app_meetme)
|
||||
12. Pickup() -- multiple extensions, PICKUPMARK; read the description!
|
||||
13. Queue()
|
||||
o New Argument: AGI
|
||||
o New option: i
|
||||
14. Random() -- is now deprecated in 1.4
|
||||
15. Read() -- replace 'skip' and 'noanswer' options with 's', 'n', add 'i' option.
|
||||
16. Record() -- New option: 'x' : ignore all terminator keys (DTMF) and keep recording until hangup
|
||||
17. UserEvent() -- slight change in behavior. Read the description.
|
||||
18. VoiceMailMain() -- new a(#) option, goes to folder # directly.
|
||||
19. WaitForSilence() -- new optional 3rd arg, time delay before returning.
|
||||
* Functions that have changes to their interfaces:
|
||||
1. CDR -- new option: u
|
||||
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 maxlogintries variable added
|
||||
o autologoffunavail variable added
|
||||
o endcall variable added
|
||||
o agentgoodbye 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!
|
||||
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 allowoverlap variable added
|
||||
o allowtransfer 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 maxcallbitratesuggest variable added
|
||||
o allowsubscribe variable added
|
||||
o videosupport variable added
|
||||
o maxcallbitrate variable added
|
||||
o g726nonstandard variable added
|
||||
o dumphistory variable added
|
||||
o allowsubscribe variable added
|
||||
o t38pt_udptl variable added
|
||||
o canreinvite variable can also now be set to 'nonat'
|
||||
o rtsavesysname variable added
|
||||
o JitterBuffer support added
|
||||
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).
|
||||
-- chan_zap
|
||||
-- Asterisk will now also look in the regular context for the fax extension while
|
||||
executing a macro. Previously, for this to work, the fax extension would have
|
||||
to be included in the macro definition.
|
||||
-- On some systems, ALERTING will be sent after PROCEEDING, so code has been
|
||||
added to account for this case.
|
||||
-- If no extension is specified on an overlap call, the 's' extension will be used.
|
||||
-- chan_sip
|
||||
-- We no longer send a "to" tag on "100 Trying" messages, as it is inappropriate
|
||||
to do so.
|
||||
-- We now respond correctly to an invite for T.38 with a "488 Not acceptable here"
|
||||
-- We now discard saved tags on 401/407 responses in case the provider we're talking
|
||||
to tries to pull a dirty trick on us and change it.
|
||||
-- rtptimeout options will now be correctly set on a peer basis rather than only global
|
||||
-- chan_mgcp
|
||||
-- Fixed setting of accountcode
|
||||
-- Fixed where *67 to block callerid only worked for first call
|
||||
-- chan_agent
|
||||
-- We now will not pass audio until the agent has acked the call if the configuration
|
||||
is set up for the agent to do so.
|
||||
-- chan_alsa
|
||||
-- Fixed problems with the unloading of this module
|
||||
-- res_agi
|
||||
-- A fix has been added to prevent calls from being hung up when more than one
|
||||
call is executing an AGI script calling the GET DATA command.
|
||||
-- AGI scripts will now continue to run even if a file was not found with the
|
||||
GET DATA command.
|
||||
-- When calling SAY NUMBER with a number like 09, we will now say "nine" instead
|
||||
of "zero"
|
||||
-- app_dial
|
||||
-- There was a problem where text frames would not be forwarded before the channel
|
||||
has been answered.
|
||||
-- app_disa
|
||||
-- Fixed the timeout used when no password is set
|
||||
-- app_queue
|
||||
-- Distinctive ring has been fixed to work for queue members
|
||||
-- rtp
|
||||
-- Fixed a logic error when setting the "rtpchecksums" option
|
||||
-- say.c
|
||||
-- A problem has been fixed with saying the date in Spanish.
|
||||
-- Makefile
|
||||
-- A line was missing for the autosupport script that caused "make rpm" to fail
|
||||
-- format_wav_gsm
|
||||
-- Fixed a problem with wav formatting that prevented files from being played
|
||||
in some media players
|
||||
-- pbx_spool
|
||||
-- Fixed if the last line of text in a file for the call spool did not contain
|
||||
a new line, it would not be processed
|
||||
-- logger
|
||||
-- Fixed the logger so that color escape sequences wouldn't be sent to the logs
|
||||
-- format_sln
|
||||
-- A lot of changes were made to correctly handle signed linear format on
|
||||
big endian machines
|
||||
-- asterisk.conf
|
||||
-- fix 'highpriority' option for asterisk.conf
|
||||
|
||||
Asterisk 1.0.7
|
||||
|
||||
-- chan_sip
|
||||
-- The fix for some codec availibility issues in 1.0.6 caused music on hold problems,
|
||||
but has now been fixed.
|
||||
-- chan_skinny
|
||||
-- A check has been added to avoid a crash.
|
||||
-- chan_iax2
|
||||
-- A feature has been added to CVS head to have the option of sending timestamps with
|
||||
trunk frames. It is not supported in 1.0, but a change has been made so that it
|
||||
will at least not choke if sent trunk timestamps.
|
||||
-- app_voicemail
|
||||
-- Some checks have been added to avoid a crash.
|
||||
-- speex
|
||||
-- The path /usr/include/speex has been added for a place to look for the speex header.
|
||||
|
||||
Asterisk 1.0.6
|
||||
|
||||
-- chan_iax2:
|
||||
-- Fixed a bug dealing with a division by zero that could cause a crash
|
||||
-- chan_sip:
|
||||
-- Behavior was changed so that when a registration fails due to DNS resolution issues,
|
||||
a retry will be attempted in 20 seconds.
|
||||
-- Peer settings were not reset to null values when reloading the configuration file.
|
||||
Behavior has been changed so that these values are now cleared.
|
||||
-- 'restrictcid' now properly works on MySQL peers.
|
||||
-- Only use the default callerid if it has been specified.
|
||||
-- Asterisk was not sending the same From: line in SIP messages during certain times.
|
||||
Fixed to make sure it stays the same. This makes some providers happier, to a working state.
|
||||
-- Certain circumstances involving a blank callerid caused asterisk to segmentation fault.
|
||||
-- There was a problem incorrectly matching codec availablity when global preferences were
|
||||
different from that of the user. To fix this, processing of SDP data has been moved
|
||||
to after determining who the call is coming from.
|
||||
-- Asterisk would run out of RTP ports while waiting for SUBSCRIBE's to expire even though
|
||||
an RTP port isn't needed in this case. This has been fixed by releasing the ports early.
|
||||
-- chan_zap:
|
||||
-- During a certain scenario when using flash and '#' transfers you would hear the
|
||||
other person and the music they were hearing. This has been fixed.
|
||||
-- A fix for a compilation issue with gcc4 was added.
|
||||
-- chan_modem_bestdata:
|
||||
-- A fix for a compilation issue with gcc4 was added.
|
||||
-- format_g729:
|
||||
-- Treat a 10-byte read as an end of file indication instead of an error. Some G729 encoders
|
||||
like to put 10-bytes at the end to indicate this.
|
||||
-- res_features:
|
||||
-- During certain situations when parking a call, both endpoints would get musiconhold.
|
||||
This has been fixed so the individual who parked the call will hear the digits and not
|
||||
musiconhold.
|
||||
-- app_dial:
|
||||
-- DIALEDPEERNUMBER is now being set, so if you attempted to use it in the past and failed
|
||||
it should work now.
|
||||
-- A callerid change caused many headaches, this has been reversed to the original 1.0 behavior.
|
||||
-- A crash caused with the combination of the 'g' option and # transfer was fixed.
|
||||
-- app_voicemail:
|
||||
-- If two people hit the voicemail system at the same time, and were leaving a message
|
||||
the second message was overwriting the first. This has been fixed so that each one
|
||||
is distinct and will not overwrite eachother.
|
||||
-- cdr_tds:
|
||||
-- If the server you were using was going down, it had the potential to bring your asterisk
|
||||
server down with it. Extra stuff has been added so as to bring in more error/connection
|
||||
checking.
|
||||
-- cdr_pgsql:
|
||||
-- This will now attempt to reconnect after a connection problem.
|
||||
-- IAXY firmware:
|
||||
-- This has been updated to version 23. It includes a fix for lost registrations.
|
||||
-- internals
|
||||
-- Behavior was changed for 'show codec <number>' to make it more intuitive. (kshumard)
|
||||
-- DNS failures and asterisk do not get along too well, this is not totally the case anymore.
|
||||
-- Asterisk will now handle DNS failures at startup more gracefully, and won't crash and
|
||||
burn.
|
||||
-- Choosing to append to a wave file would render the outputted wave file corrupt. Appending
|
||||
now works again.
|
||||
-- If you failed to define certain keys, asterisk had the potential to crash when seeing if you had
|
||||
used them.
|
||||
-- Attempting to use such things as ${EXTEN:-1} gave a wrong return value. However, this was never
|
||||
a documented feature...
|
||||
|
||||
Asterisk 1.0.5
|
||||
|
||||
-- chan_zap
|
||||
-- fix a callerid bug introduced in 1.0.4
|
||||
-- app_queue
|
||||
-- fix some penalty behavior
|
||||
|
||||
Asterisk 1.0.4
|
||||
|
||||
-- general
|
||||
-- fix memory leak evident with extensive use of variables
|
||||
-- update IAXy firmware to version 22
|
||||
-- enable some special write protection
|
||||
-- enable outbound DTMF
|
||||
-- fix seg fault with incorrect usage of SetVar
|
||||
-- other minor fixes including typos and doc updates
|
||||
-- chan_sip
|
||||
-- fix codecs to not be case sensitive
|
||||
-- Re-use auth credentials
|
||||
-- fix MWI when using type=friend
|
||||
-- fix global NAT option
|
||||
-- chan_agent / chan_local
|
||||
-- fix incorrect use count
|
||||
-- chan_zap
|
||||
-- Allow CID rings to be configured in zapata.conf
|
||||
-- no more patching needed for UK CID
|
||||
-- app_macro
|
||||
-- allow Macros to exit with '*' or '#' like regular extension processing
|
||||
-- app_voicemail
|
||||
-- don't allow '#' as a password
|
||||
-- add option to save voicemail before going to the operator
|
||||
-- fix global operator=yes
|
||||
-- app_read
|
||||
-- return 0 instead of -1 if user enters nothing
|
||||
-- res_agi
|
||||
-- don't exit AGI when file not found to stream
|
||||
-- send script parameter when using FastAGI
|
||||
|
||||
Asterisk 1.0.3
|
||||
|
||||
-- chan_zap
|
||||
-- fix seg fault when doing *0 to flash a trunk
|
||||
-- rtp
|
||||
-- seg fault fix
|
||||
-- chan_sip
|
||||
-- fix to prevent seg fault when attempting a transfer
|
||||
-- fix bug with supervised transfers
|
||||
-- fix codec preferences
|
||||
-- chan_h323
|
||||
-- fix compilation problem
|
||||
-- chan_iax2
|
||||
-- avoid a deadlock related to a static config of a BUNCH of peers
|
||||
-- cdr_pgsql
|
||||
-- fix memory leak when reading config
|
||||
-- Numerous other minor bug fixes
|
||||
|
||||
Asterisk 1.0.2
|
||||
|
||||
-- Major bugfix release
|
||||
|
||||
Asterisk 1.0.1
|
||||
|
||||
-- Added AGI over TCP support
|
||||
-- Add ability to purge callers from queue if no agents are logged in
|
||||
-- Fix inband PRI indication detection
|
||||
-- Fix for MGCP - always request digits if no RTP stream
|
||||
-- Fixed seg fault for ast_control_streamfile
|
||||
-- Make pick-up extension configurable via features.conf
|
||||
-- Numerous other bug fixes
|
||||
|
||||
Asterisk 1.0.0
|
||||
-- Use Q.931 standard cause codes for asterisk cause codes
|
||||
-- Bug fixes from the bug tracker
|
||||
Asterisk 1.0-RC2
|
||||
-- Additional CDR backends
|
||||
-- Allow muted to reconnect
|
||||
-- Call parking improvements (including SIP parking support)
|
||||
-- Added licensed hold music from FreePlayMusic
|
||||
-- GR-303 and Zap improvements
|
||||
-- More bug fixes from the bug tracker
|
||||
-- Improved FreeBSD/OpenBSD/MacOS X support
|
||||
Asterisk 1.0-RC1
|
||||
-- Innumerable bug fixes and features from the bug tracker
|
||||
-- Added Open Settlement Protocol (OSP) support
|
||||
-- Added Non-facility Associated Signalling (NFAS) Support
|
||||
-- Added alarm Monitoring support
|
||||
-- Added new MeetMe options
|
||||
-- Added GR-303 Support
|
||||
-- Added trunk groups
|
||||
-- ADPCM Standardization
|
||||
-- Numerous bug fixes
|
||||
-- Add IAX2 Firmware Support
|
||||
-- Add G.726 support
|
||||
-- Add ices/icecast support
|
||||
-- Numerous bug fixes
|
||||
Asterisk 0.7.2
|
||||
-- Countless small bug fixes from bug tracker
|
||||
-- DSP Fixes
|
||||
-- Fix unloading of Zaptel
|
||||
-- Pass Caller*ID/ANI properly on call forwarding
|
||||
-- Add indication for Italy
|
||||
Asterisk 0.7.1
|
||||
-- Fixed timed include context's and GotoIfTime
|
||||
-- Fixed chan_h323 it now gets remote ip properly instead of 127.0.0.1
|
||||
Asterisk 0.7.0
|
||||
-- Removed MP3 format and codec
|
||||
-- Can now load and unload SIP,IAX,IAX2,H323 channels without core
|
||||
-- Fixed various compiler warnings and clean up source tree
|
||||
-- Preliminary AES Support
|
||||
-- Fix SIP REINVITE
|
||||
-- Outbound SIP registration behind NAT using externip
|
||||
-- More CLI documentation and clean up
|
||||
-- Pin numbers on MeeMe
|
||||
-- Dynamic MeetMe conferences are more consistent with static conferences
|
||||
-- Added channel variables ${HANGUPCAUSE}, ${SIPDOMAIN}, ${TIMESTAMP}, ${ACCONTCODE}
|
||||
-- ODBC support for logging CDRs
|
||||
-- Indications for Norway and New Zeland
|
||||
-- Major redesign of app_voicemail
|
||||
-- Syslog support
|
||||
-- Reload logfiles with CLI command 'logger reload' and rotate logs with "logger rotate'
|
||||
-- Configurable DEBUG, NOTICE, WARNING, ERROR and ast_verbose messages now appear on remote console
|
||||
-- Properly reaping any zombie processes
|
||||
-- Added applications SayUnixTime, SetCDRUserField, HasNewVoicemail, ZapScan, Random, ResetCDR, NoCDR
|
||||
-- Make PRI Hangup Cause available to the dialplan
|
||||
-- Verify included contexts in extensions.conf
|
||||
-- Add DESTDIR support for building RPMs and packages
|
||||
-- Do route lookups on OpenBSD
|
||||
-- Add support for building on FreeBSD and OS X
|
||||
-- Add support for PostgreSQL in Voicemail
|
||||
-- Translate SIP hangup cause to PRI hangup cause where needed
|
||||
-- Better support for MOH in IAX2
|
||||
-- Fix SIP problem where channels were not removed on BYE
|
||||
-- Display codecs by name
|
||||
-- Remove MySQL and put PGSql instead for licensing reasons
|
||||
-- Better capability matching in SIP
|
||||
-- Full IBR4 compliance for chan_zap
|
||||
-- More flexible CDR handling
|
||||
-- Distinguish between BUSY and FAILURE on outbound calls
|
||||
-- Add initial support for SCCP via chan_skinny
|
||||
-- Better support for Future Group B signaling
|
||||
Asterisk 0.5.0
|
||||
-- Retain IAX2 and SIP registrations past shutdown/crash and restart
|
||||
-- True data mode bridging when possible
|
||||
-- H.323 build improvements
|
||||
-- Agent Callback-login support
|
||||
-- RFC2833 Improvements
|
||||
-- Add thread debugging
|
||||
-- Add optional pedantic SIP checking for Pingtel
|
||||
-- Allow extension names, include context, switch to use global vars.
|
||||
-- Allow variables in extensions.conf to reference previously defined ones
|
||||
-- Merge voicemail enhancements (app_voicemail2)
|
||||
-- Add multiple queueing strategies
|
||||
-- Merge support for 'T'
|
||||
-- Allow pending agent calling (Agent/:1)
|
||||
-- Add groupings to agents.conf
|
||||
-- Add video support to IAX2
|
||||
-- Zaptel optimize playback
|
||||
-- Add video support to SIP
|
||||
-- Make RTP ports configurable
|
||||
-- Add RDNIS support to SIP and IAX2
|
||||
-- Add transfer app (implement in SIP and IAX2)
|
||||
-- Make voicemail segmentable by context (app_voicemail2)
|
||||
-- Major restructuring of voicemail (app_voicemail2)
|
||||
-- Add initial ENUM support
|
||||
-- Add malloc debugging support
|
||||
-- Add preliminary Voicetronix support
|
||||
-- Add iLBC codec
|
||||
Asterisk 0.4.0
|
||||
-- Merge and edit Nick's FXO dial support
|
||||
-- Reengineer SIP registration (outbound)
|
||||
-- Support call pickup on SIP and compatibly with ZAP
|
||||
-- Support 302 Redirect on SIP
|
||||
-- Management interface improvements
|
||||
-- Add "hint" support
|
||||
-- Improve call forwarding using new "Local" channel driver.
|
||||
-- Add "Local" channel
|
||||
-- Substantial SIP enhancements including retransmissions
|
||||
-- Enforce case sensitivity on extension/context names
|
||||
-- Add monitor support (Thanks, Mahmut)
|
||||
-- Add experimental "trunk" option to IAX2 for high density VoIP
|
||||
-- Add experimental "debug channel" command
|
||||
-- Add 'C' flag to dial command to reset call detail record (handy for calling cards)
|
||||
-- Add NAT and dynamic support to MGCP
|
||||
-- Allow selection of in-band, out-of-band, or INFO based DTMF
|
||||
-- Add contributed "*80" support to blacklist numbers (Thanks James!)
|
||||
-- Add "NAT" option to sip user, peer, friend
|
||||
-- Add experimental "IAX2" protocol
|
||||
-- Change special variable "EXTEN-n" to "EXTEN:n" to follow Bash syntax
|
||||
-- Add "Enhanced" AGI with audio pass-through (voice recognition anyone?)
|
||||
-- Choose best priority from codec from allow/disallow
|
||||
-- Reject SIP calls to self
|
||||
-- Allow SIP registration to provide an alternative contact
|
||||
-- Make HOLD on SIP make use of asterisk MOH
|
||||
-- Add supervised transfer (tested with Pingtel only)
|
||||
-- Allow maxexpirey and defaultexpirey to be runtime configurable for SIP
|
||||
-- Preliminary codec 13 support (RFC3389)
|
||||
-- Add app_authenticate for general purpose authentication
|
||||
-- Optimize RTP and smoother
|
||||
-- Create special variable "EXTEN-n" where it is extension stripped by n MSD
|
||||
-- Fix uninitialized frame pointer in channel.c
|
||||
-- Add global variables support under [globals] of extensions.conf
|
||||
-- Add macro support (show application Macro)
|
||||
-- Allow [123-5] etc in extensions
|
||||
-- Allow format of App(arg1,arg2,...) instead of just App,arg1|arg2 in dialplan
|
||||
-- Add message waiting indicator to SIP
|
||||
-- Fix double free bug in channel.c
|
||||
Asterisk 0.3.0
|
||||
-- Add fastfoward, rewind, seek, and truncate functions to streams
|
||||
-- Support registration
|
||||
-- Add G729 format
|
||||
-- Permit applications to return a digit indicating new extension
|
||||
-- Change "SHUTDOWN" to "STOP" in commands
|
||||
-- SIP "Hold" fixes and VXML URI support
|
||||
-- New chan_zap with 160 sample chunk size
|
||||
-- Add DTMF, MF, and Fax tone detector to dsp routines
|
||||
-- Allow overlap dialing (inbound) on PRI
|
||||
-- Enable tone detection with PRI
|
||||
-- Add special information tone detection
|
||||
-- Add Asterisk DB support
|
||||
-- Add pulse dialing
|
||||
-- Re-record all system prompts
|
||||
-- Change "timelen" to samples for better accuracy
|
||||
-- Move to editline, eliminating readline dependency
|
||||
-- Add peer "poke" support to SIP and IAX
|
||||
-- Add experimental call progress detection
|
||||
-- Add SIP authentication (digest)
|
||||
-- Add RDNIS
|
||||
-- Reroute faxes to "fax" extension
|
||||
-- Create ISDN/modem group concept
|
||||
-- Centralize indication
|
||||
-- Add initial MGCP support
|
||||
-- SIP debugging cleanup
|
||||
-- SIP reload
|
||||
-- SIP commands (show channels, etc)
|
||||
-- Add optional busy detection
|
||||
-- Add Visual Message Waiting Indicator (MDMF and SDMF)
|
||||
-- Add ambiguous extension matching
|
||||
-- Add *69
|
||||
-- Major SIP enhancements from SIPit
|
||||
-- Rewrite of ZAP CLASS features using subchannels
|
||||
-- Enhanced call parking
|
||||
-- Add extended outgoing spool support (pbx_spool)
|
||||
Asterisk 0.2.0
|
||||
-- Outbound origination API
|
||||
-- Call management improvements
|
||||
-- Add Do Not Disturb (*78, *79)
|
||||
-- Add agents
|
||||
-- Document variables
|
||||
-- Add transfer capability on the console
|
||||
-- Add SpeeX codec translator
|
||||
-- Add call queues
|
||||
-- Add setcallerid functionality (AGI, application)
|
||||
-- Add special variables ${CALLERID}, ${EXTEN}, ${CONTEXT}, ${PRIORITY}
|
||||
-- Don't echo cancel on pure TDM connections by default
|
||||
-- Implement Async GOTO
|
||||
-- Differentiate softhangups
|
||||
-- Add date/time
|
||||
Asterisk 0.1.12
|
||||
-- Fix for Big Endian machines
|
||||
-- MySQL CDR Engine
|
||||
-- Various SIP fixes and enhancements
|
||||
-- Add "zapateller application and arbitrary tone pairs
|
||||
-- Don't always start at "s"
|
||||
-- Separate linear mode for pseudo and real
|
||||
-- Add initial RTP and SIP support (no jitter buffer yet, unknown stability)
|
||||
-- Add 'h' extension, executed on hangup
|
||||
-- Add duration timer to message info
|
||||
-- Add web based voicemail checking ("make webvmail")
|
||||
-- Add ast_queue_frame function and eliminate frame pipes in most drivers
|
||||
-- Centralize host access (and possibly future ACL's)
|
||||
-- Add Caller*ID on PhoneJack (Thanks Nathan)
|
||||
-- Add "safe_asterisk" wrapper script to auto-restart Asterisk
|
||||
-- Indicate ringback on chan_phone
|
||||
-- Add answer confirmation (press '#' to confirm answer)
|
||||
-- Add distinctive ring support (e.g. Dial,Zap/4r2)
|
||||
-- Add ANSI/vt100 color support
|
||||
-- Make parking configurable through parking.conf
|
||||
-- Fix the empty voicemail problem
|
||||
-- Add Music On Hold
|
||||
-- Add ADSI Compiler (app_adsiprog)
|
||||
-- Extensive DISA re-work to improve tone generation
|
||||
-- Reset all idle channels every 10 minutes on a PRI
|
||||
-- Reset channels which are hungup with "channel in use"
|
||||
-- Implement VNAK support in chan_iax
|
||||
-- Fix chan_oss to support proper hangups and autoanswer
|
||||
-- Make shutdown properly hangup channels
|
||||
-- Add idling capability to chan_zap for idle-net
|
||||
-- Add "MeetMe" conferencing app (app_meetme)
|
||||
-- Add timing information to include
|
||||
Asterisk 0.1.11
|
||||
-- Add ISDN RAS capability
|
||||
-- Add stutter dialtone to Chan Zap
|
||||
-- Add "#include" capability to config files.
|
||||
-- Add call-forward variable to Chan Zap (*72, *73)
|
||||
-- Optimize IAX flow when transfer isn't possible
|
||||
-- Allow transmission of ANI over IAX
|
||||
Asterisk 0.1.10
|
||||
-- Make ast_readstring parameter be the max # of digits, not the max size with \0
|
||||
-- Make up any missing messages on the fly
|
||||
-- Add support for specific DTMF interruption to saying numbers
|
||||
-- Add new "u" and "b" options to condense busy/unavail handling
|
||||
-- Add support for RSA authentication on IAX calls
|
||||
-- Add support for ADSI compatible CPE
|
||||
-- Outgoing call queue
|
||||
-- Remote dialplan fixes for Quicknet
|
||||
-- Added AGI commands supporting TDD functions (RECEIVE CHAR & TDD MODE)
|
||||
-- Added TDD support (send/receive text in chan_zap)
|
||||
-- Fix all strncpy references
|
||||
-- Implement CSV CDR backend
|
||||
-- Implement Call Detail Records
|
||||
Asterisk 0.1.9
|
||||
-- Implement IAX quelching
|
||||
-- Allow Caller*ID to be overridden and suggested
|
||||
-- Configure defaults to use IAXTEL
|
||||
-- Allow remote dialplan polling via IAX
|
||||
-- Eliminate ast_longest_extension
|
||||
-- Implement dialplan request/reply
|
||||
-- Let peers have allow/disallow for codecs
|
||||
-- Change allow/deny to permit/deny in IAX
|
||||
-- Allow dialplan entries to match Caller*ID as well
|
||||
-- Added AGI (Asterisk Gateway Interface) scripting interface (app_agi)
|
||||
-- Added chan_zap for zapata telephony kernel interface, removed chan_tor
|
||||
-- Add convenience functions
|
||||
-- Fix race condition in channel hangup
|
||||
-- Fix memory leaks in both asterisk and iax frame allocations
|
||||
-- Add "iax show stats" command and -DTRACE_FRAMES (for frame tracing)
|
||||
-- Add DISA application (Thanks to Jim Dixon)
|
||||
-- Add IAX transfer support
|
||||
-- Add URL and HTML transmission
|
||||
-- Add application for sending images
|
||||
-- Add RedHat RPM spec file and build capability
|
||||
-- Fix GSM WAV file format bug
|
||||
-- Move ignorepat to main dialplan
|
||||
-- Add ability to specificy TOS bits in IAX
|
||||
-- Allow username:password in IAX strings
|
||||
-- Updates to PhoneJack interface
|
||||
-- Allow "servermail" in voicemail.conf to override e-mail in "from" line
|
||||
-- Add 'skip' option to app_playback
|
||||
-- Reject IAX calls on unknown extensions
|
||||
-- Fix version stuff
|
||||
Asterisk 0.1.8
|
||||
-- Keep track of version information
|
||||
-- Add -f to cause Asterisk not to fork
|
||||
-- Keep important information in voicemail .txt file
|
||||
-- Adtran Voice over Frame Relay updates
|
||||
-- Implement option setting/querying of channel drivers
|
||||
-- IAX performance improvements and protocol fixes
|
||||
-- Substantial enhancement of console channel driver
|
||||
-- Add IAX registration. Now IAX can dynamically register
|
||||
-- Add flash-hook transfer on tormenta channels
|
||||
-- Added Three Way Calling on tormenta channels
|
||||
-- Start on concept of zombie channel
|
||||
-- Add Call Waiting CallerID
|
||||
-- Keep track of who registeres contexts, includes, and extensions
|
||||
-- Added Call Waiting(tm), *67, *70, and *82 codes
|
||||
-- Move parked calls into "parkedcalls" context by default
|
||||
-- Allow dialplan to be displayed
|
||||
-- Allow "=>" instead of just "=" to make instantiation clearer
|
||||
-- Asterisk forks if called with no arguments
|
||||
-- Add remote control by running asterisk -vvvc
|
||||
-- Adjust verboseness with "set verbose" now
|
||||
-- No longer requires libaudiofile
|
||||
-- Install beep
|
||||
-- Make PBX Config module reload extensions on SIGHUP
|
||||
-- Allow modules to be reloaded when SIGHUP is received
|
||||
-- Variables now contain line numbers
|
||||
-- Make dialer send in band signalling
|
||||
-- Add record application
|
||||
-- Added PRI signalling to Tormenta driver
|
||||
-- Allow use of BYEXTENSION in "Goto"
|
||||
-- Allow adjustment of gains on tormenta channels
|
||||
-- Added raw PCM file format support
|
||||
-- Add U-law translator
|
||||
-- Fix DTMF handling in bridge code
|
||||
-- Fix access control with IAX
|
||||
* Asterisk 0.1.7
|
||||
-- Update configuration files and add some missing sounds
|
||||
-- Added ability to include one context in another
|
||||
-- Rewrite of PBX switching
|
||||
-- Major mods to dialler application
|
||||
-- Added Caller*ID spill reception
|
||||
-- Added Dialogic VOX file format support
|
||||
-- Added ADPCM Codec
|
||||
-- Add Tormenta driver (RBS signalling)
|
||||
-- Add Caller*ID spill creation
|
||||
-- Rewrite of translation layer entirely
|
||||
-- Add ability to run PBX without additional thread
|
||||
* Asterisk 0.1.6
|
||||
-- Make app_dial handle a lack of translators smoothly
|
||||
-- Add ISDN4Linux support -- dtmf is weird...
|
||||
-- Minor bug fixes
|
||||
* Asterisk 0.1.5
|
||||
-- Fix a small mistake in IAX
|
||||
-- Fix the QuickNet driver to work with newer cards
|
||||
* Asterisk 0.1.4
|
||||
-- Update VoFR some more
|
||||
-- Fix the QuickNet driver to work with LineJack
|
||||
-- Add ability to pass images for IAX.
|
||||
* Asterisk 0.1.3
|
||||
-- Update VoFR for latest sangoma code
|
||||
-- Update QuickNet Driver
|
||||
-- Add text message handling
|
||||
-- Fix transfers to use "default" if not in current context
|
||||
-- Add call parking
|
||||
-- Improve format/content negotiation
|
||||
-- Added support for multiple languages
|
||||
-- Bug fixes, as always...
|
||||
* Asterisk 0.1.2
|
||||
-- Updated README file with a "Getting Started" section
|
||||
-- Added sample sounds and configuration files.
|
||||
-- Added LPC10 very low bandwidth (low quality) compression
|
||||
-- Enhanced translation selection mechanism.
|
||||
-- Enhanced IAX jitter buffer, improved reliability
|
||||
-- Support echo cancelation on PhoneJack
|
||||
-- Updated PhoneJack driver to std. Telephony interface
|
||||
-- Added app_echo for evaluating VoIP latency
|
||||
-- Added app_system to execute arbitrary programs
|
||||
-- Updated sample configuration files
|
||||
-- Added OSS channel driver (full duplex only)
|
||||
-- Added IAX implementation
|
||||
-- Fixed some deadlocks.
|
||||
-- A whole bunch of bug fixes
|
||||
* Asterisk 0.1.1
|
||||
-- Revised translator, fixed some general race conditions throughout *
|
||||
-- Made dialer somewhat more aware of incompatible voice channels
|
||||
-- Added Voice Modem driver and A/Open Modem Driver stub
|
||||
-- Added MP3 decoder channel
|
||||
-- Added Microsoft WAV49 support
|
||||
-- Revised License -- Pure GPL, nothing else
|
||||
-- Modified Copyright statement since code is still currently owned by author
|
||||
-- Added RAW GSM headerless data format
|
||||
-- Innumerable bug fixes
|
||||
* Asterisk 0.1.0
|
||||
-- Initial Release
|
||||
|
||||
341
COPYING
341
COPYING
@@ -1,341 +0,0 @@
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
136
CREDITS
136
CREDITS
@@ -1,6 +1,6 @@
|
||||
|
||||
=== DEVELOPMENT SUPPORT ===
|
||||
We'd like to thank the following companies for helping fund development of
|
||||
I'd like to thank the following companies for helping fund development of
|
||||
Asterisk:
|
||||
|
||||
Pilosoft, Inc. - for supporting ADSI development in Asterisk
|
||||
@@ -13,8 +13,6 @@ Telesthetic - for supporting SIP development
|
||||
|
||||
Christos Ricudis - for substantial code contributions
|
||||
|
||||
nic.at - ENUM support in Asterisk
|
||||
|
||||
Paul Bagyenda, Digital Solutions - for initial Voicetronix driver development
|
||||
|
||||
=== WISHLIST CONTRIBUTERS ===
|
||||
@@ -27,151 +25,51 @@ Wasim - Hangup detect
|
||||
* Thanks to QuickNet Technologies for their donation of an Internet
|
||||
PhoneJack and Linejack card to the project. (http://www.quicknet.net)
|
||||
|
||||
* Thanks to VoipSupply for their donation of Sipura ATAs to the project for
|
||||
T.38 testing. (http://www.voipsupply.com)
|
||||
|
||||
* Thanks to Grandstream for their donation of ATAs to the project for
|
||||
T.38 testing. (http://www.grandstream.com)
|
||||
|
||||
=== MISCELLANEOUS PATCHES ===
|
||||
Jim Dixon - Zapata Telephony and app_rpt
|
||||
http://www.zapatatelephony.org/app_rpt.html
|
||||
|
||||
Russell Bryant - Asterisk 1.0 maintainer and misc. enhancements
|
||||
russelb@clemson.edu
|
||||
|
||||
Anthony Minessale II - Countless big and small fixes, and relentless forward push
|
||||
ChanSpy, ForkCDR, ControlPlayback, While/EndWhile, DumpChan, Dictate,
|
||||
MacroIf, ExecIf, ExecIfTime, RetryDial, MixMonitor applications; many realtime
|
||||
concepts and implementation pieces, including res_config_odbc; format_slin;
|
||||
cdr_custom; several features in Dial including L(), G() and enhancements to
|
||||
M() and D(); several CDR enhancements including CDR variables; attended
|
||||
transfer; one touch record; native MOH; manager eventmask; command line '-t'
|
||||
flag to allow recording/voicemail on nfs shares; #exec command and multiline
|
||||
comments in config files; setvar in iax and sip configs.
|
||||
anthmct@yahoo.com http://www.asterlink.com
|
||||
|
||||
Anthony Minessale - Countless big and small fixes, and relentless forward push
|
||||
anthmct@yahoo.com http://www.asterlink.com
|
||||
James Golovich - Innumerable contributions
|
||||
You can find him and asterisk-perl at http://asterisk.gnuinter.net
|
||||
|
||||
You can find him and asterisk-perl at http://asterisk.gnuinter.net
|
||||
Andre Bierwirth - Extension hints and status
|
||||
|
||||
Oliver Daudey - ISDN4Linux fixes
|
||||
|
||||
Pauline Middelink - ISDN4Linux patches and some general patches.
|
||||
She can be found at http://www.polyware.nl/~middelink/En/
|
||||
|
||||
She can be found at http://www.polyware.nl/~middelink/En/
|
||||
Jean-Denis Girard - Various contributions from the South Pacific Islands
|
||||
jd-girard@esoft.pf http://www.esoft.pf
|
||||
|
||||
William Jordan / Vonage - MySQL enhancements to Voicemail
|
||||
jd-girard@esoft.pf http://www.esoft.pf
|
||||
William Jordan / Vonage - MySQL enhancmenets to Voicemail
|
||||
wjordan@vonage.com
|
||||
|
||||
Jac Kersing - Various fixes
|
||||
|
||||
Steven Critchfield - Seek and Trunc functions for playback and recording
|
||||
critch@basesys.com
|
||||
|
||||
critch@basesys.com
|
||||
Jefferson Noxon - app_lookupcidname, app_db, and various other contributions
|
||||
|
||||
Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
|
||||
|
||||
Ross Finlayson - Dynamic RTP payload support
|
||||
|
||||
Mahmut Fettahlioglu - Audio recording, music-on-hold changes, alaw file
|
||||
format, and various fixes. Can be contacted at mahmut@oa.com.au
|
||||
|
||||
format, and various fixes. Can be contacted at mahmut@oa.com.au
|
||||
James Dennis - Cisco SIP compatibility patches to work with SIP service
|
||||
providers. Can be contacted at asterisk@jdennis.net
|
||||
|
||||
Tilghman Lesher - ast_localtime(); ast_say_date_with_format();
|
||||
GotoIfTime, Random, SayUnixTime, HasNewVoicemail applications;
|
||||
CUT, SORT, EVAL, CURL, FIELDQTY, STRFTIME, QUEUEAGENT* functions;
|
||||
and other innumerable bug fixes. http://asterisk.drunkcoder.com/
|
||||
|
||||
providers. Can be contacted at asterisk@jdennis.net
|
||||
Tilghman Lesher - - Route lookup code; ast_localtime(), ast_say_date_with_format();
|
||||
GotoIfTime, Random, SayUnixTime, HasNewVoicemail, and Cut applications,
|
||||
along with various other patches. http://asterisk.drunkcoder.com/
|
||||
Jayson Vantuyl - Manager protocol changes, various other bugs.
|
||||
jvantuyl@computingedge.net
|
||||
|
||||
Thorsten Lockert - OpenBSD, FreeBSD ports, making MacOS X port run on 10.3,
|
||||
dialplan include verification, route lookup on OpenBSD, SNMP agent
|
||||
support (res_snmp), various other bugs. tholo@sigmasoft.com
|
||||
|
||||
dialplan include verification, route lookup on OpenBSD, various other
|
||||
bugs. tholo@sigmasoft.com
|
||||
Brian West - ODBC support and Bug Marshaling
|
||||
|
||||
Josh Roberson - chan_zap reload support, Advanced Voicemail Features, other misc. patches,
|
||||
and Bug Marshalling. - josh@asteriasgi.com, http://www.asteriasgi.com
|
||||
|
||||
William Waites - syslog support, SIP NAT traversal for SIP-UA. ww@styx.org
|
||||
|
||||
Rich Murphey - Porting to FreeBSD, NetBSD, OpenBSD, and Darwin.
|
||||
rich@whiteoaklabs.com http://whiteoaklabs.com
|
||||
|
||||
Simon Lockhart - Porting to Solaris (based on work of Logan ???)
|
||||
simon@slimey.org
|
||||
|
||||
Olle E. Johansson - SIP RFC compliance, documentation and testing, testing, testing
|
||||
oej@edvina.net, http://edvina.net
|
||||
|
||||
Steve Kann - new jitter buffer for IAX2
|
||||
stevek@stevek.com
|
||||
|
||||
Constantine Filin - major contributions to the Asterisk Realtime Architecture
|
||||
|
||||
Steve Murphy - privacy support, $[ ] parser upgrade, AEL2 parser upgrade
|
||||
|
||||
Claude Patry - bug fixes, feature enhancements, and bug marshalling
|
||||
cpatry@gmail.com
|
||||
|
||||
Miroslav Nachev, miro@space-comm.com COSMOS Software Enterprises, Ltd.
|
||||
- for Variable for No Answer Timeout for Attended Transfer
|
||||
|
||||
Slav Klenov & Vanheuverzwijn Joachim - development of the generic jitterbuffer
|
||||
Securax Ltd. info@securax.be
|
||||
|
||||
Roy Sigurd Karlsbakk - providing funding for generic jitterbuffer development
|
||||
roy@karlsbakk.net, Briiz Telecom AS
|
||||
|
||||
Voop A/S, Nuvio Inc, Inotel S.A and Foniris Telecom A/S - funding for rewrite of SIP transfers
|
||||
|
||||
Philippe Sultan - RADIUS CDR module
|
||||
INRIA, http://www.inria.fr/
|
||||
|
||||
John Martin, Aupix - Improved video support in the SIP channel
|
||||
|
||||
Steve Underwood - Provided T.38 pass through support.
|
||||
|
||||
George Konstantoulakis - Support for Greek in voicemail added by InAccess Networks (work funded by HOL, www.hol.gr) gkon@inaccessnetworks.com
|
||||
|
||||
Daniel Nylander - Support for Swedish and Norwegian languages in voicemail. http://www.danielnylander.se/
|
||||
|
||||
Stojan Sljivic - An option for maximum number of messsages per mailbox in voicemail. Also an issue with voicemail synchronization has been fixed. GDS Partners www.gdspartners.com . stojan.sljivic@gdspartners.com
|
||||
|
||||
Bartosz Supczinski - Support for Polish added by DIR (www.dir.pl) Bartosz.Supczinski@dir.pl
|
||||
|
||||
James Rothenberger - Support for IMAP storage integration added by OneBizTone LLC Work funded by University of Pennsylvania jar@onebiztone.com
|
||||
|
||||
Paul Cadach - Bringing chan_h323 up to date, bug fixes, and more!
|
||||
|
||||
=== OTHER CONTRIBUTIONS ===
|
||||
John Todd - Monkey sounds and associated teletorture prompt
|
||||
Michael Jerris - bug marshaling
|
||||
Leif Madsen, Jared Smith and Jim van Meggelen - the Asterisk book
|
||||
available under a Creative Commons License at http://www.asteriskdocs.org
|
||||
Brian M. Clapper - poll.c emulation
|
||||
This product includes software developed by Brian M. Clapper <bmc@clapper.org>
|
||||
|
||||
=== HOLD MUSIC ===
|
||||
Music provided by www.opsound.org
|
||||
|
||||
=== OTHER SOURCE CODE IN ASTERISK ===
|
||||
Asterisk uses libedit, the lightweight readline replacement from NetBSD.
|
||||
The cdr_radius module uses libradiusclient-ng, which is also from NetBSD.
|
||||
They are BSD-licensed and require the following statement:
|
||||
|
||||
This product includes software developed by the NetBSD
|
||||
Foundation, Inc. and its contributors.
|
||||
|
||||
Digium did not implement the codecs in Asterisk. Here is the copyright on the
|
||||
I did not implement the codecs in asterisk. Here is the copyright on the
|
||||
GSM source:
|
||||
|
||||
Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
|
||||
@@ -196,7 +94,7 @@ And the copyright on the ADPCM source:
|
||||
Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
|
||||
Netherlands.
|
||||
|
||||
All Rights Reserved
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
|
||||
@@ -11,7 +11,10 @@ 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,6 +28,9 @@ Zaptel 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.
|
||||
|
||||
@@ -43,26 +49,16 @@ Non-zaptel 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
|
||||
|
||||
389
LICENSE
389
LICENSE
@@ -1,68 +1,341 @@
|
||||
Asterisk is distributed under the GNU General Public License version 2
|
||||
and is also available under alternative licenses negotiated directly
|
||||
with Digium, Inc. If you obtained Asterisk under the GPL, then the GPL
|
||||
applies to all loadable Asterisk modules used on your system as well,
|
||||
except as defined below. The GPL (version 2) is included in this
|
||||
source tree in the file COPYING.
|
||||
|
||||
This package also includes various components that are not part of
|
||||
Asterisk itself; these components are in the 'contrib' directory
|
||||
and its subdirectories. Most of these components are also
|
||||
distributed under the GPL version 2 as well, except for the following:
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
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).
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Digium, Inc. (formerly Linux Support Services) holds copyright
|
||||
and/or sufficient licenses to all components of the Asterisk
|
||||
package, and therefore can grant, at its sole discretion, the ability
|
||||
for companies, individuals, or organizations to create proprietary or
|
||||
Open Source (even if not GPL) modules which may be dynamically linked at
|
||||
runtime with the portions of Asterisk which fall under our
|
||||
copyright/license umbrella, or are distributed under more flexible
|
||||
licenses than GPL.
|
||||
Preamble
|
||||
|
||||
If you wish to use our code in other GPL programs, don't worry --
|
||||
there is no requirement that you provide the same exception in your
|
||||
GPL'd products (although if you've written a module for Asterisk we
|
||||
would strongly encourage you to make the same exception that we do).
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
Specific permission is also granted to link Asterisk with OpenSSL and
|
||||
OpenH323 and distribute the resulting binary files.
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
In addition, Asterisk implements two management/control protocols: the
|
||||
Asterisk Manager Interface (AMI) and the Asterisk Gateway Interface
|
||||
(AGI). It is our belief that applications using these protocols to
|
||||
manage or control an Asterisk instance do not have to be licensed
|
||||
under the GPL or a compatible license, as we believe these protocols
|
||||
do not create a 'derivative work' as referred to in the GPL. However,
|
||||
should any court or other judiciary body find that these protocols do
|
||||
fall under the terms of the GPL, then we hereby grant you a license to
|
||||
use these protocols in combination with Asterisk in external
|
||||
applications licensed under any license you wish.
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
The 'Asterisk' name and logos are trademarks owned by Digium, Inc.,
|
||||
and use of them is subject to our trademark licensing policies. If you
|
||||
wish to use these trademarks for purposes other than simple
|
||||
redistribution of Asterisk source code obtained from Digium, you
|
||||
should contact our licensing department to determine the necessary
|
||||
steps you must take. For more information on this policy, please read
|
||||
http://www.digium.com/en/company/profile/trademarkpolicy.php
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
If you have any questions regarding our licensing policy, please
|
||||
contact us:
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
+1.877.344.4861 (via telephone in the USA)
|
||||
+1.256.428.6000 (via telephone outside the USA)
|
||||
+1.256.864.0464 (via FAX inside or outside the USA)
|
||||
IAX2/misery.digium.com/6000 (via IAX2)
|
||||
licensing@digium.com (via email)
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Digium, Inc.
|
||||
445 Jan Davis Drive
|
||||
Huntsville, AL 35806
|
||||
USA
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
|
||||
@@ -1,118 +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
|
||||
#
|
||||
|
||||
ifneq ($(findstring MALLOC_DEBUG,$(MENUSELECT_CFLAGS)),)
|
||||
ifeq ($(findstring astmm.h,$(ASTCFLAGS)),)
|
||||
ASTCFLAGS+=-include $(ASTTOPDIR)/include/asterisk/astmm.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
|
||||
ASTCFLAGS+=${GC_CFLAGS}
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STATIC_BUILD,$(MENUSELECT_CFLAGS)),)
|
||||
STATIC_BUILD=-static
|
||||
endif
|
||||
|
||||
include $(ASTTOPDIR)/Makefile.rules
|
||||
|
||||
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
|
||||
rm -f .*.o.d .*.oo.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
|
||||
@@ -1,73 +0,0 @@
|
||||
#
|
||||
# Asterisk -- A telephony toolkit for Linux.
|
||||
#
|
||||
# Makefile rules
|
||||
#
|
||||
# Copyright (C) 2006, Digium, Inc.
|
||||
#
|
||||
# Kevin P. Fleming <kpfleming@digium.com>
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License
|
||||
#
|
||||
|
||||
# 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
|
||||
|
||||
ifeq ($(NOISY_BUILD),)
|
||||
ECHO_PREFIX=@
|
||||
CMD_PREFIX=@
|
||||
else
|
||||
ECHO_PREFIX=@\#
|
||||
CMD_PREFIX=
|
||||
endif
|
||||
|
||||
ifeq ($(findstring DONT_OPTIMIZE,$(MENUSELECT_CFLAGS)),)
|
||||
# More GSM codec optimization
|
||||
# Uncomment to enable MMXTM optimizations for x86 architecture CPU's
|
||||
# which support MMX instructions. This should be newer pentiums,
|
||||
# ppro's, etc, as well as the AMD K6 and K7.
|
||||
#K6OPT=-DK6OPT
|
||||
|
||||
OPTIMIZE?=-O6
|
||||
ASTCFLAGS+=$(OPTIMIZE)
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(ECHO_PREFIX) echo " [CC] $< -> $@"
|
||||
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MD -MT $@ -MF .$(subst /,_,$@).d -MP
|
||||
|
||||
%.o: %.s
|
||||
$(ECHO_PREFIX) echo " [AS] $< -> $@"
|
||||
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MD -MT $@ -MF .$(subst /,_,$@).d -MP
|
||||
|
||||
%.oo: %.cc
|
||||
$(ECHO_PREFIX) echo " [CXX] $< -> $@"
|
||||
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(ASTCFLAGS)) -MD -MT $@ -MF .$(subst /,_,$@).d -MP
|
||||
|
||||
%.c: %.y
|
||||
$(ECHO_PREFIX) echo " [BISON] $< -> $@"
|
||||
$(CMD_PREFIX) bison -o $@ -d --name-prefix=ast_yy $<
|
||||
|
||||
%.c: %.fl
|
||||
$(ECHO_PREFIX) echo " [FLEX] $< -> $@"
|
||||
$(CMD_PREFIX) flex -o $@ --full $<
|
||||
|
||||
%.so: %.o
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $^ $(PTHREAD_LIBS) $(LIBS)
|
||||
|
||||
%.so: %.oo
|
||||
$(ECHO_PREFIX) echo " [LDXX] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $^ $(PTHREAD_LIBS) $(LIBS)
|
||||
|
||||
%: %.o
|
||||
$(ECHO_PREFIX) echo " [LD] $^ -> $@"
|
||||
$(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(PTHREAD_CFLAGS) $(ASTLDFLAGS) $^ $(PTHREAD_LIBS) $(LIBS)
|
||||
|
||||
dist-clean::
|
||||
185
README
185
README
@@ -1,17 +1,12 @@
|
||||
The Asterisk(R) Open Source PBX
|
||||
The Asterisk Open Source PBX
|
||||
by Mark Spencer <markster@digium.com>
|
||||
and the Asterisk.org developer community
|
||||
|
||||
Copyright (C) 2001-2006 Digium, Inc.
|
||||
and other copyright holders.
|
||||
Copyright (C) 2001-2004 Digium
|
||||
================================================================
|
||||
|
||||
* SECURITY
|
||||
It is imperative that you read and fully understand the contents of
|
||||
the security information file (doc/security.txt) before you attempt
|
||||
to configure and run an Asterisk server.
|
||||
the SECURITY file before you attempt to configure an Asterisk server.
|
||||
|
||||
* WHAT IS ASTERISK ?
|
||||
* WHAT IS ASTERISK
|
||||
Asterisk is an Open Source PBX and telephony toolkit. It is, in a
|
||||
sense, middleware between Internet and telephony channels on the bottom,
|
||||
and Internet and telephony applications at the top. For more information
|
||||
@@ -19,137 +14,95 @@ on the project itself, please visit the Asterisk home page at:
|
||||
|
||||
http://www.asterisk.org
|
||||
|
||||
In addition you'll find lots of information compiled by the Asterisk
|
||||
In addition you'll find lot's of information compiled by the Asterisk
|
||||
community on this Wiki:
|
||||
|
||||
http://www.voip-info.org/wiki-Asterisk
|
||||
|
||||
There is a book on Asterisk published by O'Reilly under the
|
||||
Creative Commons License. It is available in book stores as well
|
||||
as in a downloadable version on the http://www.asteriskdocs.org
|
||||
web site.
|
||||
* LICENSING
|
||||
Asterisk is distributed under GNU General Public License. The GPL also
|
||||
must apply to all loadable modules as well, except as defined below.
|
||||
|
||||
* SUPPORTED OPERATING SYSTEMS
|
||||
Digium, Inc. (formerly Linux Support Services) retains copyright to all
|
||||
of the core Asterisk system, and therefore can grant, at its sole discretion,
|
||||
the ability for companies, individuals, or organizations to create proprietary
|
||||
or Open Source (but non-GPL'd) modules which may be dynamically linked at
|
||||
runtime with the portions of Asterisk which fall under our copyright
|
||||
umbrella, or are distributed under more flexible licenses than GPL.
|
||||
|
||||
|
||||
If you wish to use our code in other GPL programs, don't worry -- there
|
||||
is no requirement that you provide the same exemption in your GPL'd
|
||||
products (although if you've written a module for Asterisk we would
|
||||
strongly encourage you to make the same exemption that we do).
|
||||
|
||||
Specific permission is also granted to OpenSSL and OpenH323 to link to
|
||||
Asterisk.
|
||||
|
||||
If you have any questions, whatsoever, regarding our licensing policy,
|
||||
please contact us.
|
||||
|
||||
Modules that are GPL-licensed and not available under Digium's
|
||||
licensing scheme are added to the Asterisk-addons CVS module.
|
||||
|
||||
* REQUIRED COMPONENTS
|
||||
|
||||
== Linux ==
|
||||
The Asterisk Open Source PBX is developed and tested primarily on the
|
||||
GNU/Linux operating system, and is supported on every major GNU/Linux
|
||||
distribution.
|
||||
Currently, the Asterisk Open Source PBX is only known to run on the
|
||||
Linux OS, although it may be portable to other UNIX-like operating systems
|
||||
(like FreeBSD) as well.
|
||||
|
||||
== Others ==
|
||||
Asterisk has also been 'ported' and reportedly runs properly on other
|
||||
operating systems as well, including Sun Solaris, Apple's Mac OS X, and
|
||||
the BSD variants.
|
||||
|
||||
* GETTING STARTED
|
||||
|
||||
First, be sure you've got supported hardware (but note that you don't need
|
||||
ANY special hardware, not even a soundcard) to install and run Asterisk.
|
||||
|
||||
Supported telephony hardware includes:
|
||||
First, be sure you've got supported hardware (but note that you don't need ANY hardware, not even a soundcard) to install and run Asterisk. Supported are:
|
||||
|
||||
* All Wildcard (tm) products from Digium (www.digium.com)
|
||||
* QuickNet Internet PhoneJack and LineJack (http://www.quicknet.net)
|
||||
* any full duplex sound card supported by ALSA or OSS
|
||||
* any ISDN card supported by mISDN on Linux (BRI)
|
||||
* The Xorcom AstriBank channel bank
|
||||
* VoiceTronix OpenLine products
|
||||
* Full Duplex Sound Card supported by Linux
|
||||
* Adtran Atlas 800 Plus
|
||||
* ISDN4Linux compatible ISDN card
|
||||
* Tormenta Dual T1 card (www.bsdtelephony.com.mx)
|
||||
|
||||
The are several drivers for ISDN BRI cards available from third party sources.
|
||||
Check the voip-info.org wiki for more information on chan_capi and
|
||||
zaphfc.
|
||||
Hint: CAPI compatible ISDN cards can be run using the add-on channel chan_capi.
|
||||
|
||||
* UPGRADING FROM AN EARLIER VERSION
|
||||
So let's proceed:
|
||||
|
||||
If you are updating from a previous version of Asterisk, make sure you
|
||||
read the UPGRADE.txt file in the source directory. There are some files
|
||||
and configuration options that you will have to change, even though we
|
||||
made every effort possible to maintain backwards compatibility.
|
||||
1) Run "make"
|
||||
2) Run "make install"
|
||||
|
||||
In order to discover new features to use, please check the configuration
|
||||
examples in the /configs directory of the source code distribution.
|
||||
To discover the major new features of Asterisk 1.2, please visit
|
||||
http://edvina.net/asterisk1-2/
|
||||
|
||||
* NEW INSTALLATIONS
|
||||
|
||||
Ensure that your system contains a compatible compiler and development
|
||||
libraries. Asterisk requires either the GNU Compiler Collection (GCC) version
|
||||
3.0 or higher, or a compiler that supports the C99 specification and some of
|
||||
the gcc language extensions. In addition, your system needs to have the C
|
||||
library headers available, and the headers and libraries for OpenSSL,
|
||||
ncurses and zlib.
|
||||
On many distributions, these files are installed by packages with names like
|
||||
'glibc-devel', 'ncurses-devel', 'openssl-devel' and 'zlib-devel' or similar.
|
||||
|
||||
So let's proceed:
|
||||
|
||||
1) Read this README file.
|
||||
|
||||
There are more documents than this one in the doc/ directory.
|
||||
You may also want to check the configuration files that contain
|
||||
examples and reference guides. They are all in the configs/
|
||||
directory.
|
||||
|
||||
2) Run "./configure"
|
||||
|
||||
Execute the configure script to guess values for system-dependent
|
||||
variables used during compilation.
|
||||
|
||||
3) Run "make menuselect" [optional]
|
||||
|
||||
This is needed if you want to select the modules that will be
|
||||
compiled and to check modules dependencies.
|
||||
|
||||
4) Run "make"
|
||||
|
||||
Assuming the build completes successfully:
|
||||
|
||||
5) Run "make install"
|
||||
|
||||
Each time you update or checkout from the repository, you are strongly
|
||||
encouraged to ensure all previous object files are removed to avoid internal
|
||||
inconsistency in Asterisk. Normally, this is automatically done with
|
||||
the presence of the file .cleancount, which increments each time a 'make clean'
|
||||
is required, and the file .lastclean, which contains the last .cleancount used.
|
||||
|
||||
If this is your first time working with Asterisk, you may wish to install
|
||||
If this is your first time working with Asterisk, you may wish to install
|
||||
the sample PBX, with demonstration extensions, etc. If so, run:
|
||||
|
||||
6) "make samples"
|
||||
"make samples"
|
||||
|
||||
Doing so will overwrite any existing config files you have.
|
||||
Doing so will overwrite any existing config files you have. If you are lacking a soundcard you won't be able to use the DIAL command on the console, though.
|
||||
|
||||
Finally, you can launch Asterisk in the foreground mode (not a daemon)
|
||||
with:
|
||||
Finally, you can launch Asterisk with:
|
||||
|
||||
# asterisk -vvvc
|
||||
./asterisk -vvvc
|
||||
|
||||
You'll see a bunch of verbose messages fly by your screen as Asterisk
|
||||
You'll see a bunch of verbose messages fly by your screen as Asterisk
|
||||
initializes (that's the "very very verbose" mode). When it's ready, if
|
||||
you specified the "c" then you'll get a command line console, that looks
|
||||
like this:
|
||||
|
||||
*CLI>
|
||||
|
||||
You can type "help" at any time to get help with the system. For help
|
||||
You can type "help" at any time to get help with the system. For help
|
||||
with a specific command, type "help <command>". To start the PBX using
|
||||
your sound card, you can type "dial" to dial the PBX. Then you can use
|
||||
"answer", "hangup", and "dial" to simulate the actions of a telephone.
|
||||
Remember that if you don't have a full duplex sound card (and Asterisk
|
||||
will tell you somewhere in its verbose messages if you do/don't) then it
|
||||
Remember that if you don't have a full duplex sound card (And asterisk
|
||||
will tell you somewhere in its verbose messages if you do/don't) than it
|
||||
won't work right (not yet).
|
||||
|
||||
"man asterisk" at the Unix/Linux command prompt will give you detailed
|
||||
information on how to start and stop Asterisk, as well as all the command
|
||||
line options for starting Asterisk.
|
||||
|
||||
Feel free to look over the configuration files in /etc/asterisk, where
|
||||
Feel free to look over the configuration files in /etc/asterisk, where
|
||||
you'll find a lot of information about what you can do with Asterisk.
|
||||
|
||||
* ABOUT CONFIGURATION FILES
|
||||
|
||||
All Asterisk configuration files share a common format. Comments are
|
||||
All Asterisk configuration files share a common format. Comments are
|
||||
delimited by ';' (since '#' of course, being a DTMF digit, may occur in
|
||||
many places). A configuration file is divided into sections whose names
|
||||
appear in []'s. Each section typically contains two types of statements,
|
||||
@@ -158,12 +111,12 @@ parameters'. Internally the use of '=' and '=>' is exactly the same, so
|
||||
they're used only to help make the configuration file easier to
|
||||
understand, and do not affect how it is actually parsed.
|
||||
|
||||
Entries of the form 'variable=value' set the value of some parameter in
|
||||
asterisk. For example, in zapata.conf, one might specify:
|
||||
Entries of the form 'variable=value' set the value of some parameter in
|
||||
asterisk. For example, in tormenta.conf, one might specify:
|
||||
|
||||
switchtype=national
|
||||
|
||||
in order to indicate to Asterisk that the switch they are connecting to is
|
||||
In order to indicate to Asterisk that the switch they are connecting to is
|
||||
of the type "national". In general, the parameter will apply to
|
||||
instantiations which occur below its specification. For example, if the
|
||||
configuration file read:
|
||||
@@ -174,18 +127,18 @@ configuration file read:
|
||||
switchtype = dms100
|
||||
channel => 25-47
|
||||
|
||||
the "national" switchtype would be applied to channels one through
|
||||
Then, the "national" switchtype would be applied to channels one through
|
||||
four and channels 10 through 12, whereas the "dms100" switchtype would
|
||||
apply to channels 25 through 47.
|
||||
|
||||
The "object => parameters" instantiates an object with the given
|
||||
The "object => parameters" instantiates an object with the given
|
||||
parameters. For example, the line "channel => 25-47" creates objects for
|
||||
the channels 25 through 47 of the card, obtaining the settings
|
||||
the channels 25 through 47 of the tormenta card, obtaining the settings
|
||||
from the variables specified above.
|
||||
|
||||
* SPECIAL NOTE ON TIME
|
||||
|
||||
Those using SIP phones should be aware that Asterisk is sensitive to
|
||||
Those using SIP phones should be aware the Asterisk is sensitive to
|
||||
large jumps in time. Manually changing the system time using date(1)
|
||||
(or other similar commands) may cause SIP registrations and other
|
||||
internal processes to fail. If your system cannot keep accurate time
|
||||
@@ -203,7 +156,7 @@ apparent. The use of daylight savings time in a Linux system is
|
||||
purely a user interface issue and does not affect the operation of the
|
||||
Linux kernel or Asterisk. The system clock on Linux kernels operates
|
||||
on UTC. UTC does not use daylight savings time.
|
||||
|
||||
|
||||
Also note that this issue is separate from the clocking of TDM
|
||||
channels, and is known to at least affect SIP registrations.
|
||||
|
||||
@@ -243,20 +196,18 @@ these changes to take effect.
|
||||
above you can try adding the command "ulimit -n 8192" to the script
|
||||
that starts Asterisk.
|
||||
|
||||
|
||||
* MORE INFORMATION
|
||||
|
||||
See the doc directory for more documentation on various features. Again,
|
||||
please read all the configuration samples that include documentation on
|
||||
the configuration options.
|
||||
See the doc directory for more documentation.
|
||||
|
||||
Finally, you may wish to visit the web site and join the mailing list if
|
||||
Finally, you may wish to visit the web site and join the mailing list if
|
||||
you're interested in getting more information.
|
||||
|
||||
http://www.asterisk.org/support
|
||||
http://www.asterisk.org/index.php?menu=support
|
||||
|
||||
Welcome to the growing worldwide community of Asterisk users!
|
||||
Welcome to the growing worldwide community of Asterisk users!
|
||||
|
||||
Mark Spencer
|
||||
|
||||
----
|
||||
Asterisk is a trademark belonging to Digium, inc
|
||||
|
||||
|
||||
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
|
||||
41
SECURITY
Normal file
41
SECURITY
Normal file
@@ -0,0 +1,41 @@
|
||||
==== Security Notes with Asterisk ====
|
||||
|
||||
PLEASE READ THE FOLLOWING IMPORTANT SECURITY RELATED INFORMATION.
|
||||
IMPROPER CONFIGURATION OF ASTERISK COULD ALLOW UNAUTHORIZED USE OF YOUR
|
||||
FACILITIES, POTENTIALLY INCURRING SUBSTANTIAL CHARGES.
|
||||
|
||||
First and foremost remember this:
|
||||
|
||||
USE THE EXTENSION CONTEXTS TO ISOLATE OUTGOING OR TOLL SERVICES FROM ANY
|
||||
INCOMING CONNECTIONS.
|
||||
|
||||
You should consider that if any channel, incoming line, etc can enter an
|
||||
extension context that it has the capability of accessing any extension
|
||||
within that context.
|
||||
|
||||
Therefore, you should NOT allow access to outgoing or toll services in
|
||||
contexts that are accessible (especially without a password) from incoming
|
||||
channels, be they IAX channels, FX or other trunks, or even untrusted
|
||||
stations within you network. In particular, never ever put outgoing toll
|
||||
services in the "default" context. To make things easier, you can include
|
||||
the "default" context within other private contexts by using:
|
||||
|
||||
include => default
|
||||
|
||||
in the appropriate section. A well designed PBX might look like this:
|
||||
|
||||
[longdistance]
|
||||
exten => _91NXXNXXXXXX,1,Dial(Zap/g2/${EXTEN:1})
|
||||
include => local
|
||||
|
||||
[local]
|
||||
exten => _9NXXNXXX,1,Dial(Zap/g2/${EXTEN:1})
|
||||
include => default
|
||||
|
||||
[default]
|
||||
exten => 6123,Dial(Zap/1)
|
||||
|
||||
|
||||
DON'T FORGET TO TAKE THE DEMO CONTEXT OUT OF YOUR DEFAULT CONTEXT. There
|
||||
isn't really a security reason, it just will keep people from wanting to
|
||||
play with your asterisk setup remotely.
|
||||
495
UPGRADE.txt
495
UPGRADE.txt
@@ -1,495 +0,0 @@
|
||||
Information for Upgrading From Previous Asterisk Releases
|
||||
=========================================================
|
||||
|
||||
Build Process (configure script):
|
||||
|
||||
Asterisk now uses an autoconf-generated configuration script to learn how it
|
||||
should build itself for your system. As it is a standard script, running:
|
||||
|
||||
$ ./configure --help
|
||||
|
||||
will show you all the options available. This script can be used to tell the
|
||||
build process what libraries you have on your system (if it cannot find them
|
||||
automatically), which libraries you wish to have ignored even though they may
|
||||
be present, etc.
|
||||
|
||||
You must run the configure script before Asterisk will build, although it will
|
||||
attempt to automatically run it for you with no options specified; for most
|
||||
users, that will result in a similar build to what they would have had before
|
||||
the configure script was added to the build process (except for having to run
|
||||
'make' again after the configure script is run). Note that the configure script
|
||||
does NOT need to be re-run just to rebuild Asterisk; you only need to re-run it
|
||||
when your system configuration changes or you wish to build Asterisk with
|
||||
different options.
|
||||
|
||||
Build Process (module selection):
|
||||
|
||||
The Asterisk source tree now includes a basic module selection and build option
|
||||
selection tool called 'menuselect'. Run 'make menuselect' to make your choices.
|
||||
In this tool, you can disable building of modules that you don't care about,
|
||||
turn on/off global options for the build and see which modules will not
|
||||
(and cannot) be built because your system does not have the required external
|
||||
dependencies installed.
|
||||
|
||||
The resulting file from menuselect is called 'menuselect.makeopts'. Note that
|
||||
the resulting menuselect.makeopts file generally contains which modules *not*
|
||||
to build. The modules listed in this file indicate which modules have unmet
|
||||
dependencies, a present conflict, or have been disabled by the user in the
|
||||
menuselect interface. Compiler Flags can also be set in the menuselect
|
||||
interface. In this case, the resulting file contains which CFLAGS are in use,
|
||||
not which ones are not in use.
|
||||
|
||||
If you would like to save your choices and have them applied against all
|
||||
builds, the file can be copied to '~/.asterisk.makeopts' or
|
||||
'/etc/asterisk.makeopts'.
|
||||
|
||||
Build Process (Makefile targets):
|
||||
|
||||
The 'valgrind' and 'dont-optimize' targets have been removed; their functionality
|
||||
is available by enabling the DONT_OPTIMIZE setting in the 'Compiler Flags' menu
|
||||
in the menuselect tool.
|
||||
|
||||
It is now possible to run most make targets against a single subdirectory; from
|
||||
the top level directory, for example, 'make channels' will run 'make all' in the
|
||||
'channels' subdirectory. This also is true for 'clean', 'distclean' and 'depend'.
|
||||
|
||||
Sound (prompt) and Music On Hold files:
|
||||
|
||||
Beginning with Asterisk 1.4, the sound files and music on hold files supplied for
|
||||
use with Asterisk have been replaced with new versions produced from high quality
|
||||
master recordings, and are available in three languages (English, French and
|
||||
Spanish) and in five formats (WAV (uncompressed), mu-Law, a-Law, GSM and G.729).
|
||||
In addition, the music on hold files provided by opsound.org Music are now available
|
||||
in the same five formats, but no longer available in MP3 format.
|
||||
|
||||
The Asterisk 1.4 tarball packages will only include English prompts in GSM format,
|
||||
(as were supplied with previous releases) and the opsound.org MOH files in WAV format.
|
||||
All of the other variations can be installed by running 'make menuselect' and
|
||||
selecting the packages you wish to install; when you run 'make install', those
|
||||
packages will be downloaded and installed along with the standard files included
|
||||
in the tarball.
|
||||
|
||||
If for some reason you expect to not have Internet access at the time you will be
|
||||
running 'make install', you can make your package selections using menuselect and
|
||||
then run 'make sounds' to download (only) the sound packages; this will leave the
|
||||
sound packages in the 'sounds' subdirectory to be used later during installation.
|
||||
|
||||
WARNING: Asterisk 1.4 supports a new layout for sound files in multiple languages;
|
||||
instead of the alternate-language files being stored in subdirectories underneath
|
||||
the existing files (for French, that would be digits/fr, letters/fr, phonetic/fr,
|
||||
etc.) the new layout creates one directory under /var/lib/asterisk/sounds for the
|
||||
language itself, then places all the sound files for that language under that
|
||||
directory and its subdirectories. This is the layout that will be created if you
|
||||
select non-English languages to be installed via menuselect, HOWEVER Asterisk does
|
||||
not default to this layout and will not find the files in the places it expects them
|
||||
to be. If you wish to use this layout, make sure you put 'languageprefix=yes' in your
|
||||
/etc/asterisk/asterisk.conf file, so that Asterisk will know how the files were
|
||||
installed.
|
||||
|
||||
PBX Core:
|
||||
|
||||
* The (very old and undocumented) ability to use BYEXTENSION for dialing
|
||||
instead of ${EXTEN} has been removed.
|
||||
|
||||
* Builtin (res_features) transfer functionality attempts to use the context
|
||||
defined in TRANSFER_CONTEXT variable of the transferer channel first. If
|
||||
not set, it uses the transferee variable. If not set in any channel, it will
|
||||
attempt to use the last non macro context. If not possible, it will default
|
||||
to the current context.
|
||||
|
||||
* The autofallthrough setting introduced in Asterisk 1.2 now defaults to 'yes';
|
||||
if your dialplan relies on the ability to 'run off the end' of an extension
|
||||
and wait for a new extension without using WaitExten() to accomplish that,
|
||||
you will need set autofallthrough to 'no' in your extensions.conf file.
|
||||
|
||||
Command Line Interface:
|
||||
|
||||
* 'show channels concise', designed to be used by applications that will parse
|
||||
its output, previously used ':' characters to separate fields. However, some
|
||||
of those fields can easily contain that character, making the output not
|
||||
parseable. The delimiter has been changed to '!'.
|
||||
|
||||
Applications:
|
||||
|
||||
* In previous Asterisk releases, many applications would jump to priority n+101
|
||||
to indicate some kind of status or error condition. This functionality was
|
||||
marked deprecated in Asterisk 1.2. An option to disable it was provided with
|
||||
the default value set to 'on'. The default value for the global priority
|
||||
jumping option is now 'off'.
|
||||
|
||||
* The applications Cut, Sort, DBGet, DBPut, SetCIDNum, SetCIDName, SetRDNIS,
|
||||
AbsoluteTimeout, DigitTimeout, ResponseTimeout, SetLanguage, GetGroupCount,
|
||||
and GetGroupMatchCount were all deprecated in version 1.2, and therefore have
|
||||
been removed in this version. You should use the equivalent dialplan
|
||||
function in places where you have previously used one of these applications.
|
||||
|
||||
* The application SetGlobalVar has been deprecated. You should replace uses
|
||||
of this application with the following combination of Set and GLOBAL():
|
||||
Set(GLOBAL(name)=value). You may also access global variables exclusively by
|
||||
using the GLOBAL() dialplan function, instead of relying on variable
|
||||
interpolation falling back to globals when no channel variable is set.
|
||||
|
||||
* The application SetVar has been renamed to Set. The syntax SetVar was marked
|
||||
deprecated in version 1.2 and is no longer recognized in this version. The
|
||||
use of Set with multiple argument pairs has also been deprecated. Please
|
||||
separate each name/value pair into its own dialplan line.
|
||||
|
||||
* app_read has been updated to use the newer options codes, using "skip" or
|
||||
"noanswer" will not work. Use s or n. Also there is a new feature i, for
|
||||
using indication tones, so typing in skip would give you unexpected results.
|
||||
|
||||
* OSPAuth is added to authenticate OSP tokens in in_bound call setup messages.
|
||||
|
||||
* The CONNECT event in the queue_log from app_queue now has a second field
|
||||
in addition to the holdtime field. It contains the unique ID of the
|
||||
queue member channel that is taking the call. This is useful when trying
|
||||
to link recording filenames back to a particular call from the queue.
|
||||
|
||||
* The old/current behavior of app_queue has a serial type behavior
|
||||
in that the queue will make all waiting callers wait in the queue
|
||||
even if there is more than one available member ready to take
|
||||
calls until the head caller is connected with the member they
|
||||
were trying to get to. The next waiting caller in line then
|
||||
becomes the head caller, and they are then connected with the
|
||||
next available member and all available members and waiting callers
|
||||
waits while this happens. This cycle continues until there are
|
||||
no more available members or waiting callers, whichever comes first.
|
||||
The new behavior, enabled by setting autofill=yes in queues.conf
|
||||
either at the [general] level to default for all queues or
|
||||
to set on a per-queue level, makes sure that when the waiting
|
||||
callers are connecting with available members in a parallel fashion
|
||||
until there are no more available members or no more waiting callers,
|
||||
whichever comes first. This is probably more along the lines of how
|
||||
one would expect a queue should work and in most cases, you will want
|
||||
to enable this new behavior. If you do not specify or comment out this
|
||||
option, it will default to "no" to keep backward compatability with the old
|
||||
behavior.
|
||||
|
||||
* Queues depend on the channel driver reporting the proper state
|
||||
for each member of the queue. To get proper signalling on
|
||||
queue members that use the SIP channel driver, you need to
|
||||
enable a call limit (could be set to a high value so it
|
||||
is not put into action) and also make sure that both inbound
|
||||
and outbound calls are accounted for.
|
||||
|
||||
Example:
|
||||
|
||||
[general]
|
||||
limitonpeer = yes
|
||||
|
||||
[peername]
|
||||
type=friend
|
||||
call-limit=10
|
||||
|
||||
|
||||
* The app_queue application now has the ability to use MixMonitor to
|
||||
record conversations queue members are having with queue callers. Please
|
||||
see configs/queues.conf.sample for more information on this option.
|
||||
|
||||
* The app_queue application strategy called 'roundrobin' has been deprecated
|
||||
for this release. Users are encouraged to use 'rrmemory' instead, since it
|
||||
provides more 'true' round-robin call delivery. For the Asterisk 1.6 release,
|
||||
'rrmemory' will be renamed 'roundrobin'.
|
||||
|
||||
* The app_queue application option called 'monitor-join' has been deprecated
|
||||
for this release. Users are encouraged to use 'monitor-type=mixmonitor' instead,
|
||||
since it provides the same functionality but is not dependent on soxmix or some
|
||||
other external program in order to mix the audio.
|
||||
|
||||
* app_meetme: The 'm' option (monitor) is renamed to 'l' (listen only), and
|
||||
the 'm' option now provides the functionality of "initially muted".
|
||||
In practice, most existing dialplans using the 'm' flag should not notice
|
||||
any difference, unless the keypad menu is enabled, allowing the user
|
||||
to unmute themsleves.
|
||||
|
||||
* ast_play_and_record would attempt to cancel the recording if a DTMF
|
||||
'0' was received. This behavior was not documented in most of the
|
||||
applications that used ast_play_and_record and the return codes from
|
||||
ast_play_and_record weren't checked for properly.
|
||||
ast_play_and_record has been changed so that '0' no longer cancels a
|
||||
recording. If you want to allow DTMF digits to cancel an
|
||||
in-progress recording use ast_play_and_record_full which allows you
|
||||
to specify which DTMF digits can be used to accept a recording and
|
||||
which digits can be used to cancel a recording.
|
||||
|
||||
* ast_app_messagecount has been renamed to ast_app_inboxcount. There is now a
|
||||
new ast_app_messagecount function which takes a single context/mailbox/folder
|
||||
mailbox specification and returns the message count for that folder only.
|
||||
This addresses the deficiency of not being able to count the number of
|
||||
messages in folders other than INBOX and Old.
|
||||
|
||||
* The exit behavior of the AGI applications has changed. Previously, when
|
||||
a connection to an AGI server failed, the application would cause the channel
|
||||
to immediately stop dialplan execution and hangup. Now, the only time that
|
||||
the AGI applications will cause the channel to stop dialplan execution is
|
||||
when the channel itself requests hangup. The AGI applications now set an
|
||||
AGISTATUS variable which will allow you to find out whether running the AGI
|
||||
was successful or not.
|
||||
|
||||
Previously, there was no way to handle the case where Asterisk was unable to
|
||||
locally execute an AGI script for some reason. In this case, dialplan
|
||||
execution will continue as it did before, but the AGISTATUS variable will be
|
||||
set to "FAILURE".
|
||||
|
||||
A locally executed AGI script can now exit with a non-zero exit code and this
|
||||
failure will be detected by Asterisk. If an AGI script exits with a non-zero
|
||||
exit code, the AGISTATUS variable will be set to "FAILURE" as opposed to
|
||||
"SUCCESS".
|
||||
|
||||
* app_voicemail: The ODBC_STORAGE capability now requires the extended table format
|
||||
previously used only by EXTENDED_ODBC_STORAGE. This means that you will need to update
|
||||
your table format using the schema provided in doc/odbcstorage.txt
|
||||
|
||||
* app_waitforsilence: Fixes have been made to this application which changes the
|
||||
default behavior with how quickly it returns. You can maintain "old-style" behavior
|
||||
with the addition/use of a third "timeout" parameter.
|
||||
Please consult the application documentation and make changes to your dialplan
|
||||
if appropriate.
|
||||
|
||||
Manager:
|
||||
|
||||
* After executing the 'status' manager action, the "Status" manager events
|
||||
included the header "CallerID:" which was actually only the CallerID number,
|
||||
and not the full CallerID string. This header has been renamed to
|
||||
"CallerIDNum". For compatibility purposes, the CallerID parameter will remain
|
||||
until after the release of 1.4, when it will be removed. Please use the time
|
||||
during the 1.4 release to make this transition.
|
||||
|
||||
* The AgentConnect event now has an additional field called "BridgedChannel"
|
||||
which contains the unique ID of the queue member channel that is taking the
|
||||
call. This is useful when trying to link recording filenames back to
|
||||
a particular call from the queue.
|
||||
|
||||
* app_userevent has been modified to always send Event: UserEvent with the
|
||||
additional header UserEvent: <userspec>. Also, the Channel and UniqueID
|
||||
headers are not automatically sent, unless you specify them as separate
|
||||
arguments. Please see the application help for the new syntax.
|
||||
|
||||
* app_meetme: Mute and Unmute events are now reported via the Manager API.
|
||||
Native Manager API commands MeetMeMute and MeetMeUnmute are provided, which
|
||||
are easier to use than "Action Command:". The MeetMeStopTalking event has
|
||||
also been deprecated in favor of the already existing MeetmeTalking event
|
||||
with a "Status" of "on" or "off" added.
|
||||
|
||||
* OriginateFailure and OriginateSuccess events were replaced by event
|
||||
OriginateResponse with a header named "Response" to indicate success or
|
||||
failure
|
||||
|
||||
Variables:
|
||||
|
||||
* The builtin variables ${CALLERID}, ${CALLERIDNAME}, ${CALLERIDNUM},
|
||||
${CALLERANI}, ${DNID}, ${RDNIS}, ${DATETIME}, ${TIMESTAMP}, ${ACCOUNTCODE},
|
||||
and ${LANGUAGE} have all been deprecated in favor of their related dialplan
|
||||
functions. You are encouraged to move towards the associated dialplan
|
||||
function, as these variables will be removed in a future release.
|
||||
|
||||
* The CDR-CSV variables uniqueid, userfield, and basing time on GMT are now
|
||||
adjustable from cdr.conf, instead of recompiling.
|
||||
|
||||
* OSP applications exports several new variables, ${OSPINHANDLE},
|
||||
${OSPOUTHANDLE}, ${OSPINTOKEN}, ${OSPOUTTOKEN}, ${OSPCALLING},
|
||||
${OSPINTIMELIMIT}, and ${OSPOUTTIMELIMIT}
|
||||
|
||||
* Builtin transfer functionality sets the variable ${TRANSFERERNAME} in the new
|
||||
created channel. This variables holds the channel name of the transferer.
|
||||
|
||||
* The dial plan variable PRI_CAUSE will be removed from future versions
|
||||
of Asterisk.
|
||||
It is replaced by adding a cause value to the hangup() application.
|
||||
|
||||
Functions:
|
||||
|
||||
* The function ${CHECK_MD5()} has been deprecated in favor of using an
|
||||
expression: $[${MD5(<string>)} = ${saved_md5}].
|
||||
|
||||
* The 'builtin' functions that used to be combined in pbx_functions.so are
|
||||
now built as separate modules. If you are not using 'autoload=yes' in your
|
||||
modules.conf file then you will need to explicitly load the modules that
|
||||
contain the functions you want to use.
|
||||
|
||||
* The ENUMLOOKUP() function with the 'c' option (for counting the number of
|
||||
records), but the lookup fails to match any records, the returned value will
|
||||
now be "0" instead of blank.
|
||||
|
||||
* The REALTIME() function is now available in version 1.4 and app_realtime has
|
||||
been deprecated in favor of the new function. app_realtime will be removed
|
||||
completely with the version 1.6 release so please take the time between
|
||||
releases to make any necessary changes
|
||||
|
||||
* The QUEUEAGENTCOUNT() function has been deprecated in favor of
|
||||
QUEUE_MEMBER_COUNT().
|
||||
|
||||
The IAX2 channel:
|
||||
|
||||
* It is possible that previous configurations depended on the order in which
|
||||
peers and users were specified in iax.conf for forcing the order in which
|
||||
chan_iax2 matched against them. This behavior is going away and is considered
|
||||
deprecated in this version. Avoid having ambiguous peer and user entries and
|
||||
to make things easy on yourself, always set the "username" option for users
|
||||
so that the remote end can match on that exactly instead of trying to infer
|
||||
which user you want based on host.
|
||||
|
||||
If you would like to go ahead and use the new behavior which doesn't use the
|
||||
order in the config file to influence matching order, then change the
|
||||
MAX_PEER_BUCKETS define in chan_iax2.c to a value greater than one. An
|
||||
example is provided there. By changing this, you will get *much* better
|
||||
performance on systems that do a lot of peer and user lookups as they will be
|
||||
stored in memory in a much more efficient manner.
|
||||
|
||||
* The "mailboxdetail" option has been deprecated. Previously, if this option
|
||||
was not enabled, the 2 byte MSGCOUNT information element would be set to all
|
||||
1's to indicate there there is some number of messages waiting. With this
|
||||
option enabled, the number of new messages were placed in one byte and the
|
||||
number of old messages are placed in the other. This is now the default
|
||||
(and the only) behavior.
|
||||
|
||||
The SIP channel:
|
||||
|
||||
* The "incominglimit" setting is replaced by the "call-limit" setting in
|
||||
sip.conf.
|
||||
|
||||
* OSP support code is removed from SIP channel to OSP applications. ospauth
|
||||
option in sip.conf is removed to osp.conf as authpolicy. allowguest option
|
||||
in sip.conf cannot be set as osp anymore.
|
||||
|
||||
* The Asterisk RTP stack has been changed in regards to RFC2833 reception
|
||||
and transmission. Packets will now be sent with proper duration instead of all
|
||||
at once. If you are receiving calls from a pre-1.4 Asterisk installation you
|
||||
will want to turn on the rfc2833compensate option. Without this option your
|
||||
DTMF reception may act poorly.
|
||||
|
||||
* The $SIPUSERAGENT dialplan variable is deprecated and will be removed
|
||||
in coming versions of Asterisk. Please use the dialplan function
|
||||
SIPCHANINFO(useragent) instead.
|
||||
|
||||
* The ALERT_INFO dialplan variable is deprecated and will be removed
|
||||
in coming versions of Asterisk. Please use the dialplan application
|
||||
sipaddheader() to add the "Alert-Info" header to the outbound invite.
|
||||
|
||||
* The "canreinvite" option has changed. canreinvite=yes used to disable
|
||||
re-invites if you had NAT=yes. In 1.4, you need to set canreinvite=nonat
|
||||
to disable re-invites when NAT=yes. This is propably what you want.
|
||||
The settings are now: "yes", "no", "nonat", "update". Please consult
|
||||
sip.conf.sample for detailed information.
|
||||
|
||||
The Zap channel:
|
||||
|
||||
* Support for MFC/R2 has been removed, as it has not been functional for some
|
||||
time and it has no maintainer.
|
||||
|
||||
The Agent channel:
|
||||
|
||||
* Callback mode (AgentCallbackLogin) is now deprecated, since the entire function
|
||||
it provided can be done using dialplan logic, without requiring additional
|
||||
channel and module locks (which frequently caused deadlocks). An example of
|
||||
how to do this using AEL dialplan is in doc/queues-with-callback-members.txt.
|
||||
|
||||
The G726-32 codec:
|
||||
|
||||
* It has been determined that previous versions of Asterisk used the wrong codeword
|
||||
packing order for G726-32 data. This version supports both available packing orders,
|
||||
and can transcode between them. It also now selects the proper order when
|
||||
negotiating with a SIP peer based on the codec name supplied in the SDP. However,
|
||||
there are existing devices that improperly request one order and then use another;
|
||||
Sipura and Grandstream ATAs are known to do this, and there may be others. To
|
||||
be able to continue to use these devices with this version of Asterisk and the
|
||||
G726-32 codec, a configuration parameter called 'g726nonstandard' has been added
|
||||
to sip.conf, so that Asterisk can use the packing order expected by the device (even
|
||||
though it requested a different order). In addition, the internal format number for
|
||||
G726-32 has been changed, and the old number is now assigned to AAL2-G726-32. The
|
||||
result of this is that this version of Asterisk will be able to interoperate over
|
||||
IAX2 with older versions of Asterisk, as long as this version is told to allow
|
||||
'g726aal2' instead of 'g726' as the codec for the call.
|
||||
|
||||
Installation:
|
||||
|
||||
* On BSD systems, the installation directories have changed to more "FreeBSDish"
|
||||
directories. On startup, Asterisk will look for the main configuration in
|
||||
/usr/local/etc/asterisk/asterisk.conf
|
||||
If you have an old installation, you might want to remove the binaries and
|
||||
move the configuration files to the new locations. The following directories
|
||||
are now default:
|
||||
ASTLIBDIR /usr/local/lib/asterisk
|
||||
ASTVARLIBDIR /usr/local/share/asterisk
|
||||
ASTETCDIR /usr/local/etc/asterisk
|
||||
ASTBINDIR /usr/local/bin/asterisk
|
||||
ASTSBINDIR /usr/local/sbin/asterisk
|
||||
|
||||
Music on Hold:
|
||||
|
||||
* The music on hold handling has been changed in some significant ways in hopes
|
||||
to make it work in a way that is much less confusing to users. Behavior will
|
||||
not change if the same configuration is used from older versions of Asterisk.
|
||||
However, there are some new configuration options that will make things work
|
||||
in a way that makes more sense.
|
||||
|
||||
Previously, many of the channel drivers had an option called "musicclass" or
|
||||
something similar. This option set what music on hold class this channel
|
||||
would *hear* when put on hold. Some people expected (with good reason) that
|
||||
this option was to configure what music on hold class to play when putting
|
||||
the bridged channel on hold. This option has now been deprecated.
|
||||
|
||||
Two new music on hold related configuration options for channel drivers have
|
||||
been introduced. Some channel drivers support both options, some just one,
|
||||
and some support neither of them. Check the sample configuration files to see
|
||||
which options apply to which channel driver.
|
||||
|
||||
The "mohsuggest" option specifies which music on hold class to suggest to the
|
||||
bridged channel when putting them on hold. The only way that this class can
|
||||
be overridden is if the bridged channel has a specific music class set that
|
||||
was done in the dialplan using Set(CHANNEL(musicclass)=something).
|
||||
|
||||
The "mohinterpret" option is similar to the old "musicclass" option. It
|
||||
specifies which music on hold class this channel would like to listen to when
|
||||
put on hold. This music class is only effective if this channel has no music
|
||||
class set on it from the dialplan and the bridged channel putting this one on
|
||||
hold had no "mohsuggest" setting.
|
||||
|
||||
The IAX2 and Zap channel drivers have an additional feature for the
|
||||
"mohinterpret" option. If this option is set to "passthrough", then these
|
||||
channel drivers will pass through the HOLD message in signalling instead of
|
||||
starting music on hold on the channel. An example for how this would be
|
||||
useful is in an enterprise network of Asterisk servers. When one phone on one
|
||||
server puts a phone on a different server on hold, the remote server will be
|
||||
responsible for playing the hold music to its local phone that was put on
|
||||
hold instead of the far end server across the network playing the music.
|
||||
|
||||
CDR Records:
|
||||
|
||||
* The behavior of the "clid" field of the CDR has always been that it will
|
||||
contain the callerid ANI if it is set, or the callerid number if ANI was not
|
||||
set. When using the "callerid" option for various channel drivers, some
|
||||
would set ANI and some would not. This has been cleared up so that all
|
||||
channel drivers set ANI. If you would like to change the callerid number
|
||||
on the channel from the dialplan and have that change also show up in the
|
||||
CDR, then you *must* set CALLERID(ANI) as well as CALLERID(num).
|
||||
|
||||
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.
|
||||
986
acinclude.m4
986
acinclude.m4
@@ -1,986 +0,0 @@
|
||||
# AST_GCC_ATTRIBUTE([attribute name])
|
||||
|
||||
AC_DEFUN([AST_GCC_ATTRIBUTE],
|
||||
[
|
||||
AC_MSG_CHECKING(for compiler 'attribute $1' support)
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
AC_COMPILE_IFELSE(
|
||||
AC_LANG_PROGRAM([static void __attribute__(($1)) *test(void *muffin, ...) {}],
|
||||
[]),
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
|
||||
AC_MSG_RESULT(no))
|
||||
]
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
)
|
||||
|
||||
# AST_EXT_LIB_SETUP([package symbol name], [package friendly name], [package option name], [additional help text])
|
||||
|
||||
AC_DEFUN([AST_EXT_LIB_SETUP],
|
||||
[
|
||||
$1_DESCRIP="$2"
|
||||
$1_OPTION="$3"
|
||||
AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH $4]),[
|
||||
case ${withval} in
|
||||
n|no)
|
||||
USE_$1=no
|
||||
;;
|
||||
y|ye|yes)
|
||||
$1_MANDATORY="yes"
|
||||
;;
|
||||
*)
|
||||
$1_DIR="${withval}"
|
||||
$1_MANDATORY="yes"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
PBX_$1=0
|
||||
AC_SUBST([$1_LIB])
|
||||
AC_SUBST([$1_INCLUDE])
|
||||
AC_SUBST([$1_DIR])
|
||||
AC_SUBST([PBX_$1])
|
||||
])
|
||||
|
||||
# AST_EXT_LIB_CHECK([package symbol name], [package library name], [function to check], [package header], [additional LIB data])
|
||||
|
||||
AC_DEFUN([AST_EXT_LIB_CHECK],
|
||||
[
|
||||
if test "${USE_$1}" != "no"; then
|
||||
pbxlibdir=""
|
||||
if test "x${$1_DIR}" != "x"; then
|
||||
if test -d ${$1_DIR}/lib; then
|
||||
pbxlibdir="-L${$1_DIR}/lib"
|
||||
else
|
||||
pbxlibdir="-L${$1_DIR}"
|
||||
fi
|
||||
fi
|
||||
AC_CHECK_LIB([$2], [$3], [AST_$1_FOUND=yes], [AST_$1_FOUND=no], ${pbxlibdir} $5)
|
||||
|
||||
if test "${AST_$1_FOUND}" = "yes"; then
|
||||
$1_LIB="-l$2 $5"
|
||||
$1_HEADER_FOUND="1"
|
||||
if test "x${$1_DIR}" != "x"; then
|
||||
$1_LIB="${pbxlibdir} ${$1_LIB}"
|
||||
$1_INCLUDE="-I${$1_DIR}/include"
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} -I${$1_DIR}/include"
|
||||
if test "x$4" != "x" ; then
|
||||
AC_CHECK_HEADER([${$1_DIR}/include/$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
|
||||
fi
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
else
|
||||
if test "x$4" != "x" ; then
|
||||
AC_CHECK_HEADER([$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
|
||||
fi
|
||||
fi
|
||||
if test "x${$1_HEADER_FOUND}" = "x0" ; then
|
||||
if test -n "${$1_MANDATORY}" ;
|
||||
then
|
||||
AC_MSG_NOTICE([***])
|
||||
AC_MSG_NOTICE([*** It appears that you do not have the $2 development package installed.])
|
||||
AC_MSG_NOTICE([*** Please install it to include ${$1_DESCRIP} support, or re-run configure])
|
||||
AC_MSG_NOTICE([*** without explicitly specifying --with-${$1_OPTION}])
|
||||
exit 1
|
||||
fi
|
||||
$1_LIB=""
|
||||
$1_INCLUDE=""
|
||||
PBX_$1=0
|
||||
else
|
||||
PBX_$1=1
|
||||
AC_DEFINE_UNQUOTED([HAVE_$1], 1, [Define to indicate the ${$1_DESCRIP} library])
|
||||
fi
|
||||
elif test -n "${$1_MANDATORY}";
|
||||
then
|
||||
AC_MSG_NOTICE([***])
|
||||
AC_MSG_NOTICE([*** The ${$1_DESCRIP} installation on this system appears to be broken.])
|
||||
AC_MSG_NOTICE([*** Either correct the installation, or run configure])
|
||||
AC_MSG_NOTICE([*** without explicitly specifying --with-${$1_OPTION}])
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
# AST_C_COMPILE_CHECK can be used for testing for various items in header files
|
||||
|
||||
# AST_C_COMPILE_CHECK([package], [expression], [header file], [version])
|
||||
AC_DEFUN([AST_C_COMPILE_CHECK],
|
||||
[
|
||||
if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
|
||||
AC_MSG_CHECKING([if "$2" compiles using $3])
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
if test "x${$1_DIR}" != "x"; then
|
||||
$1_INCLUDE="-I${$1_DIR}/include"
|
||||
fi
|
||||
CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
|
||||
|
||||
AC_COMPILE_IFELSE(
|
||||
[ AC_LANG_PROGRAM( [#include <$3>],
|
||||
[ $2; ]
|
||||
)],
|
||||
[ AC_MSG_RESULT(yes)
|
||||
PBX_$1=1
|
||||
AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
|
||||
AC_DEFINE([HAVE_$1_VERSION], $4, [Define $1 headers version])
|
||||
],
|
||||
[ AC_MSG_RESULT(no) ]
|
||||
)
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_GNU_MAKE], [AC_CACHE_CHECK(for GNU make, GNU_MAKE,
|
||||
GNU_MAKE='Not Found' ;
|
||||
GNU_MAKE_VERSION_MAJOR=0 ;
|
||||
GNU_MAKE_VERSION_MINOR=0 ;
|
||||
for a in make gmake gnumake ; do
|
||||
if test -z "$a" ; then continue ; fi ;
|
||||
if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
|
||||
GNU_MAKE=$a ;
|
||||
GNU_MAKE_VERSION_MAJOR=`$GNU_MAKE --version | grep "GNU Make" | cut -f3 -d' ' | cut -f1 -d'.'`
|
||||
GNU_MAKE_VERSION_MINOR=`$GNU_MAKE --version | grep "GNU Make" | cut -f2 -d'.' | cut -c1-2`
|
||||
break;
|
||||
fi
|
||||
done ;
|
||||
) ;
|
||||
if test "x$GNU_MAKE" = "xNot Found" ; then
|
||||
AC_MSG_ERROR( *** Please install GNU make. It is required to build Asterisk!)
|
||||
exit 1
|
||||
fi
|
||||
AC_SUBST([GNU_MAKE])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_PWLIB], [
|
||||
PWLIB_INCDIR=
|
||||
PWLIB_LIBDIR=
|
||||
AC_LANG_PUSH([C++])
|
||||
if test "${PWLIBDIR:-unset}" != "unset" ; then
|
||||
AC_CHECK_HEADER(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
|
||||
fi
|
||||
if test "${HAS_PWLIB:-unset}" = "unset" ; then
|
||||
if test "${OPENH323DIR:-unset}" != "unset"; then
|
||||
AC_CHECK_HEADER(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
|
||||
fi
|
||||
if test "${HAS_PWLIB:-unset}" != "unset" ; then
|
||||
PWLIBDIR="${OPENH323DIR}/../pwlib"
|
||||
else
|
||||
AC_CHECK_HEADER(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
|
||||
if test "${HAS_PWLIB:-unset}" != "unset" ; then
|
||||
PWLIBDIR="${HOME}/pwlib"
|
||||
else
|
||||
AC_CHECK_HEADER(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
|
||||
if test "${HAS_PWLIB:-unset}" != "unset" ; then
|
||||
AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
|
||||
if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
|
||||
AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
|
||||
fi
|
||||
PWLIB_INCDIR="/usr/local/include"
|
||||
PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
|
||||
if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
|
||||
if test "x$LIB64" != "x"; then
|
||||
PWLIB_LIBDIR="/usr/local/lib64"
|
||||
else
|
||||
PWLIB_LIBDIR="/usr/local/lib"
|
||||
fi
|
||||
fi
|
||||
PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
|
||||
PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
|
||||
else
|
||||
AC_CHECK_HEADER(/usr/include/ptlib.h, HAS_PWLIB=1, )
|
||||
if test "${HAS_PWLIB:-unset}" != "unset" ; then
|
||||
AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
|
||||
PWLIB_INCDIR="/usr/include"
|
||||
PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
|
||||
if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
|
||||
if test "x$LIB64" != "x"; then
|
||||
PWLIB_LIBDIR="/usr/lib64"
|
||||
else
|
||||
PWLIB_LIBDIR="/usr/lib"
|
||||
fi
|
||||
fi
|
||||
PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
|
||||
PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
#if test "${HAS_PWLIB:-unset}" = "unset" ; then
|
||||
# echo "Cannot find pwlib - please install or set PWLIBDIR and try again"
|
||||
# exit
|
||||
#fi
|
||||
|
||||
if test "${HAS_PWLIB:-unset}" != "unset" ; then
|
||||
if test "${PWLIBDIR:-unset}" = "unset" ; then
|
||||
if test "${PTLIB_CONFIG:-unset}" != "unset" ; then
|
||||
PWLIBDIR=`$PTLIB_CONFIG --prefix`
|
||||
else
|
||||
echo "Cannot find ptlib-config - please install and try again"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$PWLIBDIR" = "x/usr" -o "x$PWLIBDIR" = "x/usr/"; then
|
||||
PWLIBDIR="/usr/share/pwlib"
|
||||
PWLIB_INCDIR="/usr/include"
|
||||
if test "x$LIB64" != "x"; then
|
||||
PWLIB_LIBDIR="/usr/lib64"
|
||||
else
|
||||
PWLIB_LIBDIR="/usr/lib"
|
||||
fi
|
||||
fi
|
||||
if test "x$PWLIBDIR" = "x/usr/local" -o "x$PWLIBDIR" = "x/usr/"; then
|
||||
PWLIBDIR="/usr/local/share/pwlib"
|
||||
PWLIB_INCDIR="/usr/local/include"
|
||||
if test "x$LIB64" != "x"; then
|
||||
PWLIB_LIBDIR="/usr/local/lib64"
|
||||
else
|
||||
PWLIB_LIBDIR="/usr/local/lib"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "${PWLIB_INCDIR:-unset}" = "unset"; then
|
||||
PWLIB_INCDIR="${PWLIBDIR}/include"
|
||||
fi
|
||||
if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
|
||||
PWLIB_LIBDIR="${PWLIBDIR}/lib"
|
||||
fi
|
||||
|
||||
AC_SUBST([PWLIBDIR])
|
||||
AC_SUBST([PWLIB_INCDIR])
|
||||
AC_SUBST([PWLIB_LIBDIR])
|
||||
fi
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_OPENH323_PLATFORM], [
|
||||
PWLIB_OSTYPE=
|
||||
case "$host_os" in
|
||||
linux*) PWLIB_OSTYPE=linux ;
|
||||
;;
|
||||
freebsd* ) PWLIB_OSTYPE=FreeBSD ;
|
||||
;;
|
||||
openbsd* ) PWLIB_OSTYPE=OpenBSD ;
|
||||
ENDLDLIBS="-lossaudio" ;
|
||||
;;
|
||||
netbsd* ) PWLIB_OSTYPE=NetBSD ;
|
||||
ENDLDLIBS="-lossaudio" ;
|
||||
;;
|
||||
solaris* | sunos* ) PWLIB_OSTYPE=solaris ;
|
||||
;;
|
||||
darwin* ) PWLIB_OSTYPE=Darwin ;
|
||||
;;
|
||||
beos*) PWLIB_OSTYPE=beos ;
|
||||
STDCCFLAGS="$STDCCFLAGS -D__BEOS__"
|
||||
;;
|
||||
cygwin*) PWLIB_OSTYPE=cygwin ;
|
||||
;;
|
||||
mingw*) PWLIB_OSTYPE=mingw ;
|
||||
STDCCFLAGS="$STDCCFLAGS -mms-bitfields" ;
|
||||
ENDLDLIBS="-lwinmm -lwsock32 -lsnmpapi -lmpr -lcomdlg32 -lgdi32 -lavicap32" ;
|
||||
;;
|
||||
* ) PWLIB_OSTYPE="$host_os" ;
|
||||
AC_MSG_WARN("OS $PWLIB_OSTYPE not recognized - proceed with caution!") ;
|
||||
;;
|
||||
esac
|
||||
|
||||
PWLIB_MACHTYPE=
|
||||
case "$host_cpu" in
|
||||
x86 | i686 | i586 | i486 | i386 ) PWLIB_MACHTYPE=x86
|
||||
;;
|
||||
|
||||
x86_64) PWLIB_MACHTYPE=x86_64 ;
|
||||
P_64BIT=1 ;
|
||||
LIB64=1 ;
|
||||
;;
|
||||
|
||||
alpha | alphaev56 | alphaev6 | alphaev67 | alphaev7) PWLIB_MACHTYPE=alpha ;
|
||||
P_64BIT=1 ;
|
||||
;;
|
||||
|
||||
sparc ) PWLIB_MACHTYPE=sparc ;
|
||||
;;
|
||||
|
||||
powerpc ) PWLIB_MACHTYPE=ppc ;
|
||||
;;
|
||||
|
||||
ppc ) PWLIB_MACHTYPE=ppc ;
|
||||
;;
|
||||
|
||||
powerpc64 ) PWLIB_MACHTYPE=ppc64 ;
|
||||
P_64BIT=1 ;
|
||||
LIB64=1 ;
|
||||
;;
|
||||
|
||||
ppc64 ) PWLIB_MACHTYPE=ppc64 ;
|
||||
P_64BIT=1 ;
|
||||
LIB64=1 ;
|
||||
;;
|
||||
|
||||
ia64) PWLIB_MACHTYPE=ia64 ;
|
||||
P_64BIT=1 ;
|
||||
;;
|
||||
|
||||
s390x) PWLIB_MACHTYPE=s390x ;
|
||||
P_64BIT=1 ;
|
||||
LIB64=1 ;
|
||||
;;
|
||||
|
||||
s390) PWLIB_MACHTYPE=s390 ;
|
||||
;;
|
||||
|
||||
* ) PWLIB_MACHTYPE="$host_cpu";
|
||||
AC_MSG_WARN("CPU $PWLIB_MACHTYPE not recognized - proceed with caution!") ;;
|
||||
esac
|
||||
|
||||
PWLIB_PLATFORM="${PWLIB_OSTYPE}_${PWLIB_MACHTYPE}"
|
||||
|
||||
AC_SUBST([PWLIB_PLATFORM])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_OPENH323], [
|
||||
OPENH323_INCDIR=
|
||||
OPENH323_LIBDIR=
|
||||
AC_LANG_PUSH([C++])
|
||||
if test "${OPENH323DIR:-unset}" != "unset" ; then
|
||||
AC_CHECK_HEADER(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
|
||||
fi
|
||||
if test "${HAS_OPENH323:-unset}" = "unset" ; then
|
||||
AC_CHECK_HEADER(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
|
||||
if test "${HAS_OPENH323:-unset}" != "unset" ; then
|
||||
OPENH323DIR="${PWLIBDIR}/../openh323"
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} -I${PWLIB_INCDIR}/openh323 -I${PWLIB_INCDIR}"
|
||||
AC_CHECK_HEADER(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}", [#include <ptlib.h>])
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
else
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} -I${HOME}/openh323/include -I${PWLIB_INCDIR}"
|
||||
AC_CHECK_HEADER(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
if test "${HAS_OPENH323:-unset}" != "unset" ; then
|
||||
OPENH323DIR="${HOME}/openh323"
|
||||
else
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} -I/usr/local/include/openh323 -I${PWLIB_INCDIR}"
|
||||
AC_CHECK_HEADER(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
if test "${HAS_OPENH323:-unset}" != "unset" ; then
|
||||
OPENH323DIR="/usr/local/share/openh323"
|
||||
OPENH323_INCDIR="/usr/local/include/openh323"
|
||||
if test "x$LIB64" != "x"; then
|
||||
OPENH323_LIBDIR="/usr/local/lib64"
|
||||
else
|
||||
OPENH323_LIBDIR="/usr/local/lib"
|
||||
fi
|
||||
else
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
CPPFLAGS="${CPPFLAGS} -I/usr/include/openh323 -I${PWLIB_INCDIR}"
|
||||
AC_CHECK_HEADER(/usr/include/openh323/h323.h, HAS_OPENH323=1, , [#include <ptlib.h>])
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
if test "${HAS_OPENH323:-unset}" != "unset" ; then
|
||||
OPENH323DIR="/usr/share/openh323"
|
||||
OPENH323_INCDIR="/usr/include/openh323"
|
||||
if test "x$LIB64" != "x"; then
|
||||
OPENH323_LIBDIR="/usr/lib64"
|
||||
else
|
||||
OPENH323_LIBDIR="/usr/lib"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "${HAS_OPENH323:-unset}" != "unset" ; then
|
||||
if test "${OPENH323_INCDIR:-unset}" = "unset"; then
|
||||
OPENH323_INCDIR="${OPENH323DIR}/include"
|
||||
fi
|
||||
if test "${OPENH323_LIBDIR:-unset}" = "unset"; then
|
||||
OPENH323_LIBDIR="${OPENH323DIR}/lib"
|
||||
fi
|
||||
|
||||
OPENH323_LIBDIR="`cd ${OPENH323_LIBDIR}; pwd`"
|
||||
OPENH323_INCDIR="`cd ${OPENH323_INCDIR}; pwd`"
|
||||
OPENH323DIR="`cd ${OPENH323DIR}; pwd`"
|
||||
|
||||
AC_SUBST([OPENH323DIR])
|
||||
AC_SUBST([OPENH323_INCDIR])
|
||||
AC_SUBST([OPENH323_LIBDIR])
|
||||
fi
|
||||
AC_LANG_POP([C++])
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_PWLIB_VERSION], [
|
||||
if test "${HAS_$2:-unset}" != "unset"; then
|
||||
$2_VERSION=`grep "$2_VERSION" ${$2_INCDIR}/$3 | cut -f2 -d ' ' | sed -e 's/"//g'`
|
||||
$2_MAJOR_VERSION=`echo ${$2_VERSION} | cut -f1 -d.`
|
||||
$2_MINOR_VERSION=`echo ${$2_VERSION} | cut -f2 -d.`
|
||||
$2_BUILD_NUMBER=`echo ${$2_VERSION} | cut -f3 -d.`
|
||||
let $2_VER=${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}
|
||||
let $2_REQ=$4*10000+$5*100+$6
|
||||
|
||||
AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)
|
||||
if test ${$2_VER} -lt ${$2_REQ}; then
|
||||
AC_MSG_RESULT(no)
|
||||
unset HAS_$2
|
||||
else
|
||||
AC_MSG_RESULT(yes)
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_PWLIB_BUILD], [
|
||||
if test "${HAS_$2:-unset}" != "unset"; then
|
||||
AC_MSG_CHECKING($1 installation validity)
|
||||
|
||||
saved_cppflags="${CPPFLAGS}"
|
||||
saved_libs="${LIBS}"
|
||||
if test "${$2_LIB:-unset}" != "unset"; then
|
||||
LIBS="${LIBS} ${$2_LIB} $7"
|
||||
else
|
||||
LIBS="${LIBS} -L${$2_LIBDIR} -l${PLATFORM_$2} $7"
|
||||
fi
|
||||
CPPFLAGS="${CPPFLAGS} -I${$2_INCDIR} $6"
|
||||
|
||||
AC_LANG_PUSH([C++])
|
||||
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([$4],[$5])],
|
||||
[ AC_MSG_RESULT(yes)
|
||||
ac_cv_lib_$2="yes"
|
||||
],
|
||||
[ AC_MSG_RESULT(no)
|
||||
ac_cv_lib_$2="no"
|
||||
]
|
||||
)
|
||||
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
LIBS="${saved_libs}"
|
||||
CPPFLAGS="${saved_cppflags}"
|
||||
|
||||
if test "${ac_cv_lib_$2}" = "yes"; then
|
||||
if test "${$2_LIB:-undef}" = "undef"; then
|
||||
if test "${$2_LIBDIR}" != "" -a "${$2_LIBDIR}" != "/usr/lib"; then
|
||||
$2_LIB="-L${$2_LIBDIR} -l${PLATFORM_$2}"
|
||||
else
|
||||
$2_LIB="-l${PLATFORM_$2}"
|
||||
fi
|
||||
fi
|
||||
if test "${$2_INCDIR}" != "" -a "${$2_INCDIR}" != "/usr/include"; then
|
||||
$2_INCLUDE="-I${$2_INCDIR}"
|
||||
fi
|
||||
PBX_$2=1
|
||||
AC_DEFINE([HAVE_$2], 1, [$3])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN(
|
||||
[AST_CHECK_OPENH323_BUILD], [
|
||||
if test "${HAS_OPENH323:-unset}" != "unset"; then
|
||||
AC_MSG_CHECKING(OpenH323 build option)
|
||||
OPENH323_SUFFIX=
|
||||
prefixes="h323_${PWLIB_PLATFORM}_ h323_ openh323"
|
||||
for pfx in $prefixes; do
|
||||
files=`ls -l ${OPENH323_LIBDIR}/lib${pfx}*.so* 2>/dev/null`
|
||||
libfile=
|
||||
if test -n "$files"; then
|
||||
for f in $files; do
|
||||
if test -f $f -a ! -L $f; then
|
||||
libfile=`basename $f`
|
||||
break;
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if test -n "$libfile"; then
|
||||
OPENH323_PREFIX=$pfx
|
||||
break;
|
||||
fi
|
||||
done
|
||||
if test "${libfile:-unset}" != "unset"; then
|
||||
OPENH323_SUFFIX=`eval "echo ${libfile} | sed -e 's/lib${OPENH323_PREFIX}\(@<:@^.@:>@*\)\..*/\1/'"`
|
||||
fi
|
||||
case "${OPENH323_SUFFIX}" in
|
||||
n)
|
||||
OPENH323_BUILD="notrace";;
|
||||
r)
|
||||
OPENH323_BUILD="opt";;
|
||||
d)
|
||||
OPENH323_BUILD="debug";;
|
||||
*)
|
||||
if test "${OPENH323_PREFIX:-undef}" = "openh323"; then
|
||||
notrace=`eval "grep NOTRACE ${OPENH323DIR}/openh323u.mak | grep = | sed -e 's/@<:@A-Z0-9_@:>@*@<:@ @:>@*=@<:@ @:>@*//'"`
|
||||
if test "x$notrace" = "x"; then
|
||||
notrace="0"
|
||||
fi
|
||||
if test "$notrace" -ne 0; then
|
||||
OPENH323_BUILD="notrace"
|
||||
else
|
||||
OPENH323_BUILD="opt"
|
||||
fi
|
||||
OPENH323_LIB="-l${OPENH323_PREFIX}"
|
||||
else
|
||||
OPENH323_BUILD="notrace"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT(${OPENH323_BUILD})
|
||||
|
||||
AC_SUBST([OPENH323_SUFFIX])
|
||||
AC_SUBST([OPENH323_BUILD])
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
# AST_FUNC_FORK
|
||||
# -------------
|
||||
AN_FUNCTION([fork], [AST_FUNC_FORK])
|
||||
AN_FUNCTION([vfork], [AST_FUNC_FORK])
|
||||
AC_DEFUN([AST_FUNC_FORK],
|
||||
[AC_REQUIRE([AC_TYPE_PID_T])dnl
|
||||
AC_CHECK_HEADERS(vfork.h)
|
||||
AC_CHECK_FUNCS(fork vfork)
|
||||
if test "x$ac_cv_func_fork" = xyes; then
|
||||
_AST_FUNC_FORK
|
||||
else
|
||||
ac_cv_func_fork_works=$ac_cv_func_fork
|
||||
fi
|
||||
if test "x$ac_cv_func_fork_works" = xcross; then
|
||||
case $host in
|
||||
*-*-amigaos* | *-*-msdosdjgpp* | *-*-uclinux* | *-*-linux-uclibc* )
|
||||
# Override, as these systems have only a dummy fork() stub
|
||||
ac_cv_func_fork_works=no
|
||||
;;
|
||||
*)
|
||||
ac_cv_func_fork_works=yes
|
||||
;;
|
||||
esac
|
||||
AC_MSG_WARN([result $ac_cv_func_fork_works guessed because of cross compilation])
|
||||
fi
|
||||
ac_cv_func_vfork_works=$ac_cv_func_vfork
|
||||
if test "x$ac_cv_func_vfork" = xyes; then
|
||||
_AC_FUNC_VFORK
|
||||
fi;
|
||||
if test "x$ac_cv_func_fork_works" = xcross; then
|
||||
ac_cv_func_vfork_works=$ac_cv_func_vfork
|
||||
AC_MSG_WARN([result $ac_cv_func_vfork_works guessed because of cross compilation])
|
||||
fi
|
||||
|
||||
if test "x$ac_cv_func_vfork_works" = xyes; then
|
||||
AC_DEFINE(HAVE_WORKING_VFORK, 1, [Define to 1 if `vfork' works.])
|
||||
else
|
||||
AC_DEFINE(vfork, fork, [Define as `fork' if `vfork' does not work.])
|
||||
fi
|
||||
if test "x$ac_cv_func_fork_works" = xyes; then
|
||||
AC_DEFINE(HAVE_WORKING_FORK, 1, [Define to 1 if `fork' works.])
|
||||
fi
|
||||
])# AST_FUNC_FORK
|
||||
|
||||
|
||||
# _AST_FUNC_FORK
|
||||
# -------------
|
||||
AC_DEFUN([_AST_FUNC_FORK],
|
||||
[AC_CACHE_CHECK(for working fork, ac_cv_func_fork_works,
|
||||
[AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
|
||||
[
|
||||
/* By Ruediger Kuhlmann. */
|
||||
return fork () < 0;
|
||||
])],
|
||||
[ac_cv_func_fork_works=yes],
|
||||
[ac_cv_func_fork_works=no],
|
||||
[ac_cv_func_fork_works=cross])])]
|
||||
)# _AST_FUNC_FORK
|
||||
|
||||
# AST_PROG_LD
|
||||
# ----------
|
||||
# find the pathname to the GNU or non-GNU linker
|
||||
AC_DEFUN([AST_PROG_LD],
|
||||
[AC_ARG_WITH([gnu-ld],
|
||||
[AC_HELP_STRING([--with-gnu-ld],
|
||||
[assume the C compiler uses GNU ld @<:@default=no@:>@])],
|
||||
[test "$withval" = no || with_gnu_ld=yes],
|
||||
[with_gnu_ld=no])
|
||||
AC_REQUIRE([AST_PROG_SED])dnl
|
||||
AC_REQUIRE([AC_PROG_CC])dnl
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])dnl
|
||||
AC_REQUIRE([AC_CANONICAL_BUILD])dnl
|
||||
ac_prog=ld
|
||||
if test "$GCC" = yes; then
|
||||
# Check if gcc -print-prog-name=ld gives a path.
|
||||
AC_MSG_CHECKING([for ld used by $CC])
|
||||
case $host in
|
||||
*-*-mingw*)
|
||||
# gcc leaves a trailing carriage return which upsets mingw
|
||||
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
|
||||
*)
|
||||
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
|
||||
esac
|
||||
case $ac_prog in
|
||||
# Accept absolute paths.
|
||||
[[\\/]]* | ?:[[\\/]]*)
|
||||
re_direlt='/[[^/]][[^/]]*/\.\./'
|
||||
# Canonicalize the pathname of ld
|
||||
ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'`
|
||||
while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
|
||||
ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"`
|
||||
done
|
||||
test -z "$LD" && LD="$ac_prog"
|
||||
;;
|
||||
"")
|
||||
# If it fails, then pretend we aren't using GCC.
|
||||
ac_prog=ld
|
||||
;;
|
||||
*)
|
||||
# If it is relative, then search for the first ld in PATH.
|
||||
with_gnu_ld=unknown
|
||||
;;
|
||||
esac
|
||||
elif test "$with_gnu_ld" = yes; then
|
||||
AC_MSG_CHECKING([for GNU ld])
|
||||
else
|
||||
AC_MSG_CHECKING([for non-GNU ld])
|
||||
fi
|
||||
AC_CACHE_VAL(lt_cv_path_LD,
|
||||
[if test -z "$LD"; then
|
||||
lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
|
||||
for ac_dir in $PATH; do
|
||||
IFS="$lt_save_ifs"
|
||||
test -z "$ac_dir" && ac_dir=.
|
||||
if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
|
||||
lt_cv_path_LD="$ac_dir/$ac_prog"
|
||||
# Check to see if the program is GNU ld. I'd rather use --version,
|
||||
# but apparently some variants of GNU ld only accept -v.
|
||||
# Break only if it was the GNU/non-GNU ld that we prefer.
|
||||
case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
|
||||
*GNU* | *'with BFD'*)
|
||||
test "$with_gnu_ld" != no && break
|
||||
;;
|
||||
*)
|
||||
test "$with_gnu_ld" != yes && break
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
IFS="$lt_save_ifs"
|
||||
else
|
||||
lt_cv_path_LD="$LD" # Let the user override the test with a path.
|
||||
fi])
|
||||
LD="$lt_cv_path_LD"
|
||||
if test -n "$LD"; then
|
||||
AC_MSG_RESULT($LD)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
|
||||
AST_PROG_LD_GNU
|
||||
])# AST_PROG_LD
|
||||
|
||||
|
||||
# AST_PROG_LD_GNU
|
||||
# --------------
|
||||
AC_DEFUN([AST_PROG_LD_GNU],
|
||||
[AC_REQUIRE([AST_PROG_EGREP])dnl
|
||||
AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
|
||||
[# I'd rather use --version here, but apparently some GNU lds only accept -v.
|
||||
case `$LD -v 2>&1 </dev/null` in
|
||||
*GNU* | *'with BFD'*)
|
||||
lt_cv_prog_gnu_ld=yes
|
||||
;;
|
||||
*)
|
||||
lt_cv_prog_gnu_ld=no
|
||||
;;
|
||||
esac])
|
||||
with_gnu_ld=$lt_cv_prog_gnu_ld
|
||||
])# AST_PROG_LD_GNU
|
||||
|
||||
# AST_PROG_EGREP
|
||||
# -------------
|
||||
m4_ifndef([AST_PROG_EGREP], [AC_DEFUN([AST_PROG_EGREP],
|
||||
[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
|
||||
[if echo a | (grep -E '(a|b)') >/dev/null 2>&1
|
||||
then ac_cv_prog_egrep='grep -E'
|
||||
else ac_cv_prog_egrep='egrep'
|
||||
fi])
|
||||
EGREP=$ac_cv_prog_egrep
|
||||
AC_SUBST([EGREP])
|
||||
])]) # AST_PROG_EGREP
|
||||
|
||||
# AST_PROG_SED
|
||||
# -----------
|
||||
# Check for a fully functional sed program that truncates
|
||||
# as few characters as possible. Prefer GNU sed if found.
|
||||
AC_DEFUN([AST_PROG_SED],
|
||||
[AC_CACHE_CHECK([for a sed that does not truncate output], ac_cv_path_SED,
|
||||
[dnl ac_script should not contain more than 99 commands (for HP-UX sed),
|
||||
dnl but more than about 7000 bytes, to catch a limit in Solaris 8 /usr/ucb/sed.
|
||||
ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
|
||||
for ac_i in 1 2 3 4 5 6 7; do
|
||||
ac_script="$ac_script$as_nl$ac_script"
|
||||
done
|
||||
echo "$ac_script" | sed 99q >conftest.sed
|
||||
$as_unset ac_script || ac_script=
|
||||
_AC_PATH_PROG_FEATURE_CHECK(SED, [sed gsed],
|
||||
[_AC_FEATURE_CHECK_LENGTH([ac_path_SED], [ac_cv_path_SED],
|
||||
["$ac_path_SED" -f conftest.sed])])])
|
||||
SED="$ac_cv_path_SED"
|
||||
AC_SUBST([SED])dnl
|
||||
rm -f conftest.sed
|
||||
])# AST_PROG_SED
|
||||
|
||||
dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
dnl
|
||||
dnl @summary figure out how to build C programs using POSIX threads
|
||||
dnl
|
||||
dnl This macro figures out how to build C programs using POSIX threads.
|
||||
dnl It sets the PTHREAD_LIBS output variable to the threads library and
|
||||
dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
|
||||
dnl C compiler flags that are needed. (The user can also force certain
|
||||
dnl compiler flags/libs to be tested by setting these environment
|
||||
dnl variables.)
|
||||
dnl
|
||||
dnl Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
dnl multi-threaded programs (defaults to the value of CC otherwise).
|
||||
dnl (This is necessary on AIX to use the special cc_r compiler alias.)
|
||||
dnl
|
||||
dnl NOTE: You are assumed to not only compile your program with these
|
||||
dnl flags, but also link it with them as well. e.g. you should link
|
||||
dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
|
||||
dnl $LIBS
|
||||
dnl
|
||||
dnl If you are only building threads programs, you may wish to use
|
||||
dnl these variables in your default LIBS, CFLAGS, and CC:
|
||||
dnl
|
||||
dnl LIBS="$PTHREAD_LIBS $LIBS"
|
||||
dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
dnl CC="$PTHREAD_CC"
|
||||
dnl
|
||||
dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
|
||||
dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
|
||||
dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
dnl
|
||||
dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
|
||||
dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
|
||||
dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
|
||||
dnl default action will define HAVE_PTHREAD.
|
||||
dnl
|
||||
dnl Please let the authors know if this macro fails on any platform, or
|
||||
dnl if you have any other suggestions or comments. This macro was based
|
||||
dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
|
||||
dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
|
||||
dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
|
||||
dnl We are also grateful for the helpful feedback of numerous users.
|
||||
dnl
|
||||
dnl @category InstalledPackages
|
||||
dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
dnl @version 2006-05-29
|
||||
dnl @license GPLWithACException
|
||||
|
||||
AC_DEFUN([ACX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
acx_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
|
||||
AC_MSG_RESULT($acx_pthread_ok)
|
||||
if test x"$acx_pthread_ok" = xno; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
|
||||
acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$acx_pthread_ok" = xno; then
|
||||
for flag in $acx_pthread_flags; do
|
||||
|
||||
case $flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
|
||||
if test x"$acx_pthread_config" = xno; then continue; fi
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
AC_TRY_LINK([#include <pthread.h>],
|
||||
[pthread_t th; pthread_join(th, 0);
|
||||
pthread_attr_init(0); pthread_cleanup_push(0, 0);
|
||||
pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
|
||||
[acx_pthread_ok=yes])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
AC_MSG_RESULT($acx_pthread_ok)
|
||||
if test "x$acx_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$acx_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
|
||||
[attr_name=$attr; break])
|
||||
done
|
||||
AC_MSG_RESULT($attr_name)
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case "${host_cpu}-${host_os}" in
|
||||
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
|
||||
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
|
||||
esac
|
||||
AC_MSG_RESULT(${flag})
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
|
||||
# More AIX lossage: must compile with xlc_r or cc_r
|
||||
if test x"$GCC" != xyes; then
|
||||
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
|
||||
else
|
||||
PTHREAD_CC=$CC
|
||||
fi
|
||||
else
|
||||
PTHREAD_CC="$CC"
|
||||
fi
|
||||
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
AC_SUBST(PTHREAD_CFLAGS)
|
||||
AC_SUBST(PTHREAD_CC)
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$acx_pthread_ok" = xyes; then
|
||||
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||||
:
|
||||
else
|
||||
acx_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_RESTORE
|
||||
])dnl ACX_PTHREAD
|
||||
409
acl.c
Normal file
409
acl.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Various sorts of access control
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <asterisk/acl.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/ioctl.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#include <fcntl.h>
|
||||
#include <net/route.h>
|
||||
|
||||
AST_MUTEX_DEFINE_STATIC(routeseq_lock);
|
||||
#endif
|
||||
|
||||
|
||||
struct ast_ha {
|
||||
/* Host access rule */
|
||||
struct in_addr netaddr;
|
||||
struct in_addr netmask;
|
||||
int sense;
|
||||
struct ast_ha *next;
|
||||
};
|
||||
|
||||
/* Default IP - if not otherwise set, don't breathe garbage */
|
||||
static struct in_addr __ourip = { 0x00000000 };
|
||||
|
||||
struct my_ifreq {
|
||||
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "eth0", "ppp0", etc. */
|
||||
struct sockaddr_in ifru_addr;
|
||||
};
|
||||
|
||||
/* Free HA structure */
|
||||
void ast_free_ha(struct ast_ha *ha)
|
||||
{
|
||||
struct ast_ha *hal;
|
||||
while(ha) {
|
||||
hal = ha;
|
||||
ha = ha->next;
|
||||
free(hal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy HA structure */
|
||||
static void ast_copy_ha(struct ast_ha *from, struct ast_ha *to)
|
||||
{
|
||||
memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
|
||||
memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
|
||||
to->sense = from->sense;
|
||||
}
|
||||
|
||||
/* Create duplicate of ha structure */
|
||||
static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
|
||||
{
|
||||
struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
|
||||
|
||||
/* Copy from original to new object */
|
||||
ast_copy_ha(original, new_ha);
|
||||
|
||||
return(new_ha);
|
||||
|
||||
}
|
||||
|
||||
/* Create duplicate HA link list */
|
||||
/* Used in chan_sip2 templates */
|
||||
struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
|
||||
{
|
||||
struct ast_ha *start=original;
|
||||
struct ast_ha *ret = NULL;
|
||||
struct ast_ha *link,*prev=NULL;
|
||||
|
||||
while(start) {
|
||||
link = ast_duplicate_ha(start); /* Create copy of this object */
|
||||
if (prev)
|
||||
prev->next = link; /* Link previous to this object */
|
||||
|
||||
if (!ret)
|
||||
ret = link; /* Save starting point */
|
||||
|
||||
start = start->next; /* Go to next object */
|
||||
prev = link; /* Save pointer to this object */
|
||||
}
|
||||
return (ret); /* Return start of list */
|
||||
}
|
||||
|
||||
struct ast_ha *ast_append_ha(char *sense, char *stuff, struct ast_ha *path)
|
||||
{
|
||||
struct ast_ha *ha = malloc(sizeof(struct ast_ha));
|
||||
char *nm="255.255.255.255";
|
||||
char tmp[256] = "";
|
||||
struct ast_ha *prev = NULL;
|
||||
struct ast_ha *ret;
|
||||
int x,z;
|
||||
unsigned int y;
|
||||
ret = path;
|
||||
while(path) {
|
||||
prev = path;
|
||||
path = path->next;
|
||||
}
|
||||
if (ha) {
|
||||
strncpy(tmp, stuff, sizeof(tmp) - 1);
|
||||
nm = strchr(tmp, '/');
|
||||
if (!nm)
|
||||
nm = "255.255.255.255";
|
||||
else {
|
||||
*nm = '\0';
|
||||
nm++;
|
||||
}
|
||||
if (!strchr(nm, '.')) {
|
||||
if ((sscanf(nm, "%i", &x) == 1) && (x >= 0) && (x <= 32)) {
|
||||
y = 0;
|
||||
for (z=0;z<x;z++) {
|
||||
y >>= 1;
|
||||
y |= 0x80000000;
|
||||
}
|
||||
ha->netmask.s_addr = htonl(y);
|
||||
}
|
||||
} else if (!inet_aton(nm, &ha->netmask)) {
|
||||
ast_log(LOG_WARNING, "%s not a valid netmask\n", nm);
|
||||
free(ha);
|
||||
return path;
|
||||
}
|
||||
if (!inet_aton(tmp, &ha->netaddr)) {
|
||||
ast_log(LOG_WARNING, "%s not a valid IP\n", tmp);
|
||||
free(ha);
|
||||
return path;
|
||||
}
|
||||
ha->netaddr.s_addr &= ha->netmask.s_addr;
|
||||
if (!strncasecmp(sense, "p", 1)) {
|
||||
ha->sense = AST_SENSE_ALLOW;
|
||||
} else {
|
||||
ha->sense = AST_SENSE_DENY;
|
||||
}
|
||||
ha->next = NULL;
|
||||
if (prev)
|
||||
prev->next = ha;
|
||||
else
|
||||
ret = ha;
|
||||
}
|
||||
ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n",stuff, nm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
|
||||
{
|
||||
/* Start optimistic */
|
||||
int res = AST_SENSE_ALLOW;
|
||||
while(ha) {
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
char iabuf2[INET_ADDRSTRLEN];
|
||||
/* DEBUG */
|
||||
ast_log(LOG_DEBUG,
|
||||
"##### Testing %s with %s\n",
|
||||
ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
|
||||
ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
|
||||
/* For each rule, if this address and the netmask = the net address
|
||||
apply the current rule */
|
||||
if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == (ha->netaddr.s_addr))
|
||||
res = ha->sense;
|
||||
ha = ha->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_get_ip(struct sockaddr_in *sin, char *value)
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct ast_hostent ahp;
|
||||
hp = ast_gethostbyname(value, &ahp);
|
||||
if (hp) {
|
||||
memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* iface is the interface (e.g. eth0); address is the return value */
|
||||
int ast_lookup_iface(char *iface, struct in_addr *address) {
|
||||
int mysock, res = 0;
|
||||
struct my_ifreq ifreq;
|
||||
|
||||
memset(&ifreq, 0, sizeof(ifreq));
|
||||
strncpy(ifreq.ifrn_name,iface,sizeof(ifreq.ifrn_name) - 1);
|
||||
|
||||
mysock = socket(PF_INET,SOCK_DGRAM,IPPROTO_IP);
|
||||
res = ioctl(mysock,SIOCGIFADDR,&ifreq);
|
||||
|
||||
close(mysock);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
|
||||
memcpy((char *)address,(char *)&__ourip,sizeof(__ourip));
|
||||
return -1;
|
||||
} else {
|
||||
memcpy((char *)address,(char *)&ifreq.ifru_addr.sin_addr,sizeof(ifreq.ifru_addr.sin_addr));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
|
||||
{
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
struct sockaddr_in *sin;
|
||||
struct sockaddr *sa;
|
||||
struct {
|
||||
struct rt_msghdr m_rtm;
|
||||
char m_space[512];
|
||||
} m_rtmsg;
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
char *cp, *p;
|
||||
int i, l, s, seq, flags;
|
||||
pid_t pid = getpid();
|
||||
static int routeseq; /* Protected by "routeseq_lock" mutex */
|
||||
|
||||
p = ast_strdupa(ast_inet_ntoa(iabuf, sizeof(iabuf), *them));
|
||||
memset(us, 0, sizeof(struct in_addr));
|
||||
|
||||
memset(&m_rtmsg, 0, sizeof(m_rtmsg));
|
||||
m_rtmsg.m_rtm.rtm_type = RTM_GET;
|
||||
m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
|
||||
ast_mutex_lock(&routeseq_lock);
|
||||
seq = ++routeseq;
|
||||
ast_mutex_unlock(&routeseq_lock);
|
||||
m_rtmsg.m_rtm.rtm_seq = seq;
|
||||
m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_IFA;
|
||||
m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) + sizeof(struct sockaddr_in);
|
||||
sin = (struct sockaddr_in *)m_rtmsg.m_space;
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_len = sizeof(struct sockaddr_in);
|
||||
sin->sin_addr = *them;
|
||||
|
||||
if ((s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) < 0) {
|
||||
ast_log(LOG_ERROR, "Error opening routing socket\n");
|
||||
return -1;
|
||||
}
|
||||
flags = fcntl(s, F_GETFL);
|
||||
fcntl(s, F_SETFL, flags | O_NONBLOCK);
|
||||
if (write(s, (char *)&m_rtmsg, m_rtmsg.m_rtm.rtm_msglen) < 0) {
|
||||
ast_log(LOG_ERROR, "Error writing to routing socket: %s\n", strerror(errno));
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
do {
|
||||
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
|
||||
} while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != seq || m_rtmsg.m_rtm.rtm_pid != pid));
|
||||
if (l < 0) {
|
||||
if (errno != EAGAIN)
|
||||
ast_log(LOG_ERROR, "Error reading from routing socket\n");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
|
||||
if (m_rtmsg.m_rtm.rtm_version != RTM_VERSION) {
|
||||
ast_log(LOG_ERROR, "Unsupported route socket protocol version\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (m_rtmsg.m_rtm.rtm_msglen != l)
|
||||
ast_log(LOG_WARNING, "Message length mismatch, in packet %d, returned %d\n",
|
||||
m_rtmsg.m_rtm.rtm_msglen, l);
|
||||
|
||||
if (m_rtmsg.m_rtm.rtm_errno) {
|
||||
ast_log(LOG_ERROR, "RTM_GET got %s (%d)\n",
|
||||
strerror(m_rtmsg.m_rtm.rtm_errno), m_rtmsg.m_rtm.rtm_errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cp = (char *)m_rtmsg.m_space;
|
||||
if (m_rtmsg.m_rtm.rtm_addrs)
|
||||
for (i = 1; i; i <<= 1)
|
||||
if (m_rtmsg.m_rtm.rtm_addrs & i) {
|
||||
sa = (struct sockaddr *)cp;
|
||||
if (i == RTA_IFA && sa->sa_family == AF_INET) {
|
||||
sin = (struct sockaddr_in *)sa;
|
||||
*us = sin->sin_addr;
|
||||
ast_log(LOG_DEBUG, "Found route to %s, output from our address %s.\n", p, ast_inet_ntoa(iabuf, sizeof(iabuf), *us));
|
||||
return 0;
|
||||
}
|
||||
cp += sa->sa_len > 0 ?
|
||||
(1 + ((sa->sa_len - 1) | (sizeof(long) - 1))) :
|
||||
sizeof(long);
|
||||
}
|
||||
|
||||
ast_log(LOG_DEBUG, "No route found for address %s!\n", p);
|
||||
return -1;
|
||||
#else
|
||||
FILE *PROC;
|
||||
unsigned int remote_ip;
|
||||
int res = 1;
|
||||
char line[256];
|
||||
remote_ip = them->s_addr;
|
||||
|
||||
PROC = fopen("/proc/net/route","r");
|
||||
if (!PROC) {
|
||||
bzero(us,sizeof(struct in_addr));
|
||||
return -1;
|
||||
}
|
||||
/* First line contains headers */
|
||||
fgets(line,sizeof(line),PROC);
|
||||
|
||||
while (!feof(PROC)) {
|
||||
char iface[256];
|
||||
unsigned int dest, gateway, mask;
|
||||
int i,fieldnum;
|
||||
char *fields[40];
|
||||
|
||||
fgets(line,sizeof(line),PROC);
|
||||
|
||||
fieldnum = 0;
|
||||
for (i=0;i<sizeof(line);i++) {
|
||||
char *offset;
|
||||
|
||||
fields[fieldnum++] = line + i;
|
||||
offset = strchr(line + i,'\t');
|
||||
if (offset == NULL) {
|
||||
/* Exit loop */
|
||||
break;
|
||||
} else if (fieldnum >= 9) {
|
||||
/* Short-circuit: can't break at 8, since the end of field 7 is figured when fieldnum=8 */
|
||||
break;
|
||||
} else {
|
||||
*offset = '\0';
|
||||
i = offset - line;
|
||||
}
|
||||
}
|
||||
if (fieldnum >= 8) {
|
||||
|
||||
sscanf(fields[0],"%s",iface);
|
||||
sscanf(fields[1],"%x",&dest);
|
||||
sscanf(fields[2],"%x",&gateway);
|
||||
sscanf(fields[7],"%x",&mask);
|
||||
#if 0
|
||||
{ char iabuf[INET_ADDRSTRLEN];
|
||||
printf("Addr: %s %08x Dest: %08x Mask: %08x\n", ast_inet_ntoa(iabuf, sizeof(iabuf), *them), remote_ip, dest, mask); }
|
||||
#endif
|
||||
/* Looks simple, but here is the magic */
|
||||
if (((remote_ip & mask) ^ dest) == 0) {
|
||||
res = ast_lookup_iface(iface,us);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(PROC);
|
||||
if (res == 1) {
|
||||
ast_log(LOG_WARNING, "Yikes! No default route?!!\n");
|
||||
bzero(us,sizeof(struct in_addr));
|
||||
return -2;
|
||||
} else if (res) {
|
||||
/* We've already warned in subroutine */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
|
||||
{
|
||||
char ourhost[MAXHOSTNAMELEN]="";
|
||||
struct ast_hostent ahp;
|
||||
struct hostent *hp;
|
||||
struct in_addr saddr;
|
||||
|
||||
/* just use the bind address if it is nonzero */
|
||||
if (ntohl(bindaddr.sin_addr.s_addr)) {
|
||||
memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
|
||||
return 0;
|
||||
}
|
||||
/* try to use our hostname */
|
||||
if (gethostname(ourhost, sizeof(ourhost)-1)) {
|
||||
ast_log(LOG_WARNING, "Unable to get hostname\n");
|
||||
} else {
|
||||
hp = ast_gethostbyname(ourhost, &ahp);
|
||||
if (hp) {
|
||||
memcpy(ourip, hp->h_addr, sizeof(*ourip));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* A.ROOT-SERVERS.NET. */
|
||||
if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -30,18 +30,12 @@
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
This file contains the code for implementing encryption and decryption
|
||||
for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It
|
||||
can optionally be replaced by code written in assembler using NASM. For
|
||||
further details see the file aesopt.h
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief This file contains the code for implementing encryption and decryption
|
||||
* for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It
|
||||
* can optionally be replaced by code written in assembler using NASM. For
|
||||
* further details see the file aesopt.h
|
||||
*
|
||||
* \author Dr Brian Gladman <brg@gladman.me.uk>
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
@@ -30,17 +30,11 @@
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
This file contains the code for implementing the key schedule for AES
|
||||
(Rijndael) for block and key sizes of 16, 24, and 32 bytes. See aesopt.h
|
||||
for further details including optimisation.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief This file contains the code for implementing the key schedule for AES
|
||||
* (Rijndael) for block and key sizes of 16, 24, and 32 bytes. See aesopt.h
|
||||
* for further details including optimisation.
|
||||
*
|
||||
* \author Dr Brian Gladman <brg@gladman.me.uk>
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
@@ -135,8 +135,7 @@
|
||||
#ifndef _AESOPT_H
|
||||
#define _AESOPT_H
|
||||
|
||||
#include "asterisk/aes.h"
|
||||
#include "asterisk/endian.h"
|
||||
#include <asterisk/aes.h>
|
||||
|
||||
/* CONFIGURATION - USE OF DEFINES
|
||||
|
||||
@@ -147,6 +146,25 @@
|
||||
#if clauses.
|
||||
*/
|
||||
|
||||
/* PLATFORM SPECIFIC INCLUDES */
|
||||
|
||||
#if defined( __OpenBSD__ )
|
||||
# include <machine/types.h>
|
||||
# include <sys/endian.h>
|
||||
#elif defined( __FreeBSD__ ) || defined( __NetBSD__ )
|
||||
# include <sys/types.h>
|
||||
# include <sys/endian.h>
|
||||
#elif defined( BSD ) && ( BSD >= 199103 ) || defined(__APPLE__)
|
||||
# include <machine/endian.h>
|
||||
#elif defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
|
||||
# include <endian.h>
|
||||
#if !defined(__APPLE__)
|
||||
# include <byteswap.h>
|
||||
#endif
|
||||
#elif defined( linux )
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
/* BYTE ORDER IN 32-BIT WORDS
|
||||
|
||||
To obtain the highest speed on processors with 32-bit words, this code
|
||||
48
agi/Makefile
48
agi/Makefile
@@ -1,47 +1,43 @@
|
||||
#
|
||||
# Asterisk -- A telephony toolkit for Linux.
|
||||
#
|
||||
# Makefile for AGI-related stuff
|
||||
# Makefile for PBX frontends (dynamically loaded)
|
||||
#
|
||||
# Copyright (C) 1999-2006, Digium
|
||||
# Copyright (C) 1999, Mark Spencer
|
||||
#
|
||||
# Mark Spencer <markster@digium.com>
|
||||
# Mark Spencer <markster@linux-support.net>
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License
|
||||
#
|
||||
|
||||
.PHONY: clean all uninstall
|
||||
AGIS=agi-test.agi eagi-test eagi-sphinx-test
|
||||
|
||||
AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi
|
||||
CFLAGS+=
|
||||
|
||||
ifeq ($(OSARCH),SunOS)
|
||||
LIBS+=-lsocket -lnsl
|
||||
endif
|
||||
|
||||
include $(ASTTOPDIR)/Makefile.rules
|
||||
|
||||
all: $(AGIS)
|
||||
|
||||
strcompat.c: ../main/strcompat.c
|
||||
@cp $< $@
|
||||
|
||||
eagi-test: eagi-test.o strcompat.o
|
||||
|
||||
eagi-sphinx-test: eagi-sphinx-test.o
|
||||
all: depend $(AGIS)
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(AGI_DIR)
|
||||
for x in $(AGIS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(AGI_DIR) ; done
|
||||
|
||||
uninstall:
|
||||
for x in $(AGIS); do rm -f $(DESTDIR)$(AGI_DIR)/$$x ; done
|
||||
eagi-test: eagi-test.o
|
||||
$(CC) $(CFLAGS) -o eagi-test eagi-test.o
|
||||
|
||||
eagi-sphinx-test: eagi-sphinx-test.o
|
||||
$(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o look eagi-test eagi-sphinx-test
|
||||
rm -f .*.o.d .*.oo.d *.s *.i
|
||||
rm -f strcompat.c
|
||||
rm -f *.so *.o look .depend eagi-test eagi-sphinx-test
|
||||
|
||||
ifneq ($(wildcard .*.d),)
|
||||
include .*.d
|
||||
%.so : %.o
|
||||
$(CC) -shared -Xlinker -x -o $@ $<
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
depend: .depend
|
||||
|
||||
.depend:
|
||||
../mkdep $(CFLAGS) `ls *.c`
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/compat.h"
|
||||
|
||||
#define AUDIO_FILENO (STDERR_FILENO + 1)
|
||||
|
||||
#define SPHINX_HOST "192.168.1.108"
|
||||
|
||||
@@ -12,10 +12,6 @@
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
#include "asterisk/compat.h"
|
||||
|
||||
#define AUDIO_FILENO (STDERR_FILENO + 1)
|
||||
|
||||
static int read_environment(void)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,17 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* u-Law to Signed linear conversion
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief u-Law to Signed linear conversion
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/alaw.h"
|
||||
#include <asterisk/alaw.h>
|
||||
|
||||
#define AMI_MASK 0x55
|
||||
|
||||
@@ -71,7 +55,7 @@ static inline short int alaw2linear (unsigned char alaw)
|
||||
int seg;
|
||||
|
||||
alaw ^= AMI_MASK;
|
||||
i = ((alaw & 0x0F) << 4) + 8 /* rounding error */;
|
||||
i = ((alaw & 0x0F) << 4);
|
||||
seg = (((int) alaw & 0x70) >> 4);
|
||||
if (seg)
|
||||
i = (i + 0x100) << (seg - 1);
|
||||
115
apps/Makefile
115
apps/Makefile
@@ -1,47 +1,104 @@
|
||||
#
|
||||
# Asterisk -- A telephony toolkit for Linux.
|
||||
#
|
||||
# Makefile for PBX applications
|
||||
# Makefile for PBX frontends (dynamically loaded)
|
||||
#
|
||||
# Copyright (C) 1999-2006, Digium, Inc.
|
||||
# Copyright (C) 1999, Mark Spencer
|
||||
#
|
||||
# Mark Spencer <markster@linux-support.net>
|
||||
#
|
||||
# This program is free software, distributed under the terms of
|
||||
# the GNU General Public License
|
||||
#
|
||||
|
||||
-include ../menuselect.makeopts ../menuselect.makedeps
|
||||
USE_MYSQL_VM_INTERFACE=0
|
||||
USE_POSTGRES_VM_INTERFACE=0
|
||||
|
||||
MENUSELECT_CATEGORY=APPS
|
||||
MENUSELECT_DESCRIPTION=Applications
|
||||
#APPS=app_dial.so app_playback.so app_directory.so app_intercom.so app_mp3.so
|
||||
APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\
|
||||
app_system.so app_echo.so app_record.so app_image.so app_url.so app_disa.so \
|
||||
app_qcall.so app_adsiprog.so app_getcpeid.so app_milliwatt.so \
|
||||
app_zapateller.so app_setcallerid.so app_festival.so \
|
||||
app_queue.so app_senddtmf.so app_parkandannounce.so app_striplsd.so \
|
||||
app_setcidname.so app_lookupcidname.so app_substring.so app_macro.so \
|
||||
app_authenticate.so app_softhangup.so app_lookupblacklist.so \
|
||||
app_waitforring.so app_privacy.so app_db.so app_chanisavail.so \
|
||||
app_enumlookup.so app_transfer.so app_setcidnum.so app_cdr.so \
|
||||
app_hasnewvoicemail.so app_sayunixtime.so app_cut.so app_read.so \
|
||||
app_setcdruserfield.so app_random.so app_ices.so app_eval.so \
|
||||
app_nbscat.so app_sendtext.so app_exec.so app_sms.so \
|
||||
app_groupcount.so app_txtcidname.so app_controlplayback.so \
|
||||
app_talkdetect.so app_alarmreceiver.so app_userevent.so app_verbose.so \
|
||||
app_test.so app_forkcdr.so
|
||||
|
||||
ALL_C_MODS:=$(patsubst %.c,%,$(wildcard app_*.c))
|
||||
ALL_CC_MODS:=$(patsubst %.cc,%,$(wildcard app_*.cc))
|
||||
|
||||
C_MODS:=$(filter-out $(MENUSELECT_APPS),$(ALL_C_MODS))
|
||||
CC_MODS:=$(filter-out $(MENUSELECT_APPS),$(ALL_CC_MODS))
|
||||
|
||||
LOADABLE_MODS:=$(C_MODS) $(CC_MODS)
|
||||
|
||||
ifneq ($(findstring apps,$(MENUSELECT_EMBED)),)
|
||||
EMBEDDED_MODS:=$(LOADABLE_MODS)
|
||||
LOADABLE_MODS:=
|
||||
ifneq (${OSARCH},Darwin)
|
||||
APPS+=app_intercom.so
|
||||
endif
|
||||
|
||||
MENUSELECT_OPTS_app_directory:=$(MENUSELECT_OPTS_app_voicemail)
|
||||
ifneq ($(findstring ODBC_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
|
||||
MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
|
||||
MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
|
||||
endif
|
||||
ifneq ($(findstring IMAP_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
|
||||
MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
|
||||
MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
|
||||
#APPS+=app_sql_postgres.so
|
||||
#APPS+=app_sql_odbc.so
|
||||
#APPS+=app_rpt.so
|
||||
|
||||
APPS+=$(shell if [ -f /usr/include/linux/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
|
||||
APPS+=$(shell if [ -f /usr/local/include/zaptel.h ]; then echo "app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so" ; fi)
|
||||
APPS+=$(shell if [ -f /usr/include/osp/osp.h ]; then echo "app_osplookup.so" ; fi)
|
||||
|
||||
CFLAGS+=-fPIC
|
||||
|
||||
ifeq ($(USE_POSTGRES_VM_INTERFACE),1)
|
||||
CFLAGS+=-DUSEPOSTGRESVM
|
||||
endif
|
||||
|
||||
ifeq (SunOS,$(shell uname))
|
||||
MENUSELECT_DEPENDS_app_chanspy+=RT
|
||||
RT_LIB=-lrt
|
||||
ifeq ($(USE_MYSQL_VM_INTERFACE),1)
|
||||
CFLAGS+=-DUSEMYSQLVM
|
||||
endif
|
||||
|
||||
all: _all
|
||||
all: $(APPS)
|
||||
|
||||
include $(ASTTOPDIR)/Makefile.moddir_rules
|
||||
clean:
|
||||
rm -f *.so *.o look .depend
|
||||
|
||||
%.so : %.o
|
||||
$(CC) $(SOLINK) -o $@ $<
|
||||
|
||||
app_rpt.so : app_rpt.o
|
||||
$(CC) $(SOLINK) -o $@ $< -ltonezone
|
||||
|
||||
install: all
|
||||
for x in $(APPS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done
|
||||
rm -f $(DESTDIR)$(MODULES_DIR)/app_datetime.so
|
||||
|
||||
app_voicemail.so : app_voicemail.o
|
||||
ifeq ($(USE_MYSQL_VM_INTERFACE),1)
|
||||
$(CC) $(SOLINK) -o $@ $(MLFLAGS) $< -L/usr/lib/mysql -lmysqlclient -lz
|
||||
else
|
||||
ifeq ($(USE_POSTGRES_VM_INTERFACE),1)
|
||||
$(CC) $(SOLINK) -o $@ $(MLFLAGS) $< -lpq
|
||||
else
|
||||
$(CC) $(SOLINK) -o $@ $(MLFLAGS) $<
|
||||
endif
|
||||
endif
|
||||
|
||||
app_sql_postgres.o: app_sql_postgres.c
|
||||
$(CC) -pipe -I/usr/local/pgsql/include $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
|
||||
|
||||
app_sql_postgres.so: app_sql_postgres.o
|
||||
$(CC) $(SOLINK) -o $@ $< -L/usr/local/pgsql/lib -lpq
|
||||
|
||||
app_sql_odbc.so: app_sql_odbc.o
|
||||
$(CC) $(SOLINK) -o $@ $< -lodbc
|
||||
|
||||
look: look.c
|
||||
$(CC) -pipe -O6 -g look.c -o look -lncurses
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
depend: .depend
|
||||
|
||||
.depend:
|
||||
../mkdep $(CFLAGS) `ls *.c`
|
||||
|
||||
env:
|
||||
env
|
||||
|
||||
@@ -1,39 +1,26 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Program Asterisk ADSI Scripts into phone
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Program Asterisk ADSI Scripts into phone
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>res_adsi</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/adsi.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
@@ -43,15 +30,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/adsi.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "../asterisk.h"
|
||||
#include "../astconf.h"
|
||||
|
||||
static char *tdesc = "Asterisk ADSI Programming Application";
|
||||
|
||||
static char *app = "ADSIProg";
|
||||
|
||||
@@ -60,8 +42,13 @@ static char *synopsis = "Load Asterisk ADSI Scripts into phone";
|
||||
/* #define DUMP_MESSAGES */
|
||||
|
||||
static char *descrip =
|
||||
" ADSIProg(script): This application programs an ADSI Phone with the given\n"
|
||||
"script. If nothing is specified, the default script (asterisk.adsi) is used.\n";
|
||||
" ADSIProg(script): Programs an ADSI Phone with the given script.\n"
|
||||
"If none is specified, the default is used. Returns 0 unless CPE\n"
|
||||
"is hungup.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct adsi_event {
|
||||
int id;
|
||||
@@ -172,9 +159,9 @@ struct adsi_script {
|
||||
struct adsi_flag flags[7];
|
||||
|
||||
/* Stuff from adsi script */
|
||||
unsigned char sec[5];
|
||||
char sec[5];
|
||||
char desc[19];
|
||||
unsigned char fdn[5];
|
||||
char fdn[5];
|
||||
int ver;
|
||||
};
|
||||
|
||||
@@ -413,7 +400,7 @@ static struct adsi_flag *getflagbyname(struct adsi_script *state, char *name, ch
|
||||
ast_log(LOG_WARNING, "No more flag space at line %d of %s\n", lineno, script);
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname));
|
||||
strncpy(state->flags[state->numflags].vname, name, sizeof(state->flags[state->numflags].vname) - 1);
|
||||
state->flags[state->numflags].id = state->numflags + 1;
|
||||
state->numflags++;
|
||||
return &state->flags[state->numflags-1];
|
||||
@@ -516,7 +503,7 @@ static struct adsi_soft_key *getkeybyname(struct adsi_script *state, char *name,
|
||||
ast_log(LOG_WARNING, "No more key space at line %d of %s\n", lineno, script);
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname));
|
||||
strncpy(state->keys[state->numkeys].vname, name, sizeof(state->keys[state->numkeys].vname) - 1);
|
||||
state->keys[state->numkeys].id = state->numkeys + 2;
|
||||
state->numkeys++;
|
||||
return &state->keys[state->numkeys-1];
|
||||
@@ -532,7 +519,7 @@ static struct adsi_subscript *getsubbyname(struct adsi_script *state, char *name
|
||||
ast_log(LOG_WARNING, "No more subscript space at line %d of %s\n", lineno, script);
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname));
|
||||
strncpy(state->subs[state->numsubs].vname, name, sizeof(state->subs[state->numsubs].vname) - 1);
|
||||
state->subs[state->numsubs].id = state->numsubs;
|
||||
state->numsubs++;
|
||||
return &state->subs[state->numsubs-1];
|
||||
@@ -551,7 +538,7 @@ static struct adsi_state *getstatebyname(struct adsi_script *state, char *name,
|
||||
ast_log(LOG_WARNING, "No more state space at line %d of %s\n", lineno, script);
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname));
|
||||
strncpy(state->states[state->numstates].vname, name, sizeof(state->states[state->numstates].vname) - 1);
|
||||
state->states[state->numstates].id = state->numstates + 1;
|
||||
state->numstates++;
|
||||
return &state->states[state->numstates-1];
|
||||
@@ -570,7 +557,7 @@ static struct adsi_display *getdisplaybyname(struct adsi_script *state, char *na
|
||||
ast_log(LOG_WARNING, "No more display space at line %d of %s\n", lineno, script);
|
||||
return NULL;
|
||||
}
|
||||
ast_copy_string(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname));
|
||||
strncpy(state->displays[state->numdisplays].vname, name, sizeof(state->displays[state->numdisplays].vname) - 1);
|
||||
state->displays[state->numdisplays].id = state->numdisplays + 1;
|
||||
state->numdisplays++;
|
||||
return &state->displays[state->numdisplays-1];
|
||||
@@ -1056,7 +1043,7 @@ static int adsi_process(struct adsi_script *state, char *buf, char *script, int
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ast_copy_string(tmp2, tmp, sizeof(tmp2));
|
||||
strncpy(tmp2, tmp, sizeof(tmp2) - 1);
|
||||
}
|
||||
if (strlen(tmp2) > 18) {
|
||||
ast_log(LOG_WARNING, "Truncating full name to 18 characters at line %d of %s\n", lineno, script);
|
||||
@@ -1349,7 +1336,7 @@ static struct adsi_script *compile_script(char *script)
|
||||
int x, err;
|
||||
struct adsi_script *scr;
|
||||
if (script[0] == '/')
|
||||
ast_copy_string(fn, script, sizeof(fn));
|
||||
strncpy(fn, script, sizeof(fn) - 1);
|
||||
else
|
||||
snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, script);
|
||||
f = fopen(fn, "r");
|
||||
@@ -1357,10 +1344,13 @@ 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)) {
|
||||
@@ -1435,18 +1425,18 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
{
|
||||
struct adsi_script *scr;
|
||||
int x;
|
||||
unsigned char buf[1024];
|
||||
char buf[1024];
|
||||
int bytes;
|
||||
scr = compile_script(script);
|
||||
if (!scr)
|
||||
return -1;
|
||||
|
||||
/* Start an empty ADSI Session */
|
||||
if (ast_adsi_load_session(chan, NULL, 0, 1) < 1)
|
||||
if (adsi_load_session(chan, NULL, 0, 1) < 1)
|
||||
return -1;
|
||||
|
||||
/* Now begin the download attempt */
|
||||
if (ast_adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
|
||||
if (adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
|
||||
/* User rejected us for some reason */
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User rejected download attempt\n");
|
||||
@@ -1460,7 +1450,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
for (x=0;x<scr->numkeys;x++) {
|
||||
if (bytes + scr->keys[x].retstrlen > 253) {
|
||||
/* Send what we've collected so far */
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
@@ -1473,7 +1463,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
#endif
|
||||
}
|
||||
if (bytes) {
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
@@ -1484,7 +1474,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
for (x=0;x<scr->numdisplays;x++) {
|
||||
if (bytes + scr->displays[x].datalen > 253) {
|
||||
/* Send what we've collected so far */
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
@@ -1497,7 +1487,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
#endif
|
||||
}
|
||||
if (bytes) {
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
@@ -1508,7 +1498,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
for (x=0;x<scr->numsubs;x++) {
|
||||
if (bytes + scr->subs[x].datalen > 253) {
|
||||
/* Send what we've collected so far */
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
@@ -1521,7 +1511,7 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
#endif
|
||||
}
|
||||
if (bytes) {
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
|
||||
ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
|
||||
return -1;
|
||||
}
|
||||
@@ -1529,11 +1519,11 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
|
||||
|
||||
bytes = 0;
|
||||
bytes += ast_adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
|
||||
bytes += ast_adsi_set_line(buf, ADSI_INFO_PAGE, 1);
|
||||
if (ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
|
||||
bytes += adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
|
||||
bytes += adsi_set_line(buf, ADSI_INFO_PAGE, 1);
|
||||
if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
|
||||
return -1;
|
||||
if (ast_adsi_end_download(chan)) {
|
||||
if (adsi_end_download(chan)) {
|
||||
/* Download failed for some reason */
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Download attempt failed\n");
|
||||
@@ -1542,21 +1532,18 @@ static int adsi_prog(struct ast_channel *chan, char *script)
|
||||
return -1;
|
||||
}
|
||||
free(scr);
|
||||
ast_adsi_unload_session(chan);
|
||||
adsi_unload_session(chan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adsi_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (ast_strlen_zero(data))
|
||||
struct localuser *u;
|
||||
if (!data || ast_strlen_zero(data))
|
||||
data = "asterisk.adsi";
|
||||
|
||||
if (!ast_adsi_available(chan)) {
|
||||
LOCAL_USER_ADD(u);
|
||||
if (!adsi_available(chan)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "ADSI Unavailable on CPE. Not bothering to try.\n");
|
||||
} else {
|
||||
@@ -1564,27 +1551,34 @@ static int adsi_exec(struct ast_channel *chan, void *data)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "ADSI Available on CPE. Attempting Upload.\n");
|
||||
res = adsi_prog(chan, data);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, adsi_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Asterisk ADSI Programming Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 2004 - 2005 Steve Rodgers
|
||||
* Central Station Alarm receiver for Ademco Contact ID
|
||||
*
|
||||
* Copyright (C) 2004 Steve Rodgers
|
||||
*
|
||||
* Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
* \brief Central Station Alarm receiver for Ademco Contact ID
|
||||
* \author Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
|
||||
*
|
||||
* the GNU General Public License
|
||||
*
|
||||
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
*
|
||||
* Use at your own risk. Please consult the GNU GPL license document included with Asterisk. *
|
||||
* Use at your own risk. Please consult the GNU GPL license document included with Asterisk details. *
|
||||
*
|
||||
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/ulaw.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/dsp.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/localtime.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/astdb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -41,23 +41,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/ulaw.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
#define ALMRCV_CONFIG "alarmreceiver.conf"
|
||||
#define ADEMCO_CONTACT_ID "ADEMCO_CONTACT_ID"
|
||||
|
||||
@@ -68,19 +51,19 @@ struct event_node{
|
||||
|
||||
typedef struct event_node event_node_t;
|
||||
|
||||
static char *tdesc = "Alarm Receiver for Asterisk";
|
||||
|
||||
static char *app = "AlarmReceiver";
|
||||
|
||||
static char *synopsis = "Provide support for receiving alarm reports from a burglar or fire alarm panel";
|
||||
static char *synopsis = "Provide support for receving alarm reports from a burglar or fire alarm panel";
|
||||
static char *descrip =
|
||||
" AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n"
|
||||
"Contact ID. This application should be called whenever there is an alarm\n"
|
||||
"panel calling in to dump its events. The application will handshake with the\n"
|
||||
"alarm panel, and receive events, validate them, handshake them, and store them\n"
|
||||
"until the panel hangs up. Once the panel hangs up, the application will run the\n"
|
||||
"system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n"
|
||||
"the events to the standard input of the application. The configuration file also\n"
|
||||
"contains settings for DTMF timing, and for the loudness of the acknowledgement\n"
|
||||
"tones.\n";
|
||||
"Alarm receiver application for Asterisk. Only 1 signalling format is supported at this time:\n"
|
||||
"Ademco Contact ID. This application should be called whenever there is an alarm panel calling in\n"
|
||||
"to dump its events. The application will handshake with the alarm panel, and receive events,\n"
|
||||
"validate them, handshake them, and store them until the panel hangs up. Once the panel hangs up,\n"
|
||||
"the application will run the command line specified by the eventcmd setting in alarmreceiver.conf\n"
|
||||
"and pipe the events to the standard input of the application. Alarmreceiver.conf also contains settings\n"
|
||||
"for DTMF timing, and for the loudness of the acknowledgement tones.\n";
|
||||
|
||||
/* Config Variables */
|
||||
|
||||
@@ -93,10 +76,18 @@ static char event_app[128] = {'\0'};
|
||||
static char db_family[128] = {'\0'};
|
||||
static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
|
||||
|
||||
|
||||
/* Misc variables */
|
||||
|
||||
|
||||
static char event_file[14] = "/event-XXXXXX";
|
||||
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/*
|
||||
* Attempt to access a database variable and increment it,
|
||||
* provided that the user defined db-family in alarmreceiver.conf
|
||||
@@ -112,7 +103,7 @@ static void database_increment( char *key )
|
||||
char value[16];
|
||||
|
||||
|
||||
if (ast_strlen_zero(db_family))
|
||||
if(!strlen(db_family))
|
||||
return; /* If not defined, don't do anything */
|
||||
|
||||
res = ast_db_get(db_family, key, value, sizeof(value) - 1);
|
||||
@@ -136,7 +127,7 @@ static void database_increment( char *key )
|
||||
res = ast_db_put(db_family, key, value);
|
||||
|
||||
if((res)&&(option_verbose >= 4))
|
||||
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error\n");
|
||||
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error");
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -206,7 +197,6 @@ static int send_tone_burst(struct ast_channel *chan, float freq, int duration, i
|
||||
|
||||
i += wf.datalen / 8;
|
||||
if (i > duration) {
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
if (ast_write(chan, &wf)){
|
||||
@@ -214,7 +204,6 @@ static int send_tone_burst(struct ast_channel *chan, float freq, int duration, i
|
||||
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Failed to write frame on %s\n", chan->name);
|
||||
ast_log(LOG_WARNING, "AlarmReceiver Failed to write frame on %s\n",chan->name);
|
||||
res = -1;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -224,6 +213,20 @@ static int send_tone_burst(struct ast_channel *chan, float freq, int duration, i
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the difference in milliseconds between two timeval structs
|
||||
*/
|
||||
|
||||
static int ms_diff(struct timeval *tv1, struct timeval *tv2){
|
||||
|
||||
int ms;
|
||||
|
||||
ms = (tv1->tv_sec - tv2->tv_sec) * 1000;
|
||||
ms += (tv1->tv_usec - tv2->tv_usec) / 1000;
|
||||
|
||||
return(ms);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential
|
||||
* treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent
|
||||
@@ -241,12 +244,14 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
|
||||
int i = 0;
|
||||
int r;
|
||||
struct ast_frame *f;
|
||||
struct timeval lastdigittime;
|
||||
struct timeval now, lastdigittime;
|
||||
|
||||
lastdigittime = ast_tvnow();
|
||||
gettimeofday(&lastdigittime,NULL);
|
||||
for(;;){
|
||||
gettimeofday(&now,NULL);
|
||||
|
||||
/* if outa time, leave */
|
||||
if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
|
||||
if (ms_diff(&now,&lastdigittime) >
|
||||
((i > 0) ? sdto : fdto)){
|
||||
if(option_verbose >= 4)
|
||||
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
|
||||
@@ -291,7 +296,7 @@ static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int
|
||||
if(i >= length)
|
||||
break;
|
||||
|
||||
lastdigittime = ast_tvnow();
|
||||
gettimeofday(&lastdigittime,NULL);
|
||||
}
|
||||
|
||||
digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
|
||||
@@ -313,8 +318,8 @@ static int write_metadata( FILE *logfile, char *signalling_type, struct ast_chan
|
||||
char timestamp[80];
|
||||
|
||||
/* Extract the caller ID location */
|
||||
if (chan->cid.cid_num)
|
||||
ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
|
||||
|
||||
strncpy(workstring, chan->callerid, sizeof(workstring) - 1);
|
||||
workstring[sizeof(workstring) - 1] = '\0';
|
||||
|
||||
ast_callerid_parse(workstring, &cn, &cl);
|
||||
@@ -389,11 +394,11 @@ static int log_events(struct ast_channel *chan, char *signalling_type, event_no
|
||||
FILE *logfile;
|
||||
event_node_t *elp = event;
|
||||
|
||||
if (!ast_strlen_zero(event_spool_dir)) {
|
||||
if(strlen(event_spool_dir)){
|
||||
|
||||
/* Make a template */
|
||||
|
||||
ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
|
||||
strncpy(workstring, event_spool_dir, sizeof(workstring) - 1);
|
||||
strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
|
||||
|
||||
/* Make the temporary file */
|
||||
@@ -513,7 +518,7 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
|
||||
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
|
||||
|
||||
if(!got_some_digits){
|
||||
got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
|
||||
got_some_digits = (strlen(event)) ? 1 : 0;
|
||||
ack_retries++;
|
||||
}
|
||||
continue;
|
||||
@@ -549,12 +554,13 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
|
||||
|
||||
checksum = checksum % 15;
|
||||
|
||||
if (checksum) {
|
||||
if(checksum){
|
||||
database_increment("checksum-errors");
|
||||
if (option_verbose >= 2)
|
||||
if(option_verbose >= 2){
|
||||
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Nonzero checksum\n");
|
||||
ast_log(LOG_DEBUG, "AlarmReceiver: Nonzero checksum\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the message type for correctness */
|
||||
@@ -571,14 +577,20 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
|
||||
|
||||
events_received++;
|
||||
|
||||
/* Queue the Event */
|
||||
if (!(enew = ast_calloc(1, sizeof(*enew)))) {
|
||||
/* Queue the Event */
|
||||
|
||||
if((enew = malloc(sizeof(event_node_t))) == NULL){
|
||||
if(option_verbose >= 1)
|
||||
ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
|
||||
ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
|
||||
res = -1;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(enew, 0, sizeof(event_node_t));
|
||||
|
||||
enew->next = NULL;
|
||||
ast_copy_string(enew->data, event, sizeof(enew->data));
|
||||
strncpy(enew->data, event, sizeof(enew->data) - 1);
|
||||
|
||||
/*
|
||||
* Insert event onto end of list
|
||||
@@ -626,13 +638,13 @@ static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int
|
||||
static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
event_node_t *elp, *efree;
|
||||
char signalling_type[64] = "";
|
||||
|
||||
event_node_t *event_head = NULL;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Set write and read formats to ULAW */
|
||||
|
||||
@@ -641,19 +653,17 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
|
||||
ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
|
||||
ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set default values for this invokation of the application */
|
||||
|
||||
ast_copy_string(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type));
|
||||
strncpy(signalling_type, ADEMCO_CONTACT_ID, sizeof(signalling_type) - 1);
|
||||
|
||||
|
||||
/* Answer the channel if it is not already */
|
||||
@@ -666,7 +676,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
res = ast_answer(chan);
|
||||
|
||||
if (res) {
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -705,7 +715,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
* Do we exec a command line at the end?
|
||||
*/
|
||||
|
||||
if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
|
||||
if((!res) && (strlen(event_app)) && (event_head)){
|
||||
ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
|
||||
ast_safe_system(event_app);
|
||||
}
|
||||
@@ -721,7 +731,7 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -733,17 +743,16 @@ static int alarmreceiver_exec(struct ast_channel *chan, void *data)
|
||||
static int load_config(void)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
const char *p;
|
||||
char *p;
|
||||
|
||||
/* Read in the config file */
|
||||
|
||||
cfg = ast_config_load(ALMRCV_CONFIG);
|
||||
cfg = ast_load(ALMRCV_CONFIG);
|
||||
|
||||
if(!cfg){
|
||||
|
||||
if(option_verbose >= 4)
|
||||
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
|
||||
return 0;
|
||||
}
|
||||
else{
|
||||
|
||||
@@ -751,7 +760,7 @@ static int load_config(void)
|
||||
p = ast_variable_retrieve(cfg, "general", "eventcmd");
|
||||
|
||||
if(p){
|
||||
ast_copy_string(event_app, p, sizeof(event_app));
|
||||
strncpy(event_app, p, sizeof(event_app) - 1);
|
||||
event_app[sizeof(event_app) - 1] = '\0';
|
||||
}
|
||||
|
||||
@@ -791,26 +800,26 @@ static int load_config(void)
|
||||
p = ast_variable_retrieve(cfg, "general", "eventspooldir");
|
||||
|
||||
if(p){
|
||||
ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
|
||||
strncpy(event_spool_dir, p, sizeof(event_spool_dir) - 1);
|
||||
event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
|
||||
}
|
||||
|
||||
p = ast_variable_retrieve(cfg, "general", "timestampformat");
|
||||
|
||||
if(p){
|
||||
ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
|
||||
strncpy(time_stamp_format, p, sizeof(time_stamp_format) - 1);
|
||||
time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
|
||||
}
|
||||
|
||||
p = ast_variable_retrieve(cfg, "general", "db-family");
|
||||
|
||||
if(p){
|
||||
ast_copy_string(db_family, p, sizeof(db_family));
|
||||
strncpy(db_family, p, sizeof(db_family) - 1);
|
||||
db_family[sizeof(db_family) - 1] = '\0';
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -819,23 +828,31 @@ static int load_config(void)
|
||||
*/
|
||||
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
load_config();
|
||||
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
char *key()
|
||||
{
|
||||
if(load_config())
|
||||
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
|
||||
else
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");
|
||||
|
||||
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,
|
||||
);
|
||||
@@ -1,252 +1,172 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Execute arbitrary authenticate commands
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Execute arbitrary authenticate commands
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/astdb.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
enum {
|
||||
OPT_ACCOUNT = (1 << 0),
|
||||
OPT_DATABASE = (1 << 1),
|
||||
OPT_JUMP = (1 << 2),
|
||||
OPT_MULTIPLE = (1 << 3),
|
||||
OPT_REMOVE = (1 << 4),
|
||||
} auth_option_flags;
|
||||
|
||||
AST_APP_OPTIONS(auth_app_options, {
|
||||
AST_APP_OPTION('a', OPT_ACCOUNT),
|
||||
AST_APP_OPTION('d', OPT_DATABASE),
|
||||
AST_APP_OPTION('j', OPT_JUMP),
|
||||
AST_APP_OPTION('m', OPT_MULTIPLE),
|
||||
AST_APP_OPTION('r', OPT_REMOVE),
|
||||
});
|
||||
|
||||
static char *tdesc = "Authentication Application";
|
||||
|
||||
static char *app = "Authenticate";
|
||||
|
||||
static char *synopsis = "Authenticate a user";
|
||||
|
||||
static char *descrip =
|
||||
" Authenticate(password[|options[|maxdigits]]): This application asks the caller\n"
|
||||
"to enter a given password in order to continue dialplan execution. If the password\n"
|
||||
"begins with the '/' character, it is interpreted as a file which contains a list of\n"
|
||||
"valid passwords, listed 1 password per line in the file.\n"
|
||||
" When using a database key, the value associated with the key can be anything.\n"
|
||||
"Users have three attempts to authenticate before the channel is hung up. If the\n"
|
||||
"passsword is invalid, the 'j' option is specified, and priority n+101 exists,\n"
|
||||
"dialplan execution will continnue at this location.\n"
|
||||
" Options:\n"
|
||||
" a - Set the channels' account code to the password that is entered\n"
|
||||
" d - Interpret the given path as database key, not a literal file\n"
|
||||
" j - Support jumping to n+101 if authentication fails\n"
|
||||
" m - Interpret the given path as a file which contains a list of account\n"
|
||||
" codes and password hashes delimited with ':', listed one per line in\n"
|
||||
" the file. When one of the passwords is matched, the channel will have\n"
|
||||
" its account code set to the corresponding account code in the file.\n"
|
||||
" r - Remove the database key upon successful entry (valid with 'd' only)\n"
|
||||
" maxdigits - maximum acceptable number of digits. Stops reading after\n"
|
||||
" maxdigits have been entered (without requiring the user to\n"
|
||||
" press the '#' key).\n"
|
||||
" Defaults to 0 - no limit - wait for the user press the '#' key.\n"
|
||||
;
|
||||
" Authenticate(password[|options]): Requires a user to enter a"
|
||||
"given password in order to continue execution. If the\n"
|
||||
"password begins with the '/' character, it is interpreted as\n"
|
||||
"a file which contains a list of valid passwords (1 per line).\n"
|
||||
"an optional set of opions may be provided by concatenating any\n"
|
||||
"of the following letters:\n"
|
||||
" a - Set account code to the password that is entered\n"
|
||||
" d - Interpret path as database key, not literal file\n"
|
||||
" r - Remove database key upon successful entry (valid with 'd' only)\n"
|
||||
"\n"
|
||||
"When using a database key, the value associated with the key can be\n"
|
||||
"anything.\n"
|
||||
"Returns 0 if the user enters a valid password within three\n"
|
||||
"tries, or -1 otherwise (or on hangup).\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int auth_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int retries;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
char password[256]="";
|
||||
char passwd[256];
|
||||
char *opts;
|
||||
char *prompt;
|
||||
int maxdigits;
|
||||
char *argcopy =NULL;
|
||||
struct ast_flags flags = {0};
|
||||
|
||||
AST_DECLARE_APP_ARGS(arglist,
|
||||
AST_APP_ARG(password);
|
||||
AST_APP_ARG(options);
|
||||
AST_APP_ARG(maxdigits);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!data || ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
argcopy = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(arglist,argcopy);
|
||||
|
||||
if (!ast_strlen_zero(arglist.options)) {
|
||||
ast_app_parse_options(auth_app_options, &flags, NULL, arglist.options);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(arglist.maxdigits)) {
|
||||
maxdigits = atoi(arglist.maxdigits);
|
||||
if ((maxdigits<1) || (maxdigits>sizeof(passwd)-2))
|
||||
maxdigits = sizeof(passwd) - 2;
|
||||
} else {
|
||||
maxdigits = sizeof(passwd) - 2;
|
||||
}
|
||||
|
||||
strncpy(password, data, sizeof(password) - 1);
|
||||
opts=strchr(password, '|');
|
||||
if (opts) {
|
||||
*opts = 0;
|
||||
opts++;
|
||||
} else
|
||||
opts = "";
|
||||
/* Start asking for password */
|
||||
prompt = "agent-pass";
|
||||
for (retries = 0; retries < 3; retries++) {
|
||||
res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0);
|
||||
res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
|
||||
if (res < 0)
|
||||
break;
|
||||
res = 0;
|
||||
if (arglist.password[0] == '/') {
|
||||
if (ast_test_flag(&flags,OPT_DATABASE)) {
|
||||
if (password[0] == '/') {
|
||||
if (strchr(opts, 'd')) {
|
||||
char tmp[256];
|
||||
/* Compare against a database key */
|
||||
if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
|
||||
if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) {
|
||||
/* It's a good password */
|
||||
if (ast_test_flag(&flags,OPT_REMOVE)) {
|
||||
ast_db_del(arglist.password + 1, passwd);
|
||||
if (strchr(opts, 'r')) {
|
||||
ast_db_del(password + 1, passwd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Compare against a file */
|
||||
FILE *f;
|
||||
f = fopen(arglist.password, "r");
|
||||
f = fopen(password, "r");
|
||||
if (f) {
|
||||
char buf[256] = "";
|
||||
char md5passwd[33] = "";
|
||||
char *md5secret = NULL;
|
||||
|
||||
while (!feof(f)) {
|
||||
while(!feof(f)) {
|
||||
fgets(buf, sizeof(buf), f);
|
||||
if (!ast_strlen_zero(buf)) {
|
||||
size_t len = strlen(buf);
|
||||
if (buf[len - 1] == '\n')
|
||||
buf[len - 1] = '\0';
|
||||
if (ast_test_flag(&flags,OPT_MULTIPLE)) {
|
||||
md5secret = strchr(buf, ':');
|
||||
if (md5secret == NULL)
|
||||
continue;
|
||||
*md5secret = '\0';
|
||||
md5secret++;
|
||||
ast_md5_hash(md5passwd, passwd);
|
||||
if (!strcmp(md5passwd, md5secret)) {
|
||||
if (ast_test_flag(&flags,OPT_ACCOUNT))
|
||||
ast_cdr_setaccount(chan, buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(passwd, buf)) {
|
||||
if (ast_test_flag(&flags,OPT_ACCOUNT))
|
||||
ast_cdr_setaccount(chan, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!feof(f) && !ast_strlen_zero(buf)) {
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
if (!ast_strlen_zero(buf) && !strcmp(passwd, buf))
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (!ast_strlen_zero(buf)) {
|
||||
if (ast_test_flag(&flags,OPT_MULTIPLE)) {
|
||||
if (md5secret && !strcmp(md5passwd, md5secret))
|
||||
break;
|
||||
} else {
|
||||
if (!strcmp(passwd, buf))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ast_strlen_zero(buf) && !strcmp(passwd, buf))
|
||||
break;
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
|
||||
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", password, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
/* Compare against a fixed password */
|
||||
if (!strcmp(passwd, arglist.password))
|
||||
if (!strcmp(passwd, password))
|
||||
break;
|
||||
}
|
||||
prompt="auth-incorrect";
|
||||
}
|
||||
if ((retries < 3) && !res) {
|
||||
if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
|
||||
if (strchr(opts, 'a'))
|
||||
ast_cdr_setaccount(chan, passwd);
|
||||
res = ast_streamfile(chan, "auth-thankyou", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
} else {
|
||||
if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0) {
|
||||
res = 0;
|
||||
} else {
|
||||
if (!ast_streamfile(chan, "vm-goodbye", chan->language))
|
||||
res = ast_waitstream(chan, "");
|
||||
res = -1;
|
||||
}
|
||||
if (!res)
|
||||
res = ast_streamfile(chan, "vm-goodbye", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
res = -1;
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, auth_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,78 +1,66 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Applictions connected with CDR engine
|
||||
*
|
||||
* Copyright (C) 2003, Digium
|
||||
*
|
||||
* Martin Pycko <martinp@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Applications connected with CDR engine
|
||||
*
|
||||
* Martin Pycko <martinp@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/pbx.h"
|
||||
|
||||
static char *nocdr_descrip =
|
||||
" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n"
|
||||
"current call.\n";
|
||||
static char *tdesc = "Make sure asterisk doesn't save CDR for a certain call";
|
||||
|
||||
static char *nocdr_descrip = "NoCDR(): makes sure there won't be any CDR written for a certain call";
|
||||
static char *nocdr_app = "NoCDR";
|
||||
static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call";
|
||||
static char *nocdr_synopsis = "Make sure asterisk doesn't save CDR for a certain call";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int nocdr_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (chan->cdr) {
|
||||
ast_set_flag(chan->cdr, AST_CDR_FLAG_POST_DISABLED);
|
||||
ast_cdr_free(chan->cdr);
|
||||
chan->cdr = NULL;
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(nocdr_app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(nocdr_app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(nocdr_app, nocdr_exec, nocdr_synopsis, nocdr_descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Tell Asterisk to not maintain a CDR for the current call");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,99 +1,69 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* James Golovich <james@gnuinter.net>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Check if Channel is Available
|
||||
*
|
||||
* \brief Check if Channel is Available
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
* \author James Golovich <james@gnuinter.net>
|
||||
|
||||
* \ingroup applications
|
||||
* Copyright (C) 2003, Digium
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* James Golovich <james@gnuinter.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Check if channel is available";
|
||||
|
||||
static char *app = "ChanIsAvail";
|
||||
|
||||
static char *synopsis = "Check channel availability";
|
||||
static char *synopsis = "Check if channel is available";
|
||||
|
||||
static char *descrip =
|
||||
" ChanIsAvail(Technology/resource[&Technology2/resource2...][|options]): \n"
|
||||
"This application will check to see if any of the specified channels are\n"
|
||||
"available. The following variables will be set by this application:\n"
|
||||
" ${AVAILCHAN} - the name of the available channel, if one exists\n"
|
||||
" ${AVAILORIGCHAN} - the canonical channel name that was used to create the channel\n"
|
||||
" ${AVAILSTATUS} - the status code for the available channel\n"
|
||||
" Options:\n"
|
||||
" s - Consider the channel unavailable if the channel is in use at all\n"
|
||||
" j - Support jumping to priority n+101 if no channel is available\n";
|
||||
" ChanIsAvail(Technology/resource[&Technology2/resource2...]): \n"
|
||||
"Checks is any of the requested channels are available. If none\n"
|
||||
"of the requested channels are available the new priority will be\n"
|
||||
"n+101 (unless such a priority does not exist or on error, in which\n"
|
||||
"case ChanIsAvail will return -1).\n"
|
||||
"If any of the requested channels are available, the next priority will be n+1,\n"
|
||||
"the channel variable ${AVAILCHAN} will be set to the name of the available channel\n"
|
||||
"and the ChanIsAvail app will return 0.\n"
|
||||
"${AVAILORIGCHAN} is the canonical channel name that was used to create the channel.\n"
|
||||
"${AVAILSTATUS} is the status code for the channel.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int chanavail_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=-1, inuse=-1, option_state=0, priority_jump=0;
|
||||
int status;
|
||||
struct ast_module_user *u;
|
||||
char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur;
|
||||
int res=-1;
|
||||
struct localuser *u;
|
||||
char info[512], tmp[512], *peers, *tech, *number, *rest, *cur;
|
||||
struct ast_channel *tempchan;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(reqchans);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
info = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, info);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 's'))
|
||||
option_state = 1;
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
peers = args.reqchans;
|
||||
strncpy(info, (char *)data, sizeof(info)-1);
|
||||
peers = info;
|
||||
if (peers) {
|
||||
cur = peers;
|
||||
do {
|
||||
@@ -107,67 +77,61 @@ static int chanavail_exec(struct ast_channel *chan, void *data)
|
||||
number = strchr(tech, '/');
|
||||
if (!number) {
|
||||
ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
*number = '\0';
|
||||
number++;
|
||||
|
||||
if (option_state) {
|
||||
/* If the pbx says in use then don't bother trying further.
|
||||
This is to permit testing if someone's on a call, even if the
|
||||
channel can permit more calls (ie callwaiting, sip calls, etc). */
|
||||
|
||||
snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
|
||||
status = inuse = ast_device_state(trychan);
|
||||
}
|
||||
if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
|
||||
if ((tempchan = ast_request(tech, chan->nativeformats, number))) {
|
||||
pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
|
||||
/* Store the originally used channel too */
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
|
||||
pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
|
||||
snprintf(tmp, sizeof(tmp), "%d", status);
|
||||
pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
|
||||
ast_hangup(tempchan);
|
||||
tempchan = NULL;
|
||||
res = 1;
|
||||
break;
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "%d", status);
|
||||
pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
|
||||
}
|
||||
cur = rest;
|
||||
} while (cur);
|
||||
}
|
||||
|
||||
if (res < 1) {
|
||||
pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
|
||||
pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
|
||||
if (priority_jump || ast_opt_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority+=100;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, chanavail_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Check channel availability");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,140 +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 (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");
|
||||
@@ -1,856 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
|
||||
* Copyright (C) 2005 - 2008, Digium, Inc.
|
||||
*
|
||||
* A license has been granted to Digium (via disclaimer) for the use of
|
||||
* this code.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief ChanSpy: Listen in on any channel.
|
||||
*
|
||||
* \author Anthony Minessale II <anthmct@yahoo.com>
|
||||
* \author Joshua Colp <jcolp@digium.com>
|
||||
* \author Russell Bryant <russell@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/features.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
|
||||
#define AST_NAME_STRLEN 256
|
||||
|
||||
static const char *tdesc = "Listen to a channel, and optionally whisper into it";
|
||||
static const char *app_chan = "ChanSpy";
|
||||
static const char *desc_chan =
|
||||
" ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
|
||||
"audio from an Asterisk channel. This includes the audio coming in and\n"
|
||||
"out of the channel being spied on. If the 'chanprefix' parameter is specified,\n"
|
||||
"only channels beginning with this string will be spied upon.\n"
|
||||
" While spying, the following actions may be performed:\n"
|
||||
" - Dialing # cycles the volume level.\n"
|
||||
" - Dialing * will stop spying and look for another channel to spy on.\n"
|
||||
" - Dialing a series of digits followed by # builds a channel name to append\n"
|
||||
" to 'chanprefix'. For example, executing ChanSpy(Agent) and then dialing\n"
|
||||
" the digits '1234#' while spying will begin spying on the channel\n"
|
||||
" 'Agent/1234'.\n"
|
||||
" Options:\n"
|
||||
" b - Only spy on channels involved in a bridged call.\n"
|
||||
" g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
|
||||
" contain 'grp' in an optional : delimited list.\n"
|
||||
" q - Don't play a beep when beginning to spy on a channel, or speak the\n"
|
||||
" selected channel name.\n"
|
||||
" r[(basename)] - Record the session to the monitor spool directory. An\n"
|
||||
" optional base for the filename may be specified. The\n"
|
||||
" default is 'chanspy'.\n"
|
||||
" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
|
||||
" negative value refers to a quieter setting.\n"
|
||||
" w - Enable 'whisper' mode, so the spying channel can talk to\n"
|
||||
" the spied-on channel.\n"
|
||||
" W - Enable 'private whisper' mode, so the spying channel can\n"
|
||||
" talk to the spied-on channel but cannot listen to that\n"
|
||||
" channel.\n"
|
||||
;
|
||||
|
||||
static const char *app_ext = "ExtenSpy";
|
||||
static const char *desc_ext =
|
||||
" ExtenSpy(exten[@context][|options]): This application is used to listen to the\n"
|
||||
"audio from an Asterisk channel. This includes the audio coming in and\n"
|
||||
"out of the channel being spied on. Only channels created by outgoing calls for the\n"
|
||||
"specified extension will be selected for spying. If the optional context is not\n"
|
||||
"supplied, the current channel's context will be used.\n"
|
||||
" While spying, the following actions may be performed:\n"
|
||||
" - Dialing # cycles the volume level.\n"
|
||||
" - Dialing * will stop spying and look for another channel to spy on.\n"
|
||||
" Options:\n"
|
||||
" b - Only spy on channels involved in a bridged call.\n"
|
||||
" g(grp) - Match only channels where their ${SPYGROUP} variable is set to\n"
|
||||
" contain 'grp' in an optional : delimited list.\n"
|
||||
" q - Don't play a beep when beginning to spy on a channel, or speak the\n"
|
||||
" selected channel name.\n"
|
||||
" r[(basename)] - Record the session to the monitor spool directory. An\n"
|
||||
" optional base for the filename may be specified. The\n"
|
||||
" default is 'chanspy'.\n"
|
||||
" v([value]) - Adjust the initial volume in the range from -4 to 4. A\n"
|
||||
" negative value refers to a quieter setting.\n"
|
||||
" w - Enable 'whisper' mode, so the spying channel can talk to\n"
|
||||
" the spied-on channel.\n"
|
||||
" W - Enable 'private whisper' mode, so the spying channel can\n"
|
||||
" talk to the spied-on channel but cannot listen to that\n"
|
||||
" channel.\n"
|
||||
;
|
||||
|
||||
enum {
|
||||
OPTION_QUIET = (1 << 0), /* Quiet, no announcement */
|
||||
OPTION_BRIDGED = (1 << 1), /* Only look at bridged calls */
|
||||
OPTION_VOLUME = (1 << 2), /* Specify initial volume */
|
||||
OPTION_GROUP = (1 << 3), /* Only look at channels in group */
|
||||
OPTION_RECORD = (1 << 4),
|
||||
OPTION_WHISPER = (1 << 5),
|
||||
OPTION_PRIVATE = (1 << 6), /* Private Whisper mode */
|
||||
} chanspy_opt_flags;
|
||||
|
||||
enum {
|
||||
OPT_ARG_VOLUME = 0,
|
||||
OPT_ARG_GROUP,
|
||||
OPT_ARG_RECORD,
|
||||
OPT_ARG_ARRAY_SIZE,
|
||||
} chanspy_opt_args;
|
||||
|
||||
AST_APP_OPTIONS(spy_opts, {
|
||||
AST_APP_OPTION('q', OPTION_QUIET),
|
||||
AST_APP_OPTION('b', OPTION_BRIDGED),
|
||||
AST_APP_OPTION('w', OPTION_WHISPER),
|
||||
AST_APP_OPTION('W', OPTION_PRIVATE),
|
||||
AST_APP_OPTION_ARG('v', OPTION_VOLUME, OPT_ARG_VOLUME),
|
||||
AST_APP_OPTION_ARG('g', OPTION_GROUP, OPT_ARG_GROUP),
|
||||
AST_APP_OPTION_ARG('r', OPTION_RECORD, OPT_ARG_RECORD),
|
||||
});
|
||||
|
||||
|
||||
struct chanspy_translation_helper {
|
||||
/* spy data */
|
||||
struct ast_audiohook spy_audiohook;
|
||||
struct ast_audiohook whisper_audiohook;
|
||||
int fd;
|
||||
int volfactor;
|
||||
};
|
||||
|
||||
static void *spy_alloc(struct ast_channel *chan, void *data)
|
||||
{
|
||||
/* just store the data pointer in the channel structure */
|
||||
return data;
|
||||
}
|
||||
|
||||
static void spy_release(struct ast_channel *chan, void *data)
|
||||
{
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct chanspy_translation_helper *csth = data;
|
||||
struct ast_frame *f;
|
||||
|
||||
ast_audiohook_lock(&csth->spy_audiohook);
|
||||
if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
ast_audiohook_unlock(&csth->spy_audiohook);
|
||||
return -1;
|
||||
}
|
||||
|
||||
f = ast_audiohook_read_frame(&csth->spy_audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR);
|
||||
|
||||
ast_audiohook_unlock(&csth->spy_audiohook);
|
||||
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
if (ast_write(chan, f)) {
|
||||
ast_frfree(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (csth->fd)
|
||||
write(csth->fd, f->data, f->datalen);
|
||||
|
||||
ast_frfree(f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_generator spygen = {
|
||||
.alloc = spy_alloc,
|
||||
.release = spy_release,
|
||||
.generate = spy_generate,
|
||||
};
|
||||
|
||||
static int start_spying(struct ast_channel *chan, const char *spychan_name, struct ast_audiohook *audiohook)
|
||||
{
|
||||
int res;
|
||||
struct ast_channel *peer;
|
||||
|
||||
ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan_name, chan->name);
|
||||
|
||||
res = ast_audiohook_attach(chan, audiohook);
|
||||
|
||||
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
|
||||
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct chanspy_ds {
|
||||
struct ast_channel *chan;
|
||||
ast_mutex_t lock;
|
||||
};
|
||||
|
||||
static int channel_spy(struct ast_channel *chan, struct chanspy_ds *spyee_chanspy_ds,
|
||||
int *volfactor, int fd, const struct ast_flags *flags)
|
||||
{
|
||||
struct chanspy_translation_helper csth;
|
||||
int running = 0, res, x = 0;
|
||||
char inp[24] = {0};
|
||||
char *name;
|
||||
struct ast_frame *f;
|
||||
struct ast_silence_generator *silgen = NULL;
|
||||
struct ast_channel *spyee = NULL;
|
||||
const char *spyer_name;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
spyer_name = ast_strdupa(chan->name);
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
ast_mutex_lock(&spyee_chanspy_ds->lock);
|
||||
if (spyee_chanspy_ds->chan) {
|
||||
spyee = spyee_chanspy_ds->chan;
|
||||
ast_channel_lock(spyee);
|
||||
}
|
||||
ast_mutex_unlock(&spyee_chanspy_ds->lock);
|
||||
|
||||
if (!spyee)
|
||||
return 0;
|
||||
|
||||
/* We now hold the channel lock on spyee */
|
||||
|
||||
if (ast_check_hangup(chan) || ast_check_hangup(spyee)) {
|
||||
ast_channel_unlock(spyee);
|
||||
return 0;
|
||||
}
|
||||
|
||||
name = ast_strdupa(spyee->name);
|
||||
if (option_verbose >= 2)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Spying on channel %s\n", name);
|
||||
|
||||
memset(&csth, 0, sizeof(csth));
|
||||
|
||||
ast_audiohook_init(&csth.spy_audiohook, AST_AUDIOHOOK_TYPE_SPY, "ChanSpy");
|
||||
|
||||
if (start_spying(spyee, spyer_name, &csth.spy_audiohook)) {
|
||||
ast_audiohook_destroy(&csth.spy_audiohook);
|
||||
ast_channel_unlock(spyee);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_WHISPER)) {
|
||||
ast_audiohook_init(&csth.whisper_audiohook, AST_AUDIOHOOK_TYPE_WHISPER, "ChanSpy");
|
||||
start_spying(spyee, spyer_name, &csth.whisper_audiohook);
|
||||
}
|
||||
|
||||
ast_channel_unlock(spyee);
|
||||
spyee = NULL;
|
||||
|
||||
csth.volfactor = *volfactor;
|
||||
|
||||
if (csth.volfactor) {
|
||||
csth.spy_audiohook.options.read_volume = csth.volfactor;
|
||||
csth.spy_audiohook.options.write_volume = csth.volfactor;
|
||||
}
|
||||
|
||||
csth.fd = fd;
|
||||
|
||||
if (ast_test_flag(flags, OPTION_PRIVATE))
|
||||
silgen = ast_channel_start_silence_generator(chan);
|
||||
else
|
||||
ast_activate_generator(chan, &spygen, &csth);
|
||||
|
||||
/* We can no longer rely on 'spyee' being an actual channel;
|
||||
it can be hung up and freed out from under us. However, the
|
||||
channel destructor will put NULL into our csth.spy.chan
|
||||
field when that happens, so that is our signal that the spyee
|
||||
channel has gone away.
|
||||
*/
|
||||
|
||||
/* Note: it is very important that the ast_waitfor() be the first
|
||||
condition in this expression, so that if we wait for some period
|
||||
of time before receiving a frame from our spying channel, we check
|
||||
for hangup on the spied-on channel _after_ knowing that a frame
|
||||
has arrived, since the spied-on channel could have gone away while
|
||||
we were waiting
|
||||
*/
|
||||
while ((res = ast_waitfor(chan, -1) > -1) && csth.spy_audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
if (!(f = ast_read(chan)) || ast_check_hangup(chan)) {
|
||||
running = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_WHISPER) && (f->frametype == AST_FRAME_VOICE)) {
|
||||
ast_audiohook_lock(&csth.whisper_audiohook);
|
||||
ast_audiohook_write_frame(&csth.whisper_audiohook, AST_AUDIOHOOK_DIRECTION_WRITE, f);
|
||||
ast_audiohook_unlock(&csth.whisper_audiohook);
|
||||
ast_frfree(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = (f->frametype == AST_FRAME_DTMF) ? f->subclass : 0;
|
||||
ast_frfree(f);
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
if (x == sizeof(inp))
|
||||
x = 0;
|
||||
|
||||
if (res < 0) {
|
||||
running = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (res == '*') {
|
||||
running = 0;
|
||||
break;
|
||||
} else if (res == '#') {
|
||||
if (!ast_strlen_zero(inp)) {
|
||||
running = atoi(inp);
|
||||
break;
|
||||
}
|
||||
|
||||
(*volfactor)++;
|
||||
if (*volfactor > 4)
|
||||
*volfactor = -4;
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Setting spy volume on %s to %d\n", chan->name, *volfactor);
|
||||
csth.volfactor = *volfactor;
|
||||
csth.spy_audiohook.options.read_volume = csth.volfactor;
|
||||
csth.spy_audiohook.options.write_volume = csth.volfactor;
|
||||
} else if (res >= '0' && res <= '9') {
|
||||
inp[x++] = res;
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_PRIVATE))
|
||||
ast_channel_stop_silence_generator(chan, silgen);
|
||||
else
|
||||
ast_deactivate_generator(chan);
|
||||
|
||||
if (ast_test_flag(flags, OPTION_WHISPER)) {
|
||||
ast_audiohook_lock(&csth.whisper_audiohook);
|
||||
ast_audiohook_detach(&csth.whisper_audiohook);
|
||||
ast_audiohook_unlock(&csth.whisper_audiohook);
|
||||
ast_audiohook_destroy(&csth.whisper_audiohook);
|
||||
}
|
||||
|
||||
ast_audiohook_lock(&csth.spy_audiohook);
|
||||
ast_audiohook_detach(&csth.spy_audiohook);
|
||||
ast_audiohook_unlock(&csth.spy_audiohook);
|
||||
ast_audiohook_destroy(&csth.spy_audiohook);
|
||||
|
||||
if (option_verbose >= 2)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \note This relies on the embedded lock to be recursive, as it may be called
|
||||
* due to a call to chanspy_ds_free with the lock held there.
|
||||
*/
|
||||
static void chanspy_ds_destroy(void *data)
|
||||
{
|
||||
struct chanspy_ds *chanspy_ds = data;
|
||||
|
||||
/* Setting chan to be NULL is an atomic operation, but we don't want this
|
||||
* value to change while this lock is held. The lock is held elsewhere
|
||||
* while it performs non-atomic operations with this channel pointer */
|
||||
|
||||
ast_mutex_lock(&chanspy_ds->lock);
|
||||
chanspy_ds->chan = NULL;
|
||||
ast_mutex_unlock(&chanspy_ds->lock);
|
||||
}
|
||||
|
||||
static void chanspy_ds_chan_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
|
||||
{
|
||||
struct chanspy_ds *chanspy_ds = data;
|
||||
|
||||
ast_mutex_lock(&chanspy_ds->lock);
|
||||
chanspy_ds->chan = new_chan;
|
||||
ast_mutex_unlock(&chanspy_ds->lock);
|
||||
}
|
||||
|
||||
static const struct ast_datastore_info chanspy_ds_info = {
|
||||
.type = "chanspy",
|
||||
.destroy = chanspy_ds_destroy,
|
||||
.chan_fixup = chanspy_ds_chan_fixup,
|
||||
};
|
||||
|
||||
static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
|
||||
{
|
||||
if (!chanspy_ds)
|
||||
return NULL;
|
||||
|
||||
ast_mutex_lock(&chanspy_ds->lock);
|
||||
if (chanspy_ds->chan) {
|
||||
struct ast_datastore *datastore;
|
||||
struct ast_channel *chan;
|
||||
|
||||
chan = chanspy_ds->chan;
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, NULL))) {
|
||||
ast_channel_datastore_remove(chan, datastore);
|
||||
/* chanspy_ds->chan is NULL after this call */
|
||||
chanspy_ds_destroy(datastore->data);
|
||||
datastore->data = NULL;
|
||||
ast_channel_datastore_free(datastore);
|
||||
}
|
||||
ast_channel_unlock(chan);
|
||||
}
|
||||
ast_mutex_unlock(&chanspy_ds->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! \note Returns the channel in the chanspy_ds locked as well as the chanspy_ds locked */
|
||||
static struct chanspy_ds *setup_chanspy_ds(struct ast_channel *chan, struct chanspy_ds *chanspy_ds)
|
||||
{
|
||||
struct ast_datastore *datastore = NULL;
|
||||
|
||||
ast_mutex_lock(&chanspy_ds->lock);
|
||||
|
||||
if (!(datastore = ast_channel_datastore_alloc(&chanspy_ds_info, NULL))) {
|
||||
ast_mutex_unlock(&chanspy_ds->lock);
|
||||
chanspy_ds = chanspy_ds_free(chanspy_ds);
|
||||
ast_channel_unlock(chan);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chanspy_ds->chan = chan;
|
||||
datastore->data = chanspy_ds;
|
||||
ast_channel_datastore_add(chan, datastore);
|
||||
|
||||
return chanspy_ds;
|
||||
}
|
||||
|
||||
static struct chanspy_ds *next_channel(struct ast_channel *chan,
|
||||
const struct ast_channel *last, const char *spec,
|
||||
const char *exten, const char *context, struct chanspy_ds *chanspy_ds)
|
||||
{
|
||||
struct ast_channel *this;
|
||||
|
||||
redo:
|
||||
if (spec)
|
||||
this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
|
||||
else if (exten)
|
||||
this = ast_walk_channel_by_exten_locked(last, exten, context);
|
||||
else
|
||||
this = ast_channel_walk_locked(last);
|
||||
|
||||
if (!this)
|
||||
return NULL;
|
||||
|
||||
if (!strncmp(this->name, "Zap/pseudo", 10)) {
|
||||
ast_channel_unlock(this);
|
||||
goto redo;
|
||||
} else if (this == chan) {
|
||||
last = this;
|
||||
ast_channel_unlock(this);
|
||||
goto redo;
|
||||
}
|
||||
|
||||
return setup_chanspy_ds(this, chanspy_ds);
|
||||
}
|
||||
|
||||
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
|
||||
int volfactor, const int fd, const char *mygroup, const char *spec,
|
||||
const char *exten, const char *context)
|
||||
{
|
||||
char nameprefix[AST_NAME_STRLEN];
|
||||
char peer_name[AST_NAME_STRLEN + 5];
|
||||
signed char zero_volume = 0;
|
||||
int waitms;
|
||||
int res;
|
||||
char *ptr;
|
||||
int num;
|
||||
int num_spyed_upon = 1;
|
||||
struct chanspy_ds chanspy_ds;
|
||||
|
||||
ast_mutex_init(&chanspy_ds.lock);
|
||||
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
ast_answer(chan);
|
||||
|
||||
ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
|
||||
|
||||
waitms = 100;
|
||||
|
||||
for (;;) {
|
||||
struct chanspy_ds *peer_chanspy_ds = NULL, *next_chanspy_ds = NULL;
|
||||
struct ast_channel *prev = NULL, *peer = NULL;
|
||||
|
||||
if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
|
||||
res = ast_streamfile(chan, "beep", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
else if (res < 0) {
|
||||
ast_clear_flag(chan, AST_FLAG_SPYING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res = ast_waitfordigit(chan, waitms);
|
||||
if (res < 0) {
|
||||
ast_clear_flag(chan, AST_FLAG_SPYING);
|
||||
break;
|
||||
}
|
||||
|
||||
/* reset for the next loop around, unless overridden later */
|
||||
waitms = 100;
|
||||
num_spyed_upon = 0;
|
||||
|
||||
for (peer_chanspy_ds = next_channel(chan, prev, spec, exten, context, &chanspy_ds);
|
||||
peer_chanspy_ds;
|
||||
chanspy_ds_free(peer_chanspy_ds), prev = peer,
|
||||
peer_chanspy_ds = next_chanspy_ds ? next_chanspy_ds :
|
||||
next_channel(chan, prev, spec, exten, context, &chanspy_ds), next_chanspy_ds = NULL) {
|
||||
const char *group;
|
||||
int igrp = !mygroup;
|
||||
char *groups[25];
|
||||
int num_groups = 0;
|
||||
char *dup_group;
|
||||
int x;
|
||||
char *s;
|
||||
|
||||
peer = peer_chanspy_ds->chan;
|
||||
|
||||
ast_mutex_unlock(&peer_chanspy_ds->lock);
|
||||
|
||||
if (peer == prev) {
|
||||
ast_channel_unlock(peer);
|
||||
chanspy_ds_free(peer_chanspy_ds);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ast_check_hangup(chan)) {
|
||||
ast_channel_unlock(peer);
|
||||
chanspy_ds_free(peer_chanspy_ds);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer)) {
|
||||
ast_channel_unlock(peer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING)) {
|
||||
ast_channel_unlock(peer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mygroup) {
|
||||
if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
|
||||
dup_group = ast_strdupa(group);
|
||||
num_groups = ast_app_separate_args(dup_group, ':', groups,
|
||||
sizeof(groups) / sizeof(groups[0]));
|
||||
}
|
||||
|
||||
for (x = 0; x < num_groups; x++) {
|
||||
if (!strcmp(mygroup, groups[x])) {
|
||||
igrp = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!igrp) {
|
||||
ast_channel_unlock(peer);
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(peer_name, "spy-");
|
||||
strncat(peer_name, peer->name, AST_NAME_STRLEN - 4 - 1);
|
||||
ptr = strchr(peer_name, '/');
|
||||
*ptr++ = '\0';
|
||||
|
||||
for (s = peer_name; s < ptr; s++)
|
||||
*s = tolower(*s);
|
||||
|
||||
/* We have to unlock the peer channel here to avoid a deadlock.
|
||||
* So, when we need to dereference it again, we have to lock the
|
||||
* datastore and get the pointer from there to see if the channel
|
||||
* is still valid. */
|
||||
ast_channel_unlock(peer);
|
||||
|
||||
if (!ast_test_flag(flags, OPTION_QUIET)) {
|
||||
if (ast_fileexists(peer_name, NULL, NULL) != -1) {
|
||||
res = ast_streamfile(chan, peer_name, chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
if (res) {
|
||||
chanspy_ds_free(peer_chanspy_ds);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
res = ast_say_character_str(chan, peer_name, "", chan->language);
|
||||
if ((num = atoi(ptr)))
|
||||
ast_say_digits(chan, atoi(ptr), "", chan->language);
|
||||
}
|
||||
|
||||
res = channel_spy(chan, peer_chanspy_ds, &volfactor, fd, flags);
|
||||
num_spyed_upon++;
|
||||
|
||||
if (res == -1) {
|
||||
chanspy_ds_free(peer_chanspy_ds);
|
||||
break;
|
||||
} else if (res > 1 && spec) {
|
||||
struct ast_channel *next;
|
||||
|
||||
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
|
||||
|
||||
if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
|
||||
peer_chanspy_ds = chanspy_ds_free(peer_chanspy_ds);
|
||||
next_chanspy_ds = setup_chanspy_ds(next, &chanspy_ds);
|
||||
} else {
|
||||
/* stay on this channel, if it is still valid */
|
||||
|
||||
ast_mutex_lock(&peer_chanspy_ds->lock);
|
||||
if (peer_chanspy_ds->chan) {
|
||||
ast_channel_lock(peer_chanspy_ds->chan);
|
||||
next_chanspy_ds = peer_chanspy_ds;
|
||||
peer_chanspy_ds = NULL;
|
||||
} else {
|
||||
/* the channel is gone */
|
||||
ast_mutex_unlock(&peer_chanspy_ds->lock);
|
||||
next_chanspy_ds = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
peer = NULL;
|
||||
}
|
||||
}
|
||||
if (res == -1 || ast_check_hangup(chan))
|
||||
break;
|
||||
}
|
||||
|
||||
ast_clear_flag(chan, AST_FLAG_SPYING);
|
||||
|
||||
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
|
||||
|
||||
ast_mutex_destroy(&chanspy_ds.lock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int chanspy_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char *options = NULL;
|
||||
char *spec = NULL;
|
||||
char *argv[2];
|
||||
char *mygroup = NULL;
|
||||
char *recbase = NULL;
|
||||
int fd = 0;
|
||||
struct ast_flags flags;
|
||||
int oldwf = 0;
|
||||
int argc = 0;
|
||||
int volfactor = 0;
|
||||
int res;
|
||||
|
||||
data = ast_strdupa(data);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
|
||||
spec = argv[0];
|
||||
if (argc > 1)
|
||||
options = argv[1];
|
||||
|
||||
if (ast_strlen_zero(spec) || !strcmp(spec, "all"))
|
||||
spec = NULL;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
char *opts[OPT_ARG_ARRAY_SIZE];
|
||||
|
||||
ast_app_parse_options(spy_opts, &flags, opts, options);
|
||||
if (ast_test_flag(&flags, OPTION_GROUP))
|
||||
mygroup = opts[OPT_ARG_GROUP];
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_RECORD) &&
|
||||
!(recbase = opts[OPT_ARG_RECORD]))
|
||||
recbase = "chanspy";
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
|
||||
int vol;
|
||||
|
||||
if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
|
||||
ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
|
||||
else
|
||||
volfactor = vol;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_PRIVATE))
|
||||
ast_set_flag(&flags, OPTION_WHISPER);
|
||||
} else
|
||||
ast_clear_flag(&flags, AST_FLAGS_ALL);
|
||||
|
||||
oldwf = chan->writeformat;
|
||||
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
|
||||
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (recbase) {
|
||||
char filename[PATH_MAX];
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
|
||||
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
|
||||
ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = common_exec(chan, &flags, volfactor, fd, mygroup, spec, NULL, NULL);
|
||||
|
||||
if (fd)
|
||||
close(fd);
|
||||
|
||||
if (oldwf && ast_set_write_format(chan, oldwf) < 0)
|
||||
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int extenspy_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char *options = NULL;
|
||||
char *exten = NULL;
|
||||
char *context = NULL;
|
||||
char *argv[2];
|
||||
char *mygroup = NULL;
|
||||
char *recbase = NULL;
|
||||
int fd = 0;
|
||||
struct ast_flags flags;
|
||||
int oldwf = 0;
|
||||
int argc = 0;
|
||||
int volfactor = 0;
|
||||
int res;
|
||||
|
||||
data = ast_strdupa(data);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if ((argc = ast_app_separate_args(data, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
|
||||
context = argv[0];
|
||||
if (!ast_strlen_zero(argv[0]))
|
||||
exten = strsep(&context, "@");
|
||||
if (ast_strlen_zero(context))
|
||||
context = ast_strdupa(chan->context);
|
||||
if (argc > 1)
|
||||
options = argv[1];
|
||||
}
|
||||
|
||||
if (options) {
|
||||
char *opts[OPT_ARG_ARRAY_SIZE];
|
||||
|
||||
ast_app_parse_options(spy_opts, &flags, opts, options);
|
||||
if (ast_test_flag(&flags, OPTION_GROUP))
|
||||
mygroup = opts[OPT_ARG_GROUP];
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_RECORD) &&
|
||||
!(recbase = opts[OPT_ARG_RECORD]))
|
||||
recbase = "chanspy";
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
|
||||
int vol;
|
||||
|
||||
if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &vol) != 1) || (vol > 4) || (vol < -4))
|
||||
ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
|
||||
else
|
||||
volfactor = vol;
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_PRIVATE))
|
||||
ast_set_flag(&flags, OPTION_WHISPER);
|
||||
} else
|
||||
ast_clear_flag(&flags, AST_FLAGS_ALL);
|
||||
|
||||
oldwf = chan->writeformat;
|
||||
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
|
||||
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (recbase) {
|
||||
char filename[PATH_MAX];
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
|
||||
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
|
||||
ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
|
||||
fd = 0;
|
||||
}
|
||||
}
|
||||
|
||||
res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
|
||||
|
||||
if (fd)
|
||||
close(fd);
|
||||
|
||||
if (oldwf && ast_set_write_format(chan, oldwf) < 0)
|
||||
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res |= ast_unregister_application(app_chan);
|
||||
res |= ast_unregister_application(app_ext);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
|
||||
res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");
|
||||
@@ -1,168 +1,138 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Trivial application to control playback a sound file
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to control playback of a sound file
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Control Playback Application";
|
||||
|
||||
static const char *app = "ControlPlayback";
|
||||
static char *app = "ControlPlayback";
|
||||
|
||||
static const char *synopsis = "Play a file with fast forward and rewind";
|
||||
static char *synopsis = "Play a file with fast forward and rewind";
|
||||
|
||||
static const char *descrip =
|
||||
" ControlPlayback(file[|skipms[|ff[|rew[|stop[|pause[|restart|options]]]]]]]):\n"
|
||||
"This application will play back the given filename. By default, the '*' key\n"
|
||||
"can be used to rewind, and the '#' key can be used to fast-forward.\n"
|
||||
"Parameters:\n"
|
||||
" skipms - This is number of milliseconds to skip when rewinding or\n"
|
||||
" fast-forwarding.\n"
|
||||
" ff - Fast-forward when this DTMF digit is received.\n"
|
||||
" rew - Rewind when this DTMF digit is received.\n"
|
||||
" stop - Stop playback when this DTMF digit is received.\n"
|
||||
" pause - Pause playback when this DTMF digit is received.\n"
|
||||
" restart - Restart playback when this DTMF digit is received.\n"
|
||||
"Options:\n"
|
||||
" j - Jump to priority n+101 if the requested file is not found.\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" CPLAYBACKSTATUS - This variable contains the status of the attempt as a text\n"
|
||||
" string, one of: SUCCESS | USERSTOPPED | ERROR\n";
|
||||
static char *descrip =
|
||||
"ControlPlayback(filename[|skipms[|ffchar[|rewchar[|stopchar[|pausechr]]]]]):\n"
|
||||
" Plays back a given filename (do not put extension). Options may also\n"
|
||||
" be included following a pipe symbol. You can use * and # to rewind and\n"
|
||||
" fast forward the playback specified. If 'stopchar' is added the file will\n"
|
||||
" terminate playback when 'stopchar' is pressed. Returns -1 if the channel\n"
|
||||
" was hung up, or if the file does not exist. Returns 0 otherwise.\n\n"
|
||||
" Example: exten => 1234,1,ControlPlayback(file|4000|*|#|1|0)\n\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int is_on_phonepad(char key)
|
||||
{
|
||||
return key == 35 || key == 42 || (key >= 48 && key <= 57);
|
||||
return (key == 35 || key == 42 || (key >= 48 && key <= 57)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int controlplayback_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0, priority_jump = 0;
|
||||
int res = 0;
|
||||
int skipms = 0;
|
||||
struct ast_module_user *u;
|
||||
char *tmp;
|
||||
int argc;
|
||||
char *argv[8];
|
||||
enum arg_ids {
|
||||
arg_file = 0,
|
||||
arg_skip = 1,
|
||||
arg_fwd = 2,
|
||||
arg_rev = 3,
|
||||
arg_stop = 4,
|
||||
arg_pause = 5,
|
||||
arg_restart = 6,
|
||||
options = 7,
|
||||
};
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
struct localuser *u;
|
||||
char tmp[256];
|
||||
char *skip = NULL, *fwd = NULL, *rev = NULL, *stop = NULL, *pause = NULL, *file = NULL;
|
||||
|
||||
if (!data || ast_strlen_zero((char *)data)) {
|
||||
ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
memset(argv, 0, sizeof(argv));
|
||||
strncpy(tmp, (char *)data, sizeof(tmp)-1);
|
||||
file = tmp;
|
||||
|
||||
argc = ast_app_separate_args(tmp, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
if (argc < 1) {
|
||||
ast_log(LOG_WARNING, "ControlPlayback requires an argument (filename)\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
if ((skip=strchr(tmp,'|'))) {
|
||||
*skip++ = '\0';
|
||||
fwd=strchr(skip,'|');
|
||||
if (fwd) {
|
||||
*fwd++ = '\0';
|
||||
rev = strchr(fwd,'|');
|
||||
if (rev) {
|
||||
*rev++ = '\0';
|
||||
stop = strchr(rev,'|');
|
||||
if (stop) {
|
||||
*stop++ = '\0';
|
||||
pause = strchr(stop,'|');
|
||||
if (pause) {
|
||||
*pause++ = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skipms = argv[arg_skip] ? atoi(argv[arg_skip]) : 3000;
|
||||
skipms = skip ? atoi(skip) : 3000;
|
||||
if (!skipms)
|
||||
skipms = 3000;
|
||||
|
||||
if (!argv[arg_fwd] || !is_on_phonepad(*argv[arg_fwd]))
|
||||
argv[arg_fwd] = "#";
|
||||
if (!argv[arg_rev] || !is_on_phonepad(*argv[arg_rev]))
|
||||
argv[arg_rev] = "*";
|
||||
if (argv[arg_stop] && !is_on_phonepad(*argv[arg_stop]))
|
||||
argv[arg_stop] = NULL;
|
||||
if (argv[arg_pause] && !is_on_phonepad(*argv[arg_pause]))
|
||||
argv[arg_pause] = NULL;
|
||||
if (argv[arg_restart] && !is_on_phonepad(*argv[arg_restart]))
|
||||
argv[arg_restart] = NULL;
|
||||
if (!fwd || !is_on_phonepad(*fwd))
|
||||
fwd = "#";
|
||||
if (!rev || !is_on_phonepad(*rev))
|
||||
rev = "*";
|
||||
if (stop && !is_on_phonepad(*stop))
|
||||
stop = NULL;
|
||||
if (pause && !is_on_phonepad(*pause))
|
||||
pause = NULL;
|
||||
|
||||
if (argv[options]) {
|
||||
if (strchr(argv[options], 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
res = ast_control_streamfile(chan, argv[arg_file], argv[arg_fwd], argv[arg_rev], argv[arg_stop], argv[arg_pause], argv[arg_restart], skipms);
|
||||
res = ast_control_streamfile(chan, file, fwd, rev, stop, pause, skipms);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
/* If we stopped on one of our stop keys, return 0 */
|
||||
if (res > 0 && argv[arg_stop] && strchr(argv[arg_stop], res)) {
|
||||
if(stop && strchr(stop, res))
|
||||
res = 0;
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
|
||||
} else {
|
||||
if (res < 0) {
|
||||
if (priority_jump || ast_opt_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
|
||||
ast_log(LOG_WARNING, "ControlPlayback tried to jump to priority n+101 as requested, but priority didn't exist\n");
|
||||
}
|
||||
}
|
||||
res = 0;
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
|
||||
} else
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
res = ast_unregister_application(app);
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, controlplayback_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
198
apps/app_cut.c
Normal file
198
apps/app_cut.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Cut application
|
||||
*
|
||||
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_cut__v003@the-tilghman.com>
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
static char *tdesc = "Cuts up variables";
|
||||
|
||||
static char *app_cut = "Cut";
|
||||
|
||||
static char *cut_synopsis = "Splits a variable's content using the specified delimiter";
|
||||
|
||||
static char *cut_descrip =
|
||||
"Usage: Cut(newvar=varname,delimiter,fieldspec)\n"
|
||||
" newvar - new variable created from result string\n"
|
||||
" varname - variable you want cut\n"
|
||||
" delimiter - defaults to '-'\n"
|
||||
" fieldspec - number of the field you want (1-based offset)\n"
|
||||
" may also be specified as a range (with -)\n"
|
||||
" or group of ranges and fields (with &)\n"
|
||||
" Returns 0 or -1 on hangup or error.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int cut_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s, *newvar=NULL, *varname=NULL, *delimiter=NULL, *field=NULL;
|
||||
int args_okay = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
newvar = strsep(&s, "=");
|
||||
if (newvar && (newvar[0] != '\0')) {
|
||||
varname = strsep(&s, "|");
|
||||
if (varname && (varname[0] != '\0')) {
|
||||
delimiter = strsep(&s, "|");
|
||||
if (delimiter) {
|
||||
field = strsep(&s, "|");
|
||||
if (field) {
|
||||
args_okay = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (args_okay) {
|
||||
char d, ds[2];
|
||||
char *tmp = alloca(strlen(varname) + 4);
|
||||
char varvalue[MAXRESULT], *tmp2=varvalue;
|
||||
char retstring[MAXRESULT];
|
||||
|
||||
memset(retstring, 0, MAXRESULT);
|
||||
|
||||
if (tmp) {
|
||||
snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
|
||||
memset(varvalue, 0, sizeof(varvalue));
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (delimiter[0])
|
||||
d = delimiter[0];
|
||||
else
|
||||
d = '-';
|
||||
|
||||
/* String form of the delimiter, for use with strsep(3) */
|
||||
snprintf(ds, sizeof(ds), "%c", d);
|
||||
|
||||
pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
|
||||
|
||||
if (tmp2) {
|
||||
int curfieldnum = 1;
|
||||
while ((tmp2 != NULL) && (field != NULL)) {
|
||||
char *nextgroup = strsep(&field, "&");
|
||||
int num1 = 0, num2 = MAXRESULT;
|
||||
char trashchar;
|
||||
|
||||
if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
|
||||
/* range with both start and end */
|
||||
} else if (sscanf(nextgroup, "-%d", &num2) == 1) {
|
||||
/* range with end */
|
||||
num1 = 0;
|
||||
} else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
|
||||
/* range with start */
|
||||
num2 = MAXRESULT;
|
||||
} else if (sscanf(nextgroup, "%d", &num1) == 1) {
|
||||
/* single number */
|
||||
num2 = num1;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Cut(): Illegal range '%s'\n", nextgroup);
|
||||
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get to start, if any */
|
||||
if (num1 > 0) {
|
||||
while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
|
||||
tmp2 = index(tmp2, d) + 1;
|
||||
curfieldnum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Most frequent problem is the expectation of reordering fields */
|
||||
if ((num1 > 0) && (curfieldnum > num1)) {
|
||||
ast_log(LOG_WARNING, "Cut(): we're already past the field you wanted?\n");
|
||||
}
|
||||
|
||||
/* Re-null tmp2 if we added 1 to NULL */
|
||||
if (tmp2 == (char *)NULL + 1)
|
||||
tmp2 = NULL;
|
||||
|
||||
/* Output fields until we either run out of fields or num2 is reached */
|
||||
while ((tmp2 != NULL) && (curfieldnum <= num2)) {
|
||||
char *tmp3 = strsep(&tmp2, ds);
|
||||
int curlen = strlen(retstring);
|
||||
|
||||
if (strlen(retstring)) {
|
||||
snprintf(retstring + curlen, MAXRESULT - curlen, "%c%s", d, tmp3);
|
||||
} else {
|
||||
snprintf(retstring, MAXRESULT, "%s", tmp3);
|
||||
}
|
||||
|
||||
curfieldnum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, newvar, retstring);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app_cut);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
81
apps/app_datetime.c
Normal file
81
apps/app_datetime.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Time of day - Report the time of day
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/say.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *tdesc = "Date and Time";
|
||||
|
||||
static char *app = "DateTime";
|
||||
|
||||
static char *synopsis = "Say the date and time";
|
||||
|
||||
static char *descrip =
|
||||
" DateTime(): Says the current date and time. Returns -1 on hangup or 0\n"
|
||||
"otherwise.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int datetime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
time_t t;
|
||||
struct localuser *u;
|
||||
LOCAL_USER_ADD(u);
|
||||
time(&t);
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
res = ast_answer(chan);
|
||||
if (!res)
|
||||
res = ast_say_datetime(chan, t, "", chan->language);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, datetime_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
270
apps/app_db.c
270
apps/app_db.c
@@ -1,88 +1,86 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Database access functions
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
* Copyright (C) 2003, Jefferson Noxon
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
* Jefferson Noxon <jeff@debian.org>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Database access functions
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
* \author Jefferson Noxon <jeff@debian.org>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/astdb.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Database access functions for Asterisk extension logic";
|
||||
|
||||
static char *g_descrip =
|
||||
" DBget(varname=family/key): Retrieves a value from the Asterisk\n"
|
||||
"database and stores it in the given variable. Always returns 0. If the\n"
|
||||
"requested key is not found, jumps to priority n+101 if available.\n";
|
||||
|
||||
static char *p_descrip =
|
||||
" DBput(family/key=value): Stores the given value in the Asterisk\n"
|
||||
"database. Always returns 0.\n";
|
||||
|
||||
/*! \todo XXX Remove this application after 1.4 is relased */
|
||||
static char *d_descrip =
|
||||
" DBdel(family/key): This application will delete a key from the Asterisk\n"
|
||||
"database.\n"
|
||||
" This application has been DEPRECATED in favor of the DB_DELETE function.\n";
|
||||
" DBdel(family/key): Deletes a key from the Asterisk database. Always\n"
|
||||
"returns 0.\n";
|
||||
|
||||
static char *dt_descrip =
|
||||
" DBdeltree(family[/keytree]): This application will delete a family or keytree\n"
|
||||
"from the Asterisk database\n";
|
||||
" DBdeltree(family[/keytree]): Deletes a family or keytree from the Asterisk\n"
|
||||
"database. Always returns 0.\n";
|
||||
|
||||
static char *g_app = "DBget";
|
||||
static char *p_app = "DBput";
|
||||
static char *d_app = "DBdel";
|
||||
static char *dt_app = "DBdeltree";
|
||||
|
||||
static char *g_synopsis = "Retrieve a value from the database";
|
||||
static char *p_synopsis = "Store a value in the database";
|
||||
static char *d_synopsis = "Delete a key from the database";
|
||||
static char *dt_synopsis = "Delete a family or keytree from the database";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static int deltree_exec(struct ast_channel *chan, void *data)
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int deltree_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int arglen;
|
||||
char *argv, *family, *keytree;
|
||||
struct ast_module_user *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
arglen = strlen (data);
|
||||
argv = alloca (arglen + 1);
|
||||
if (!argv) { /* Why would this fail? */
|
||||
ast_log (LOG_DEBUG, "Memory allocation failed\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy (argv, data, arglen + 1);
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
|
||||
if (strchr(argv, '/')) {
|
||||
family = strsep(&argv, "/");
|
||||
keytree = strsep(&argv, "\0");
|
||||
if (strchr (argv, '/')) {
|
||||
family = strsep (&argv, "/");
|
||||
keytree = strsep (&argv, "\0");
|
||||
if (!family || !keytree) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
ast_module_user_remove(u);
|
||||
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
return 0;
|
||||
}
|
||||
if (ast_strlen_zero(keytree))
|
||||
if (!strlen (keytree))
|
||||
keytree = 0;
|
||||
} else {
|
||||
family = argv;
|
||||
@@ -91,77 +89,167 @@ static int deltree_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
if (option_verbose > 2) {
|
||||
if (keytree)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: family=%s, keytree=%s\n", family, keytree);
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBdeltree: family=%s, keytree=%s\n", family, keytree);
|
||||
else
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: family=%s\n", family);
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBdeltree: family=%s\n", family);
|
||||
}
|
||||
|
||||
if (ast_db_deltree(family, keytree)) {
|
||||
if (ast_db_deltree (family, keytree)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBdeltree: Error deleting key from database.\n");
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBdeltree: Error deleting key from database.\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int del_exec(struct ast_channel *chan, void *data)
|
||||
static int del_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int arglen;
|
||||
char *argv, *family, *key;
|
||||
struct ast_module_user *u;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
deprecation_warning = 1;
|
||||
ast_log(LOG_WARNING, "The DBdel application has been deprecated in favor of the DB_DELETE dialplan function!\n");
|
||||
arglen = strlen (data);
|
||||
argv = alloca (arglen + 1);
|
||||
if (!argv) { /* Why would this fail? */
|
||||
ast_log (LOG_DEBUG, "Memory allocation failed\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy (argv, data, arglen + 1);
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
|
||||
if (strchr(argv, '/')) {
|
||||
family = strsep(&argv, "/");
|
||||
key = strsep(&argv, "\0");
|
||||
if (strchr (argv, '/')) {
|
||||
family = strsep (&argv, "/");
|
||||
key = strsep (&argv, "\0");
|
||||
if (!family || !key) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
ast_module_user_remove(u);
|
||||
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
return 0;
|
||||
}
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBdel: family=%s, key=%s\n", family, key);
|
||||
if (ast_db_del(family, key)) {
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBdel: family=%s, key=%s\n", family, key);
|
||||
if (ast_db_del (family, key)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBdel: Error deleting key from database.\n");
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBdel: Error deleting key from database.\n");
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
static int put_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int arglen;
|
||||
char *argv, *value, *family, *key;
|
||||
|
||||
arglen = strlen (data);
|
||||
argv = alloca (arglen + 1);
|
||||
if (!argv) { /* Why would this fail? */
|
||||
ast_log (LOG_DEBUG, "Memory allocation failed\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy (argv, data, arglen + 1);
|
||||
|
||||
if (strchr (argv, '/') && strchr (argv, '=')) {
|
||||
family = strsep (&argv, "/");
|
||||
key = strsep (&argv, "=");
|
||||
value = strsep (&argv, "\0");
|
||||
if (!value || !family || !key) {
|
||||
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
return 0;
|
||||
}
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBput: family=%s, key=%s, value=%s\n", family, key, value);
|
||||
if (ast_db_put (family, key, value)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBput: Error writing value to database.\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int arglen;
|
||||
char *argv, *varname, *family, *key;
|
||||
char dbresult[256];
|
||||
|
||||
arglen = strlen (data);
|
||||
argv = alloca (arglen + 1);
|
||||
if (!argv) { /* Why would this fail? */
|
||||
ast_log (LOG_DEBUG, "Memory allocation failed\n");
|
||||
return 0;
|
||||
}
|
||||
memcpy (argv, data, arglen + 1);
|
||||
|
||||
if (strchr (argv, '=') && strchr (argv, '/')) {
|
||||
varname = strsep (&argv, "=");
|
||||
family = strsep (&argv, "/");
|
||||
key = strsep (&argv, "\0");
|
||||
if (!varname || !family || !key) {
|
||||
ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
return 0;
|
||||
}
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBget: varname=%s, family=%s, key=%s\n", varname, family, key);
|
||||
if (!ast_db_get (family, key, dbresult, sizeof (dbresult) - 1)) {
|
||||
pbx_builtin_setvar_helper (chan, varname, dbresult);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBget: set variable %s to %s\n", varname, dbresult);
|
||||
} else {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "DBget: Value not found in database.\n");
|
||||
/* Send the call to n+101 priority, where n is the current priority */
|
||||
if (ast_exists_extension (chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority += 100;
|
||||
}
|
||||
|
||||
} else {
|
||||
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module (void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = ast_unregister_application(dt_app);
|
||||
retval |= ast_unregister_application(d_app);
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
retval = ast_unregister_application (dt_app);
|
||||
retval |= ast_unregister_application (d_app);
|
||||
retval |= ast_unregister_application (p_app);
|
||||
retval |= ast_unregister_application (g_app);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module (void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = ast_register_application(d_app, del_exec, d_synopsis, d_descrip);
|
||||
retval |= ast_register_application(dt_app, deltree_exec, dt_synopsis, dt_descrip);
|
||||
|
||||
retval = ast_register_application (g_app, get_exec, g_synopsis, g_descrip);
|
||||
if (!retval)
|
||||
retval = ast_register_application (p_app, put_exec, p_synopsis, p_descrip);
|
||||
if (!retval)
|
||||
retval = ast_register_application (d_app, del_exec, d_synopsis, d_descrip);
|
||||
if (!retval)
|
||||
retval = ast_register_application (dt_app, deltree_exec, dt_synopsis, dt_descrip);
|
||||
return retval;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database Access Functions");
|
||||
char *description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
2362
apps/app_dial.c
2362
apps/app_dial.c
File diff suppressed because it is too large
Load Diff
@@ -1,349 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Anthony Minessale II
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* Donated by Sangoma Technologies <http://www.samgoma.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Virtual Dictation Machine Application For Asterisk
|
||||
*
|
||||
* \author Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *app = "Dictate";
|
||||
static char *synopsis = "Virtual Dictation Machine";
|
||||
static char *desc = " Dictate([<base_dir>[|<filename>]])\n"
|
||||
"Start dictation machine using optional base dir for files.\n";
|
||||
|
||||
|
||||
typedef enum {
|
||||
DFLAG_RECORD = (1 << 0),
|
||||
DFLAG_PLAY = (1 << 1),
|
||||
DFLAG_TRUNC = (1 << 2),
|
||||
DFLAG_PAUSE = (1 << 3),
|
||||
} dflags;
|
||||
|
||||
typedef enum {
|
||||
DMODE_INIT,
|
||||
DMODE_RECORD,
|
||||
DMODE_PLAY
|
||||
} dmodes;
|
||||
|
||||
#define ast_toggle_flag(it,flag) if(ast_test_flag(it, flag)) ast_clear_flag(it, flag); else ast_set_flag(it, flag)
|
||||
|
||||
static int play_and_wait(struct ast_channel *chan, char *file, char *digits)
|
||||
{
|
||||
int res = -1;
|
||||
if (!ast_streamfile(chan, file, chan->language)) {
|
||||
res = ast_waitstream(chan, digits);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int dictate_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *path = NULL, filein[256], *filename = "";
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(base);
|
||||
AST_APP_ARG(filename);
|
||||
);
|
||||
char dftbase[256];
|
||||
char *base;
|
||||
struct ast_flags flags = {0};
|
||||
struct ast_filestream *fs;
|
||||
struct ast_frame *f = NULL;
|
||||
struct ast_module_user *u;
|
||||
int ffactor = 320 * 80,
|
||||
res = 0,
|
||||
done = 0,
|
||||
oldr = 0,
|
||||
lastop = 0,
|
||||
samples = 0,
|
||||
speed = 1,
|
||||
digit = 0,
|
||||
len = 0,
|
||||
maxlen = 0,
|
||||
mode = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR);
|
||||
if (!ast_strlen_zero(data)) {
|
||||
parse = ast_strdupa(data);
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
} else
|
||||
args.argc = 0;
|
||||
|
||||
if (args.argc && !ast_strlen_zero(args.base)) {
|
||||
base = args.base;
|
||||
} else {
|
||||
base = dftbase;
|
||||
}
|
||||
if (args.argc > 1 && args.filename) {
|
||||
filename = args.filename;
|
||||
}
|
||||
oldr = chan->readformat;
|
||||
if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)) < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set to linear mode.\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_answer(chan);
|
||||
ast_safe_sleep(chan, 200);
|
||||
for (res = 0; !res;) {
|
||||
if (ast_strlen_zero(filename)) {
|
||||
if (ast_app_getdata(chan, "dictate/enter_filename", filein, sizeof(filein), 0) ||
|
||||
ast_strlen_zero(filein)) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ast_copy_string(filein, filename, sizeof(filein));
|
||||
filename = "";
|
||||
}
|
||||
mkdir(base, 0755);
|
||||
len = strlen(base) + strlen(filein) + 2;
|
||||
if (!path || len > maxlen) {
|
||||
path = alloca(len);
|
||||
memset(path, 0, len);
|
||||
maxlen = len;
|
||||
} else {
|
||||
memset(path, 0, maxlen);
|
||||
}
|
||||
|
||||
snprintf(path, len, "%s/%s", base, filein);
|
||||
fs = ast_writefile(path, "raw", NULL, O_CREAT|O_APPEND, 0, 0700);
|
||||
mode = DMODE_PLAY;
|
||||
memset(&flags, 0, sizeof(flags));
|
||||
ast_set_flag(&flags, DFLAG_PAUSE);
|
||||
digit = play_and_wait(chan, "dictate/forhelp", AST_DIGIT_ANY);
|
||||
done = 0;
|
||||
speed = 1;
|
||||
res = 0;
|
||||
lastop = 0;
|
||||
samples = 0;
|
||||
while (!done && ((res = ast_waitfor(chan, -1)) > -1) && fs && (f = ast_read(chan))) {
|
||||
if (digit) {
|
||||
struct ast_frame fr = {AST_FRAME_DTMF, digit};
|
||||
ast_queue_frame(chan, &fr);
|
||||
digit = 0;
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_DTMF)) {
|
||||
int got = 1;
|
||||
switch(mode) {
|
||||
case DMODE_PLAY:
|
||||
switch(f->subclass) {
|
||||
case '1':
|
||||
ast_set_flag(&flags, DFLAG_PAUSE);
|
||||
mode = DMODE_RECORD;
|
||||
break;
|
||||
case '2':
|
||||
speed++;
|
||||
if (speed > 4) {
|
||||
speed = 1;
|
||||
}
|
||||
res = ast_say_number(chan, speed, AST_DIGIT_ANY, chan->language, (char *) NULL);
|
||||
break;
|
||||
case '7':
|
||||
samples -= ffactor;
|
||||
if(samples < 0) {
|
||||
samples = 0;
|
||||
}
|
||||
ast_seekstream(fs, samples, SEEK_SET);
|
||||
break;
|
||||
case '8':
|
||||
samples += ffactor;
|
||||
ast_seekstream(fs, samples, SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
got = 0;
|
||||
}
|
||||
break;
|
||||
case DMODE_RECORD:
|
||||
switch(f->subclass) {
|
||||
case '1':
|
||||
ast_set_flag(&flags, DFLAG_PAUSE);
|
||||
mode = DMODE_PLAY;
|
||||
break;
|
||||
case '8':
|
||||
ast_toggle_flag(&flags, DFLAG_TRUNC);
|
||||
lastop = 0;
|
||||
break;
|
||||
default:
|
||||
got = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
got = 0;
|
||||
}
|
||||
if (!got) {
|
||||
switch(f->subclass) {
|
||||
case '#':
|
||||
done = 1;
|
||||
continue;
|
||||
break;
|
||||
case '*':
|
||||
ast_toggle_flag(&flags, DFLAG_PAUSE);
|
||||
if (ast_test_flag(&flags, DFLAG_PAUSE)) {
|
||||
digit = play_and_wait(chan, "dictate/pause", AST_DIGIT_ANY);
|
||||
} else {
|
||||
digit = play_and_wait(chan, mode == DMODE_PLAY ? "dictate/playback" : "dictate/record", AST_DIGIT_ANY);
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
ast_set_flag(&flags, DFLAG_PAUSE);
|
||||
digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
|
||||
switch(mode) {
|
||||
case DMODE_PLAY:
|
||||
digit = play_and_wait(chan, "dictate/play_help", AST_DIGIT_ANY);
|
||||
break;
|
||||
case DMODE_RECORD:
|
||||
digit = play_and_wait(chan, "dictate/record_help", AST_DIGIT_ANY);
|
||||
break;
|
||||
}
|
||||
if (digit == 0) {
|
||||
digit = play_and_wait(chan, "dictate/both_help", AST_DIGIT_ANY);
|
||||
} else if (digit < 0) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (f->frametype == AST_FRAME_VOICE) {
|
||||
switch(mode) {
|
||||
struct ast_frame *fr;
|
||||
int x;
|
||||
case DMODE_PLAY:
|
||||
if (lastop != DMODE_PLAY) {
|
||||
if (ast_test_flag(&flags, DFLAG_PAUSE)) {
|
||||
digit = play_and_wait(chan, "dictate/playback_mode", AST_DIGIT_ANY);
|
||||
if (digit == 0) {
|
||||
digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
|
||||
} else if (digit < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastop != DFLAG_PLAY) {
|
||||
lastop = DFLAG_PLAY;
|
||||
ast_closestream(fs);
|
||||
if (!(fs = ast_openstream(chan, path, chan->language)))
|
||||
break;
|
||||
ast_seekstream(fs, samples, SEEK_SET);
|
||||
chan->stream = NULL;
|
||||
}
|
||||
lastop = DMODE_PLAY;
|
||||
}
|
||||
|
||||
if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
|
||||
for (x = 0; x < speed; x++) {
|
||||
if ((fr = ast_readframe(fs))) {
|
||||
ast_write(chan, fr);
|
||||
samples += fr->samples;
|
||||
ast_frfree(fr);
|
||||
fr = NULL;
|
||||
} else {
|
||||
samples = 0;
|
||||
ast_seekstream(fs, 0, SEEK_SET);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DMODE_RECORD:
|
||||
if (lastop != DMODE_RECORD) {
|
||||
int oflags = O_CREAT | O_WRONLY;
|
||||
if (ast_test_flag(&flags, DFLAG_PAUSE)) {
|
||||
digit = play_and_wait(chan, "dictate/record_mode", AST_DIGIT_ANY);
|
||||
if (digit == 0) {
|
||||
digit = play_and_wait(chan, "dictate/paused", AST_DIGIT_ANY);
|
||||
} else if (digit < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastop = DMODE_RECORD;
|
||||
ast_closestream(fs);
|
||||
if ( ast_test_flag(&flags, DFLAG_TRUNC)) {
|
||||
oflags |= O_TRUNC;
|
||||
digit = play_and_wait(chan, "dictate/truncating_audio", AST_DIGIT_ANY);
|
||||
} else {
|
||||
oflags |= O_APPEND;
|
||||
}
|
||||
fs = ast_writefile(path, "raw", NULL, oflags, 0, 0700);
|
||||
if (ast_test_flag(&flags, DFLAG_TRUNC)) {
|
||||
ast_seekstream(fs, 0, SEEK_SET);
|
||||
ast_clear_flag(&flags, DFLAG_TRUNC);
|
||||
} else {
|
||||
ast_seekstream(fs, 0, SEEK_END);
|
||||
}
|
||||
}
|
||||
if (!ast_test_flag(&flags, DFLAG_PAUSE)) {
|
||||
res = ast_writestream(fs, f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ast_frfree(f);
|
||||
}
|
||||
}
|
||||
if (oldr) {
|
||||
ast_set_read_format(chan, oldr);
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
res = ast_unregister_application(app);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, dictate_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Virtual Dictation Machine");
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Joshua Colp
|
||||
*
|
||||
* Joshua Colp <jcolp@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Directed Call Pickup Support
|
||||
*
|
||||
* \author Joshua Colp <jcolp@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define PICKUPMARK "PICKUPMARK"
|
||||
|
||||
static const char *app = "Pickup";
|
||||
static const char *synopsis = "Directed Call Pickup";
|
||||
static const char *descrip =
|
||||
" Pickup(extension[@context][&extension2@context...]): This application can pickup any ringing channel\n"
|
||||
"that is calling the specified extension. If no context is specified, the current\n"
|
||||
"context will be used. If you use the special string \"PICKUPMARK\" for the context parameter, for example\n"
|
||||
"10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n"
|
||||
"as \"extension\".";
|
||||
|
||||
/* Perform actual pickup between two channels */
|
||||
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
|
||||
|
||||
if ((res = ast_answer(chan))) {
|
||||
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
|
||||
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((res = ast_channel_masquerade(target, chan))) {
|
||||
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Helper function that determines whether a channel is capable of being picked up */
|
||||
static int can_pickup(struct ast_channel *chan)
|
||||
{
|
||||
if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING))
|
||||
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;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Pickup requires an argument (extension)!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* Parse extension (and context if there) */
|
||||
while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
|
||||
if ((context = strchr(exten, '@')))
|
||||
*context++ = '\0';
|
||||
if (context && !strcasecmp(context, PICKUPMARK)) {
|
||||
if (!pickup_by_mark(chan, exten))
|
||||
break;
|
||||
} else {
|
||||
if (!pickup_by_exten(chan, exten, context ? context : chan->context))
|
||||
break;
|
||||
}
|
||||
ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, pickup_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");
|
||||
@@ -1,213 +1,64 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Provide a directory of extensions
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Provide a directory of extensions
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/say.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "../asterisk.h"
|
||||
#include "../astconf.h"
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
#ifdef ODBC_STORAGE
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include "asterisk/res_odbc.h"
|
||||
|
||||
static char odbc_database[80] = "asterisk";
|
||||
static char odbc_table[80] = "voicemessages";
|
||||
static char vmfmts[80] = "wav";
|
||||
#endif
|
||||
|
||||
static char *tdesc = "Extension Directory";
|
||||
static char *app = "Directory";
|
||||
|
||||
static char *synopsis = "Provide directory of voicemail extensions";
|
||||
static char *descrip =
|
||||
" Directory(vm-context[|dial-context[|options]]): This application will present\n"
|
||||
"the calling channel with a directory of extensions from which they can search\n"
|
||||
"by name. The list of names and corresponding extensions is retrieved from the\n"
|
||||
"voicemail configuration file, voicemail.conf.\n"
|
||||
" This application will immediately exit if one of the following DTMF digits are\n"
|
||||
"received and the extension to jump to exists:\n"
|
||||
" 0 - Jump to the 'o' extension, if it exists.\n"
|
||||
" * - Jump to the 'a' extension, if it exists.\n\n"
|
||||
" Parameters:\n"
|
||||
" vm-context - This is the context within voicemail.conf to use for the\n"
|
||||
" Directory.\n"
|
||||
" dial-context - This is the dialplan context to use when looking for an\n"
|
||||
" extension that the user has selected, or when jumping to the\n"
|
||||
" 'o' or 'a' extension.\n\n"
|
||||
" Options:\n"
|
||||
" e - In addition to the name, also read the extension number to the\n"
|
||||
" caller before presenting dialing options.\n"
|
||||
" f - Allow the caller to enter the first name of a user in the directory\n"
|
||||
" instead of using the last name.\n";
|
||||
" Directory(vm-context[|dial-context[|options]]): Presents the user with a directory\n"
|
||||
"of extensions from which they may select by name. The list of names \n"
|
||||
"and extensions is discovered from voicemail.conf. The vm-context argument\n"
|
||||
"is required, and specifies the context of voicemail.conf to use. The\n"
|
||||
"dial-context is the context to use for dialing the users, and defaults to\n"
|
||||
"the vm-context if unspecified. The 'f' option causes the directory to match\n"
|
||||
"based on the first name in voicemail.conf instead of the last name.\n"
|
||||
"Returns 0 unless the user hangs up. It also sets up the channel on exit\n"
|
||||
"to enter the extension the user selected.\n";
|
||||
|
||||
/* For simplicity, I'm keeping the format compatible with the voicemail config,
|
||||
but i'm open to suggestions for isolating it */
|
||||
|
||||
#define VOICEMAIL_CONFIG "voicemail.conf"
|
||||
#define DIRECTORY_CONFIG "voicemail.conf"
|
||||
|
||||
/* How many digits to read in */
|
||||
#define NUMDIGITS 3
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
#ifdef ODBC_STORAGE
|
||||
struct generic_prepare_struct {
|
||||
const char *sql;
|
||||
const char *param;
|
||||
};
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
|
||||
{
|
||||
struct generic_prepare_struct *gps = data;
|
||||
SQLHSTMT stmt;
|
||||
int res;
|
||||
|
||||
res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
|
||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = SQLPrepare(stmt, (unsigned char *)gps->sql, SQL_NTS);
|
||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", (char *)gps->sql);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(gps->param))
|
||||
SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->param), 0, (void *)gps->param, 0, NULL);
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
static void retrieve_file(char *dir)
|
||||
{
|
||||
int x = 0;
|
||||
int res;
|
||||
int fd=-1;
|
||||
size_t fdlen = 0;
|
||||
void *fdm = MAP_FAILED;
|
||||
SQLHSTMT stmt;
|
||||
char sql[256];
|
||||
char fmt[80]="", empty[10] = "";
|
||||
char *c;
|
||||
SQLLEN colsize;
|
||||
char full_fn[256];
|
||||
struct odbc_obj *obj;
|
||||
struct generic_prepare_struct gps = { .sql = sql, .param = dir };
|
||||
|
||||
obj = ast_odbc_request_obj(odbc_database, 1);
|
||||
if (obj) {
|
||||
do {
|
||||
ast_copy_string(fmt, vmfmts, sizeof(fmt));
|
||||
c = strchr(fmt, '|');
|
||||
if (c)
|
||||
*c = '\0';
|
||||
if (!strcasecmp(fmt, "wav49"))
|
||||
strcpy(fmt, "WAV");
|
||||
snprintf(full_fn, sizeof(full_fn), "%s.%s", dir, fmt);
|
||||
snprintf(sql, sizeof(sql), "SELECT recording FROM %s WHERE dir=? AND msgnum=-1", odbc_table);
|
||||
stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, &gps);
|
||||
|
||||
if (!stmt) {
|
||||
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
|
||||
break;
|
||||
}
|
||||
res = SQLFetch(stmt);
|
||||
if (res == SQL_NO_DATA) {
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
break;
|
||||
} else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
break;
|
||||
}
|
||||
fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, 0770);
|
||||
if (fd < 0) {
|
||||
ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
break;
|
||||
}
|
||||
|
||||
res = SQLGetData(stmt, 1, SQL_BINARY, empty, 0, &colsize);
|
||||
fdlen = colsize;
|
||||
if (fd > -1) {
|
||||
char tmp[1]="";
|
||||
lseek(fd, fdlen - 1, SEEK_SET);
|
||||
if (write(fd, tmp, 1) != 1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
break;
|
||||
}
|
||||
if (fd > -1)
|
||||
fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
}
|
||||
if (fdm != MAP_FAILED) {
|
||||
memset(fdm, 0, fdlen);
|
||||
res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, fdlen, &colsize);
|
||||
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
|
||||
ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
} while (0);
|
||||
ast_odbc_release_obj(obj);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
|
||||
if (fdm != MAP_FAILED)
|
||||
munmap(fdm, fdlen);
|
||||
if (fd > -1)
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *convert(const char *lastname)
|
||||
static char *convert(char *lastname)
|
||||
{
|
||||
char *tmp;
|
||||
int lcount = 0;
|
||||
tmp = ast_malloc(NUMDIGITS + 1);
|
||||
tmp = malloc(NUMDIGITS + 1);
|
||||
if (tmp) {
|
||||
while((*lastname > 32) && lcount < NUMDIGITS) {
|
||||
switch(toupper(*lastname)) {
|
||||
@@ -277,182 +128,105 @@ static char *convert(const char *lastname)
|
||||
* '1' for selected entry from directory
|
||||
* '*' for skipped entry from directory
|
||||
*/
|
||||
static int play_mailbox_owner(struct ast_channel *chan, char *context,
|
||||
char *dialcontext, char *ext, char *name, int readext,
|
||||
int fromappvm)
|
||||
{
|
||||
static int play_mailbox_owner(struct ast_channel *chan, char *context, char *dialcontext, char *ext, char *name) {
|
||||
int res = 0;
|
||||
int loop;
|
||||
int loop = 3;
|
||||
char fn[256];
|
||||
char fn2[256];
|
||||
|
||||
/* Check for the VoiceMail2 greeting first */
|
||||
snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet",
|
||||
ast_config_AST_SPOOL_DIR, context, ext);
|
||||
#ifdef ODBC_STORAGE
|
||||
retrieve_file(fn);
|
||||
#endif
|
||||
(char *)ast_config_AST_SPOOL_DIR, context, ext);
|
||||
|
||||
if (ast_fileexists(fn, NULL, chan->language) <= 0) {
|
||||
/* no file, check for an old-style Voicemail greeting */
|
||||
snprintf(fn, sizeof(fn), "%s/vm/%s/greet",
|
||||
ast_config_AST_SPOOL_DIR, ext);
|
||||
}
|
||||
#ifdef ODBC_STORAGE
|
||||
retrieve_file(fn);
|
||||
#endif
|
||||
/* Otherwise, check for an old-style Voicemail greeting */
|
||||
snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet",
|
||||
(char *)ast_config_AST_SPOOL_DIR, ext);
|
||||
|
||||
if (ast_fileexists(fn, NULL, chan->language) > 0) {
|
||||
res = ast_stream_and_wait(chan, fn, chan->language, AST_DIGIT_ANY);
|
||||
res = ast_streamfile(chan, fn, chan->language);
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
/* If Option 'e' was specified, also read the extension number with the name */
|
||||
if (readext) {
|
||||
ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY);
|
||||
res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
|
||||
} else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
|
||||
res = ast_streamfile(chan, fn2, chan->language);
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
} else {
|
||||
res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, chan->language);
|
||||
if (!ast_strlen_zero(name) && readext) {
|
||||
ast_stream_and_wait(chan, "vm-extension", chan->language, AST_DIGIT_ANY);
|
||||
res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, chan->language);
|
||||
}
|
||||
res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext,
|
||||
AST_DIGIT_ANY, chan->language);
|
||||
}
|
||||
#ifdef ODBC_STORAGE
|
||||
ast_filedelete(fn, NULL);
|
||||
#endif
|
||||
|
||||
for (loop = 3 ; loop > 0; loop--) {
|
||||
if (!res)
|
||||
res = ast_stream_and_wait(chan, "dir-instr", chan->language, AST_DIGIT_ANY);
|
||||
if (!res)
|
||||
while (loop) {
|
||||
if (!res) {
|
||||
res = ast_streamfile(chan, "dir-instr", chan->language);
|
||||
}
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
}
|
||||
if (!res) {
|
||||
res = ast_waitfordigit(chan, 3000);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
|
||||
if (res < 0) /* User hungup, so jump out now */
|
||||
break;
|
||||
if (res == '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_exists_extension(chan,dialcontext,ext,1,chan->callerid)) {
|
||||
strncpy(chan->exten, ext, sizeof(chan->exten)-1);
|
||||
chan->priority = 0;
|
||||
strncpy(chan->context, dialcontext, sizeof(chan->context)-1);
|
||||
} else {
|
||||
ast_log(LOG_WARNING,
|
||||
"Can't find extension '%s' in context '%s'. "
|
||||
"Did you pass the wrong context to Directory?\n",
|
||||
ext, dialcontext);
|
||||
res = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
/* Skip to next match in list */
|
||||
loop = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Not '1', or '*', so decrement number of tries */
|
||||
res = 0;
|
||||
loop--;
|
||||
break;
|
||||
} /* end switch */
|
||||
} /* end if */
|
||||
else {
|
||||
/* User hungup, so jump out now */
|
||||
loop = 0;
|
||||
}
|
||||
if (res == '*') /* Skip to next match in list */
|
||||
break;
|
||||
|
||||
/* Not '1', or '*', so decrement number of tries */
|
||||
res = 0;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
static struct ast_config *realtime_directory(char *context)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
struct ast_config *rtdata;
|
||||
struct ast_category *cat;
|
||||
struct ast_variable *var;
|
||||
char *mailbox;
|
||||
const char *fullname;
|
||||
const char *hidefromdir;
|
||||
char tmp[100];
|
||||
|
||||
/* Load flat file config. */
|
||||
cfg = ast_config_load(VOICEMAIL_CONFIG);
|
||||
|
||||
if (!cfg) {
|
||||
/* Loading config failed. */
|
||||
ast_log(LOG_WARNING, "Loading config failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get realtime entries, categorized by their mailbox number
|
||||
and present in the requested context */
|
||||
rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL);
|
||||
|
||||
/* if there are no results, just return the entries from the config file */
|
||||
if (!rtdata)
|
||||
return cfg;
|
||||
|
||||
/* Does the context exist within the config file? If not, make one */
|
||||
cat = ast_category_get(cfg, context);
|
||||
if (!cat) {
|
||||
cat = ast_category_new(context);
|
||||
if (!cat) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
ast_config_destroy(cfg);
|
||||
return NULL;
|
||||
}
|
||||
ast_category_append(cfg, cat);
|
||||
}
|
||||
|
||||
mailbox = NULL;
|
||||
while ( (mailbox = ast_category_browse(rtdata, mailbox)) ) {
|
||||
fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
|
||||
hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
|
||||
snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
|
||||
fullname ? fullname : "",
|
||||
hidefromdir ? hidefromdir : "no");
|
||||
var = ast_variable_new(mailbox, tmp);
|
||||
if (var)
|
||||
ast_variable_append(cat, var);
|
||||
else
|
||||
ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
|
||||
}
|
||||
ast_config_destroy(rtdata);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct ast_config *ucfg, char *context, char *dialcontext, char digit, int last, int readext, int fromappvm)
|
||||
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *context, char *dialcontext, char digit, int last)
|
||||
{
|
||||
/* Read in the first three digits.. "digit" is the first digit, already read */
|
||||
char ext[NUMDIGITS + 1], *cat;
|
||||
char ext[NUMDIGITS + 1];
|
||||
char name[80] = "";
|
||||
struct ast_variable *v;
|
||||
int res;
|
||||
int found=0;
|
||||
int lastuserchoice = 0;
|
||||
char *start, *conv, *stringp = NULL;
|
||||
const char *pos;
|
||||
int breakout = 0;
|
||||
char *start, *pos, *conv,*stringp=NULL;
|
||||
|
||||
if (ast_strlen_zero(context)) {
|
||||
if (!context || ast_strlen_zero(context)) {
|
||||
ast_log(LOG_WARNING,
|
||||
"Directory must be called with an argument "
|
||||
"(context in which to interpret extensions)\n");
|
||||
return -1;
|
||||
}
|
||||
if (digit == '0') {
|
||||
if (!ast_goto_if_exists(chan, dialcontext, "o", 1) ||
|
||||
(!ast_strlen_zero(chan->macrocontext) &&
|
||||
!ast_goto_if_exists(chan, chan->macrocontext, "o", 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Can't find extension 'o' in current context. "
|
||||
"Not Exiting the Directory!\n");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
if (digit == '*') {
|
||||
if (!ast_goto_if_exists(chan, dialcontext, "a", 1) ||
|
||||
(!ast_strlen_zero(chan->macrocontext) &&
|
||||
!ast_goto_if_exists(chan, chan->macrocontext, "a", 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Can't find extension 'a' in current context. "
|
||||
"Not Exiting the Directory!\n");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
memset(ext, 0, sizeof(ext));
|
||||
ext[0] = digit;
|
||||
res = 0;
|
||||
@@ -465,18 +239,18 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
while(v) {
|
||||
/* Find a candidate extension */
|
||||
start = strdup(v->value);
|
||||
if (start && !strcasestr(start, "hidefromdir=yes")) {
|
||||
if (start) {
|
||||
stringp=start;
|
||||
strsep(&stringp, ",");
|
||||
pos = strsep(&stringp, ",");
|
||||
if (pos) {
|
||||
ast_copy_string(name, pos, sizeof(name));
|
||||
strncpy(name, pos, sizeof(name) - 1);
|
||||
/* Grab the last name */
|
||||
if (last && strrchr(pos,' '))
|
||||
pos = strrchr(pos, ' ') + 1;
|
||||
conv = convert(pos);
|
||||
if (conv) {
|
||||
if (!strncmp(conv, ext, strlen(ext))) {
|
||||
if (!strcmp(conv, ext)) {
|
||||
/* Match! */
|
||||
found++;
|
||||
free(conv);
|
||||
@@ -493,7 +267,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
|
||||
if (v) {
|
||||
/* We have a match -- play a greeting if they have it */
|
||||
res = play_mailbox_owner(chan, context, dialcontext, v->name, name, readext, fromappvm);
|
||||
res = play_mailbox_owner(chan, context, dialcontext, v->name, name);
|
||||
switch (res) {
|
||||
case -1:
|
||||
/* user pressed '1' but extension does not exist, or
|
||||
@@ -502,11 +276,11 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
lastuserchoice = 0;
|
||||
break;
|
||||
case '1':
|
||||
/* user pressed '1' and extensions exists;
|
||||
play_mailbox_owner will already have done
|
||||
a goto() on the channel
|
||||
*/
|
||||
/* user pressed '1' and extensions exists */
|
||||
lastuserchoice = res;
|
||||
strncpy(chan->context, dialcontext, sizeof(chan->context) - 1);
|
||||
strncpy(chan->exten, v->name, sizeof(chan->exten) - 1);
|
||||
chan->priority = 0;
|
||||
break;
|
||||
case '*':
|
||||
/* user pressed '*' to skip something found */
|
||||
@@ -520,66 +294,11 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
}
|
||||
}
|
||||
|
||||
if (!res && ucfg) {
|
||||
/* Search users.conf for all names which start with those digits */
|
||||
for (cat = ast_category_browse(ucfg, NULL); cat && !res ; cat = ast_category_browse(ucfg, cat)) {
|
||||
if (!strcasecmp(cat, "general"))
|
||||
continue;
|
||||
if (!ast_true(ast_config_option(ucfg, cat, "hasdirectory")))
|
||||
continue;
|
||||
|
||||
/* Find all candidate extensions */
|
||||
if ((pos = ast_variable_retrieve(ucfg, cat, "fullname"))) {
|
||||
ast_copy_string(name, pos, sizeof(name));
|
||||
/* Grab the last name */
|
||||
if (last && strrchr(pos,' '))
|
||||
pos = strrchr(pos, ' ') + 1;
|
||||
conv = convert(pos);
|
||||
if (conv) {
|
||||
if (!strcmp(conv, ext)) {
|
||||
/* Match! */
|
||||
found++;
|
||||
/* We have a match -- play a greeting if they have it */
|
||||
res = play_mailbox_owner(chan, context, dialcontext, cat, name, readext, fromappvm);
|
||||
switch (res) {
|
||||
case -1:
|
||||
/* user pressed '1' but extension does not exist, or
|
||||
* user hungup
|
||||
*/
|
||||
lastuserchoice = 0;
|
||||
breakout = 1;
|
||||
break;
|
||||
case '1':
|
||||
/* user pressed '1' and extensions exists;
|
||||
play_mailbox_owner will already have done
|
||||
a goto() on the channel
|
||||
*/
|
||||
lastuserchoice = res;
|
||||
breakout = 1;
|
||||
break;
|
||||
case '*':
|
||||
/* user pressed '*' to skip something found */
|
||||
lastuserchoice = res;
|
||||
breakout = 0;
|
||||
res = 0;
|
||||
break;
|
||||
default:
|
||||
breakout = 1;
|
||||
break;
|
||||
}
|
||||
free(conv);
|
||||
if (breakout)
|
||||
break;
|
||||
}
|
||||
else
|
||||
free(conv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastuserchoice != '1') {
|
||||
res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language);
|
||||
if (found)
|
||||
res = ast_streamfile(chan, "dir-nomore", chan->language);
|
||||
else
|
||||
res = ast_streamfile(chan, "dir-nomatch", chan->language);
|
||||
if (!res)
|
||||
res = 1;
|
||||
return res;
|
||||
@@ -592,113 +311,93 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
|
||||
static int directory_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
struct ast_config *cfg, *ucfg;
|
||||
struct localuser *u;
|
||||
struct ast_config *cfg;
|
||||
int last = 1;
|
||||
int readext = 0;
|
||||
int fromappvm = 0;
|
||||
const char *dirintro;
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(vmcontext);
|
||||
AST_APP_ARG(dialcontext);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
char *context, *dialcontext, *dirintro, *options;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "directory requires an argument (context[,dialcontext])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'f'))
|
||||
last = 0;
|
||||
if (strchr(args.options, 'e'))
|
||||
readext = 1;
|
||||
if (strchr(args.options, 'v'))
|
||||
fromappvm = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.dialcontext))
|
||||
args.dialcontext = args.vmcontext;
|
||||
|
||||
cfg = realtime_directory(args.vmcontext);
|
||||
cfg = ast_load(DIRECTORY_CONFIG);
|
||||
if (!cfg) {
|
||||
ast_log(LOG_ERROR, "Unable to read the configuration data!\n");
|
||||
ast_module_user_remove(u);
|
||||
ast_log(LOG_WARNING, "Unable to open directory configuration %s\n", DIRECTORY_CONFIG);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ucfg = ast_config_load("users.conf");
|
||||
|
||||
dirintro = ast_variable_retrieve(cfg, args.vmcontext, "directoryintro");
|
||||
if (ast_strlen_zero(dirintro))
|
||||
LOCAL_USER_ADD(u);
|
||||
top:
|
||||
context = ast_strdupa(data);
|
||||
dialcontext = strchr(context, '|');
|
||||
if (dialcontext) {
|
||||
*dialcontext = '\0';
|
||||
dialcontext++;
|
||||
options = strchr(dialcontext, '|');
|
||||
if (options) {
|
||||
*options = '\0';
|
||||
options++;
|
||||
if (strchr(options, 'f'))
|
||||
last = 0;
|
||||
}
|
||||
} else
|
||||
dialcontext = context;
|
||||
dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
|
||||
if (!dirintro || ast_strlen_zero(dirintro))
|
||||
dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
|
||||
if (ast_strlen_zero(dirintro))
|
||||
dirintro = last ? "dir-intro" : "dir-intro-fn";
|
||||
|
||||
if (!dirintro || ast_strlen_zero(dirintro)) {
|
||||
if (last)
|
||||
dirintro = "dir-intro";
|
||||
else
|
||||
dirintro = "dir-intro-fn";
|
||||
}
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
res = ast_answer(chan);
|
||||
|
||||
for (;;) {
|
||||
if (!res)
|
||||
res = ast_stream_and_wait(chan, dirintro, chan->language, AST_DIGIT_ANY);
|
||||
ast_stopstream(chan);
|
||||
if (!res)
|
||||
res = ast_waitfordigit(chan, 5000);
|
||||
if (!res)
|
||||
res = ast_streamfile(chan, dirintro, chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
ast_stopstream(chan);
|
||||
if (!res)
|
||||
res = ast_waitfordigit(chan, 5000);
|
||||
if (res > 0) {
|
||||
res = do_directory(chan, cfg, context, dialcontext, res, last);
|
||||
if (res > 0) {
|
||||
res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm);
|
||||
if (res > 0) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
ast_stopstream(chan);
|
||||
if (res >= 0)
|
||||
continue;
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
ast_stopstream(chan);
|
||||
if (res >= 0) {
|
||||
goto top;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ucfg)
|
||||
ast_config_destroy(ucfg);
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
ast_destroy(cfg);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
res = ast_unregister_application(app);
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
#ifdef ODBC_STORAGE
|
||||
struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG);
|
||||
const char *tmp;
|
||||
|
||||
if (cfg) {
|
||||
if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
|
||||
ast_copy_string(odbc_database, tmp, sizeof(odbc_database));
|
||||
}
|
||||
if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) {
|
||||
ast_copy_string(odbc_table, tmp, sizeof(odbc_table));
|
||||
}
|
||||
if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) {
|
||||
ast_copy_string(vmfmts, tmp, sizeof(vmfmts));
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n");
|
||||
#endif
|
||||
|
||||
return ast_register_application(app, directory_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
446
apps/app_disa.c
446
apps/app_disa.c
@@ -1,80 +1,65 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* DISA -- Direct Inward System Access Application 6/20/2001
|
||||
*
|
||||
* Copyright (C) 2001, Linux Support Services, Inc.
|
||||
*
|
||||
* Jim Dixon <jim@lambdatel.com>
|
||||
*
|
||||
* Made only slightly more sane by Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief DISA -- Direct Inward System Access Application
|
||||
*
|
||||
* \author Jim Dixon <jim@lambdatel.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/indications.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/ulaw.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/indications.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/ulaw.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/stringfields.h"
|
||||
|
||||
static char *tdesc = "DISA (Direct Inward System Access) Application";
|
||||
|
||||
static char *app = "DISA";
|
||||
|
||||
static char *synopsis = "DISA (Direct Inward System Access)";
|
||||
|
||||
static char *descrip =
|
||||
"DISA(<numeric passcode>[|<context>]) or DISA(<filename>)\n"
|
||||
"The DISA, Direct Inward System Access, application allows someone from \n"
|
||||
"outside the telephone switch (PBX) to obtain an \"internal\" system \n"
|
||||
"dialtone and to place calls from it as if they were placing a call from \n"
|
||||
"within the switch.\n"
|
||||
"DISA plays a dialtone. The user enters their numeric passcode, followed by\n"
|
||||
"the pound sign (#). If the passcode is correct, the user is then given\n"
|
||||
"DISA (Direct Inward System Access) -- Allows someone from outside\n"
|
||||
"the telephone switch (PBX) to obtain an \"internal\" system dialtone\n"
|
||||
"and to place calls from it as if they were placing a call from within\n"
|
||||
"the switch. A user calls a number that connects to the DISA application\n"
|
||||
"and is given dialtone. The user enters their passcode, followed by the\n"
|
||||
"pound sign (#). If the passcode is correct, the user is then given\n"
|
||||
"system dialtone on which a call may be placed. Obviously, this type\n"
|
||||
"of access has SERIOUS security implications, and GREAT care must be\n"
|
||||
"taken NOT to compromise your security.\n\n"
|
||||
"There is a possibility of accessing DISA without password. Simply\n"
|
||||
"exchange your password with \"no-password\".\n\n"
|
||||
" Example: exten => s,1,DISA(no-password|local)\n\n"
|
||||
"Be aware that using this compromises the security of your PBX.\n\n"
|
||||
"exchange your password with no-password.\n\n"
|
||||
" Example: exten => s,1,DISA,no-password|local\n\n"
|
||||
"but be aware of using this for your security compromising.\n\n"
|
||||
"The arguments to this application (in extensions.conf) allow either\n"
|
||||
"specification of a single global passcode (that everyone uses), or\n"
|
||||
"individual passcodes contained in a file. It also allows specification\n"
|
||||
"specification of a single global password (that everyone uses), or\n"
|
||||
"individual passwords contained in a file. It also allow specification\n"
|
||||
"of the context on which the user will be dialing. If no context is\n"
|
||||
"specified, the DISA application defaults the context to \"disa\".\n"
|
||||
"Presumably a normal system will have a special context set up\n"
|
||||
"for DISA use with some or a lot of restrictions. \n\n"
|
||||
"specified, the DISA application defaults the context to \"disa\"\n"
|
||||
"presumably that a normal system will have a special context set up\n"
|
||||
"for DISA use with some or a lot of restrictions. The arguments are\n"
|
||||
"one of the following:\n\n"
|
||||
" numeric-passcode\n"
|
||||
" numeric-passcode|context\n"
|
||||
" full-pathname-of-file-that-contains-passcodes\n\n"
|
||||
"The file that contains the passcodes (if used) allows specification\n"
|
||||
"of either just a passcode (defaulting to the \"disa\" context, or\n"
|
||||
"passcode|context on each line of the file. The file may contain blank\n"
|
||||
@@ -82,27 +67,35 @@ static char *descrip =
|
||||
"above arguments may have |new-callerid-string appended to them, to\n"
|
||||
"specify a new (different) callerid to be used for this call, for\n"
|
||||
"example: numeric-passcode|context|\"My Phone\" <(234) 123-4567> or \n"
|
||||
"full-pathname-of-passcode-file|\"My Phone\" <(234) 123-4567>. Last\n"
|
||||
"but not least, |mailbox[@context] may be appended, which will cause\n"
|
||||
"a stutter-dialtone (indication \"dialrecall\") to be used, if the\n"
|
||||
"specified mailbox contains any new messages, for example:\n"
|
||||
"numeric-passcode|context||1234 (w/a changing callerid). Note that\n"
|
||||
"full-pathname-of-passcode-file|\"My Phone\" <(234) 123-4567>. Note that\n"
|
||||
"in the case of specifying the numeric-passcode, the context must be\n"
|
||||
"specified if the callerid is specified also.\n\n"
|
||||
"If login is successful, the application looks up the dialed number in\n"
|
||||
"the specified (or default) context, and executes it if found.\n"
|
||||
"If the user enters an invalid extension and extension \"i\" (invalid) \n"
|
||||
"exists in the context, it will be used. Also, if you set the 5th argument\n"
|
||||
"to 'NOANSWER', the DISA application will not answer initially.\n";
|
||||
"If login is successful, the application parses the dialed number in\n"
|
||||
"the specified (or default) context, and returns 0 with the new extension\n"
|
||||
"context filled-in and the priority set to 1, so that the PBX may\n"
|
||||
"re-apply the routing tables to it and complete the call normally.";
|
||||
|
||||
|
||||
static void play_dialtone(struct ast_channel *chan, char *mailbox)
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int firstdigittimeout = 20000; /* 20 seconds first digit timeout */
|
||||
static int digittimeout = 10000; /* 10 seconds subsequent digit timeout */
|
||||
|
||||
static int ms_diff(struct timeval *tv1, struct timeval *tv2)
|
||||
{
|
||||
int ms;
|
||||
|
||||
ms = (tv1->tv_sec - tv2->tv_sec) * 1000;
|
||||
ms += (tv1->tv_usec - tv2->tv_usec) / 1000;
|
||||
return(ms);
|
||||
}
|
||||
|
||||
static void play_dialtone(struct ast_channel *chan)
|
||||
{
|
||||
const struct tone_zone_sound *ts = NULL;
|
||||
if(ast_app_has_voicemail(mailbox, NULL))
|
||||
ts = ast_get_indication_tone(chan->zone, "dialrecall");
|
||||
else
|
||||
ts = ast_get_indication_tone(chan->zone, "dial");
|
||||
ts = ast_get_indication_tone(chan->zone, "dial");
|
||||
if (ts)
|
||||
ast_playtones_start(chan, 0, ts->data, 0);
|
||||
else
|
||||
@@ -111,92 +104,77 @@ static void play_dialtone(struct ast_channel *chan, char *mailbox)
|
||||
|
||||
static int disa_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int i,j,k,x,did_ignore,special_noanswer;
|
||||
int firstdigittimeout = 20000;
|
||||
int digittimeout = 10000;
|
||||
struct ast_module_user *u;
|
||||
char *tmp, exten[AST_MAX_EXTENSION],acctcode[20]="";
|
||||
char pwline[256];
|
||||
char ourcidname[256],ourcidnum[256];
|
||||
int i,j,k,x,did_ignore;
|
||||
struct localuser *u;
|
||||
char tmp[256],arg2[256]="",exten[AST_MAX_EXTENSION],acctcode[20]="";
|
||||
char *ourcontext,*ourcallerid;
|
||||
struct ast_frame *f;
|
||||
struct timeval lastdigittime;
|
||||
struct timeval lastout, now, lastdigittime;
|
||||
int res;
|
||||
time_t rstart;
|
||||
FILE *fp;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(passcode);
|
||||
AST_APP_ARG(context);
|
||||
AST_APP_ARG(cid);
|
||||
AST_APP_ARG(mailbox);
|
||||
AST_APP_ARG(noanswer);
|
||||
);
|
||||
char *stringp=NULL;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "DISA requires an argument (passcode/passcode file)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (chan->pbx) {
|
||||
firstdigittimeout = chan->pbx->rtimeout*1000;
|
||||
digittimeout = chan->pbx->dtimeout*1000;
|
||||
}
|
||||
|
||||
if (ast_set_write_format(chan,AST_FORMAT_ULAW)) {
|
||||
ast_log(LOG_WARNING, "Unable to set write format to Mu-law on %s\n", chan->name);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
if (ast_set_read_format(chan,AST_FORMAT_ULAW)) {
|
||||
ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n", chan->name);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_log(LOG_DEBUG, "Digittimeout: %d\n", digittimeout);
|
||||
ast_log(LOG_DEBUG, "Responsetimeout: %d\n", firstdigittimeout);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, tmp);
|
||||
|
||||
if (ast_strlen_zero(args.context))
|
||||
args.context = "disa";
|
||||
if (ast_strlen_zero(args.mailbox))
|
||||
args.mailbox = "";
|
||||
|
||||
ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
|
||||
|
||||
|
||||
special_noanswer = 0;
|
||||
if ((!args.noanswer) || strcmp(args.noanswer,"NOANSWER"))
|
||||
if (ast_set_write_format(chan,AST_FORMAT_ULAW))
|
||||
{
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
/* answer */
|
||||
ast_answer(chan);
|
||||
}
|
||||
} else special_noanswer = 1;
|
||||
ast_log(LOG_WARNING, "Unable to set write format to Mu-law on %s\n",chan->name);
|
||||
return -1;
|
||||
}
|
||||
if (ast_set_read_format(chan,AST_FORMAT_ULAW))
|
||||
{
|
||||
ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n",chan->name);
|
||||
return -1;
|
||||
}
|
||||
lastout.tv_sec = lastout.tv_usec = 0;
|
||||
if (!data || !strlen((char *)data)) {
|
||||
ast_log(LOG_WARNING, "disa requires an argument (passcode/passcode file)\n");
|
||||
return -1;
|
||||
}
|
||||
strncpy(tmp, (char *)data, sizeof(tmp)-1);
|
||||
stringp=tmp;
|
||||
strsep(&stringp, "|");
|
||||
ourcontext = strsep(&stringp, "|");
|
||||
/* if context specified, save 2nd arg and parse third */
|
||||
if (ourcontext) {
|
||||
strncpy(arg2,ourcontext, sizeof(arg2) - 1);
|
||||
ourcallerid = strsep(&stringp,"|");
|
||||
}
|
||||
/* if context not specified, use "disa" */
|
||||
else {
|
||||
arg2[0] = 0;
|
||||
ourcallerid = NULL;
|
||||
ourcontext = "disa";
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
{
|
||||
/* answer */
|
||||
ast_answer(chan);
|
||||
}
|
||||
i = k = x = 0; /* k is 0 for pswd entry, 1 for ext entry */
|
||||
did_ignore = 0;
|
||||
exten[0] = 0;
|
||||
acctcode[0] = 0;
|
||||
/* can we access DISA without password? */
|
||||
|
||||
ast_log(LOG_DEBUG, "Context: %s\n",args.context);
|
||||
ast_log(LOG_DEBUG, "Context: %s\n",ourcontext);
|
||||
|
||||
if (!strcasecmp(args.passcode, "no-password")) {
|
||||
if (!strcasecmp(tmp, "no-password"))
|
||||
{;
|
||||
k |= 1; /* We have the password */
|
||||
ast_log(LOG_DEBUG, "DISA no-password login success\n");
|
||||
}
|
||||
lastdigittime = ast_tvnow();
|
||||
gettimeofday(&lastdigittime,NULL);
|
||||
|
||||
play_dialtone(chan, args.mailbox);
|
||||
play_dialtone(chan);
|
||||
|
||||
for (;;) {
|
||||
for(;;)
|
||||
{
|
||||
gettimeofday(&now,NULL);
|
||||
/* if outa time, give em reorder */
|
||||
if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
|
||||
((k&2) ? digittimeout : firstdigittimeout)) {
|
||||
if (ms_diff(&now,&lastdigittime) >
|
||||
((k&2) ? digittimeout : firstdigittimeout))
|
||||
{
|
||||
ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
|
||||
((k&1) ? "extension" : "password"),chan->name);
|
||||
break;
|
||||
@@ -207,110 +185,108 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
|
||||
f = ast_read(chan);
|
||||
if (f == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
if (f == NULL)
|
||||
{
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_CONTROL) &&
|
||||
(f->subclass == AST_CONTROL_HANGUP)) {
|
||||
(f->subclass == AST_CONTROL_HANGUP))
|
||||
{
|
||||
ast_frfree(f);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
ast_frfree(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if not DTMF, just do it again */
|
||||
if (f->frametype != AST_FRAME_DTMF) {
|
||||
/* if not DTMF, just do it again */
|
||||
if (f->frametype != AST_FRAME_DTMF)
|
||||
{
|
||||
ast_frfree(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
j = f->subclass; /* save digit */
|
||||
ast_frfree(f);
|
||||
if (i == 0) {
|
||||
if (i == 0)
|
||||
{
|
||||
k|=2; /* We have the first digit */
|
||||
ast_playtones_stop(chan);
|
||||
}
|
||||
lastdigittime = ast_tvnow();
|
||||
gettimeofday(&lastdigittime,NULL);
|
||||
/* got a DTMF tone */
|
||||
if (i < AST_MAX_EXTENSION) { /* if still valid number of digits */
|
||||
if (!(k&1)) { /* if in password state */
|
||||
if (j == '#') { /* end of password */
|
||||
if (i < AST_MAX_EXTENSION) /* if still valid number of digits */
|
||||
{
|
||||
if (!(k&1)) /* if in password state */
|
||||
{
|
||||
if (j == '#') /* end of password */
|
||||
{
|
||||
/* see if this is an integer */
|
||||
if (sscanf(args.passcode,"%d",&j) < 1) { /* nope, it must be a filename */
|
||||
fp = fopen(args.passcode,"r");
|
||||
if (!fp) {
|
||||
ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
|
||||
ast_module_user_remove(u);
|
||||
if (sscanf(tmp,"%d",&j) < 1)
|
||||
{ /* nope, it must be a filename */
|
||||
fp = fopen(tmp,"r");
|
||||
if (!fp)
|
||||
{
|
||||
ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",tmp,chan->name);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
pwline[0] = 0;
|
||||
while(fgets(pwline,sizeof(pwline) - 1,fp)) {
|
||||
if (!pwline[0])
|
||||
continue;
|
||||
if (pwline[strlen(pwline) - 1] == '\n')
|
||||
pwline[strlen(pwline) - 1] = 0;
|
||||
if (!pwline[0])
|
||||
continue;
|
||||
/* skip comments */
|
||||
if (pwline[0] == '#')
|
||||
continue;
|
||||
if (pwline[0] == ';')
|
||||
continue;
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, pwline);
|
||||
|
||||
ast_log(LOG_DEBUG, "Mailbox: %s\n",args.mailbox);
|
||||
|
||||
/* password must be in valid format (numeric) */
|
||||
if (sscanf(args.passcode,"%d", &j) < 1)
|
||||
continue;
|
||||
/* if we got it */
|
||||
if (!strcmp(exten,args.passcode)) {
|
||||
if (ast_strlen_zero(args.context))
|
||||
args.context = "disa";
|
||||
if (ast_strlen_zero(args.mailbox))
|
||||
args.mailbox = "";
|
||||
break;
|
||||
}
|
||||
tmp[0] = 0;
|
||||
while(fgets(tmp,sizeof(tmp) - 1,fp))
|
||||
{
|
||||
char *stringp=NULL,*stringp2;
|
||||
if (!tmp[0]) continue;
|
||||
if (tmp[strlen(tmp) - 1] == '\n')
|
||||
tmp[strlen(tmp) - 1] = 0;
|
||||
if (!tmp[0]) continue;
|
||||
/* skip comments */
|
||||
if (tmp[0] == '#') continue;
|
||||
if (tmp[0] == ';') continue;
|
||||
stringp=tmp;
|
||||
strsep(&stringp, "|");
|
||||
stringp2=strsep(&stringp, "|");
|
||||
if (stringp2) {
|
||||
ourcontext=stringp2;
|
||||
stringp2=strsep(&stringp, "|");
|
||||
if (stringp2) ourcallerid=stringp2;
|
||||
}
|
||||
}
|
||||
/* password must be in valid format (numeric) */
|
||||
if (sscanf(tmp,"%d",&j) < 1) continue;
|
||||
/* if we got it */
|
||||
if (!strcmp(exten,tmp)) break;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
/* compare the two */
|
||||
if (strcmp(exten,args.passcode)) {
|
||||
}
|
||||
/* compare the two */
|
||||
if (strcmp(exten,tmp))
|
||||
{
|
||||
ast_log(LOG_WARNING,"DISA on chan %s got bad password %s\n",chan->name,exten);
|
||||
goto reorder;
|
||||
|
||||
}
|
||||
/* password good, set to dial state */
|
||||
ast_log(LOG_DEBUG,"DISA on chan %s password is good\n",chan->name);
|
||||
play_dialtone(chan, args.mailbox);
|
||||
play_dialtone(chan);
|
||||
|
||||
k|=1; /* In number mode */
|
||||
i = 0; /* re-set buffer pointer */
|
||||
exten[sizeof(acctcode)] = 0;
|
||||
ast_copy_string(acctcode, exten, sizeof(acctcode));
|
||||
strncpy(acctcode,exten, sizeof(acctcode) - 1);
|
||||
exten[0] = 0;
|
||||
ast_log(LOG_DEBUG,"Successful DISA log-in on chan %s\n", chan->name);
|
||||
ast_log(LOG_DEBUG,"Successful DISA log-in on chan %s\n",chan->name);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (j == '#') { /* end of extension */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exten[i++] = j; /* save digit */
|
||||
exten[i] = 0;
|
||||
if (!(k&1))
|
||||
continue; /* if getting password, continue doing it */
|
||||
/* if this exists */
|
||||
if (!(k&1)) continue; /* if getting password, continue doing it */
|
||||
/* if this exists */
|
||||
|
||||
if (ast_ignore_pattern(args.context, exten)) {
|
||||
play_dialtone(chan, "");
|
||||
if (ast_ignore_pattern(ourcontext, exten)) {
|
||||
play_dialtone(chan);
|
||||
did_ignore = 1;
|
||||
} else
|
||||
if (did_ignore) {
|
||||
@@ -318,50 +294,38 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
did_ignore = 0;
|
||||
}
|
||||
|
||||
/* if can do some more, do it */
|
||||
if (!ast_matchmore_extension(chan,args.context,exten,1, chan->cid.cid_num)) {
|
||||
/* if can do some more, do it */
|
||||
if (!ast_matchmore_extension(chan,ourcontext,exten,1, chan->callerid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (k == 3) {
|
||||
int recheck = 0;
|
||||
struct ast_flags flags = { AST_CDR_FLAG_POSTED };
|
||||
|
||||
if (!ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
|
||||
pbx_builtin_setvar_helper(chan, "INVALID_EXTEN", exten);
|
||||
exten[0] = 'i';
|
||||
exten[1] = '\0';
|
||||
recheck = 1;
|
||||
}
|
||||
if (!recheck || ast_exists_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
|
||||
ast_playtones_stop(chan);
|
||||
/* We're authenticated and have a target extension */
|
||||
if (!ast_strlen_zero(args.cid)) {
|
||||
ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
|
||||
ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(acctcode))
|
||||
ast_string_field_set(chan, accountcode, acctcode);
|
||||
|
||||
if (special_noanswer) flags.flags = 0;
|
||||
ast_cdr_reset(chan->cdr, &flags);
|
||||
ast_explicit_goto(chan, args.context, exten, 1);
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
if ((k==3) && (ast_exists_extension(chan,ourcontext,exten,1, chan->callerid)))
|
||||
{
|
||||
ast_playtones_stop(chan);
|
||||
/* We're authenticated and have a valid extension */
|
||||
if (ourcallerid && *ourcallerid)
|
||||
{
|
||||
if (chan->callerid) free(chan->callerid);
|
||||
chan->callerid = strdup(ourcallerid);
|
||||
}
|
||||
strncpy(chan->exten, exten, sizeof(chan->exten) - 1);
|
||||
strncpy(chan->context, ourcontext, sizeof(chan->context) - 1);
|
||||
strncpy(chan->accountcode, acctcode, sizeof(chan->accountcode) - 1);
|
||||
chan->priority = 0;
|
||||
ast_cdr_init(chan->cdr,chan);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Received invalid, but no "i" extension exists in the given context */
|
||||
|
||||
reorder:
|
||||
|
||||
ast_indicate(chan,AST_CONTROL_CONGESTION);
|
||||
/* something is invalid, give em reorder for several seconds */
|
||||
time(&rstart);
|
||||
while(time(NULL) < rstart + 10) {
|
||||
while(time(NULL) < rstart + 10)
|
||||
{
|
||||
if (ast_waitfor(chan, -1) < 0)
|
||||
break;
|
||||
f = ast_read(chan);
|
||||
@@ -370,24 +334,34 @@ reorder:
|
||||
ast_frfree(f);
|
||||
}
|
||||
ast_playtones_stop(chan);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, disa_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "DISA (Direct Inward System Access) Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key(void)
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2004 - 2005, Anthony Minessale II.
|
||||
*
|
||||
* Anthony Minessale <anthmct@yahoo.com>
|
||||
*
|
||||
* A license has been granted to Digium (via disclaimer) for the use of
|
||||
* this code.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Application to dump channel variables
|
||||
*
|
||||
* \author Anthony Minessale <anthmct@yahoo.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *app = "DumpChan";
|
||||
static char *synopsis = "Dump Info About The Calling Channel";
|
||||
static char *desc =
|
||||
" DumpChan([<min_verbose_level>])\n"
|
||||
"Displays information on channel and listing of all channel\n"
|
||||
"variables. If min_verbose_level is specified, output is only\n"
|
||||
"displayed when the verbose level is currently set to that number\n"
|
||||
"or greater. \n";
|
||||
|
||||
|
||||
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
{
|
||||
struct timeval now;
|
||||
long elapsed_seconds = 0;
|
||||
int hour = 0, min = 0, sec = 0;
|
||||
char cgrp[BUFSIZ/2];
|
||||
char pgrp[BUFSIZ/2];
|
||||
char formatbuf[BUFSIZ/2];
|
||||
|
||||
now = ast_tvnow();
|
||||
memset(buf, 0, size);
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
if (c->cdr) {
|
||||
elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
|
||||
hour = elapsed_seconds / 3600;
|
||||
min = (elapsed_seconds % 3600) / 60;
|
||||
sec = elapsed_seconds % 60;
|
||||
}
|
||||
|
||||
snprintf(buf,size,
|
||||
"Name= %s\n"
|
||||
"Type= %s\n"
|
||||
"UniqueID= %s\n"
|
||||
"CallerID= %s\n"
|
||||
"CallerIDName= %s\n"
|
||||
"DNIDDigits= %s\n"
|
||||
"RDNIS= %s\n"
|
||||
"State= %s (%d)\n"
|
||||
"Rings= %d\n"
|
||||
"NativeFormat= %s\n"
|
||||
"WriteFormat= %s\n"
|
||||
"ReadFormat= %s\n"
|
||||
"1stFileDescriptor= %d\n"
|
||||
"Framesin= %d %s\n"
|
||||
"Framesout= %d %s\n"
|
||||
"TimetoHangup= %ld\n"
|
||||
"ElapsedTime= %dh%dm%ds\n"
|
||||
"Context= %s\n"
|
||||
"Extension= %s\n"
|
||||
"Priority= %d\n"
|
||||
"CallGroup= %s\n"
|
||||
"PickupGroup= %s\n"
|
||||
"Application= %s\n"
|
||||
"Data= %s\n"
|
||||
"Blocking_in= %s\n",
|
||||
c->name,
|
||||
c->tech->type,
|
||||
c->uniqueid,
|
||||
S_OR(c->cid.cid_num, "(N/A)"),
|
||||
S_OR(c->cid.cid_name, "(N/A)"),
|
||||
S_OR(c->cid.cid_dnid, "(N/A)"),
|
||||
S_OR(c->cid.cid_rdnis, "(N/A)"),
|
||||
ast_state2str(c->_state),
|
||||
c->_state,
|
||||
c->rings,
|
||||
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->nativeformats),
|
||||
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->writeformat),
|
||||
ast_getformatname_multiple(formatbuf, sizeof(formatbuf), c->readformat),
|
||||
c->fds[0], c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
|
||||
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "", (long)c->whentohangup,
|
||||
hour,
|
||||
min,
|
||||
sec,
|
||||
c->context,
|
||||
c->exten,
|
||||
c->priority,
|
||||
ast_print_group(cgrp, sizeof(cgrp), c->callgroup),
|
||||
ast_print_group(pgrp, sizeof(pgrp), c->pickupgroup),
|
||||
( c->appl ? c->appl : "(N/A)" ),
|
||||
( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
|
||||
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dumpchan_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char vars[BUFSIZ * 4];
|
||||
char info[1024];
|
||||
int level = 0;
|
||||
static char *line = "================================================================================";
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!ast_strlen_zero(data))
|
||||
level = atoi(data);
|
||||
|
||||
pbx_builtin_serialize_variables(chan, vars, sizeof(vars));
|
||||
serialize_showchan(chan, info, sizeof(info));
|
||||
if (option_verbose >= level)
|
||||
ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n", chan->name, line, info, vars, line);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, dumpchan_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dump Info About The Calling Channel");
|
||||
130
apps/app_echo.c
130
apps/app_echo.c
@@ -1,104 +1,100 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Echo application -- play back what you hear to evaluate latency
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Echo application -- play back what you hear to evaluate latency
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
static char *tdesc = "Simple Echo Application";
|
||||
|
||||
static char *app = "Echo";
|
||||
|
||||
static char *synopsis = "Echo audio, video, or DTMF back to the calling party";
|
||||
static char *synopsis = "Echo audio read back to the user";
|
||||
|
||||
static char *descrip =
|
||||
" Echo(): This application will echo any audio, video, or DTMF frames read from\n"
|
||||
"the calling channel back to itself. If the DTMF digit '#' is received, the\n"
|
||||
"application will exit.\n";
|
||||
" Echo(): Echo audio read from channel back to the channel. Returns 0\n"
|
||||
"if the user exits with the '#' key, or -1 if the user hangs up.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int echo_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = -1;
|
||||
int format;
|
||||
struct ast_module_user *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
format = ast_best_codec(chan->nativeformats);
|
||||
ast_set_write_format(chan, format);
|
||||
ast_set_read_format(chan, format);
|
||||
|
||||
while (ast_waitfor(chan, -1) > -1) {
|
||||
struct ast_frame *f = ast_read(chan);
|
||||
int res=-1;
|
||||
struct localuser *u;
|
||||
struct ast_frame *f;
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
|
||||
ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
|
||||
/* Do our thing here */
|
||||
while(ast_waitfor(chan, -1) > -1) {
|
||||
f = ast_read(chan);
|
||||
if (!f)
|
||||
break;
|
||||
f->delivery.tv_sec = 0;
|
||||
f->delivery.tv_usec = 0;
|
||||
if (ast_write(chan, f)) {
|
||||
ast_frfree(f);
|
||||
goto end;
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
|
||||
res = 0;
|
||||
ast_frfree(f);
|
||||
goto end;
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
} else if (f->frametype == AST_FRAME_VIDEO) {
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
} else if (f->frametype == AST_FRAME_DTMF) {
|
||||
if (f->subclass == '#') {
|
||||
res = 0;
|
||||
break;
|
||||
} else
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
end:
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, echo_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Echo Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
203
apps/app_enumlookup.c
Normal file
203
apps/app_enumlookup.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Time of day - Report the time of day
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/enum.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static char *tdesc = "ENUM Lookup";
|
||||
|
||||
static char *app = "EnumLookup";
|
||||
|
||||
static char *synopsis = "Lookup number in ENUM";
|
||||
|
||||
static char *descrip =
|
||||
" EnumLookup(exten): Looks up an extension via ENUM and sets\n"
|
||||
"the variable 'ENUM'. For VoIP URIs this variable will \n"
|
||||
"look like 'TECHNOLOGY/URI' with the appropriate technology.\n"
|
||||
"Returns -1 on hangup, or 0 on completion regardless of whether the \n"
|
||||
"lookup was successful. \n"
|
||||
"Currently, the enumservices SIP, H323, IAX, IAX2 and TEL are recognized. \n"
|
||||
"A good SIP, H323, IAX or IAX2 entry will result in normal priority handling, \n"
|
||||
"whereas a good TEL entry will increase the priority by 51 (if existing).\n"
|
||||
"If the lookup was *not* successful and there exists a priority n + 101,\n"
|
||||
"then that priority will be taken next.\n" ;
|
||||
|
||||
#define ENUM_CONFIG "enum.conf"
|
||||
|
||||
static char h323driver[80] = "";
|
||||
#define H323DRIVERDEFAULT "H323"
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int enumlookup_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
char tech[80];
|
||||
char dest[80];
|
||||
char tmp[256];
|
||||
char *c,*t;
|
||||
struct localuser *u;
|
||||
if (!data || ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n");
|
||||
res = 1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (!res) {
|
||||
res = ast_get_enum(chan, data, dest, sizeof(dest), tech, sizeof(tech));
|
||||
printf("ENUM got '%d'\n", res);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
/* Parse it out */
|
||||
if (res > 0) {
|
||||
if (!strcasecmp(tech, "SIP")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "sip:", 4))
|
||||
c += 4;
|
||||
snprintf(tmp, sizeof(tmp), "SIP/%s", c);
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "h323")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "h323:", 5))
|
||||
c += 5;
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", h323driver, c);
|
||||
/* do a s!;.*!! on the H323 URI */
|
||||
t = strchr(c,';');
|
||||
if (t)
|
||||
*t = 0;
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "iax")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "iax:", 4))
|
||||
c += 4;
|
||||
snprintf(tmp, sizeof(tmp), "IAX/%s", c);
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "iax2")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "iax2:", 5))
|
||||
c += 5;
|
||||
snprintf(tmp, sizeof(tmp), "IAX2/%s", c);
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "tel")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "tel:", 4))
|
||||
c += 4;
|
||||
|
||||
if (c[0] != '+') {
|
||||
ast_log(LOG_NOTICE, "tel: uri must start with a \"+\" (got '%s')\n", c);
|
||||
res = 0;
|
||||
} else {
|
||||
/* now copy over the number, skipping all non-digits and stop at ; or NULL */
|
||||
t = tmp;
|
||||
while( *c && (*c != ';') && (t - tmp < (sizeof(tmp) - 1))) {
|
||||
if (isdigit(*c))
|
||||
*t++ = *c;
|
||||
c++;
|
||||
}
|
||||
*t = 0;
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
ast_log(LOG_NOTICE, "tel: ENUM set to \"%s\"\n", tmp);
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 51, chan->callerid))
|
||||
chan->priority += 50;
|
||||
else
|
||||
res = 0;
|
||||
}
|
||||
} else if (!ast_strlen_zero(tech)) {
|
||||
ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
/* Look for a "busy" place */
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority += 100;
|
||||
} else if (res > 0)
|
||||
res = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_config(void)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
char *s;
|
||||
|
||||
cfg = ast_load(ENUM_CONFIG);
|
||||
if (cfg) {
|
||||
if (!(s=ast_variable_retrieve(cfg, "general", "h323driver"))) {
|
||||
strncpy(h323driver, H323DRIVERDEFAULT, sizeof(h323driver) - 1);
|
||||
} else {
|
||||
strncpy(h323driver, s, sizeof(h323driver) - 1);
|
||||
}
|
||||
ast_destroy(cfg);
|
||||
return 0;
|
||||
}
|
||||
ast_log(LOG_NOTICE, "No ENUM Config file, using defaults\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
res = ast_register_application(app, enumlookup_exec, synopsis, descrip);
|
||||
if (res)
|
||||
return(res);
|
||||
if ((res=load_config())) {
|
||||
return(res);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int reload(void)
|
||||
{
|
||||
return(load_config());
|
||||
}
|
||||
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
101
apps/app_eval.c
Normal file
101
apps/app_eval.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Eval application
|
||||
*
|
||||
* Copyright (c) 2004 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_eval__v001@the-tilghman.com>
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
static char *tdesc = "Reevaluates strings";
|
||||
|
||||
static char *app_eval = "Eval";
|
||||
|
||||
static char *eval_synopsis = "Evaluates a string";
|
||||
|
||||
static char *eval_descrip =
|
||||
"Usage: Eval(newvar=somestring)\n"
|
||||
" Normally Asterisk evaluates variables inline. But what if you want to\n"
|
||||
"store variable offsets in a database, to be evaluated later? Eval is\n"
|
||||
"the answer, by allowing a string to be evaluated twice in the dialplan,\n"
|
||||
"the first time as part of the normal dialplan, and the second using Eval.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int eval_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s, *newvar=NULL, tmp[MAXRESULT];
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
newvar = strsep(&s, "=");
|
||||
if (newvar && (newvar[0] != '\0')) {
|
||||
memset(tmp, 0, MAXRESULT);
|
||||
pbx_substitute_variables_helper(chan, s, tmp, MAXRESULT - 1);
|
||||
pbx_builtin_setvar_helper(chan, newvar, tmp);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app_eval);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_eval, eval_exec, eval_synopsis, eval_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
230
apps/app_exec.c
230
apps/app_exec.c
@@ -1,221 +1,113 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
|
||||
* Portions copyright (c) 2006, Philipp Dunkel.
|
||||
* Exec application
|
||||
*
|
||||
* Tilghman Lesher <app_exec__v002@the-tilghman.com>
|
||||
* Copyright (c) 2004 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_exec__v001@the-tilghman.com>
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Exec application
|
||||
*
|
||||
* \author Tilghman Lesher <app_exec__v002@the-tilghman.com>
|
||||
* \author Philipp Dunkel <philipp.dunkel@ebox.at>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
/*! Note
|
||||
*
|
||||
* The key difference between these two apps is exit status. In a
|
||||
* nutshell, Exec tries to be transparent as possible, behaving
|
||||
* in exactly the same way as if the application it calls was
|
||||
* directly invoked from the dialplan.
|
||||
*
|
||||
* TryExec, on the other hand, provides a way to execute applications
|
||||
* and catch any possible fatal error without actually fatally
|
||||
* affecting the dialplan.
|
||||
*/
|
||||
static char *tdesc = "Executes applications";
|
||||
|
||||
static char *app_exec = "Exec";
|
||||
static char *exec_synopsis = "Executes dialplan application";
|
||||
|
||||
static char *exec_synopsis = "Exec(Appname(arguments))";
|
||||
|
||||
static char *exec_descrip =
|
||||
"Usage: Exec(appname(arguments))\n"
|
||||
"Exec(appname(arguments))\n"
|
||||
" Allows an arbitrary application to be invoked even when not\n"
|
||||
"hardcoded into the dialplan. If the underlying application\n"
|
||||
"terminates the dialplan, or if the application cannot be found,\n"
|
||||
"Exec will terminate the dialplan.\n"
|
||||
" To invoke external applications, see the application System.\n"
|
||||
" If you would like to catch any error instead, see TryExec.\n";
|
||||
"hardcoded into the dialplan. Returns whatever value the\n"
|
||||
"app returns or -2 when the app cannot be found.\n";
|
||||
|
||||
static char *app_tryexec = "TryExec";
|
||||
static char *tryexec_synopsis = "Executes dialplan application, always returning";
|
||||
static char *tryexec_descrip =
|
||||
"Usage: TryExec(appname(arguments))\n"
|
||||
" Allows an arbitrary application to be invoked even when not\n"
|
||||
"hardcoded into the dialplan. To invoke external applications\n"
|
||||
"see the application System. Always returns to the dialplan.\n"
|
||||
"The channel variable TRYSTATUS will be set to:\n"
|
||||
" SUCCESS if the application returned zero\n"
|
||||
" FAILED if the application returned non-zero\n"
|
||||
" NOAPP if the application was not found or was not specified\n";
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static char *app_execif = "ExecIf";
|
||||
static char *execif_synopsis = "Executes dialplan application, conditionally";
|
||||
static char *execif_descrip =
|
||||
"Usage: ExecIF (<expr>|<app>|<data>)\n"
|
||||
"If <expr> is true, execute and return the result of <app>(<data>).\n"
|
||||
"If <expr> is true, but <app> is not found, then the application\n"
|
||||
"will return a non-zero value.\n";
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int exec_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
char *s, *appname, *endargs, args[MAXRESULT] = "";
|
||||
struct localuser *u;
|
||||
char *s, *appname, *endargs, args[MAXRESULT];
|
||||
struct ast_app *app;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
memset(args, 0, MAXRESULT);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa(data);
|
||||
appname = strsep(&s, "(");
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
endargs = strrchr(s, ')');
|
||||
if (endargs)
|
||||
*endargs = '\0';
|
||||
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
|
||||
}
|
||||
if (appname) {
|
||||
app = pbx_findapp(appname);
|
||||
if (app) {
|
||||
res = pbx_exec(chan, app, args);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
|
||||
res = -1;
|
||||
appname = strsep(&s, "(");
|
||||
if (s) {
|
||||
endargs = strrchr(s, ')');
|
||||
if (endargs)
|
||||
*endargs = '\0';
|
||||
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
|
||||
}
|
||||
if (appname) {
|
||||
app = pbx_findapp(appname);
|
||||
if (app) {
|
||||
res = pbx_exec(chan, app, args, 1);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
|
||||
res = -2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int tryexec_exec(struct ast_channel *chan, void *data)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
char *s, *appname, *endargs, args[MAXRESULT] = "";
|
||||
struct ast_app *app;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa(data);
|
||||
appname = strsep(&s, "(");
|
||||
if (s) {
|
||||
endargs = strrchr(s, ')');
|
||||
if (endargs)
|
||||
*endargs = '\0';
|
||||
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
|
||||
}
|
||||
if (appname) {
|
||||
app = pbx_findapp(appname);
|
||||
if (app) {
|
||||
res = pbx_exec(chan, app, args);
|
||||
pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
|
||||
pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOAPP");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app_exec);
|
||||
}
|
||||
|
||||
static int execif_exec(struct ast_channel *chan, void *data)
|
||||
int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
char *myapp = NULL;
|
||||
char *mydata = NULL;
|
||||
char *expr = NULL;
|
||||
struct ast_app *app = NULL;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
expr = ast_strdupa(data);
|
||||
|
||||
if ((myapp = strchr(expr,'|'))) {
|
||||
*myapp = '\0';
|
||||
myapp++;
|
||||
if ((mydata = strchr(myapp,'|'))) {
|
||||
*mydata = '\0';
|
||||
mydata++;
|
||||
} else
|
||||
mydata = "";
|
||||
|
||||
if (pbx_checkcondition(expr)) {
|
||||
if ((app = pbx_findapp(myapp))) {
|
||||
res = pbx_exec(chan, app, mydata);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Could not find application! (%s)\n", myapp);
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR,"Invalid Syntax.\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
return ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_exec);
|
||||
res |= ast_unregister_application(app_tryexec);
|
||||
res |= ast_unregister_application(app_execif);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
char *key()
|
||||
{
|
||||
int res = ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
|
||||
res |= ast_register_application(app_tryexec, tryexec_exec, tryexec_synopsis, tryexec_descrip);
|
||||
res |= ast_register_application(app_execif, execif_exec, execif_synopsis, execif_descrip);
|
||||
return res;
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Executes dialplan applications");
|
||||
|
||||
@@ -1,578 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Kevin P. Fleming <kpfleming@digium.com>
|
||||
*
|
||||
* Portions taken from the file-based music-on-hold work
|
||||
* created by Anthony Minessale II in res_musiconhold.c
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief External IVR application interface
|
||||
*
|
||||
* \author Kevin P. Fleming <kpfleming@digium.com>
|
||||
*
|
||||
* \note Portions taken from the file-based music-on-hold work
|
||||
* created by Anthony Minessale II in res_musiconhold.c
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static const char *app = "ExternalIVR";
|
||||
|
||||
static const char *synopsis = "Interfaces with an external IVR application";
|
||||
|
||||
static const char *descrip =
|
||||
" ExternalIVR(command[|arg[|arg...]]): Forks a process to run the supplied command,\n"
|
||||
"and starts a generator on the channel. The generator's play list is\n"
|
||||
"controlled by the external application, which can add and clear entries\n"
|
||||
"via simple commands issued over its stdout. The external application\n"
|
||||
"will receive all DTMF events received on the channel, and notification\n"
|
||||
"if the channel is hung up. The application will not be forcibly terminated\n"
|
||||
"when the channel is hung up.\n"
|
||||
"See doc/externalivr.txt for a protocol specification.\n";
|
||||
|
||||
/* XXX the parser in gcc 2.95 gets confused if you don't put a space between 'name' and the comma */
|
||||
#define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
|
||||
|
||||
struct playlist_entry {
|
||||
AST_LIST_ENTRY(playlist_entry) list;
|
||||
char filename[1];
|
||||
};
|
||||
|
||||
struct ivr_localuser {
|
||||
struct ast_channel *chan;
|
||||
AST_LIST_HEAD(playlist, playlist_entry) playlist;
|
||||
AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
|
||||
int abort_current_sound;
|
||||
int playing_silence;
|
||||
int option_autoclear;
|
||||
};
|
||||
|
||||
|
||||
struct gen_state {
|
||||
struct ivr_localuser *u;
|
||||
struct ast_filestream *stream;
|
||||
struct playlist_entry *current;
|
||||
int sample_queue;
|
||||
};
|
||||
|
||||
static void send_child_event(FILE *handle, const char event, const char *data,
|
||||
const struct ast_channel *chan)
|
||||
{
|
||||
char tmp[256];
|
||||
|
||||
if (!data) {
|
||||
snprintf(tmp, sizeof(tmp), "%c,%10d", event, (int)time(NULL));
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "%c,%10d,%s", event, (int)time(NULL), data);
|
||||
}
|
||||
|
||||
fprintf(handle, "%s\n", tmp);
|
||||
ast_chan_log(LOG_DEBUG, chan, "sent '%s'\n", tmp);
|
||||
}
|
||||
|
||||
static void *gen_alloc(struct ast_channel *chan, void *params)
|
||||
{
|
||||
struct ivr_localuser *u = params;
|
||||
struct gen_state *state;
|
||||
|
||||
if (!(state = ast_calloc(1, sizeof(*state))))
|
||||
return NULL;
|
||||
|
||||
state->u = u;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void gen_closestream(struct gen_state *state)
|
||||
{
|
||||
if (!state->stream)
|
||||
return;
|
||||
|
||||
ast_closestream(state->stream);
|
||||
state->u->chan->stream = NULL;
|
||||
state->stream = NULL;
|
||||
}
|
||||
|
||||
static void gen_release(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct gen_state *state = data;
|
||||
|
||||
gen_closestream(state);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/* caller has the playlist locked */
|
||||
static int gen_nextfile(struct gen_state *state)
|
||||
{
|
||||
struct ivr_localuser *u = state->u;
|
||||
char *file_to_stream;
|
||||
|
||||
u->abort_current_sound = 0;
|
||||
u->playing_silence = 0;
|
||||
gen_closestream(state);
|
||||
|
||||
while (!state->stream) {
|
||||
state->current = AST_LIST_REMOVE_HEAD(&u->playlist, list);
|
||||
if (state->current) {
|
||||
file_to_stream = state->current->filename;
|
||||
} else {
|
||||
file_to_stream = "silence/10";
|
||||
u->playing_silence = 1;
|
||||
}
|
||||
|
||||
if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
|
||||
ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
|
||||
if (!u->playing_silence) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (!state->stream);
|
||||
}
|
||||
|
||||
static struct ast_frame *gen_readframe(struct gen_state *state)
|
||||
{
|
||||
struct ast_frame *f = NULL;
|
||||
struct ivr_localuser *u = state->u;
|
||||
|
||||
if (u->abort_current_sound ||
|
||||
(u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
|
||||
gen_closestream(state);
|
||||
AST_LIST_LOCK(&u->playlist);
|
||||
gen_nextfile(state);
|
||||
AST_LIST_UNLOCK(&u->playlist);
|
||||
}
|
||||
|
||||
if (!(state->stream && (f = ast_readframe(state->stream)))) {
|
||||
if (state->current) {
|
||||
AST_LIST_LOCK(&u->finishlist);
|
||||
AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
|
||||
AST_LIST_UNLOCK(&u->finishlist);
|
||||
state->current = NULL;
|
||||
}
|
||||
if (!gen_nextfile(state))
|
||||
f = ast_readframe(state->stream);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct gen_state *state = data;
|
||||
struct ast_frame *f = NULL;
|
||||
int res = 0;
|
||||
|
||||
state->sample_queue += samples;
|
||||
|
||||
while (state->sample_queue > 0) {
|
||||
if (!(f = gen_readframe(state)))
|
||||
return -1;
|
||||
|
||||
res = ast_write(chan, f);
|
||||
ast_frfree(f);
|
||||
if (res < 0) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
state->sample_queue -= f->samples;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct ast_generator gen =
|
||||
{
|
||||
alloc: gen_alloc,
|
||||
release: gen_release,
|
||||
generate: gen_generate,
|
||||
};
|
||||
|
||||
static struct playlist_entry *make_entry(const char *filename)
|
||||
{
|
||||
struct playlist_entry *entry;
|
||||
|
||||
if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */
|
||||
return NULL;
|
||||
|
||||
strcpy(entry->filename, filename);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static int app_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *lu;
|
||||
struct playlist_entry *entry;
|
||||
const char *args = data;
|
||||
int child_stdin[2] = { 0,0 };
|
||||
int child_stdout[2] = { 0,0 };
|
||||
int child_stderr[2] = { 0,0 };
|
||||
int res = -1;
|
||||
int gen_active = 0;
|
||||
int pid;
|
||||
char *argv[32];
|
||||
int argc = 1;
|
||||
char *buf, *command;
|
||||
FILE *child_commands = NULL;
|
||||
FILE *child_errors = NULL;
|
||||
FILE *child_events = NULL;
|
||||
struct ivr_localuser foo = {
|
||||
.playlist = AST_LIST_HEAD_INIT_VALUE,
|
||||
.finishlist = AST_LIST_HEAD_INIT_VALUE,
|
||||
};
|
||||
struct ivr_localuser *u = &foo;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
lu = ast_module_user_add(chan);
|
||||
|
||||
sigfillset(&fullset);
|
||||
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
|
||||
|
||||
u->abort_current_sound = 0;
|
||||
u->chan = chan;
|
||||
|
||||
if (ast_strlen_zero(args)) {
|
||||
ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
|
||||
ast_module_user_remove(lu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = ast_strdupa(data);
|
||||
|
||||
argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
if (pipe(child_stdin)) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (pipe(child_stdout)) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (pipe(child_stderr)) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
ast_answer(chan);
|
||||
}
|
||||
|
||||
if (ast_activate_generator(chan, &gen, u) < 0) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
|
||||
goto exit;
|
||||
} else
|
||||
gen_active = 1;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!pid) {
|
||||
/* child process */
|
||||
int i;
|
||||
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
|
||||
|
||||
if (ast_opt_high_priority)
|
||||
ast_set_priority(0);
|
||||
|
||||
dup2(child_stdin[0], STDIN_FILENO);
|
||||
dup2(child_stdout[1], STDOUT_FILENO);
|
||||
dup2(child_stderr[1], STDERR_FILENO);
|
||||
for (i = STDERR_FILENO + 1; i < 1024; i++)
|
||||
close(i);
|
||||
execv(argv[0], argv);
|
||||
fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
|
||||
_exit(1);
|
||||
} else {
|
||||
/* parent process */
|
||||
int child_events_fd = child_stdin[1];
|
||||
int child_commands_fd = child_stdout[0];
|
||||
int child_errors_fd = child_stderr[0];
|
||||
struct ast_frame *f;
|
||||
int ms;
|
||||
int exception;
|
||||
int ready_fd;
|
||||
int waitfds[2] = { child_errors_fd, child_commands_fd };
|
||||
struct ast_channel *rchan;
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
|
||||
close(child_stdin[0]);
|
||||
child_stdin[0] = 0;
|
||||
close(child_stdout[1]);
|
||||
child_stdout[1] = 0;
|
||||
close(child_stderr[1]);
|
||||
child_stderr[1] = 0;
|
||||
|
||||
if (!(child_events = fdopen(child_events_fd, "w"))) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(child_commands = fdopen(child_commands_fd, "r"))) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(child_errors = fdopen(child_errors_fd, "r"))) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
setvbuf(child_events, NULL, _IONBF, 0);
|
||||
setvbuf(child_commands, NULL, _IONBF, 0);
|
||||
setvbuf(child_errors, NULL, _IONBF, 0);
|
||||
|
||||
res = 0;
|
||||
|
||||
while (1) {
|
||||
if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
|
||||
ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ast_check_hangup(chan)) {
|
||||
ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
|
||||
send_child_event(child_events, 'H', NULL, chan);
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
ready_fd = 0;
|
||||
ms = 100;
|
||||
errno = 0;
|
||||
exception = 0;
|
||||
|
||||
rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms);
|
||||
|
||||
if (!AST_LIST_EMPTY(&u->finishlist)) {
|
||||
AST_LIST_LOCK(&u->finishlist);
|
||||
while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
|
||||
send_child_event(child_events, 'F', entry->filename, chan);
|
||||
free(entry);
|
||||
}
|
||||
AST_LIST_UNLOCK(&u->finishlist);
|
||||
}
|
||||
|
||||
if (rchan) {
|
||||
/* the channel has something */
|
||||
f = ast_read(chan);
|
||||
if (!f) {
|
||||
ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
|
||||
send_child_event(child_events, 'H', NULL, chan);
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (f->frametype == AST_FRAME_DTMF) {
|
||||
send_child_event(child_events, f->subclass, NULL, chan);
|
||||
if (u->option_autoclear) {
|
||||
if (!u->abort_current_sound && !u->playing_silence)
|
||||
send_child_event(child_events, 'T', NULL, chan);
|
||||
AST_LIST_LOCK(&u->playlist);
|
||||
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
|
||||
send_child_event(child_events, 'D', entry->filename, chan);
|
||||
free(entry);
|
||||
}
|
||||
if (!u->playing_silence)
|
||||
u->abort_current_sound = 1;
|
||||
AST_LIST_UNLOCK(&u->playlist);
|
||||
}
|
||||
} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
|
||||
ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
|
||||
send_child_event(child_events, 'H', NULL, chan);
|
||||
ast_frfree(f);
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
} else if (ready_fd == child_commands_fd) {
|
||||
char input[1024];
|
||||
|
||||
if (exception || feof(child_commands)) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fgets(input, sizeof(input), child_commands))
|
||||
continue;
|
||||
|
||||
command = ast_strip(input);
|
||||
|
||||
ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);
|
||||
|
||||
if (strlen(input) < 4)
|
||||
continue;
|
||||
|
||||
if (input[0] == 'S') {
|
||||
if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
|
||||
send_child_event(child_events, 'Z', NULL, chan);
|
||||
strcpy(&input[2], "exception");
|
||||
}
|
||||
if (!u->abort_current_sound && !u->playing_silence)
|
||||
send_child_event(child_events, 'T', NULL, chan);
|
||||
AST_LIST_LOCK(&u->playlist);
|
||||
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
|
||||
send_child_event(child_events, 'D', entry->filename, chan);
|
||||
free(entry);
|
||||
}
|
||||
if (!u->playing_silence)
|
||||
u->abort_current_sound = 1;
|
||||
entry = make_entry(&input[2]);
|
||||
if (entry)
|
||||
AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
|
||||
AST_LIST_UNLOCK(&u->playlist);
|
||||
} else if (input[0] == 'A') {
|
||||
if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
|
||||
send_child_event(child_events, 'Z', NULL, chan);
|
||||
strcpy(&input[2], "exception");
|
||||
}
|
||||
entry = make_entry(&input[2]);
|
||||
if (entry) {
|
||||
AST_LIST_LOCK(&u->playlist);
|
||||
AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
|
||||
AST_LIST_UNLOCK(&u->playlist);
|
||||
}
|
||||
} else if (input[0] == 'H') {
|
||||
ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
|
||||
send_child_event(child_events, 'H', NULL, chan);
|
||||
break;
|
||||
} else if (input[0] == 'O') {
|
||||
if (!strcasecmp(&input[2], "autoclear"))
|
||||
u->option_autoclear = 1;
|
||||
else if (!strcasecmp(&input[2], "noautoclear"))
|
||||
u->option_autoclear = 0;
|
||||
else
|
||||
ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
|
||||
}
|
||||
} else if (ready_fd == child_errors_fd) {
|
||||
char input[1024];
|
||||
|
||||
if (exception || feof(child_errors)) {
|
||||
ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fgets(input, sizeof(input), child_errors)) {
|
||||
command = ast_strip(input);
|
||||
ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
|
||||
}
|
||||
} else if ((ready_fd < 0) && ms) {
|
||||
if (errno == 0 || errno == EINTR)
|
||||
continue;
|
||||
|
||||
ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (gen_active)
|
||||
ast_deactivate_generator(chan);
|
||||
|
||||
if (child_events)
|
||||
fclose(child_events);
|
||||
|
||||
if (child_commands)
|
||||
fclose(child_commands);
|
||||
|
||||
if (child_errors)
|
||||
fclose(child_errors);
|
||||
|
||||
if (child_stdin[0])
|
||||
close(child_stdin[0]);
|
||||
|
||||
if (child_stdin[1])
|
||||
close(child_stdin[1]);
|
||||
|
||||
if (child_stdout[0])
|
||||
close(child_stdout[0]);
|
||||
|
||||
if (child_stdout[1])
|
||||
close(child_stdout[1]);
|
||||
|
||||
if (child_stderr[0])
|
||||
close(child_stderr[0]);
|
||||
|
||||
if (child_stderr[1])
|
||||
close(child_stderr[1]);
|
||||
|
||||
while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
|
||||
free(entry);
|
||||
|
||||
ast_module_user_remove(lu);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, app_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");
|
||||
@@ -1,35 +1,26 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Connect to festival
|
||||
*
|
||||
* Copyright (C) 2002, Christos Ricudis
|
||||
*
|
||||
* Christos Ricudis <ricudis@itc.auth.gr>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Connect to festival
|
||||
*
|
||||
* \author Christos Ricudis <ricudis@itc.auth.gr>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/md5.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
@@ -46,19 +37,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/md5.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "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";
|
||||
@@ -68,6 +51,9 @@ static char *descrip =
|
||||
"play it to the user, allowing any given interrupt keys to immediately terminate and return\n"
|
||||
"the value, or 'any' to allow any number back (useful in dialplan)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static char *socket_receive_file_to_buff(int fd,int *size)
|
||||
{
|
||||
@@ -82,10 +68,7 @@ static char *socket_receive_file_to_buff(int fd,int *size)
|
||||
char c;
|
||||
|
||||
bufflen = 1024;
|
||||
if (!(buff = ast_malloc(bufflen)))
|
||||
{
|
||||
/* TODO: Handle memory allocation failure */
|
||||
}
|
||||
buff = (char *)malloc(bufflen);
|
||||
*size=0;
|
||||
|
||||
for (k=0; file_stuff_key[k] != '\0';)
|
||||
@@ -95,10 +78,7 @@ static char *socket_receive_file_to_buff(int fd,int *size)
|
||||
if ((*size)+k+1 >= bufflen)
|
||||
{ /* +1 so you can add a NULL if you want */
|
||||
bufflen += bufflen/4;
|
||||
if (!(buff = ast_realloc(buff, bufflen)))
|
||||
{
|
||||
/* TODO: Handle memory allocation failure */
|
||||
}
|
||||
buff = (char *)realloc(buff,bufflen);
|
||||
}
|
||||
if (file_stuff_key[k] == c)
|
||||
k++;
|
||||
@@ -130,27 +110,17 @@ static int send_waveform_to_fd(char *waveform, int length, int fd) {
|
||||
#ifdef __PPC__
|
||||
char c;
|
||||
#endif
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
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;
|
||||
}
|
||||
for (x=0;x<256;x++) {
|
||||
if (x != fd)
|
||||
close(x);
|
||||
}
|
||||
if (ast_opt_high_priority)
|
||||
ast_set_priority(0);
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
|
||||
/*IAS */
|
||||
//IAS
|
||||
#ifdef __PPC__
|
||||
for( x=0; x<length; x+=2)
|
||||
{
|
||||
@@ -178,9 +148,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
||||
struct ast_frame f;
|
||||
char offset[AST_FRIENDLY_OFFSET];
|
||||
char frdata[2048];
|
||||
} myf = {
|
||||
.f = { 0, },
|
||||
};
|
||||
} myf;
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
@@ -191,8 +159,7 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
ast_answer(chan);
|
||||
ast_stopstream(chan);
|
||||
ast_indicate(chan, -1);
|
||||
|
||||
|
||||
owriteformat = chan->writeformat;
|
||||
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
@@ -240,18 +207,17 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
||||
myf.f.subclass = AST_FORMAT_SLINEAR;
|
||||
myf.f.datalen = res;
|
||||
myf.f.samples = res / 2;
|
||||
myf.f.mallocd = 0;
|
||||
myf.f.offset = AST_FRIENDLY_OFFSET;
|
||||
myf.f.src = __PRETTY_FUNCTION__;
|
||||
myf.f.data = myf.frdata;
|
||||
if (ast_write(chan, &myf.f) < 0) {
|
||||
res = -1;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
if (res < needed) { /* last frame */
|
||||
if (res < needed) { // last frame
|
||||
ast_log(LOG_DEBUG, "Last frame\n");
|
||||
res=0;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -264,9 +230,8 @@ static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, in
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
/* if (pid > -1) */
|
||||
/* kill(pid, SIGKILL); */
|
||||
// if (pid > -1)
|
||||
// kill(pid, SIGKILL);
|
||||
if (!res && owriteformat)
|
||||
ast_set_write_format(chan, owriteformat);
|
||||
return res;
|
||||
@@ -282,16 +247,16 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
{
|
||||
int usecache;
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct hostent *serverhost;
|
||||
struct ast_hostent ahp;
|
||||
int fd;
|
||||
FILE *fs;
|
||||
const char *host;
|
||||
const char *cachedir;
|
||||
const char *temp;
|
||||
const char *festivalcommand;
|
||||
char *host;
|
||||
char *cachedir;
|
||||
char *temp;
|
||||
char *festivalcommand;
|
||||
int port=1314;
|
||||
int n;
|
||||
char ack[4];
|
||||
@@ -311,22 +276,13 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
int fdesc = -1;
|
||||
char buffer[16384];
|
||||
int seekpos = 0;
|
||||
char *data;
|
||||
char data[256] = "";
|
||||
char *intstr;
|
||||
|
||||
struct ast_config *cfg;
|
||||
char *newfestivalcommand;
|
||||
|
||||
if (ast_strlen_zero(vdata)) {
|
||||
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
cfg = ast_config_load(FESTIVAL_CONFIG);
|
||||
cfg = ast_load(FESTIVAL_CONFIG);
|
||||
if (!cfg) {
|
||||
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
if (!(host = ast_variable_retrieve(cfg, "general", "host"))) {
|
||||
@@ -347,34 +303,20 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
}
|
||||
if (!(festivalcommand = ast_variable_retrieve(cfg, "general", "festivalcommand"))) {
|
||||
festivalcommand = "(tts_textasterisk \"%s\" 'file)(quit)\n";
|
||||
} else { /* This else parses the festivalcommand that we're sent from the config file for \n's, etc */
|
||||
int i, j;
|
||||
newfestivalcommand = alloca(strlen(festivalcommand) + 1);
|
||||
|
||||
for (i = 0, j = 0; i < strlen(festivalcommand); i++) {
|
||||
if (festivalcommand[i] == '\\' && festivalcommand[i + 1] == 'n') {
|
||||
newfestivalcommand[j++] = '\n';
|
||||
i++;
|
||||
} else if (festivalcommand[i] == '\\') {
|
||||
newfestivalcommand[j++] = festivalcommand[i + 1];
|
||||
i++;
|
||||
} else
|
||||
newfestivalcommand[j++] = festivalcommand[i];
|
||||
}
|
||||
newfestivalcommand[j] = '\0';
|
||||
festivalcommand = newfestivalcommand;
|
||||
}
|
||||
|
||||
data = ast_strdupa(vdata);
|
||||
|
||||
intstr = strchr(data, '|');
|
||||
if (intstr) {
|
||||
if (!vdata || ast_strlen_zero(vdata)) {
|
||||
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
|
||||
ast_destroy(cfg);
|
||||
return -1;
|
||||
}
|
||||
strncpy(data, vdata, sizeof(data) - 1);
|
||||
if ((intstr = strchr(data, '|'))) {
|
||||
*intstr = '\0';
|
||||
intstr++;
|
||||
if (!strcasecmp(intstr, "any"))
|
||||
intstr = AST_DIGIT_ANY;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_log(LOG_DEBUG, "Text passed to festival server : %s\n",(char *)data);
|
||||
/* Connect to local festival server */
|
||||
|
||||
@@ -382,8 +324,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
|
||||
if (fd < 0) {
|
||||
ast_log(LOG_WARNING,"festival_client: can't get socket\n");
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
ast_destroy(cfg);
|
||||
return -1;
|
||||
}
|
||||
memset(&serv_addr, 0, sizeof(serv_addr));
|
||||
@@ -392,8 +333,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
serverhost = ast_gethostbyname(host, &ahp);
|
||||
if (serverhost == (struct hostent *)0) {
|
||||
ast_log(LOG_WARNING,"festival_client: gethostbyname failed\n");
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
ast_destroy(cfg);
|
||||
return -1;
|
||||
}
|
||||
memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
|
||||
@@ -403,8 +343,7 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) {
|
||||
ast_log(LOG_WARNING,"festival_client: connect to server failed\n");
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
ast_destroy(cfg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -484,23 +423,8 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
/* This assumes only one waveform will come back, also LP is unlikely */
|
||||
wave = 0;
|
||||
do {
|
||||
int read_data;
|
||||
for (n=0; n < 3; )
|
||||
{
|
||||
read_data = read(fd,ack+n,3-n);
|
||||
/* this avoids falling in infinite loop
|
||||
* in case that festival server goes down
|
||||
* */
|
||||
if ( read_data == -1 )
|
||||
{
|
||||
ast_log(LOG_WARNING,"Unable to read from cache/festival fd\n");
|
||||
close(fd);
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
n += read_data;
|
||||
}
|
||||
n += read(fd,ack+n,3-n);
|
||||
ack[3] = '\0';
|
||||
if (strcmp(ack,"WV\n") == 0) { /* receive a waveform */
|
||||
ast_log(LOG_DEBUG,"Festival WV command\n");
|
||||
@@ -522,32 +446,37 @@ static int festival_exec(struct ast_channel *chan, void *vdata)
|
||||
}
|
||||
} while (strcmp(ack,"OK\n") != 0);
|
||||
close(fd);
|
||||
ast_config_destroy(cfg);
|
||||
ast_module_user_remove(u);
|
||||
ast_destroy(cfg);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
struct ast_config *cfg = ast_config_load(FESTIVAL_CONFIG);
|
||||
if (!cfg) {
|
||||
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
|
||||
return AST_MODULE_LOAD_DECLINE;
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
|
||||
return ast_register_application(app, festival_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Simple Festival Interface");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
112
apps/app_flash.c
112
apps/app_flash.c
@@ -1,65 +1,50 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to flash a zap trunk
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to flash a zap trunk
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>zaptel</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/zaptel.h>
|
||||
#else
|
||||
#include <zaptel.h>
|
||||
#endif /* __linux__ */
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <zaptel/zaptel.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Flash zap trunk application";
|
||||
|
||||
static char *app = "Flash";
|
||||
|
||||
static char *synopsis = "Flashes a Zap Trunk";
|
||||
|
||||
static char *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";
|
||||
" Flash(): Sends a flash on a zap trunk. This is only a hack for\n"
|
||||
"people who want to perform transfers and such via AGI and is generally\n"
|
||||
"quite useless otherwise. Returns 0 on success or -1 if this is not\n"
|
||||
"a zap trunk\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static inline int zt_wait_event(int fd)
|
||||
{
|
||||
@@ -75,10 +60,10 @@ static int flash_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = -1;
|
||||
int x;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
struct zt_params ztp;
|
||||
u = ast_module_user_add(chan);
|
||||
if (!strcasecmp(chan->tech->type, "Zap")) {
|
||||
LOCAL_USER_ADD(u);
|
||||
if (!strcasecmp(chan->type, "Zap")) {
|
||||
memset(&ztp, 0, sizeof(ztp));
|
||||
res = ioctl(chan->fds[0], ZT_GET_PARAMS, &ztp);
|
||||
if (!res) {
|
||||
@@ -101,25 +86,34 @@ static int flash_exec(struct ast_channel *chan, void *data)
|
||||
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 Zap channel\n", chan->name);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, 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;
|
||||
}
|
||||
|
||||
1113
apps/app_followme.c
1113
apps/app_followme.c
File diff suppressed because it is too large
Load Diff
@@ -1,114 +1,90 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Anthony Minessale anthmct@yahoo.com
|
||||
* Fork CDR application
|
||||
* Copyright Anthony Minessale anthmct@yahoo.com
|
||||
* Development of this app Sponsered/Funded by TAAN Softworks Corp
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Fork CDR application
|
||||
*
|
||||
* \author Anthony Minessale anthmct@yahoo.com
|
||||
*
|
||||
* \note Development of this app Sponsored/Funded by TAAN Softworks Corp
|
||||
*
|
||||
* \ingroup applications
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/cdr.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/cdr.h"
|
||||
#include "asterisk/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\n"
|
||||
"If the option 'v' is passed all cdr variables will be passed along also.\n";
|
||||
" ForkCDR(): Causes the Call Data Record to fork an additional\n"
|
||||
"cdr record starting from the time of the fork call\n";
|
||||
|
||||
|
||||
static void ast_cdr_fork(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_cdr *cdr;
|
||||
struct ast_cdr *newcdr;
|
||||
struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS };
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
cdr = chan->cdr;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
while (cdr->next)
|
||||
cdr = cdr->next;
|
||||
|
||||
if (!(newcdr = ast_cdr_dup(cdr)))
|
||||
return;
|
||||
|
||||
ast_cdr_append(cdr, newcdr);
|
||||
ast_cdr_reset(newcdr, &flags);
|
||||
|
||||
if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS))
|
||||
ast_cdr_free_vars(cdr, 0);
|
||||
|
||||
ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED);
|
||||
|
||||
static void ast_cdr_clone(struct ast_cdr *cdr) {
|
||||
struct ast_cdr *newcdr = ast_cdr_alloc();
|
||||
memcpy(newcdr,cdr,sizeof(struct ast_cdr));
|
||||
ast_cdr_append(cdr,newcdr);
|
||||
gettimeofday(&newcdr->start, NULL);
|
||||
memset(&newcdr->answer, 0, sizeof(newcdr->answer));
|
||||
ast_cdr_add_flag(cdr,AST_CDR_FLAG_CHILD|AST_CDR_FLAG_LOCKED);
|
||||
}
|
||||
|
||||
static void ast_cdr_fork(struct ast_channel *chan) {
|
||||
if(chan && chan->cdr) {
|
||||
ast_cdr_clone(chan->cdr);
|
||||
}
|
||||
}
|
||||
|
||||
static int forkcdr_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!chan->cdr) {
|
||||
ast_log(LOG_WARNING, "Channel does not have a CDR\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!ast_strlen_zero(data))
|
||||
ast_set2_flag(chan->cdr, strchr(data, 'v'), AST_CDR_FLAG_KEEP_VARS);
|
||||
|
||||
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();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, forkcdr_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,47 +1,30 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Execute arbitrary system commands
|
||||
*
|
||||
* Copyright (C) 1999-2005, Digium
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Get ADSI CPE ID
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/adsi.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/adsi.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Get ADSI CPE ID";
|
||||
|
||||
static char *app = "GetCPEID";
|
||||
|
||||
@@ -49,8 +32,12 @@ static char *synopsis = "Get ADSI CPE ID";
|
||||
|
||||
static char *descrip =
|
||||
" GetCPEID: Obtains and displays ADSI CPE ID and other information in order\n"
|
||||
"to properly setup zapata.conf for on-hook operations.\n";
|
||||
"to properly setup zapata.conf for on-hook operations.\n"
|
||||
"Returns -1 on hangup only.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice)
|
||||
{
|
||||
@@ -60,42 +47,43 @@ static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice)
|
||||
for (x=0;x<4;x++)
|
||||
tmp[x] = stuff[x];
|
||||
tmp[4] = NULL;
|
||||
return ast_adsi_print(chan, tmp, justify, voice);
|
||||
return adsi_print(chan, tmp, justify, voice);
|
||||
}
|
||||
|
||||
static int cpeid_exec(struct ast_channel *chan, void *idata)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
unsigned char cpeid[4];
|
||||
int gotgeometry = 0;
|
||||
int gotcpeid = 0;
|
||||
int width, height, buttons;
|
||||
char *data[4];
|
||||
unsigned int x;
|
||||
char data[4][80];
|
||||
char *stuff[4];
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
for (x = 0; x < 4; x++)
|
||||
data[x] = alloca(80);
|
||||
|
||||
strcpy(data[0], "** CPE Info **");
|
||||
strcpy(data[1], "Identifying CPE...");
|
||||
strcpy(data[2], "Please wait...");
|
||||
res = ast_adsi_load_session(chan, NULL, 0, 1);
|
||||
LOCAL_USER_ADD(u);
|
||||
stuff[0] = data[0];
|
||||
stuff[1] = data[1];
|
||||
stuff[2] = data[2];
|
||||
stuff[3] = data[3];
|
||||
memset(data, 0, sizeof(data));
|
||||
strncpy(stuff[0], "** CPE Info **", sizeof(data[0]) - 1);
|
||||
strncpy(stuff[1], "Identifying CPE...", sizeof(data[1]) - 1);
|
||||
strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
|
||||
res = adsi_load_session(chan, NULL, 0, 1);
|
||||
if (res > 0) {
|
||||
cpeid_setstatus(chan, data, 0);
|
||||
res = ast_adsi_get_cpeid(chan, cpeid, 0);
|
||||
cpeid_setstatus(chan, stuff, 0);
|
||||
res = adsi_get_cpeid(chan, cpeid, 0);
|
||||
if (res > 0) {
|
||||
gotcpeid = 1;
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Got CPEID of '%02x:%02x:%02x:%02x' on '%s'\n", cpeid[0], cpeid[1], cpeid[2], cpeid[3], chan->name);
|
||||
}
|
||||
if (res > -1) {
|
||||
strcpy(data[1], "Measuring CPE...");
|
||||
strcpy(data[2], "Please wait...");
|
||||
cpeid_setstatus(chan, data, 0);
|
||||
res = ast_adsi_get_cpeinfo(chan, &width, &height, &buttons, 0);
|
||||
strncpy(stuff[1], "Measuring CPE...", sizeof(data[1]) - 1);
|
||||
strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
|
||||
cpeid_setstatus(chan, stuff, 0);
|
||||
res = adsi_get_cpeinfo(chan, &width, &height, &buttons, 0);
|
||||
if (res > -1) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "CPE has %d lines, %d columns, and %d buttons on '%s'\n", height, width, buttons, chan->name);
|
||||
@@ -104,15 +92,15 @@ static int cpeid_exec(struct ast_channel *chan, void *idata)
|
||||
}
|
||||
if (res > -1) {
|
||||
if (gotcpeid)
|
||||
snprintf(data[1], 80, "CPEID: %02x:%02x:%02x:%02x", cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
|
||||
snprintf(stuff[1], sizeof(data[1]), "CPEID: %02x:%02x:%02x:%02x", cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
|
||||
else
|
||||
strcpy(data[1], "CPEID Unknown");
|
||||
strncpy(stuff[1], "CPEID Unknown", sizeof(data[1]) - 1);
|
||||
if (gotgeometry)
|
||||
snprintf(data[2], 80, "Geom: %dx%d, %d buttons", width, height, buttons);
|
||||
snprintf(stuff[2], sizeof(data[2]), "Geom: %dx%d, %d buttons", width, height, buttons);
|
||||
else
|
||||
strcpy(data[2], "Geometry unknown");
|
||||
strcpy(data[3], "Press # to exit");
|
||||
cpeid_setstatus(chan, data, 1);
|
||||
strncpy(stuff[2], "Geometry unknown", sizeof(data[2]) - 1);
|
||||
strncpy(stuff[3], "Press # to exit", sizeof(data[3]) - 1);
|
||||
cpeid_setstatus(chan, stuff, 1);
|
||||
for(;;) {
|
||||
res = ast_waitfordigit(chan, 1000);
|
||||
if (res < 0)
|
||||
@@ -122,27 +110,37 @@ static int cpeid_exec(struct ast_channel *chan, void *idata)
|
||||
break;
|
||||
}
|
||||
}
|
||||
ast_adsi_unload_session(chan);
|
||||
adsi_unload_session(chan);
|
||||
}
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, cpeid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get ADSI CPE ID");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
224
apps/app_groupcount.c
Normal file
224
apps/app_groupcount.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Group Manipulation Applications
|
||||
*
|
||||
* Copyright (c) 2004 Digium
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/utils.h>
|
||||
|
||||
static char *tdesc = "Group Management Routines";
|
||||
|
||||
static char *app_group_count = "GetGroupCount";
|
||||
static char *app_group_set = "SetGroup";
|
||||
static char *app_group_check = "CheckGroup";
|
||||
|
||||
static char *group_count_synopsis = "GetGroupCount([groupname][@category])";
|
||||
static char *group_set_synopsis = "SetGroup(groupname[@category])";
|
||||
static char *group_check_synopsis = "CheckGroup(max[@category])";
|
||||
|
||||
static char *group_count_descrip =
|
||||
"GetGroupCount([group][@category])\n"
|
||||
" Calculates the group count for the specified group, or uses\n"
|
||||
"the current channel's group if not specifed (and non-empty).\n"
|
||||
"Stores result in GROUPCOUNT. Always returns 0.\n";
|
||||
|
||||
static char *group_set_descrip =
|
||||
"SetGroup(group)\n"
|
||||
" Sets the channel group to the specified value. Equivalent to\n"
|
||||
"SetVar(GROUP=group). Always returns 0.\n";
|
||||
|
||||
static char *group_check_descrip =
|
||||
"CheckGroup(max)\n"
|
||||
" Checks that the current number of total channels in the\n"
|
||||
"current channel's group does not exceed 'max'. If the number\n"
|
||||
"does not exceed 'max', we continue to the next step. If the\n"
|
||||
"number does in fact exceed max, if priority n+101 exists, then\n"
|
||||
"execution continues at that step, otherwise -1 is returned.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#define DEFAULT_CATEGORY "GROUP"
|
||||
|
||||
static int group_get_count(char *group, char *category)
|
||||
{
|
||||
struct ast_channel *chan;
|
||||
int count = 0;
|
||||
char *test;
|
||||
if (group && !ast_strlen_zero(group)) {
|
||||
chan = ast_channel_walk_locked(NULL);
|
||||
while(chan) {
|
||||
test = pbx_builtin_getvar_helper(chan, category);
|
||||
if (test && !strcasecmp(test, group))
|
||||
count++;
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
chan = ast_channel_walk_locked(chan);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static int group_count_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int count;
|
||||
struct localuser *u;
|
||||
char *group=NULL;
|
||||
char *cat = NULL;
|
||||
char ret[80]="";
|
||||
char tmp[256]="";
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data && !ast_strlen_zero(data)) {
|
||||
strncpy(tmp, data, sizeof(tmp) - 1);
|
||||
group = tmp;
|
||||
cat = strchr(tmp, '@');
|
||||
if (cat) {
|
||||
*cat = '\0';
|
||||
cat++;
|
||||
}
|
||||
}
|
||||
if (cat)
|
||||
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
|
||||
else
|
||||
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
|
||||
|
||||
if (!group || ast_strlen_zero(group)) {
|
||||
group = pbx_builtin_getvar_helper(chan, ret);
|
||||
}
|
||||
count = group_get_count(group, ret);
|
||||
snprintf(ret, sizeof(ret), "%d", count);
|
||||
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_set_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char ret[80] = "";
|
||||
char tmp[256] = "";
|
||||
char *cat=NULL, *group=NULL;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data && !ast_strlen_zero(data)) {
|
||||
strncpy(tmp, data, sizeof(tmp) - 1);
|
||||
group = tmp;
|
||||
cat = strchr(tmp, '@');
|
||||
if (cat) {
|
||||
*cat = '\0';
|
||||
cat++;
|
||||
}
|
||||
}
|
||||
if (cat)
|
||||
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
|
||||
else
|
||||
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
|
||||
|
||||
if (group && !ast_strlen_zero(group)) {
|
||||
pbx_builtin_setvar_helper(chan, ret, group);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "SetGroup requires an argument (group name)\n");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_check_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int max, count;
|
||||
struct localuser *u;
|
||||
char ret[80] = "";
|
||||
char tmp[256] = "";
|
||||
char *cat, *group;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (data && !ast_strlen_zero(data)) {
|
||||
strncpy(tmp, data, sizeof(tmp) - 1);
|
||||
group = tmp;
|
||||
cat = strchr(tmp, '@');
|
||||
if (cat) {
|
||||
*cat = '\0';
|
||||
cat++;
|
||||
}
|
||||
if ((sscanf((char *)tmp, "%i", &max) == 1) && (max > -1)) {
|
||||
if (cat)
|
||||
snprintf(ret, sizeof(ret), "GROUP_%s", cat);
|
||||
else
|
||||
strncpy(ret, DEFAULT_CATEGORY, sizeof(ret) - 1);
|
||||
|
||||
count = group_get_count(pbx_builtin_getvar_helper(chan, ret), ret);
|
||||
if (count > max) {
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority += 100;
|
||||
else
|
||||
res = -1;
|
||||
}
|
||||
} else
|
||||
ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
|
||||
} else
|
||||
ast_log(LOG_WARNING, "CheckGroup requires an argument(max)\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
res = ast_unregister_application(app_group_count);
|
||||
res |= ast_unregister_application(app_group_set);
|
||||
res |= ast_unregister_application(app_group_check);
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
|
||||
res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
|
||||
res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Changes Copyright (c) 2004 - 2006 Todd Freeman <freeman@andrews.edu>
|
||||
* HasVoicemail application
|
||||
* Changes Copyright (c) 2004 Todd Freeman <freeman@andrews.edu>
|
||||
*
|
||||
* 95% based on HasNewVoicemail by:
|
||||
*
|
||||
@@ -9,217 +10,160 @@
|
||||
*
|
||||
* Tilghman Lesher <asterisk-hasnewvoicemail-app@the-tilghman.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief HasVoicemail application
|
||||
*
|
||||
* \author Todd Freeman <freeman@andrews.edu>
|
||||
*
|
||||
* \note 95% based on HasNewVoicemail by
|
||||
* Tilghman Lesher <asterisk-hasnewvoicemail-app@the-tilghman.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "../astconf.h"
|
||||
|
||||
static char *tdesc = "Indicator for whether a voice mailbox has messages in a given folder.";
|
||||
static char *app_hasvoicemail = "HasVoicemail";
|
||||
static char *hasvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
|
||||
static char *hasvoicemail_synopsis = "Conditionally branches to priority + 101";
|
||||
static char *hasvoicemail_descrip =
|
||||
"HasVoicemail(vmbox[/folder][@context][|varname[|options]])\n"
|
||||
"HasVoicemail(vmbox[@context][:folder][|varname])\n"
|
||||
" Branches to priority + 101, if there is voicemail in folder indicated."
|
||||
" Optionally sets <varname> to the number of messages in that folder."
|
||||
" Assumes folder of INBOX if not specified.\n"
|
||||
" The option string may contain zero or the following character:\n"
|
||||
" 'j' -- jump to priority n+101, if there is voicemail in the folder indicated.\n"
|
||||
" This application sets the following channel variable upon completion:\n"
|
||||
" HASVMSTATUS The result of the voicemail check returned as a text string as follows\n"
|
||||
" <# of messages in the folder, 0 for NONE>\n"
|
||||
"\nThis application has been deprecated in favor of the VMCOUNT() function\n";
|
||||
" Assumes folder of INBOX if not specified.\n";
|
||||
|
||||
static char *app_hasnewvoicemail = "HasNewVoicemail";
|
||||
static char *hasnewvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
|
||||
static char *hasnewvoicemail_synopsis = "Conditionally branches to priority + 101";
|
||||
static char *hasnewvoicemail_descrip =
|
||||
"HasNewVoicemail(vmbox[/folder][@context][|varname[|options]])\n"
|
||||
"Assumes folder 'INBOX' if folder is not specified. Optionally sets <varname> to the number of messages\n"
|
||||
"in that folder.\n"
|
||||
" The option string may contain zero of the following character:\n"
|
||||
" 'j' -- jump to priority n+101, if there is new voicemail in folder 'folder' or INBOX\n"
|
||||
" This application sets the following channel variable upon completion:\n"
|
||||
" HASVMSTATUS The result of the new voicemail check returned as a text string as follows\n"
|
||||
" <# of messages in the folder, 0 for NONE>\n"
|
||||
"\nThis application has been deprecated in favor of the VMCOUNT() function\n";
|
||||
"HasNewVoicemail(vmbox[@context][|varname])\n"
|
||||
" Branches to priority + 101, if there is voicemail in folder INBOX."
|
||||
" Optionally sets <varname> to the number of messages in that folder.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char *input, *varname = NULL, *vmbox, *context = "default";
|
||||
char *vmfolder;
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char vmpath[256], *temps, *input, *varname = NULL, *vmbox, *vmfolder = "INBOX", *context = "default";
|
||||
DIR *vmdir;
|
||||
struct dirent *vment;
|
||||
int vmcount = 0;
|
||||
static int dep_warning = 0;
|
||||
int priority_jump = 0;
|
||||
char tmp[12];
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(vmbox);
|
||||
AST_APP_ARG(varname);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The applications HasVoicemail and HasNewVoicemail have been deprecated. Please use the VMCOUNT() function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "HasVoicemail requires an argument (vm-box[/folder][@context][|varname[|options]])\n");
|
||||
ast_log(LOG_WARNING, "HasVoicemail requires an argument (vm-box[@context][:folder]|varname)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
input = ast_strdupa((char *)data);
|
||||
if (input) {
|
||||
temps = input;
|
||||
if ((temps = strsep(&input, "|"))) {
|
||||
if (input && !ast_strlen_zero(input))
|
||||
varname = input;
|
||||
input = temps;
|
||||
}
|
||||
if ((temps = strsep(&input, ":"))) {
|
||||
if (input && !ast_strlen_zero(input))
|
||||
vmfolder = input;
|
||||
input = temps;
|
||||
}
|
||||
if ((vmbox = strsep(&input, "@")))
|
||||
if (input && !ast_strlen_zero(input))
|
||||
context = input;
|
||||
if (!vmbox)
|
||||
vmbox = input;
|
||||
|
||||
input = ast_strdupa(data);
|
||||
snprintf(vmpath,sizeof(vmpath), "%s/voicemail/%s/%s/%s", (char *)ast_config_AST_SPOOL_DIR, context, vmbox, vmfolder);
|
||||
if (!(vmdir = opendir(vmpath))) {
|
||||
ast_log(LOG_NOTICE, "Voice mailbox %s at %s does not exist\n", vmbox, vmpath);
|
||||
} else {
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, input);
|
||||
/* No matter what the format of VM, there will always be a .txt file for each message. */
|
||||
while ((vment = readdir(vmdir)))
|
||||
if (!strncmp(vment->d_name + 7,".txt",4))
|
||||
vmcount++;
|
||||
closedir(vmdir);
|
||||
}
|
||||
/* Set the count in the channel variable */
|
||||
if (varname) {
|
||||
char tmp[12];
|
||||
snprintf(tmp, sizeof(tmp), "%d", vmcount);
|
||||
pbx_builtin_setvar_helper(chan, varname, tmp);
|
||||
}
|
||||
|
||||
vmbox = strsep(&args.vmbox, "@");
|
||||
|
||||
if (!ast_strlen_zero(args.vmbox))
|
||||
context = args.vmbox;
|
||||
|
||||
vmfolder = strchr(vmbox, '/');
|
||||
if (vmfolder) {
|
||||
*vmfolder = '\0';
|
||||
vmfolder++;
|
||||
} else {
|
||||
vmfolder = "INBOX";
|
||||
}
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
vmcount = ast_app_messagecount(context, vmbox, vmfolder);
|
||||
/* Set the count in the channel variable */
|
||||
if (varname) {
|
||||
snprintf(tmp, sizeof(tmp), "%d", vmcount);
|
||||
pbx_builtin_setvar_helper(chan, varname, tmp);
|
||||
}
|
||||
|
||||
if (vmcount > 0) {
|
||||
/* Branch to the next extension */
|
||||
if (priority_jump || ast_opt_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
if (vmcount > 0) {
|
||||
/* Branch to the next extension */
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
|
||||
chan->priority += 100;
|
||||
} else
|
||||
ast_log(LOG_WARNING, "VM box %s@%s has new voicemail, but extension %s, priority %d doesn't exist\n", vmbox, context, chan->exten, chan->priority + 101);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%d", vmcount);
|
||||
pbx_builtin_setvar_helper(chan, "HASVMSTATUS", tmp);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acf_vmcount_exec(struct ast_channel *chan, char *cmd, char *argsstr, char *buf, size_t len)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char *context;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(vmbox);
|
||||
AST_APP_ARG(folder);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(argsstr))
|
||||
return -1;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, argsstr);
|
||||
|
||||
if (strchr(args.vmbox, '@')) {
|
||||
context = args.vmbox;
|
||||
args.vmbox = strsep(&context, "@");
|
||||
} else {
|
||||
context = "default";
|
||||
ast_log(LOG_ERROR, "Out of memory error\n");
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.folder)) {
|
||||
args.folder = "INBOX";
|
||||
}
|
||||
|
||||
snprintf(buf, len, "%d", ast_app_messagecount(context, args.vmbox, args.folder));
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_custom_function acf_vmcount = {
|
||||
.name = "VMCOUNT",
|
||||
.synopsis = "Counts the voicemail in a specified mailbox",
|
||||
.syntax = "VMCOUNT(vmbox[@context][|folder])",
|
||||
.desc =
|
||||
" context - defaults to \"default\"\n"
|
||||
" folder - defaults to \"INBOX\"\n",
|
||||
.read = acf_vmcount_exec,
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_unregister(&acf_vmcount);
|
||||
res |= ast_unregister_application(app_hasvoicemail);
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
res = ast_unregister_application(app_hasvoicemail);
|
||||
res |= ast_unregister_application(app_hasnewvoicemail);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_register(&acf_vmcount);
|
||||
res |= ast_register_application(app_hasvoicemail, hasvoicemail_exec, hasvoicemail_synopsis, hasvoicemail_descrip);
|
||||
res = ast_register_application(app_hasvoicemail, hasvoicemail_exec, hasvoicemail_synopsis, hasvoicemail_descrip);
|
||||
res |= ast_register_application(app_hasnewvoicemail, hasvoicemail_exec, hasnewvoicemail_synopsis, hasnewvoicemail_descrip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Indicator for whether a voice mailbox has messages in a given folder.");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
131
apps/app_ices.c
131
apps/app_ices.c
@@ -1,34 +1,24 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -37,20 +27,13 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "../astconf.h"
|
||||
|
||||
#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";
|
||||
|
||||
static char *synopsis = "Encode and stream using 'ices'";
|
||||
@@ -58,34 +41,24 @@ 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 examples/asterisk-ices.conf). \n";
|
||||
"for ices (see examples/asterisk-ices.conf). Returns -1 on\n"
|
||||
"hangup or 0 otherwise.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int icesencode(char *filename, int fd)
|
||||
{
|
||||
int res;
|
||||
int x;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -96,13 +69,13 @@ static int icesencode(char *filename, int fd)
|
||||
/* As a last-ditch effort, try to use PATH */
|
||||
execlp("ices", "ices", filename, (char *)NULL);
|
||||
ast_log(LOG_WARNING, "Execute of ices failed\n");
|
||||
_exit(0);
|
||||
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;
|
||||
@@ -112,24 +85,20 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
struct ast_frame *f;
|
||||
char filename[256]="";
|
||||
char *c;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
last.tv_usec = 0;
|
||||
last.tv_sec = 0;
|
||||
if (!data || !strlen(data)) {
|
||||
ast_log(LOG_WARNING, "ICES requires an argument (configfile.xml)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
last = ast_tv(0, 0);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
flags = fcntl(fds[1], F_GETFL);
|
||||
fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_stopstream(chan);
|
||||
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
@@ -139,7 +108,6 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
ast_log(LOG_WARNING, "Answer failed!\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -149,11 +117,10 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
if (((char *)data)[0] == '/')
|
||||
ast_copy_string(filename, (char *) data, sizeof(filename));
|
||||
strncpy(filename, (char *)data, sizeof(filename) - 1);
|
||||
else
|
||||
snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
|
||||
/* Placeholder for options */
|
||||
@@ -184,7 +151,6 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
if (errno != EAGAIN) {
|
||||
ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
|
||||
res = -1;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -193,31 +159,38 @@ static int ices_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
}
|
||||
close(fds[1]);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (pid > -1)
|
||||
kill(pid, SIGKILL);
|
||||
if (!res && oreadformat)
|
||||
ast_set_read_format(chan, oreadformat);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, ices_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Encode and Stream via icecast and ices");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
142
apps/app_image.c
142
apps/app_image.c
@@ -1,125 +1,89 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to transmit an image
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to transmit an image
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Image Transmission Application";
|
||||
|
||||
static char *app = "SendImage";
|
||||
|
||||
static char *synopsis = "Send an image file";
|
||||
|
||||
static char *descrip =
|
||||
" SendImage(filename): Sends an image on a channel. \n"
|
||||
"If the channel supports image transport but the image send\n"
|
||||
"fails, the channel will be hung up. Otherwise, the dialplan\n"
|
||||
"continues execution.\n"
|
||||
"The option string may contain the following character:\n"
|
||||
" 'j' -- jump to priority n+101 if the channel doesn't support image transport\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" SENDIMAGESTATUS The status is the result of the attempt as a text string, one of\n"
|
||||
" OK | NOSUPPORT \n";
|
||||
" SendImage(filename): Sends an image on a channel. If the channel\n"
|
||||
"does not support image transport, and there exists a step with\n"
|
||||
"priority n + 101, then execution will continue at that step.\n"
|
||||
"Otherwise, execution will continue at the next priority level.\n"
|
||||
"SendImage only returns 0 if the image was sent correctly or if\n"
|
||||
"the channel does not support image transport, and -1 otherwise.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int sendimage_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
char *parse;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(filename);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (ast_strlen_zero(args.filename)) {
|
||||
ast_log(LOG_WARNING, "SendImage requires an argument (filename[|options])\n");
|
||||
struct localuser *u;
|
||||
if (!data || !strlen((char *)data)) {
|
||||
ast_log(LOG_WARNING, "SendImage requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
if (!ast_supports_images(chan)) {
|
||||
/* Does not support transport */
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
pbx_builtin_setvar_helper(chan, "SENDIMAGESTATUS", "NOSUPPORT");
|
||||
ast_module_user_remove(u);
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority += 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = ast_send_image(chan, args.filename);
|
||||
|
||||
if (!res)
|
||||
pbx_builtin_setvar_helper(chan, "SENDIMAGESTATUS", "OK");
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
res = ast_send_image(chan, data);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, sendimage_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Image Transmission Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
207
apps/app_intercom.c
Normal file
207
apps/app_intercom.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Use /dev/dsp as an intercom.
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/soundcard.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/soundcard.h>
|
||||
#else
|
||||
#include <soundcard.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#define DEV_DSP "/dev/audio"
|
||||
#else
|
||||
#define DEV_DSP "/dev/dsp"
|
||||
#endif
|
||||
|
||||
/* Number of 32 byte buffers -- each buffer is 2 ms */
|
||||
#define BUFFER_SIZE 32
|
||||
|
||||
static char *tdesc = "Intercom using /dev/dsp for output";
|
||||
|
||||
static char *app = "Intercom";
|
||||
|
||||
static char *synopsis = "(Obsolete) Send to Intercom";
|
||||
static char *descrip =
|
||||
" Intercom(): Sends the user to the intercom (i.e. /dev/dsp). This program\n"
|
||||
"is generally considered obselete by the chan_oss module. Returns 0 if the\n"
|
||||
"user exits with a DTMF tone, or -1 if they hangup.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
AST_MUTEX_DEFINE_STATIC(sound_lock);
|
||||
static int sound = -1;
|
||||
|
||||
static int write_audio(short *data, int len)
|
||||
{
|
||||
int res;
|
||||
struct audio_buf_info info;
|
||||
ast_mutex_lock(&sound_lock);
|
||||
if (sound < 0) {
|
||||
ast_log(LOG_WARNING, "Sound device closed?\n");
|
||||
ast_mutex_unlock(&sound_lock);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(sound, SNDCTL_DSP_GETOSPACE, &info)) {
|
||||
ast_log(LOG_WARNING, "Unable to read output space\n");
|
||||
ast_mutex_unlock(&sound_lock);
|
||||
return -1;
|
||||
}
|
||||
res = write(sound, data, len);
|
||||
ast_mutex_unlock(&sound_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int create_audio(void)
|
||||
{
|
||||
int fmt, desired, res, fd;
|
||||
fd = open(DEV_DSP, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
fmt = 0;
|
||||
res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
/* 8000 Hz desired */
|
||||
desired = 8000;
|
||||
fmt = desired;
|
||||
res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (fmt != desired) {
|
||||
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
|
||||
}
|
||||
#if 1
|
||||
/* 2 bytes * 15 units of 2^5 = 32 bytes per buffer */
|
||||
fmt = ((BUFFER_SIZE) << 16) | (0x0005);
|
||||
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
|
||||
}
|
||||
#endif
|
||||
sound = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intercom_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
struct ast_frame *f;
|
||||
int oreadformat;
|
||||
LOCAL_USER_ADD(u);
|
||||
/* Remember original read format */
|
||||
oreadformat = chan->readformat;
|
||||
/* Set mode to signed linear */
|
||||
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
/* Read packets from the channel */
|
||||
while(!res) {
|
||||
res = ast_waitfor(chan, -1);
|
||||
if (res > 0) {
|
||||
res = 0;
|
||||
f = ast_read(chan);
|
||||
if (f) {
|
||||
if (f->frametype == AST_FRAME_DTMF) {
|
||||
ast_frfree(f);
|
||||
break;
|
||||
} else {
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
if (f->subclass == AST_FORMAT_SLINEAR) {
|
||||
res = write_audio(f->data, f->datalen);
|
||||
if (res > 0)
|
||||
res = 0;
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
|
||||
}
|
||||
}
|
||||
ast_frfree(f);
|
||||
} else
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (!res)
|
||||
ast_set_read_format(chan, oreadformat);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
if (sound > -1)
|
||||
close(sound);
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
if (create_audio())
|
||||
return -1;
|
||||
return ast_register_application(app, intercom_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief IVR Demo application
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<defaultenabled>no</defaultenabled>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "IVR Demo Application";
|
||||
static char *app = "IVRDemo";
|
||||
static char *synopsis =
|
||||
" This is a skeleton application that shows you the basic structure to create your\n"
|
||||
"own asterisk applications and demonstrates the IVR demo.\n";
|
||||
|
||||
static int ivr_demo_func(struct ast_channel *chan, void *data)
|
||||
{
|
||||
ast_verbose("IVR Demo, data is %s!\n", (char *)data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_IVR_DECLARE_MENU(ivr_submenu, "IVR Demo Sub Menu", 0,
|
||||
{
|
||||
{ "s", AST_ACTION_BACKGROUND, "demo-abouttotry" },
|
||||
{ "s", AST_ACTION_WAITOPTION },
|
||||
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
|
||||
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
|
||||
{ "1", AST_ACTION_RESTART },
|
||||
{ "2", AST_ACTION_PLAYLIST, "digits/2;digits/3" },
|
||||
{ "3", AST_ACTION_CALLBACK, ivr_demo_func },
|
||||
{ "4", AST_ACTION_TRANSFER, "demo|s|1" },
|
||||
{ "*", AST_ACTION_REPEAT },
|
||||
{ "#", AST_ACTION_UPONE },
|
||||
{ NULL }
|
||||
});
|
||||
|
||||
AST_IVR_DECLARE_MENU(ivr_demo, "IVR Demo Main Menu", 0,
|
||||
{
|
||||
{ "s", AST_ACTION_BACKGROUND, "demo-congrats" },
|
||||
{ "g", AST_ACTION_BACKGROUND, "demo-instruct" },
|
||||
{ "g", AST_ACTION_WAITOPTION },
|
||||
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
|
||||
{ "1", AST_ACTION_RESTART },
|
||||
{ "2", AST_ACTION_MENU, &ivr_submenu },
|
||||
{ "2", AST_ACTION_RESTART },
|
||||
{ "i", AST_ACTION_PLAYBACK, "invalid" },
|
||||
{ "i", AST_ACTION_REPEAT, (void *)(unsigned long)2 },
|
||||
{ "#", AST_ACTION_EXIT },
|
||||
{ NULL },
|
||||
});
|
||||
|
||||
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* Do our thing here */
|
||||
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
res = ast_answer(chan);
|
||||
if (!res)
|
||||
res = ast_ivr_menu_run(chan, &ivr_demo, data);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, skel_exec, tdesc, synopsis);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "IVR Demo Application");
|
||||
@@ -1,160 +1,114 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to lookup the callerid number, and see if it is blacklisted
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to lookup the callerid number, and see if it is blacklisted
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/astdb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/options.h"
|
||||
static char *tdesc = "Look up Caller*ID name/number from blacklist database";
|
||||
|
||||
static char *app = "LookupBlacklist";
|
||||
|
||||
static char *synopsis = "Look up Caller*ID name/number from blacklist database";
|
||||
|
||||
static char *descrip =
|
||||
" LookupBlacklist(options): Looks up the Caller*ID number on the active\n"
|
||||
"channel in the Asterisk database (family 'blacklist'). \n"
|
||||
"The option string may contain the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the number/name is found in the blacklist\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" LOOKUPBLSTATUS The status of the Blacklist lookup as a text string, one of\n"
|
||||
" FOUND | NOTFOUND\n"
|
||||
"Example: exten => 1234,1,LookupBlacklist()\n\n"
|
||||
"This application is deprecated and may be removed from a future release.\n"
|
||||
"Please use the dialplan function BLACKLIST() instead.\n";
|
||||
" LookupBlacklist: Looks up the Caller*ID number on the active\n"
|
||||
"channel in the Asterisk database (family 'blacklist'). If the\n"
|
||||
"number is found, and if there exists a priority n + 101,\n"
|
||||
"where 'n' is the priority of the current instance, then the\n"
|
||||
"channel will be setup to continue at that priority level.\n"
|
||||
"Otherwise, it returns 0. Does nothing if no Caller*ID was received on the\n"
|
||||
"channel.\n"
|
||||
"Example: database put blacklist <name/number> 1\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static int blacklist_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
char blacklist[1];
|
||||
int bl = 0;
|
||||
|
||||
if (chan->cid.cid_num) {
|
||||
if (!ast_db_get("blacklist", chan->cid.cid_num, blacklist, sizeof (blacklist)))
|
||||
bl = 1;
|
||||
}
|
||||
if (chan->cid.cid_name) {
|
||||
if (!ast_db_get("blacklist", chan->cid.cid_name, blacklist, sizeof (blacklist)))
|
||||
bl = 1;
|
||||
}
|
||||
|
||||
snprintf(buf, len, "%d", bl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function blacklist_function = {
|
||||
.name = "BLACKLIST",
|
||||
.synopsis = "Check if the callerid is on the blacklist",
|
||||
.desc = "Uses astdb to check if the Caller*ID is in family 'blacklist'. Returns 1 or 0.\n",
|
||||
.syntax = "BLACKLIST()",
|
||||
.read = blacklist_read,
|
||||
};
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int
|
||||
lookupblacklist_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
char old_cid[144] = "", *num, *name;
|
||||
char blacklist[1];
|
||||
struct ast_module_user *u;
|
||||
char shrunknum[64] = "";
|
||||
struct localuser *u;
|
||||
int bl = 0;
|
||||
int priority_jump = 0;
|
||||
static int dep_warning = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!dep_warning) {
|
||||
dep_warning = 1;
|
||||
ast_log(LOG_WARNING, "LookupBlacklist is deprecated. Please use ${BLACKLIST()} instead.\n");
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(data)) {
|
||||
if (strchr(data, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (chan->cid.cid_num) {
|
||||
if (!ast_db_get("blacklist", chan->cid.cid_num, blacklist, sizeof (blacklist))) {
|
||||
LOCAL_USER_ADD (u);
|
||||
if (chan->callerid)
|
||||
{
|
||||
strncpy (old_cid, chan->callerid, sizeof (old_cid) - 1);
|
||||
ast_callerid_parse (old_cid, &name, &num);
|
||||
if (num)
|
||||
strncpy (shrunknum, num, sizeof (shrunknum) - 1);
|
||||
else
|
||||
num = shrunknum;
|
||||
|
||||
ast_shrink_phone_number (shrunknum);
|
||||
if (!ast_db_get ("blacklist", shrunknum, blacklist, sizeof (blacklist)))
|
||||
{
|
||||
if (option_verbose > 2)
|
||||
ast_log(LOG_NOTICE, "Blacklisted number %s found\n",chan->cid.cid_num);
|
||||
ast_log(LOG_NOTICE, "Blacklisted number %s found\n",shrunknum);
|
||||
bl = 1;
|
||||
}
|
||||
else if (!ast_db_get ("blacklist", name, blacklist, sizeof (blacklist)))
|
||||
{
|
||||
if (option_verbose > 2)
|
||||
ast_log (LOG_NOTICE,"Blacklisted name \"%s\" found\n",name);
|
||||
bl = 1;
|
||||
}
|
||||
}
|
||||
if (chan->cid.cid_name) {
|
||||
if (!ast_db_get("blacklist", chan->cid.cid_name, blacklist, sizeof (blacklist))) {
|
||||
if (option_verbose > 2)
|
||||
ast_log (LOG_NOTICE,"Blacklisted name \"%s\" found\n",chan->cid.cid_name);
|
||||
bl = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bl) {
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "FOUND");
|
||||
} else
|
||||
pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "NOTFOUND");
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
|
||||
if (bl && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority+=100;
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
res |= ast_custom_function_unregister(&blacklist_function);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application (app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module (void)
|
||||
{
|
||||
int res = ast_custom_function_register(&blacklist_function);
|
||||
res |= ast_register_application (app, lookupblacklist_exec, synopsis,descrip);
|
||||
return ast_register_application (app, lookupblacklist_exec, synopsis,descrip);
|
||||
}
|
||||
|
||||
char *description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Look up Caller*ID name/number from blacklist database");
|
||||
char *key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,49 +1,31 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to set callerid name from database, based on directory number
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set callerid name from database, based on directory number
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/astdb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
static char *tdesc = "Look up CallerID Name from local database";
|
||||
|
||||
static char *app = "LookupCIDName";
|
||||
|
||||
@@ -55,49 +37,75 @@ static char *descrip =
|
||||
"Caller*ID name. Does nothing if no Caller*ID was received on the\n"
|
||||
"channel. This is useful if you do not subscribe to Caller*ID\n"
|
||||
"name delivery, or if you want to change the names on some incoming\n"
|
||||
"calls.\n\n"
|
||||
"LookupCIDName is deprecated. Please use ${DB(cidname/${CALLERID(num)})}\n"
|
||||
"instead.\n";
|
||||
"calls. Always returns 0.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static int lookupcidname_exec (struct ast_channel *chan, void *data)
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int
|
||||
lookupcidname_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
char dbname[64];
|
||||
struct ast_module_user *u;
|
||||
static int dep_warning = 0;
|
||||
char old_cid[144] = "", *num, *name;
|
||||
char new_cid[144];
|
||||
char dbname[64];
|
||||
char shrunknum[64] = "";
|
||||
struct localuser *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
if (!dep_warning) {
|
||||
dep_warning = 1;
|
||||
ast_log(LOG_WARNING, "LookupCIDName is deprecated. Please use ${DB(cidname/${CALLERID(num)})} instead.\n");
|
||||
LOCAL_USER_ADD (u);
|
||||
if (chan->callerid)
|
||||
{
|
||||
strncpy (old_cid, chan->callerid, sizeof (old_cid) - 1);
|
||||
ast_callerid_parse (old_cid, &name, &num); /* this destroys the original string */
|
||||
if (num) /* It's possible to get an empty number */
|
||||
strncpy (shrunknum, num, sizeof (shrunknum) - 1);
|
||||
else
|
||||
num = shrunknum;
|
||||
ast_shrink_phone_number (shrunknum);
|
||||
if (!ast_db_get ("cidname", shrunknum, dbname, sizeof (dbname)))
|
||||
{
|
||||
snprintf (new_cid, sizeof (new_cid), "\"%s\" <%s>", dbname, num);
|
||||
ast_set_callerid (chan, new_cid, 0);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",
|
||||
new_cid);
|
||||
}
|
||||
if (chan->cid.cid_num) {
|
||||
if (!ast_db_get ("cidname", chan->cid.cid_num, dbname, sizeof (dbname))) {
|
||||
ast_set_callerid (chan, NULL, dbname, NULL);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID name to %s\n",
|
||||
dbname);
|
||||
}
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int
|
||||
unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application (app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application (app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int
|
||||
load_module (void)
|
||||
{
|
||||
return ast_register_application (app, lookupcidname_exec, synopsis, descrip);
|
||||
return ast_register_application (app, lookupcidname_exec, synopsis,
|
||||
descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Look up CallerID Name from local database");
|
||||
char *
|
||||
description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int
|
||||
usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
722
apps/app_macro.c
722
apps/app_macro.c
@@ -1,557 +1,253 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Macro Implementation
|
||||
*
|
||||
* Copyright (C) 2003, Digium
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Dial plan macro Implementation
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_ARGS 80
|
||||
|
||||
/* special result value used to force macro exit */
|
||||
#define MACRO_EXIT_RESULT 1024
|
||||
static char *tdesc = "Extension Macros";
|
||||
|
||||
static char *descrip =
|
||||
" Macro(macroname|arg1|arg2...): Executes a macro using the context\n"
|
||||
"'macro-<macroname>', jumping to the 's' extension of that context and\n"
|
||||
"executing each step, then returning when the steps end. \n"
|
||||
"The calling extension, context, and priority are stored in ${MACRO_EXTEN}, \n"
|
||||
"executing each step, then returning when the steps end. The calling\n"
|
||||
"extension, context, and priority are stored in ${MACRO_EXTEN}, \n"
|
||||
"${MACRO_CONTEXT} and ${MACRO_PRIORITY} respectively. Arguments become\n"
|
||||
"${ARG1}, ${ARG2}, etc in the macro context.\n"
|
||||
"If you Goto out of the Macro context, the Macro will terminate and control\n"
|
||||
"will be returned at the location of the Goto.\n"
|
||||
"If ${MACRO_OFFSET} is set at termination, Macro will attempt to continue\n"
|
||||
"at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n"
|
||||
"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";
|
||||
|
||||
static char *if_descrip =
|
||||
" MacroIf(<expr>?macroname_a[|arg1][:macroname_b[|arg1]])\n"
|
||||
"Executes macro defined in <macroname_a> if <expr> is true\n"
|
||||
"(otherwise <macroname_b> if provided)\n"
|
||||
"Arguments and return values as in application macro()\n";
|
||||
|
||||
static char *exclusive_descrip =
|
||||
" MacroExclusive(macroname|arg1|arg2...):\n"
|
||||
"Executes macro defined in the context 'macro-macroname'\n"
|
||||
"Only one call at a time may run the macro.\n"
|
||||
"(we'll wait if another call is busy executing in the Macro)\n"
|
||||
"Arguments and return values as in application Macro()\n";
|
||||
|
||||
static char *exit_descrip =
|
||||
" MacroExit():\n"
|
||||
"Causes the currently running macro to exit as if it had\n"
|
||||
"ended normally by running out of priorities to execute.\n"
|
||||
"If used outside a macro, will likely cause unexpected\n"
|
||||
"behavior.\n";
|
||||
"${ARG1}, ${ARG2}, etc in the macro context. Macro returns -1 if\n"
|
||||
"any step in the macro returns -1, and 0 otherwise. If you Goto out\n"
|
||||
"of the Macro context, the Macro will terminate and control will be return\n"
|
||||
"at the location of the Goto. Otherwise if ${MACRO_OFFSET} is set at\n"
|
||||
"termination, Macro will attempt to continue at priority\n"
|
||||
"MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.\n";
|
||||
|
||||
static char *app = "Macro";
|
||||
static char *if_app = "MacroIf";
|
||||
static char *exclusive_app = "MacroExclusive";
|
||||
static char *exit_app = "MacroExit";
|
||||
|
||||
static char *synopsis = "Macro Implementation";
|
||||
static char *if_synopsis = "Conditional Macro Implementation";
|
||||
static char *exclusive_synopsis = "Exclusive Macro Implementation";
|
||||
static char *exit_synopsis = "Exit From Macro";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
|
||||
{
|
||||
struct ast_exten *e;
|
||||
struct ast_include *i;
|
||||
struct ast_context *c2;
|
||||
|
||||
for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
|
||||
if (ast_extension_match(ast_get_extension_name(e), exten)) {
|
||||
int needmatch = ast_get_extension_matchcid(e);
|
||||
if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
|
||||
(!needmatch)) {
|
||||
/* This is the matching extension we want */
|
||||
struct ast_exten *p;
|
||||
for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
|
||||
if (priority != ast_get_extension_priority(p))
|
||||
continue;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No match; run through includes */
|
||||
for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
|
||||
for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
|
||||
if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
|
||||
e = find_matching_priority(c2, exten, priority, callerid);
|
||||
if (e)
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
|
||||
{
|
||||
const char *s;
|
||||
char *tmp;
|
||||
char *cur, *rest;
|
||||
char *macro;
|
||||
char fullmacro[80];
|
||||
char varname[80];
|
||||
char runningapp[80], runningdata[1024];
|
||||
char *oldargs[MAX_ARGS + 1] = { NULL, };
|
||||
int argc, x;
|
||||
int res=0;
|
||||
char oldexten[256]="";
|
||||
int oldpriority, gosub_level = 0;
|
||||
char pc[80], depthc[12];
|
||||
char oldcontext[AST_MAX_CONTEXT] = "";
|
||||
const char *inhangupc;
|
||||
int offset, depth = 0, maxdepth = 7;
|
||||
int setmacrocontext=0;
|
||||
int autoloopflag, dead = 0, inhangup = 0;
|
||||
|
||||
char *save_macro_exten;
|
||||
char *save_macro_context;
|
||||
char *save_macro_priority;
|
||||
char *save_macro_offset;
|
||||
struct ast_module_user *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);
|
||||
|
||||
/* does the user want a deeper rabbit hole? */
|
||||
s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION");
|
||||
if (s)
|
||||
sscanf(s, "%d", &maxdepth);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (depth >= maxdepth) {
|
||||
ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
snprintf(depthc, sizeof(depthc), "%d", depth + 1);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
rest = tmp;
|
||||
macro = strsep(&rest, "|");
|
||||
if (ast_strlen_zero(macro)) {
|
||||
ast_log(LOG_WARNING, "Invalid macro name specified\n");
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
|
||||
if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->cid.cid_num)) {
|
||||
if (!ast_context_find(fullmacro))
|
||||
ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
|
||||
else
|
||||
ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we are to run the macro exclusively, take the mutex */
|
||||
if (exclusive) {
|
||||
ast_log(LOG_DEBUG, "Locking macrolock for '%s'\n", fullmacro);
|
||||
ast_autoservice_start(chan);
|
||||
if (ast_context_lockmacro(fullmacro)) {
|
||||
ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
|
||||
ast_autoservice_stop(chan);
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
ast_autoservice_stop(chan);
|
||||
}
|
||||
|
||||
/* Save old info */
|
||||
oldpriority = chan->priority;
|
||||
ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
|
||||
ast_copy_string(oldcontext, chan->context, sizeof(oldcontext));
|
||||
if (ast_strlen_zero(chan->macrocontext)) {
|
||||
ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext));
|
||||
ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten));
|
||||
chan->macropriority = chan->priority;
|
||||
setmacrocontext=1;
|
||||
}
|
||||
argc = 1;
|
||||
/* Save old macro variables */
|
||||
save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
|
||||
|
||||
save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
|
||||
|
||||
save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
|
||||
snprintf(pc, sizeof(pc), "%d", oldpriority);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
|
||||
|
||||
save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
|
||||
|
||||
/* Setup environment for new run */
|
||||
chan->exten[0] = 's';
|
||||
chan->exten[1] = '\0';
|
||||
ast_copy_string(chan->context, fullmacro, sizeof(chan->context));
|
||||
chan->priority = 1;
|
||||
|
||||
while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
|
||||
const char *s;
|
||||
/* Save copy of old arguments if we're overwriting some, otherwise
|
||||
let them pass through to the other macro */
|
||||
snprintf(varname, sizeof(varname), "ARG%d", argc);
|
||||
s = pbx_builtin_getvar_helper(chan, varname);
|
||||
if (s)
|
||||
oldargs[argc] = ast_strdup(s);
|
||||
pbx_builtin_setvar_helper(chan, varname, cur);
|
||||
argc++;
|
||||
}
|
||||
autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
|
||||
ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
|
||||
while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
|
||||
struct ast_context *c;
|
||||
struct ast_exten *e;
|
||||
runningapp[0] = '\0';
|
||||
runningdata[0] = '\0';
|
||||
|
||||
/* 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')) ||
|
||||
(res == '*') || (res == '#')) {
|
||||
/* Just return result as to the previous application as if it had been dialed */
|
||||
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
|
||||
break;
|
||||
}
|
||||
switch(res) {
|
||||
case MACRO_EXIT_RESULT:
|
||||
res = 0;
|
||||
goto out;
|
||||
case AST_PBX_KEEPALIVE:
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
|
||||
else if (option_verbose > 1)
|
||||
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
|
||||
goto out;
|
||||
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 (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);
|
||||
goto out;
|
||||
}
|
||||
chan->priority++;
|
||||
}
|
||||
out:
|
||||
/* 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);
|
||||
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]) {
|
||||
if (!dead)
|
||||
pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
|
||||
free(oldargs[x]);
|
||||
} else if (!dead) {
|
||||
pbx_builtin_setvar_helper(chan, varname, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore macro variables */
|
||||
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)
|
||||
free(save_macro_context);
|
||||
if (save_macro_priority)
|
||||
free(save_macro_priority);
|
||||
|
||||
if (!dead && setmacrocontext) {
|
||||
chan->macrocontext[0] = '\0';
|
||||
chan->macroexten[0] = '\0';
|
||||
chan->macropriority = 0;
|
||||
}
|
||||
|
||||
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
|
||||
normally if there is any problem */
|
||||
if (sscanf(offsets, "%d", &offset) == 1) {
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->cid.cid_num)) {
|
||||
chan->priority += 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_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int macro_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return _macro_exec(chan, data, 0);
|
||||
}
|
||||
char tmp[256] = "";
|
||||
char *cur, *rest;
|
||||
char *macro;
|
||||
char fullmacro[80];
|
||||
char varname[80];
|
||||
char *oldargs[MAX_ARGS + 1] = { NULL, };
|
||||
int argc, x;
|
||||
int res=0;
|
||||
char oldexten[256]="";
|
||||
int oldpriority;
|
||||
char pc[80];
|
||||
char oldcontext[256] = "";
|
||||
char *offsets;
|
||||
int offset;
|
||||
int setmacrocontext=0;
|
||||
|
||||
char *save_macro_exten;
|
||||
char *save_macro_context;
|
||||
char *save_macro_priority;
|
||||
char *save_macro_offset;
|
||||
|
||||
if (!data || ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Invalid Macro incantation\n");
|
||||
return 0;
|
||||
}
|
||||
strncpy(tmp, data, sizeof(tmp) - 1);
|
||||
rest = tmp;
|
||||
macro = strsep(&rest, "|");
|
||||
if (!macro || ast_strlen_zero(macro)) {
|
||||
ast_log(LOG_WARNING, "Invalid macro name specified\n");
|
||||
return 0;
|
||||
}
|
||||
snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
|
||||
if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->callerid)) {
|
||||
if (!ast_context_find(fullmacro))
|
||||
ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
|
||||
else
|
||||
ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
|
||||
return 0;
|
||||
}
|
||||
/* Save old info */
|
||||
oldpriority = chan->priority;
|
||||
strncpy(oldexten, chan->exten, sizeof(oldexten) - 1);
|
||||
strncpy(oldcontext, chan->context, sizeof(oldcontext) - 1);
|
||||
if (ast_strlen_zero(chan->macrocontext)) {
|
||||
strncpy(chan->macrocontext, chan->context, sizeof(chan->macrocontext) - 1);
|
||||
strncpy(chan->macroexten, chan->exten, sizeof(chan->macroexten) - 1);
|
||||
chan->macropriority = chan->priority;
|
||||
setmacrocontext=1;
|
||||
}
|
||||
argc = 1;
|
||||
/* Save old macro variables */
|
||||
save_macro_exten = pbx_builtin_getvar_helper(chan, "MACRO_EXTEN");
|
||||
if (save_macro_exten) save_macro_exten = strdup(save_macro_exten);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
|
||||
|
||||
static int macroexclusive_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return _macro_exec(chan, data, 1);
|
||||
}
|
||||
save_macro_context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT");
|
||||
if (save_macro_context) save_macro_context = strdup(save_macro_context);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
|
||||
|
||||
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;
|
||||
save_macro_priority = pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY");
|
||||
if (save_macro_priority) save_macro_priority = strdup(save_macro_priority);
|
||||
snprintf(pc, sizeof(pc), "%d", oldpriority);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
|
||||
|
||||
save_macro_offset = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET");
|
||||
if (save_macro_offset) save_macro_offset = strdup(save_macro_offset);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
/* Setup environment for new run */
|
||||
chan->exten[0] = 's';
|
||||
chan->exten[1] = '\0';
|
||||
strncpy(chan->context, fullmacro, sizeof(chan->context) - 1);
|
||||
chan->priority = 1;
|
||||
|
||||
if (!(expr = ast_strdupa(data))) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((label_a = strchr(expr, '?'))) {
|
||||
*label_a = '\0';
|
||||
label_a++;
|
||||
if ((label_b = strchr(label_a, ':'))) {
|
||||
*label_b = '\0';
|
||||
label_b++;
|
||||
while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
|
||||
/* Save copy of old arguments if we're overwriting some, otherwise
|
||||
let them pass through to the other macro */
|
||||
snprintf(varname, sizeof(varname), "ARG%d", argc);
|
||||
oldargs[argc] = pbx_builtin_getvar_helper(chan, varname);
|
||||
if (oldargs[argc])
|
||||
oldargs[argc] = strdup(oldargs[argc]);
|
||||
pbx_builtin_setvar_helper(chan, varname, cur);
|
||||
argc++;
|
||||
}
|
||||
while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
|
||||
if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid))) {
|
||||
/* Something bad happened, or a hangup has been requested. */
|
||||
if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
|
||||
(res == '*') || (res == '#')) {
|
||||
/* Just return result as to the previous application as if it had been dialed */
|
||||
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
|
||||
break;
|
||||
}
|
||||
if (pbx_checkcondition(expr))
|
||||
res = macro_exec(chan, label_a);
|
||||
else if (label_b)
|
||||
res = macro_exec(chan, label_b);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Invalid Syntax.\n");
|
||||
switch(res) {
|
||||
case AST_PBX_KEEPALIVE:
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
|
||||
else if (option_verbose > 1)
|
||||
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
|
||||
else if (option_verbose > 1)
|
||||
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (strcasecmp(chan->context, fullmacro)) {
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
|
||||
break;
|
||||
}
|
||||
/* don't stop executing extensions when we're in "h" */
|
||||
if (chan->_softhangup && strcasecmp(oldexten,"h")) {
|
||||
ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
|
||||
chan->exten, chan->priority);
|
||||
goto out;
|
||||
}
|
||||
chan->priority++;
|
||||
}
|
||||
out:
|
||||
for (x=1;x<argc;x++) {
|
||||
/* Restore old arguments and delete ours */
|
||||
snprintf(varname, sizeof(varname), "ARG%d", x);
|
||||
if (oldargs[x]) {
|
||||
pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
|
||||
free(oldargs[x]);
|
||||
} else {
|
||||
pbx_builtin_setvar_helper(chan, varname, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
/* Restore macro variables */
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
|
||||
if (save_macro_exten) free(save_macro_exten);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
|
||||
if (save_macro_context) free(save_macro_context);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
|
||||
if (save_macro_priority) free(save_macro_priority);
|
||||
if (setmacrocontext) {
|
||||
chan->macrocontext[0] = '\0';
|
||||
chan->macroexten[0] = '\0';
|
||||
chan->macropriority = 0;
|
||||
}
|
||||
|
||||
return res;
|
||||
if (!strcasecmp(chan->context, fullmacro)) {
|
||||
/* If we're leaving the macro normally, restore original information */
|
||||
chan->priority = oldpriority;
|
||||
strncpy(chan->context, oldcontext, sizeof(chan->context) - 1);
|
||||
if (!(chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO)) {
|
||||
/* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
|
||||
strncpy(chan->exten, oldexten, sizeof(chan->exten) - 1);
|
||||
if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
|
||||
/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
|
||||
normally if there is any problem */
|
||||
if (sscanf(offsets, "%d", &offset) == 1) {
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->callerid)) {
|
||||
chan->priority += offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
|
||||
if (save_macro_offset) free(save_macro_offset);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int macro_exit_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
return MACRO_EXIT_RESULT;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, macro_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(if_app);
|
||||
res |= ast_unregister_application(exit_app);
|
||||
res |= ast_unregister_application(app);
|
||||
res |= ast_unregister_application(exclusive_app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
char *key()
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
|
||||
res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
|
||||
res |= ast_register_application(exclusive_app, macroexclusive_exec, exclusive_synopsis, exclusive_descrip);
|
||||
res |= ast_register_application(app, macro_exec, synopsis, descrip);
|
||||
|
||||
return res;
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros");
|
||||
|
||||
4966
apps/app_meetme.c
4966
apps/app_meetme.c
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,29 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Digital Milliwatt Test
|
||||
*
|
||||
* Copyright (C) 2002, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Digital Milliwatt Test
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "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";
|
||||
|
||||
@@ -50,12 +32,19 @@ static char *synopsis = "Generate a Constant 1000Hz tone at 0dbm (mu-law)";
|
||||
static char *descrip =
|
||||
"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)
|
||||
@@ -66,34 +55,31 @@ static void milliwatt_release(struct ast_channel *chan, void *data)
|
||||
|
||||
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
unsigned char buf[AST_FRIENDLY_OFFSET + 640];
|
||||
const int maxsamples = sizeof (buf) / sizeof (buf[0]);
|
||||
int i, *indexp = (int *) data;
|
||||
struct ast_frame wf = {
|
||||
.frametype = AST_FRAME_VOICE,
|
||||
.subclass = AST_FORMAT_ULAW,
|
||||
.offset = AST_FRIENDLY_OFFSET,
|
||||
.data = buf + AST_FRIENDLY_OFFSET,
|
||||
.src = __FUNCTION__,
|
||||
};
|
||||
struct ast_frame wf;
|
||||
unsigned char waste[AST_FRIENDLY_OFFSET];
|
||||
unsigned char buf[640];
|
||||
int i,*indexp = (int *) data;
|
||||
|
||||
/* Instead of len, use samples, because channel.c generator_force
|
||||
* generate(chan, tmp, 0, 160) ignores len. In any case, len is
|
||||
* a multiple of samples, given by number of samples times bytes per
|
||||
* sample. In the case of ulaw, len = samples. for signed linear
|
||||
* len = 2 * samples */
|
||||
|
||||
if (samples > maxsamples) {
|
||||
ast_log(LOG_WARNING, "Only doing %d samples (%d requested)\n", maxsamples, samples);
|
||||
samples = maxsamples;
|
||||
if (len > sizeof(buf))
|
||||
{
|
||||
ast_log(LOG_WARNING,"Only doing %d bytes (%d bytes requested)\n",(int)sizeof(buf),len);
|
||||
len = sizeof(buf);
|
||||
}
|
||||
len = samples * sizeof (buf[0]);
|
||||
waste[0] = 0; /* make compiler happy */
|
||||
wf.frametype = AST_FRAME_VOICE;
|
||||
wf.subclass = AST_FORMAT_ULAW;
|
||||
wf.offset = AST_FRIENDLY_OFFSET;
|
||||
wf.mallocd = 0;
|
||||
wf.data = buf;
|
||||
wf.datalen = len;
|
||||
wf.samples = samples;
|
||||
wf.samples = wf.datalen;
|
||||
wf.src = "app_milliwatt";
|
||||
wf.delivery.tv_sec = 0;
|
||||
wf.delivery.tv_usec = 0;
|
||||
/* create a buffer containing the digital milliwatt pattern */
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
buf[AST_FRIENDLY_OFFSET + i] = digital_milliwatt[(*indexp)++];
|
||||
buf[i] = digital_milliwatt[(*indexp)++];
|
||||
*indexp &= 7;
|
||||
}
|
||||
if (ast_write(chan,&wf) < 0)
|
||||
@@ -114,8 +100,8 @@ static struct ast_generator milliwattgen =
|
||||
static int milliwatt_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
|
||||
struct ast_module_user *u;
|
||||
u = ast_module_user_add(chan);
|
||||
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)
|
||||
@@ -125,29 +111,38 @@ static int milliwatt_exec(struct ast_channel *chan, void *data)
|
||||
if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0)
|
||||
{
|
||||
ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
while(!ast_safe_sleep(chan, 10000));
|
||||
ast_deactivate_generator(chan);
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, 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;
|
||||
}
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Anthony Minessale II
|
||||
* Copyright (C) 2005 - 2006, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Kevin P. Fleming <kpfleming@digium.com>
|
||||
*
|
||||
* Based on app_muxmon.c provided by
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief MixMonitor() - Record a call and mix the audio during the recording
|
||||
* \ingroup applications
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
* \author Kevin P. Fleming <kpfleming@digium.com>
|
||||
*
|
||||
* \note Based on app_muxmon.c provided by
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/audiohook.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
|
||||
|
||||
static const char *app = "MixMonitor";
|
||||
static const char *synopsis = "Record a call and mix the audio during the recording";
|
||||
static const char *desc = ""
|
||||
" MixMonitor(<file>.<ext>[|<options>[|<command>]])\n\n"
|
||||
"Records the audio on the current channel to the specified file.\n"
|
||||
"If the filename is an absolute path, uses that path, otherwise\n"
|
||||
"creates the file in the configured monitoring directory from\n"
|
||||
"asterisk.conf.\n\n"
|
||||
"Valid options:\n"
|
||||
" a - Append to the file instead of overwriting it.\n"
|
||||
" b - Only save audio to the file while the channel is bridged.\n"
|
||||
" Note: Does not include conferences or sounds played to each bridged\n"
|
||||
" party.\n"
|
||||
" v(<x>) - Adjust the heard volume by a factor of <x> (range -4 to 4)\n"
|
||||
" V(<x>) - Adjust the spoken volume by a factor of <x> (range -4 to 4)\n"
|
||||
" W(<x>) - Adjust the both heard and spoken volumes by a factor of <x>\n"
|
||||
" (range -4 to 4)\n\n"
|
||||
"<command> will be executed when the recording is over\n"
|
||||
"Any strings matching ^{X} will be unescaped to ${X}.\n"
|
||||
"All variables will be evaluated at the time MixMonitor is called.\n"
|
||||
"The variable MIXMONITOR_FILENAME will contain the filename used to record.\n"
|
||||
"";
|
||||
|
||||
static const char *stop_app = "StopMixMonitor";
|
||||
static const char *stop_synopsis = "Stop recording a call through MixMonitor";
|
||||
static const char *stop_desc = ""
|
||||
" StopMixMonitor()\n\n"
|
||||
"Stops the audio recording that was started with a call to MixMonitor()\n"
|
||||
"on the current channel.\n"
|
||||
"";
|
||||
|
||||
struct module_symbols *me;
|
||||
|
||||
static const char *mixmonitor_spy_type = "MixMonitor";
|
||||
|
||||
struct mixmonitor {
|
||||
struct ast_audiohook audiohook;
|
||||
char *filename;
|
||||
char *post_process;
|
||||
char *name;
|
||||
unsigned int flags;
|
||||
struct ast_channel *chan;
|
||||
};
|
||||
|
||||
enum {
|
||||
MUXFLAG_APPEND = (1 << 1),
|
||||
MUXFLAG_BRIDGED = (1 << 2),
|
||||
MUXFLAG_VOLUME = (1 << 3),
|
||||
MUXFLAG_READVOLUME = (1 << 4),
|
||||
MUXFLAG_WRITEVOLUME = (1 << 5),
|
||||
} mixmonitor_flags;
|
||||
|
||||
enum {
|
||||
OPT_ARG_READVOLUME = 0,
|
||||
OPT_ARG_WRITEVOLUME,
|
||||
OPT_ARG_VOLUME,
|
||||
OPT_ARG_ARRAY_SIZE,
|
||||
} mixmonitor_args;
|
||||
|
||||
AST_APP_OPTIONS(mixmonitor_opts, {
|
||||
AST_APP_OPTION('a', MUXFLAG_APPEND),
|
||||
AST_APP_OPTION('b', MUXFLAG_BRIDGED),
|
||||
AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
|
||||
AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
|
||||
AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
|
||||
});
|
||||
|
||||
static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
|
||||
{
|
||||
struct ast_channel *peer;
|
||||
int res;
|
||||
|
||||
if (!chan)
|
||||
return -1;
|
||||
|
||||
res = ast_audiohook_attach(chan, audiohook);
|
||||
|
||||
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
|
||||
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define SAMPLES_PER_FRAME 160
|
||||
|
||||
static void *mixmonitor_thread(void *obj)
|
||||
{
|
||||
struct mixmonitor *mixmonitor = obj;
|
||||
struct ast_filestream *fs = NULL;
|
||||
unsigned int oflags;
|
||||
char *ext;
|
||||
int errflag = 0;
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
|
||||
|
||||
ast_audiohook_lock(&mixmonitor->audiohook);
|
||||
|
||||
while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING) {
|
||||
struct ast_frame *fr = NULL;
|
||||
|
||||
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;
|
||||
|
||||
if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || ast_bridged_channel(mixmonitor->chan)) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* All done! free it. */
|
||||
ast_frame_free(fr, 0);
|
||||
}
|
||||
|
||||
ast_audiohook_detach(&mixmonitor->audiohook);
|
||||
ast_audiohook_unlock(&mixmonitor->audiohook);
|
||||
ast_audiohook_destroy(&mixmonitor->audiohook);
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
free(mixmonitor);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void launch_monitor_thread(struct ast_channel *chan, const char *filename, unsigned int flags,
|
||||
int readvol, int writevol, const char *post_process)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_t thread;
|
||||
struct mixmonitor *mixmonitor;
|
||||
char postprocess2[1024] = "";
|
||||
size_t len;
|
||||
|
||||
len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
|
||||
|
||||
/* If a post process system command is given attach it to the structure */
|
||||
if (!ast_strlen_zero(post_process)) {
|
||||
char *p1, *p2;
|
||||
|
||||
p1 = ast_strdupa(post_process);
|
||||
for (p2 = p1; *p2 ; p2++) {
|
||||
if (*p2 == '^' && *(p2+1) == '{') {
|
||||
*p2 = '$';
|
||||
}
|
||||
}
|
||||
|
||||
pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
|
||||
if (!ast_strlen_zero(postprocess2))
|
||||
len += strlen(postprocess2) + 1;
|
||||
}
|
||||
|
||||
/* Pre-allocate mixmonitor structure and spy */
|
||||
if (!(mixmonitor = calloc(1, len))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy over flags and channel name */
|
||||
mixmonitor->flags = flags;
|
||||
mixmonitor->chan = chan;
|
||||
mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
|
||||
strcpy(mixmonitor->name, chan->name);
|
||||
if (!ast_strlen_zero(postprocess2)) {
|
||||
mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
|
||||
strcpy(mixmonitor->post_process, postprocess2);
|
||||
}
|
||||
|
||||
mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
|
||||
strcpy(mixmonitor->filename, filename);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
}
|
||||
|
||||
static int mixmonitor_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int x, readvol = 0, writevol = 0;
|
||||
struct ast_module_user *u;
|
||||
struct ast_flags flags = {0};
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(filename);
|
||||
AST_APP_ARG(options);
|
||||
AST_APP_ARG(post_process);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (ast_strlen_zero(args.filename)) {
|
||||
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args.options) {
|
||||
char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
|
||||
|
||||
ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
|
||||
ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
|
||||
} else if ((sscanf(opts[OPT_ARG_READVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) {
|
||||
ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
|
||||
} else {
|
||||
readvol = get_volfactor(x);
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
|
||||
ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
|
||||
} else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) {
|
||||
ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
|
||||
} else {
|
||||
writevol = get_volfactor(x);
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
|
||||
ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
|
||||
} else if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) {
|
||||
ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
|
||||
} else {
|
||||
readvol = writevol = get_volfactor(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if not provided an absolute path, use the system-configured monitoring directory */
|
||||
if (args.filename[0] != '/') {
|
||||
char *build;
|
||||
|
||||
build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
|
||||
sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
|
||||
args.filename = build;
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
|
||||
launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stop_mixmonitor_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mixmonitor_cli(int fd, int argc, char **argv)
|
||||
{
|
||||
struct ast_channel *chan;
|
||||
|
||||
if (argc < 3)
|
||||
return RESULT_SHOWUSAGE;
|
||||
|
||||
if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) {
|
||||
ast_cli(fd, "No channel matching '%s' found.\n", argv[2]);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!strcasecmp(argv[1], "start"))
|
||||
mixmonitor_exec(chan, argv[3]);
|
||||
else if (!strcasecmp(argv[1], "stop"))
|
||||
ast_audiohook_detach_source(chan, mixmonitor_spy_type);
|
||||
|
||||
ast_channel_unlock(chan);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static char *complete_mixmonitor_cli(const char *line, const char *word, int pos, int state)
|
||||
{
|
||||
return ast_complete_channels(line, word, pos, state, 2);
|
||||
}
|
||||
|
||||
static struct ast_cli_entry cli_mixmonitor[] = {
|
||||
{ { "mixmonitor", NULL, NULL },
|
||||
mixmonitor_cli, "Execute a MixMonitor command.",
|
||||
"mixmonitor <start|stop> <chan_name> [args]\n\n"
|
||||
"The optional arguments are passed to the\n"
|
||||
"MixMonitor application when the 'start' command is used.\n",
|
||||
complete_mixmonitor_cli },
|
||||
};
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
|
||||
res = ast_unregister_application(stop_app);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
|
||||
res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
|
||||
res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");
|
||||
@@ -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");
|
||||
152
apps/app_mp3.c
152
apps/app_mp3.c
@@ -1,34 +1,24 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Silly application to play an MP3 file -- uses mpg123
|
||||
*
|
||||
* Copyright (C) 1999-2004, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Silly application to play an MP3 file -- uses mpg123
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -37,52 +27,35 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define LOCAL_MPG_123 "/usr/local/bin/mpg123"
|
||||
#define MPG_123 "/usr/bin/mpg123"
|
||||
|
||||
static char *tdesc = "Silly MP3 Application";
|
||||
|
||||
static char *app = "MP3Player";
|
||||
|
||||
static char *synopsis = "Play an MP3 file or stream";
|
||||
|
||||
static char *descrip =
|
||||
" MP3Player(location) Executes mpg123 to play the given location,\n"
|
||||
"which typically would be a filename or a URL. User can exit by pressing\n"
|
||||
"any key on the dialpad, or by hanging up.";
|
||||
" MP3Player(location) Executes mpg123 to play the given location\n"
|
||||
"which typically would be a filename or a URL. Returns -1 on\n"
|
||||
"hangup or 0 otherwise. User can exit by pressing any key\n.";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int mp3play(char *filename, int fd)
|
||||
{
|
||||
int res;
|
||||
int x;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
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;
|
||||
}
|
||||
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++) {
|
||||
for (x=0;x<256;x++) {
|
||||
if (x != STDOUT_FILENO)
|
||||
close(x);
|
||||
}
|
||||
@@ -104,7 +77,7 @@ static int mp3play(char *filename, int fd)
|
||||
execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
|
||||
}
|
||||
ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
|
||||
_exit(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int timed_read(int fd, void *data, int datalen, int timeout)
|
||||
@@ -125,57 +98,66 @@ static int timed_read(int fd, void *data, int datalen, int timeout)
|
||||
static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
int fds[2];
|
||||
int ms = -1;
|
||||
int pid = -1;
|
||||
int owriteformat;
|
||||
int timeout = 2000;
|
||||
struct timeval next;
|
||||
struct timeval now, next;
|
||||
struct ast_frame *f;
|
||||
struct myframe {
|
||||
struct ast_frame f;
|
||||
char offset[AST_FRIENDLY_OFFSET];
|
||||
short frdata[160];
|
||||
} myf;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "MP3 Playback requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_stopstream(chan);
|
||||
|
||||
owriteformat = chan->writeformat;
|
||||
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
res = mp3play((char *)data, fds[1]);
|
||||
if (!strncasecmp((char *)data, "http://", 7)) {
|
||||
timeout = 10000;
|
||||
}
|
||||
/* Wait 1000 ms first */
|
||||
next = ast_tvnow();
|
||||
next = now;
|
||||
next.tv_sec += 1;
|
||||
if (res >= 0) {
|
||||
pid = res;
|
||||
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
|
||||
user */
|
||||
for (;;) {
|
||||
ms = ast_tvdiff_ms(next, ast_tvnow());
|
||||
gettimeofday(&now, NULL);
|
||||
ms = (next.tv_sec - now.tv_sec) * 1000;
|
||||
ms += (next.tv_usec - now.tv_usec) / 1000;
|
||||
#if 0
|
||||
printf("ms: %d\n", ms);
|
||||
#endif
|
||||
if (ms <= 0) {
|
||||
#if 0
|
||||
{
|
||||
static struct timeval last;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
|
||||
last = tv;
|
||||
}
|
||||
#endif
|
||||
res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
|
||||
if (res > 0) {
|
||||
myf.f.frametype = AST_FRAME_VOICE;
|
||||
@@ -197,7 +179,14 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
|
||||
next.tv_usec += res / 2 * 125;
|
||||
if (next.tv_usec >= 1000000) {
|
||||
next.tv_usec -= 1000000;
|
||||
next.tv_sec++;
|
||||
}
|
||||
#if 0
|
||||
printf("Next: %d\n", ms);
|
||||
#endif
|
||||
} else {
|
||||
ms = ast_waitfor(chan, ms);
|
||||
if (ms < 0) {
|
||||
@@ -225,31 +214,38 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (pid > -1)
|
||||
kill(pid, SIGKILL);
|
||||
if (!res && owriteformat)
|
||||
ast_set_write_format(chan, owriteformat);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, mp3_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Silly application to play an NBScat file -- uses nbscat8k
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Silly application to play an NBScat file -- uses nbscat8k
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -38,22 +28,10 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define LOCAL_NBSCAT "/usr/local/bin/nbscat8k"
|
||||
#define NBSCAT "/usr/bin/nbscat8k"
|
||||
|
||||
#ifndef AF_LOCAL
|
||||
#define AF_LOCAL AF_UNIX
|
||||
#endif
|
||||
static char *tdesc = "Silly NBS Stream Application";
|
||||
|
||||
static char *app = "NBScat";
|
||||
|
||||
@@ -61,33 +39,24 @@ static char *synopsis = "Play an NBS local stream";
|
||||
|
||||
static char *descrip =
|
||||
" NBScat: Executes nbscat to listen to the local NBS stream.\n"
|
||||
"User can exit by pressing any key\n.";
|
||||
"Returns -1 on\n hangup or 0 otherwise. User can exit by \n"
|
||||
"pressing any key\n.";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int NBScatplay(int fd)
|
||||
{
|
||||
int res;
|
||||
int x;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -95,7 +64,7 @@ static int NBScatplay(int fd)
|
||||
execl(NBSCAT, "nbscat8k", "-d", (char *)NULL);
|
||||
execl(LOCAL_NBSCAT, "nbscat8k", "-d", (char *)NULL);
|
||||
ast_log(LOG_WARNING, "Execute of nbscat8k failed\n");
|
||||
_exit(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int timed_read(int fd, void *data, int datalen)
|
||||
@@ -116,48 +85,57 @@ static int timed_read(int fd, void *data, int datalen)
|
||||
static int NBScat_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
int fds[2];
|
||||
int ms = -1;
|
||||
int pid = -1;
|
||||
int owriteformat;
|
||||
struct timeval next;
|
||||
struct timeval now, next;
|
||||
struct ast_frame *f;
|
||||
struct myframe {
|
||||
struct ast_frame f;
|
||||
char offset[AST_FRIENDLY_OFFSET];
|
||||
short frdata[160];
|
||||
} myf;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create socketpair\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_stopstream(chan);
|
||||
|
||||
owriteformat = chan->writeformat;
|
||||
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = NBScatplay(fds[1]);
|
||||
/* Wait 1000 ms first */
|
||||
next = ast_tvnow();
|
||||
next = now;
|
||||
next.tv_sec += 1;
|
||||
if (res >= 0) {
|
||||
pid = res;
|
||||
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
|
||||
user */
|
||||
for (;;) {
|
||||
ms = ast_tvdiff_ms(next, ast_tvnow());
|
||||
gettimeofday(&now, NULL);
|
||||
ms = (next.tv_sec - now.tv_sec) * 1000;
|
||||
ms += (next.tv_usec - now.tv_usec) / 1000;
|
||||
#if 0
|
||||
printf("ms: %d\n", ms);
|
||||
#endif
|
||||
if (ms <= 0) {
|
||||
#if 0
|
||||
{
|
||||
static struct timeval last;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
printf("Since last: %ld\n", (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000);
|
||||
last = tv;
|
||||
}
|
||||
#endif
|
||||
res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
|
||||
if (res > 0) {
|
||||
myf.f.frametype = AST_FRAME_VOICE;
|
||||
@@ -179,7 +157,14 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
|
||||
next.tv_usec += res / 2 * 125;
|
||||
if (next.tv_usec >= 1000000) {
|
||||
next.tv_usec -= 1000000;
|
||||
next.tv_sec++;
|
||||
}
|
||||
#if 0
|
||||
printf("Next: %d\n", ms);
|
||||
#endif
|
||||
} else {
|
||||
ms = ast_waitfor(chan, ms);
|
||||
if (ms < 0) {
|
||||
@@ -207,31 +192,38 @@ static int NBScat_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (pid > -1)
|
||||
kill(pid, SIGKILL);
|
||||
if (!res && owriteformat)
|
||||
ast_set_write_format(chan, owriteformat);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, NBScat_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
1876
apps/app_osplookup.c
1876
apps/app_osplookup.c
File diff suppressed because it is too large
Load Diff
203
apps/app_page.c
203
apps/app_page.c
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2004 - 2006 Digium, Inc. All rights reserved.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* This code is released under the GNU General Public License
|
||||
* version 2.0. See LICENSE for more information.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief page() - Paging application
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>zaptel</depend>
|
||||
<depend>app_meetme</depend>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/chanvars.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/dial.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
|
||||
static const char *app_page= "Page";
|
||||
|
||||
static const char *page_synopsis = "Pages phones";
|
||||
|
||||
static const char *page_descrip =
|
||||
"Page(Technology/Resource&Technology2/Resource2[|options])\n"
|
||||
" Places outbound calls to the given technology / resource and dumps\n"
|
||||
"them into a conference bridge as muted participants. The original\n"
|
||||
"caller is dumped into the conference as a speaker and the room is\n"
|
||||
"destroyed when the original caller leaves. Valid options are:\n"
|
||||
" d - full duplex audio\n"
|
||||
" q - quiet, do not play beep to caller\n"
|
||||
" r - record the page into a file (see 'r' for app_meetme)\n";
|
||||
|
||||
enum {
|
||||
PAGE_DUPLEX = (1 << 0),
|
||||
PAGE_QUIET = (1 << 1),
|
||||
PAGE_RECORD = (1 << 2),
|
||||
} page_opt_flags;
|
||||
|
||||
AST_APP_OPTIONS(page_opts, {
|
||||
AST_APP_OPTION('d', PAGE_DUPLEX),
|
||||
AST_APP_OPTION('q', PAGE_QUIET),
|
||||
AST_APP_OPTION('r', PAGE_RECORD),
|
||||
});
|
||||
|
||||
#define MAX_DIALS 128
|
||||
|
||||
static int page_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char *options, *tech, *resource, *tmp;
|
||||
char meetmeopts[88], originator[AST_CHANNEL_NAME];
|
||||
struct ast_flags flags = { 0 };
|
||||
unsigned int confid = ast_random();
|
||||
struct ast_app *app;
|
||||
int res = 0, pos = 0, i = 0;
|
||||
struct ast_dial *dials[MAX_DIALS];
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!(app = pbx_findapp("MeetMe"))) {
|
||||
ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
};
|
||||
|
||||
options = ast_strdupa(data);
|
||||
|
||||
ast_copy_string(originator, chan->name, sizeof(originator));
|
||||
if ((tmp = strchr(originator, '-')))
|
||||
*tmp = '\0';
|
||||
|
||||
tmp = strsep(&options, "|");
|
||||
if (options)
|
||||
ast_app_parse_options(page_opts, &flags, NULL, options);
|
||||
|
||||
snprintf(meetmeopts, sizeof(meetmeopts), "MeetMe|%ud|%s%sqxdw(5)", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m"),
|
||||
(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
|
||||
|
||||
/* Go through parsing/calling each device */
|
||||
while ((tech = strsep(&tmp, "&"))) {
|
||||
struct ast_dial *dial = NULL;
|
||||
|
||||
/* don't call the originating device */
|
||||
if (!strcasecmp(tech, originator))
|
||||
continue;
|
||||
|
||||
/* If no resource is available, continue on */
|
||||
if (!(resource = strchr(tech, '/'))) {
|
||||
ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
|
||||
continue;
|
||||
}
|
||||
|
||||
*resource++ = '\0';
|
||||
|
||||
/* Create a dialing structure */
|
||||
if (!(dial = ast_dial_create())) {
|
||||
ast_log(LOG_WARNING, "Failed to create dialing structure.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Append technology and resource */
|
||||
ast_dial_append(dial, tech, resource);
|
||||
|
||||
/* Set ANSWER_EXEC as global option */
|
||||
ast_dial_option_global_enable(dial, AST_DIAL_OPTION_ANSWER_EXEC, meetmeopts);
|
||||
|
||||
/* Run this dial in async mode */
|
||||
ast_dial_run(dial, chan, 1);
|
||||
|
||||
/* Put in our dialing array */
|
||||
dials[pos++] = dial;
|
||||
}
|
||||
|
||||
if (!ast_test_flag(&flags, PAGE_QUIET)) {
|
||||
res = ast_streamfile(chan, "beep", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
}
|
||||
|
||||
if (!res) {
|
||||
snprintf(meetmeopts, sizeof(meetmeopts), "%ud|A%s%sqxd", confid, (ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t"),
|
||||
(ast_test_flag(&flags, PAGE_RECORD) ? "r" : "") );
|
||||
pbx_exec(chan, app, meetmeopts);
|
||||
}
|
||||
|
||||
/* Go through each dial attempt cancelling, joining, and destroying */
|
||||
for (i = 0; i < pos; i++) {
|
||||
struct ast_dial *dial = dials[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_module_user_remove(u);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_page);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_page, page_exec, page_synopsis, page_descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Page Multiple Phones");
|
||||
|
||||
@@ -1,55 +1,38 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2006, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* ParkAndAnnounce application for Asterisk
|
||||
* Author: Ben Miller <bgmiller@dccinc.com>
|
||||
* With TONS of help from Mark!
|
||||
*
|
||||
* Asterisk is Copyrighted as follows
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief ParkAndAnnounce application for Asterisk
|
||||
*
|
||||
* \author Ben Miller <bgmiller@dccinc.com>
|
||||
* \arg With TONS of help from Mark!
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/channel_pvt.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/features.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/say.h>
|
||||
#include <asterisk/lock.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/features.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
static char *tdesc = "Call Parking and Announce Application";
|
||||
|
||||
static char *app = "ParkAndAnnounce";
|
||||
|
||||
@@ -57,54 +40,51 @@ static char *synopsis = "Park and Announce";
|
||||
|
||||
static char *descrip =
|
||||
" ParkAndAnnounce(announce:template|timeout|dial|[return_context]):\n"
|
||||
"Park a call into the parkinglot and announce the call to another channel.\n"
|
||||
"\n"
|
||||
"announce template: Colon-separated list of files to announce. The word PARKED\n"
|
||||
" will be replaced by a say_digits of the extension in which\n"
|
||||
" the call is parked.\n"
|
||||
"timeout: Time in seconds before the call returns into the return\n"
|
||||
" context.\n"
|
||||
"dial: The app_dial style resource to call to make the\n"
|
||||
" announcement. Console/dsp calls the console.\n"
|
||||
"return_context: The goto-style label to jump the call back into after\n"
|
||||
" timeout. Default <priority+1>.\n"
|
||||
"\n"
|
||||
"The variable ${PARKEDAT} will contain the parking extension into which the\n"
|
||||
"call was placed. Use with the Local channel to allow the dialplan to make\n"
|
||||
"use of this information.\n";
|
||||
"Park a call into the parkinglot and announce the call over the console.\n"
|
||||
"announce template: colon separated list of files to announce, the word PARKED\n"
|
||||
" will be replaced by a say_digits of the ext the call is parked in\n"
|
||||
"timeout: time in seconds before the call returns into the return context.\n"
|
||||
"dial: The app_dial style resource to call to make the announcement. Console/dsp calls the console.\n"
|
||||
"return_context: the goto style label to jump the call back into after timeout. default=prio+1\n";
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
char *return_context;
|
||||
int lot, timeout = 0, dres;
|
||||
int l, lot, timeout = 0, dres;
|
||||
char *working, *context, *exten, *priority, *dial, *dialtech, *dialstr;
|
||||
char *template, *tpl_working, *tpl_current;
|
||||
char *tmp[100];
|
||||
char buf[13];
|
||||
int looptemp=0,i=0;
|
||||
char *s;
|
||||
char *s,*orig_s;
|
||||
|
||||
struct ast_channel *dchan;
|
||||
struct outgoing_helper oh;
|
||||
int outstate;
|
||||
|
||||
struct ast_module_user *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
struct localuser *u;
|
||||
if(!data || (data && !strlen(data))) {
|
||||
ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
l=strlen(data)+2;
|
||||
orig_s=malloc(l);
|
||||
if(!orig_s) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
s=orig_s;
|
||||
strncpy(s,data,l);
|
||||
|
||||
template=strsep(&s,"|");
|
||||
if(! template) {
|
||||
ast_log(LOG_WARNING, "PARK: An announce template must be defined\n");
|
||||
ast_module_user_remove(u);
|
||||
free(orig_s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -115,7 +95,7 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
dial=strsep(&s, "|");
|
||||
if(!dial) {
|
||||
ast_log(LOG_WARNING, "PARK: A dial resource must be specified i.e: Console/dsp or Zap/g1/5551212\n");
|
||||
ast_module_user_remove(u);
|
||||
free(orig_s);
|
||||
return -1;
|
||||
} else {
|
||||
dialtech=strsep(&dial, "/");
|
||||
@@ -147,26 +127,29 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
if(atoi(priority) < 0) {
|
||||
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
|
||||
ast_module_user_remove(u);
|
||||
free(orig_s);
|
||||
return -1;
|
||||
}
|
||||
/* At this point we have a priority and maybe an extension and a context */
|
||||
chan->priority = atoi(priority);
|
||||
if (exten)
|
||||
ast_copy_string(chan->exten, exten, sizeof(chan->exten));
|
||||
if (context)
|
||||
ast_copy_string(chan->context, context, sizeof(chan->context));
|
||||
if(exten && strcasecmp(exten, "BYEXTENSION"))
|
||||
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
|
||||
if(context)
|
||||
strncpy(chan->context, context, sizeof(chan->context)-1);
|
||||
} else { /* increment the priority by default*/
|
||||
chan->priority++;
|
||||
}
|
||||
|
||||
|
||||
if(option_verbose > 2) {
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
|
||||
if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->callerid);
|
||||
if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->callerid)) {
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
|
||||
before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
|
||||
|
||||
@@ -178,11 +161,7 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
/* Now place the call to the extention */
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", lot);
|
||||
memset(&oh, 0, sizeof(oh));
|
||||
oh.parent_channel = chan;
|
||||
oh.vars = ast_variable_new("_PARKEDAT", buf);
|
||||
dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
|
||||
dchan = ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->callerid);
|
||||
|
||||
if(dchan) {
|
||||
if(dchan->_state == AST_STATE_UP) {
|
||||
@@ -193,12 +172,14 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", dchan->name);
|
||||
ast_log(LOG_WARNING, "PARK: Channel %s was never answered for the announce.\n", dchan->name);
|
||||
ast_hangup(dchan);
|
||||
ast_module_user_remove(u);
|
||||
free(orig_s);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
|
||||
ast_module_user_remove(u);
|
||||
free(orig_s);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -211,7 +192,7 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
tpl_working = template;
|
||||
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,":");
|
||||
@@ -234,27 +215,39 @@ static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
ast_stopstream(dchan);
|
||||
ast_hangup(dchan);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
free(orig_s);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
/* return ast_register_application(app, park_exec); */
|
||||
return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,494 +1,118 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Trivial application to playback a sound file
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to playback a sound file
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/say.h"
|
||||
static char *tdesc = "Trivial Playback Application";
|
||||
|
||||
static char *app = "Playback";
|
||||
|
||||
static char *synopsis = "Play a file";
|
||||
|
||||
static char *descrip =
|
||||
" Playback(filename[&filename2...][|option]): Plays back given filenames (do not put\n"
|
||||
"extension). Options may also be included following a pipe symbol. The 'skip'\n"
|
||||
"option causes the playback of the message to be skipped if the channel\n"
|
||||
"is not in the 'up' state (i.e. it hasn't been answered yet). If 'skip' is \n"
|
||||
" Playback(filename[|option]): Plays back a given filename (do not put\n"
|
||||
"extension). Options may also be included following a pipe symbol. The 'skip'\n"
|
||||
"option causes the playback of the message to be skipped if the channel\n"
|
||||
"is not in the 'up' state (i.e. it hasn't been answered yet. If 'skip' is \n"
|
||||
"specified, the application will return immediately should the channel not be\n"
|
||||
"off hook. Otherwise, unless 'noanswer' is specified, the channel will\n"
|
||||
"off hook. Otherwise, unless 'noanswer' is specified, the channel channel will\n"
|
||||
"be answered before the sound is played. Not all channels support playing\n"
|
||||
"messages while still on hook. If 'j' is specified, the application\n"
|
||||
"will jump to priority n+101 if present when a file specified to be played\n"
|
||||
"does not exist.\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" PLAYBACKSTATUS The status of the playback attempt as a text string, one of\n"
|
||||
" SUCCESS | FAILED\n"
|
||||
"See Also: Background (application) -- for playing soundfiles that are interruptible\n"
|
||||
" WaitExten (application) -- wait for digits from caller, optionally play music on hold\n"
|
||||
;
|
||||
"messages while still hook. Returns -1 if the channel was hung up, or if the\n"
|
||||
"file does not exist. Returns 0 otherwise.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static struct ast_config *say_cfg = NULL;
|
||||
/* save the say' api calls.
|
||||
* The first entry is NULL if we have the standard source,
|
||||
* otherwise we are sourcing from here.
|
||||
* 'say load [new|old]' will enable the new or old method, or report status
|
||||
*/
|
||||
static const void * say_api_buf[40];
|
||||
static const char *say_old = "old";
|
||||
static const char *say_new = "new";
|
||||
|
||||
static void save_say_mode(const void *arg)
|
||||
{
|
||||
int i = 0;
|
||||
say_api_buf[i++] = arg;
|
||||
|
||||
say_api_buf[i++] = ast_say_number_full;
|
||||
say_api_buf[i++] = ast_say_enumeration_full;
|
||||
say_api_buf[i++] = ast_say_digit_str_full;
|
||||
say_api_buf[i++] = ast_say_character_str_full;
|
||||
say_api_buf[i++] = ast_say_phonetic_str_full;
|
||||
say_api_buf[i++] = ast_say_datetime;
|
||||
say_api_buf[i++] = ast_say_time;
|
||||
say_api_buf[i++] = ast_say_date;
|
||||
say_api_buf[i++] = ast_say_datetime_from_now;
|
||||
say_api_buf[i++] = ast_say_date_with_format;
|
||||
}
|
||||
|
||||
static void restore_say_mode(void *arg)
|
||||
{
|
||||
int i = 0;
|
||||
say_api_buf[i++] = arg;
|
||||
|
||||
ast_say_number_full = say_api_buf[i++];
|
||||
ast_say_enumeration_full = say_api_buf[i++];
|
||||
ast_say_digit_str_full = say_api_buf[i++];
|
||||
ast_say_character_str_full = say_api_buf[i++];
|
||||
ast_say_phonetic_str_full = say_api_buf[i++];
|
||||
ast_say_datetime = say_api_buf[i++];
|
||||
ast_say_time = say_api_buf[i++];
|
||||
ast_say_date = say_api_buf[i++];
|
||||
ast_say_datetime_from_now = say_api_buf[i++];
|
||||
ast_say_date_with_format = say_api_buf[i++];
|
||||
}
|
||||
|
||||
/*
|
||||
* Typical 'say' arguments in addition to the date or number or string
|
||||
* to say. We do not include 'options' because they may be different
|
||||
* in recursive calls, and so they are better left as an external
|
||||
* parameter.
|
||||
*/
|
||||
typedef struct {
|
||||
struct ast_channel *chan;
|
||||
const char *ints;
|
||||
const char *language;
|
||||
int audiofd;
|
||||
int ctrlfd;
|
||||
} say_args_t;
|
||||
|
||||
static int s_streamwait3(const say_args_t *a, const char *fn)
|
||||
{
|
||||
int res = ast_streamfile(a->chan, fn, a->language);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to play message %s\n", fn);
|
||||
return res;
|
||||
}
|
||||
res = (a->audiofd > -1 && a->ctrlfd > -1) ?
|
||||
ast_waitstream_full(a->chan, a->ints, a->audiofd, a->ctrlfd) :
|
||||
ast_waitstream(a->chan, a->ints);
|
||||
ast_stopstream(a->chan);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* the string is 'prefix:data' or prefix:fmt:data'
|
||||
* with ':' being invalid in strings.
|
||||
*/
|
||||
static int do_say(say_args_t *a, const char *s, const char *options, int depth)
|
||||
{
|
||||
struct ast_variable *v;
|
||||
char *lang, *x, *rule = NULL;
|
||||
int ret = 0;
|
||||
struct varshead head = { .first = NULL, .last = NULL };
|
||||
struct ast_var_t *n;
|
||||
|
||||
if (depth++ > 10) {
|
||||
ast_log(LOG_WARNING, "recursion too deep, exiting\n");
|
||||
return -1;
|
||||
} else if (!say_cfg) {
|
||||
ast_log(LOG_WARNING, "no say.conf, cannot spell '%s'\n", s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* scan languages same as in file.c */
|
||||
if (a->language == NULL)
|
||||
a->language = "en"; /* default */
|
||||
lang = ast_strdupa(a->language);
|
||||
for (;;) {
|
||||
for (v = ast_variable_browse(say_cfg, lang); v ; v = v->next) {
|
||||
if (ast_extension_match(v->name, s)) {
|
||||
rule = ast_strdupa(v->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rule)
|
||||
break;
|
||||
if ( (x = strchr(lang, '_')) )
|
||||
*x = '\0'; /* try without suffix */
|
||||
else if (strcmp(lang, "en"))
|
||||
lang = "en"; /* last resort, try 'en' if not done yet */
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (!rule)
|
||||
return 0;
|
||||
|
||||
/* skip up to two prefixes to get the value */
|
||||
if ( (x = strchr(s, ':')) )
|
||||
s = x + 1;
|
||||
if ( (x = strchr(s, ':')) )
|
||||
s = x + 1;
|
||||
n = ast_var_assign("SAY", s);
|
||||
AST_LIST_INSERT_HEAD(&head, n, entries);
|
||||
|
||||
/* scan the body, one piece at a time */
|
||||
while ( !ret && (x = strsep(&rule, ",")) ) { /* exit on key */
|
||||
char fn[128];
|
||||
const char *p, *fmt, *data; /* format and data pointers */
|
||||
|
||||
/* prepare a decent file name */
|
||||
x = ast_skip_blanks(x);
|
||||
ast_trim_blanks(x);
|
||||
|
||||
/* replace variables */
|
||||
memset(fn, 0, sizeof(fn)); /* XXX why isn't done in pbx_substitute_variables_helper! */
|
||||
pbx_substitute_variables_varshead(&head, x, fn, sizeof(fn));
|
||||
|
||||
/* locate prefix and data, if any */
|
||||
fmt = 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;
|
||||
struct localuser *u;
|
||||
char tmp[256];
|
||||
char *options;
|
||||
int option_skip=0;
|
||||
int option_say=0;
|
||||
int option_noanswer = 0;
|
||||
int priority_jump = 0;
|
||||
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(filenames);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
char *stringp;
|
||||
if (!data || ast_strlen_zero((char *)data)) {
|
||||
ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
AST_STANDARD_APP_ARGS(args, tmp);
|
||||
|
||||
if (args.options) {
|
||||
if (strcasestr(args.options, "skip"))
|
||||
option_skip = 1;
|
||||
if (strcasestr(args.options, "say"))
|
||||
option_say = 1;
|
||||
if (strcasestr(args.options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
strncpy(tmp, (char *)data, sizeof(tmp)-1);
|
||||
stringp=tmp;
|
||||
strsep(&stringp, "|");
|
||||
options = strsep(&stringp, "|");
|
||||
if (options && !strcasecmp(options, "skip"))
|
||||
option_skip = 1;
|
||||
if (options && !strcasecmp(options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
if (option_skip) {
|
||||
/* At the user's option, skip if the line is not up */
|
||||
goto done;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
} else if (!option_noanswer)
|
||||
/* Otherwise answer unless we're supposed to send this while on-hook */
|
||||
res = ast_answer(chan);
|
||||
}
|
||||
if (!res) {
|
||||
char *back = args.filenames;
|
||||
char *front;
|
||||
|
||||
ast_stopstream(chan);
|
||||
while (!res && (front = strsep(&back, "&"))) {
|
||||
if (option_say)
|
||||
res = say_full(chan, front, "", chan->language, NULL, -1, -1);
|
||||
else
|
||||
res = ast_streamfile(chan, front, chan->language);
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, "");
|
||||
ast_stopstream(chan);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
res = 0;
|
||||
mres = 1;
|
||||
}
|
||||
res = ast_streamfile(chan, tmp, chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
else {
|
||||
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
|
||||
res = 0;
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
done:
|
||||
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int reload(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
if (say_cfg) {
|
||||
ast_config_destroy(say_cfg);
|
||||
ast_log(LOG_NOTICE, "Reloading say.conf\n");
|
||||
}
|
||||
say_cfg = ast_config_load("say.conf");
|
||||
/*
|
||||
* XXX here we should sort rules according to the same order
|
||||
* we have in pbx.c so we have the same matching behaviour.
|
||||
*/
|
||||
return 0;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
if (say_cfg)
|
||||
ast_config_destroy(say_cfg);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
say_cfg = ast_config_load("say.conf");
|
||||
ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
|
||||
return ast_register_application(app, playback_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
|
||||
.load = load_module,
|
||||
.unload = unload_module,
|
||||
.reload = reload,
|
||||
);
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,156 +1,85 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Block all calls without Caller*ID, require phone # to be entered
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Block all calls without Caller*ID, require phone # to be entered
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/config.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PRIV_CONFIG "privacy.conf"
|
||||
|
||||
static char *tdesc = "Require phone number to be entered, if no CallerID sent";
|
||||
|
||||
static char *app = "PrivacyManager";
|
||||
|
||||
static char *synopsis = "Require phone number to be entered, if no CallerID sent";
|
||||
|
||||
static char *descrip =
|
||||
" PrivacyManager([maxretries[|minlength[|options]]]): If no Caller*ID \n"
|
||||
"is sent, PrivacyManager answers the channel and asks the caller to\n"
|
||||
"enter their phone number. The caller is given 3 attempts to do so.\n"
|
||||
"The application does nothing if Caller*ID was received on the channel.\n"
|
||||
" Configuration file privacy.conf contains two variables:\n"
|
||||
" maxretries default 3 -maximum number of attempts the caller is allowed \n"
|
||||
" to input a callerid.\n"
|
||||
" minlength default 10 -minimum allowable digits in the input callerid number.\n"
|
||||
"If you don't want to use the config file and have an i/o operation with\n"
|
||||
"every call, you can also specify maxretries and minlength as application\n"
|
||||
"parameters. Doing so supercedes any values set in privacy.conf.\n"
|
||||
"The option string may contain the following character: \n"
|
||||
" 'j' -- jump to n+101 priority after <maxretries> failed attempts to collect\n"
|
||||
" the minlength number of digits.\n"
|
||||
"The application sets the following channel variable upon completion: \n"
|
||||
"PRIVACYMGRSTATUS The status of the privacy manager's attempt to collect \n"
|
||||
" a phone number from the user. A text string that is either:\n"
|
||||
" SUCCESS | FAILED \n"
|
||||
;
|
||||
" PrivacyManager: If no Caller*ID is sent, PrivacyManager answers the\n"
|
||||
"channel and asks the caller to enter their 10 digit phone number.\n"
|
||||
"The caller is given 3 attempts. If after 3 attempts, they do not enter\n"
|
||||
"their 10 digit phone number, and if there exists a priority n + 101,\n"
|
||||
"where 'n' is the priority of the current instance, then the\n"
|
||||
"channel will be setup to continue at that priority level.\n"
|
||||
"Otherwise, it returns 0. Does nothing if Caller*ID was received on the\n"
|
||||
"channel.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int
|
||||
privacy_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int retries;
|
||||
int maxretries = 3;
|
||||
int minlength = 10;
|
||||
int x = 0;
|
||||
const char *s;
|
||||
char phone[30];
|
||||
struct ast_module_user *u;
|
||||
struct ast_config *cfg = NULL;
|
||||
char *parse = NULL;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(maxretries);
|
||||
AST_APP_ARG(minlength);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
int x;
|
||||
char *s;
|
||||
char phone[10];
|
||||
char new_cid[144];
|
||||
struct localuser *u;
|
||||
struct ast_config *cfg;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!ast_strlen_zero(chan->cid.cid_num)) {
|
||||
LOCAL_USER_ADD (u);
|
||||
if (chan->callerid)
|
||||
{
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/*Answer the channel if it is not already*/
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(data)) {
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.maxretries) {
|
||||
if (sscanf(args.maxretries, "%d", &x) == 1)
|
||||
maxretries = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid max retries argument\n");
|
||||
}
|
||||
if (args.minlength) {
|
||||
if (sscanf(args.minlength, "%d", &x) == 1)
|
||||
minlength = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid min length argument\n");
|
||||
}
|
||||
if (args.options)
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
|
||||
}
|
||||
|
||||
if (!x)
|
||||
{
|
||||
/*Read in the config file*/
|
||||
cfg = ast_config_load(PRIV_CONFIG);
|
||||
/*Read in the config file*/
|
||||
cfg = ast_load(PRIV_CONFIG);
|
||||
|
||||
if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
|
||||
if (sscanf(s, "%d", &x) == 1)
|
||||
maxretries = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid max retries argument\n");
|
||||
}
|
||||
|
||||
if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
|
||||
if (sscanf(s, "%d", &x) == 1)
|
||||
minlength = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid min length argument\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*Play unidentified call*/
|
||||
res = ast_safe_sleep(chan, 1000);
|
||||
@@ -159,21 +88,23 @@ static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
|
||||
if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
|
||||
if (sscanf(s, "%d", &x) == 1) {
|
||||
maxretries = x;
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Invalid max retries argument\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*Ask for 10 digit number, give 3 attempts*/
|
||||
for (retries = 0; retries < maxretries; retries++) {
|
||||
if (!res)
|
||||
res = ast_streamfile(chan, "privacy-prompt", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
|
||||
if (!res )
|
||||
res = ast_readstring(chan, phone, sizeof(phone) - 1, /* digit timeout ms */ 3200, /* first digit timeout */ 5000, "#");
|
||||
|
||||
res = ast_app_getdata(chan, "privacy-prompt", phone, sizeof(phone), 0);
|
||||
if (res < 0)
|
||||
break;
|
||||
|
||||
/*Make sure we get at least digits*/
|
||||
if (strlen(phone) >= minlength )
|
||||
/*Make sure we get 10 digits*/
|
||||
if (strlen(phone) == 10)
|
||||
break;
|
||||
else {
|
||||
res = ast_streamfile(chan, "privacy-incorrect", chan->language);
|
||||
@@ -183,50 +114,57 @@ static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
}
|
||||
|
||||
/*Got a number, play sounds and send them on their way*/
|
||||
if ((retries < maxretries) && res >= 0 ) {
|
||||
if ((retries < maxretries) && !res) {
|
||||
res = ast_streamfile(chan, "privacy-thankyou", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
|
||||
ast_set_callerid (chan, phone, "Privacy Manager", NULL);
|
||||
|
||||
/* Clear the unavailable presence bit so if it came in on PRI
|
||||
* the caller id will now be passed out to other channels
|
||||
*/
|
||||
chan->cid.cid_pres &= (AST_PRES_UNAVAILABLE ^ 0xFF);
|
||||
|
||||
if (option_verbose > 2) {
|
||||
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s, callerpres to %d\n",phone,chan->cid.cid_pres);
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "SUCCESS");
|
||||
snprintf (new_cid, sizeof (new_cid), "\"%s\" <%s>", "Privacy Manager", phone);
|
||||
ast_set_callerid (chan, new_cid, 0);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID to %s\n",new_cid);
|
||||
} else {
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
pbx_builtin_setvar_helper(chan, "PRIVACYMGRSTATUS", "FAILED");
|
||||
/*Send the call to n+101 priority, where n is the current priority*/
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority+=100;
|
||||
}
|
||||
if (cfg)
|
||||
ast_config_destroy(cfg);
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int
|
||||
unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application (app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application (app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int
|
||||
load_module (void)
|
||||
{
|
||||
return ast_register_application (app, privacy_exec, synopsis, descrip);
|
||||
return ast_register_application (app, privacy_exec, synopsis,
|
||||
descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");
|
||||
char *
|
||||
description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int
|
||||
usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
394
apps/app_qcall.c
Normal file
394
apps/app_qcall.c
Normal file
@@ -0,0 +1,394 @@
|
||||
/** @file app_qcall.c
|
||||
*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Call back a party and connect them to a running pbx thread
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*
|
||||
* Call a user from a file contained within a queue (/var/spool/asterisk/qcall)
|
||||
*
|
||||
* The queue is a directory containing files with the call request information
|
||||
* as a single line of text as follows:
|
||||
*
|
||||
* Dialstring Caller-ID Extension Maxsecs [Identifier] [Required-response]
|
||||
*
|
||||
* Dialstring -- A Dial String (The number to be called) in the
|
||||
* format Technology/Number, such IAX/mysys/1234 or Zap/g1/1234
|
||||
*
|
||||
* Caller-ID -- A Standard nomalized representation of the Caller-ID of
|
||||
* the number being dialed (generally 10 digits in the US). Leave as
|
||||
* "asreceived" to use the default Caller*ID
|
||||
*
|
||||
* Extension -- The Extension (optionally Extension@context) that the
|
||||
* user should be "transferred" to after acceptance of the call.
|
||||
*
|
||||
* Maxsecs -- The Maximum time of the call in seconds. Specify 0 for infinite.
|
||||
*
|
||||
* Identifier -- The "Identifier" of the request. This is used to determine
|
||||
* the names of the audio prompt files played. The first prompt, the one that
|
||||
* asks for the input, is just the exact string specified as the identifier.
|
||||
* The second prompt, the one that is played after the correct input is given,
|
||||
* (generally a "thank you" recording), is the specified string with "-ok"
|
||||
* added to the end. So, if you specify "foo" as the identifier, your first
|
||||
* prompt file that will be played will be "foo" and the second one will be
|
||||
* "foo-ok". If omitted no prompt is given
|
||||
*
|
||||
* Required-Response (Optional) -- Specify a digit string to be used as the
|
||||
* acceptance "code" if you desire it to be something other then "1". This
|
||||
* can be used to implement some sort of PIN or security system. It may be
|
||||
* more then a single character.
|
||||
*
|
||||
* NOTE: It is important to remember that the process that creates these
|
||||
* files needs keep and maintain a write lock (using flock with the LOCK_EX
|
||||
* option) when writing these files.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/file.h>
|
||||
#include "../astconf.h"
|
||||
|
||||
static char qdir[255];
|
||||
static char *tdesc = "Call from Queue";
|
||||
static pthread_t qcall_thread;
|
||||
static int debug = 0;
|
||||
STANDARD_LOCAL_USER;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#define OLDESTOK 14400 /* not any more then this number of secs old */
|
||||
#define INITIALONE 1 /* initial wait before the first one in secs */
|
||||
#define NEXTONE 600 /* wait before trying it again in secs */
|
||||
#define MAXWAITFORANSWER 45000 /* max call time before answer */
|
||||
/* define either one or both of these two if your application requires it */
|
||||
#if 0
|
||||
#define ACCTCODE "SOMETHING" /* Account code */
|
||||
#define AMAFLAGS AST_CDR_BILLING /* AMA flags */
|
||||
#endif
|
||||
/* define this if you want to have a particular CLID display on the user's
|
||||
phone when they receive the call */
|
||||
#if 0
|
||||
#define OURCLID "2564286275" /* The callerid to be displayed when calling */
|
||||
#endif
|
||||
|
||||
static void *qcall_do(void *arg);
|
||||
|
||||
static void *qcall(void *ignore)
|
||||
{
|
||||
pthread_t dialer_thread;
|
||||
DIR *dirp;
|
||||
FILE *fp;
|
||||
struct dirent *dp;
|
||||
char fname[80];
|
||||
struct stat mystat;
|
||||
time_t t;
|
||||
void *arg;
|
||||
pthread_attr_t attr;
|
||||
|
||||
time(&t);
|
||||
if (debug) printf("@@@@ qcall starting at %s",ctime(&t));
|
||||
for(;;)
|
||||
{
|
||||
time(&t);
|
||||
dirp = opendir(qdir);
|
||||
if (!dirp)
|
||||
{
|
||||
perror("app_qcall:Cannot open queue directory");
|
||||
break;
|
||||
}
|
||||
while((dp = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (dp->d_name[0] == '.') continue;
|
||||
snprintf(fname, sizeof(fname), "%s/%s", qdir, dp->d_name);
|
||||
if (stat(fname,&mystat) == -1)
|
||||
{
|
||||
perror("app_qcall:stat");
|
||||
fprintf(stderr,"%s\n",fname);
|
||||
continue;
|
||||
}
|
||||
/* if not a regular file, skip it */
|
||||
if ((mystat.st_mode & S_IFMT) != S_IFREG) continue;
|
||||
/* if not yet .... */
|
||||
if (mystat.st_atime == mystat.st_mtime)
|
||||
{ /* first time */
|
||||
if ((mystat.st_atime + INITIALONE) > t)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ /* already looked at once */
|
||||
if ((mystat.st_atime + NEXTONE) > t) continue;
|
||||
}
|
||||
/* if too old */
|
||||
if (mystat.st_mtime < (t - OLDESTOK))
|
||||
{
|
||||
/* kill it, its too old */
|
||||
unlink(fname);
|
||||
continue;
|
||||
}
|
||||
/* "touch" file's access time */
|
||||
fp = fopen(fname,"r");
|
||||
if (fp) fclose(fp);
|
||||
/* make a copy of the filename string, so that we
|
||||
may go on and use the buffer */
|
||||
arg = (void *) strdup(fname);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (ast_pthread_create(&dialer_thread,&attr,qcall_do,arg) == -1)
|
||||
{
|
||||
perror("qcall: Cannot create thread");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
sleep(1);
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
/* single thread with one file (request) to dial */
|
||||
static void *qcall_do(void *arg)
|
||||
{
|
||||
char fname[300] = "";
|
||||
char dialstr[300];
|
||||
char extstr[300];
|
||||
char ident[300] = "";
|
||||
char reqinp[300] = "";
|
||||
char buf[300];
|
||||
char clid[300],*tele,*context;
|
||||
FILE *fp;
|
||||
int ms = MAXWAITFORANSWER,maxsecs;
|
||||
struct ast_channel *channel;
|
||||
time_t t;
|
||||
|
||||
/* get the filename from the arg */
|
||||
strncpy(fname,(char *)arg, sizeof(fname) - 1);
|
||||
free(arg);
|
||||
time(&t);
|
||||
fp = fopen(fname,"r");
|
||||
if (!fp) /* if cannot open request file */
|
||||
{
|
||||
perror("qcall_do:fopen");
|
||||
fprintf(stderr,"%s\n",fname);
|
||||
unlink(fname);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
/* lock the file */
|
||||
if (flock(fileno(fp),LOCK_EX) == -1)
|
||||
{
|
||||
perror("qcall_do:flock");
|
||||
fprintf(stderr,"%s\n",fname);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
/* default required input for acknowledgement */
|
||||
reqinp[0] = '1';
|
||||
reqinp[1] = '\0';
|
||||
/* default no ident */
|
||||
ident[0] = '\0'; /* default no ident */
|
||||
if (fscanf(fp,"%s %s %s %d %s %s",dialstr,clid,
|
||||
extstr,&maxsecs,ident,reqinp) < 4)
|
||||
{
|
||||
fprintf(stderr,"qcall_do:file line invalid in file %s:\n",fname);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
flock(fileno(fp),LOCK_UN);
|
||||
fclose(fp);
|
||||
tele = strchr(dialstr,'/');
|
||||
if (!tele)
|
||||
{
|
||||
fprintf(stderr,"qcall_do:Dial number must be in format tech/number\n");
|
||||
unlink(fname);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
*tele++ = 0;
|
||||
channel = ast_request(dialstr,AST_FORMAT_SLINEAR,tele);
|
||||
if (channel)
|
||||
{
|
||||
ast_set_read_format(channel,AST_FORMAT_SLINEAR);
|
||||
ast_set_write_format(channel,AST_FORMAT_SLINEAR);
|
||||
#ifdef OURCLID
|
||||
if (channel->callerid)
|
||||
free(channel->callerid);
|
||||
channel->callerid = strdup(OURCLID);
|
||||
if (channel->ani)
|
||||
free(channel->ani);
|
||||
channel->ani = strdup(OURCLID);
|
||||
#endif
|
||||
channel->whentohangup = 0;
|
||||
channel->appl = "AppQcall";
|
||||
channel->data = "(Outgoing Line)";
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Qcall initiating call to %s/%s on %s (%s)\n",
|
||||
dialstr,tele,channel->name,fname);
|
||||
ast_call(channel,tele,MAXWAITFORANSWER);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"qcall_do:Sorry unable to obtain channel\n");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
if (strcasecmp(clid, "asreceived")) {
|
||||
if (channel->callerid) free(channel->callerid);
|
||||
channel->callerid = NULL;
|
||||
if (channel->ani) free(channel->ani);
|
||||
channel->ani = NULL;
|
||||
}
|
||||
if (channel->_state == AST_STATE_UP)
|
||||
if (debug) printf("@@@@ Autodial:Line is Up\n");
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Qcall waiting for answer on %s\n",
|
||||
channel->name);
|
||||
while(ms > 0){
|
||||
struct ast_frame *f;
|
||||
ms = ast_waitfor(channel,ms);
|
||||
f = ast_read(channel);
|
||||
if (!f)
|
||||
{
|
||||
if (debug) printf("@@@@ qcall_do:Hung Up\n");
|
||||
unlink(fname);
|
||||
break;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_CONTROL)
|
||||
{
|
||||
if (f->subclass == AST_CONTROL_HANGUP)
|
||||
{
|
||||
if (debug) printf("@@@@ qcall_do:Hung Up\n");
|
||||
unlink(fname);
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
if (f->subclass == AST_CONTROL_ANSWER)
|
||||
{
|
||||
if (debug) printf("@@@@ qcall_do:Phone Answered\n");
|
||||
if (channel->_state == AST_STATE_UP)
|
||||
{
|
||||
unlink(fname);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Qcall got answer on %s\n",
|
||||
channel->name);
|
||||
usleep(1500000);
|
||||
if (strlen(ident)) {
|
||||
ast_streamfile(channel,ident,0);
|
||||
if (ast_readstring(channel,buf,strlen(reqinp),10000,5000,"#"))
|
||||
{
|
||||
ast_stopstream(channel);
|
||||
if (debug) printf("@@@@ qcall_do: timeout or hangup in dtmf read\n");
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
ast_stopstream(channel);
|
||||
if (strcmp(buf,reqinp)) /* if not match */
|
||||
{
|
||||
if (debug) printf("@@@@ qcall_do: response (%s) does not match required (%s)\n",buf,reqinp);
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
/* okay, now we go for it */
|
||||
context = strchr(extstr,'@');
|
||||
if (!context) context = "default";
|
||||
else *context++ = 0;
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Qcall got accept, now putting through to %s@%s on %s\n",
|
||||
extstr,context,channel->name);
|
||||
if (strlen(ident)) {
|
||||
strncat(ident,"-ok", sizeof(ident) - strlen(ident) - 1);
|
||||
/* if file existent, play it */
|
||||
if (!ast_streamfile(channel,ident,0))
|
||||
{
|
||||
ast_waitstream(channel,"");
|
||||
ast_stopstream(channel);
|
||||
}
|
||||
}
|
||||
if (strcasecmp(clid, "asreceived")) {
|
||||
channel->callerid = strdup(clid);
|
||||
channel->ani = strdup(clid);
|
||||
}
|
||||
channel->language[0] = 0;
|
||||
channel->dnid = strdup(extstr);
|
||||
#ifdef AMAFLAGS
|
||||
channel->amaflags = AMAFLAGS;
|
||||
#endif
|
||||
#ifdef ACCTCODE
|
||||
strncpy(channel->accountcode, ACCTCODE, sizeof(chan->accountcode) - 1);
|
||||
#else
|
||||
channel->accountcode[0] = 0;
|
||||
#endif
|
||||
if (maxsecs) /* if finite length call */
|
||||
{
|
||||
time(&channel->whentohangup);
|
||||
channel->whentohangup += maxsecs;
|
||||
}
|
||||
strncpy(channel->exten, extstr, sizeof(channel->exten) - 1);
|
||||
strncpy(channel->context, context, sizeof(channel->context) - 1);
|
||||
channel->priority = 1;
|
||||
if(debug) printf("Caller ID is %s\n", channel->callerid);
|
||||
ast_pbx_run(channel);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
}
|
||||
else if(f->subclass==AST_CONTROL_RINGING)
|
||||
if (debug) printf("@@@@ qcall_do:Phone Ringing end\n");
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
ast_hangup(channel);
|
||||
if (debug) printf("@@@@ qcall_do:Hung up channel\n");
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
snprintf(qdir, sizeof(qdir), "%s/%s", ast_config_AST_SPOOL_DIR, "qcall");
|
||||
mkdir(qdir,0760);
|
||||
ast_pthread_create(&qcall_thread,NULL,qcall,NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
5370
apps/app_queue.c
5370
apps/app_queue.c
File diff suppressed because it is too large
Load Diff
@@ -1,45 +1,29 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (c) 2003 - 2005 Tilghman Lesher. All rights reserved.
|
||||
* Random application
|
||||
*
|
||||
* Copyright (c) 2003-2004 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <asterisk__app_random__200508@the-tilghman.com>
|
||||
* Tilghman Lesher <asterisk__app_random__20040111@the-tilghman.com>
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage or distribution.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Random application
|
||||
*
|
||||
* \author Tilghman Lesher <asterisk__app_random__200508@the-tilghman.com>
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
/*! \todo The Random() app should be removed from trunk following the release of 1.4 */
|
||||
static char *tdesc = "Random goto";
|
||||
|
||||
static char *app_random = "Random";
|
||||
|
||||
@@ -47,62 +31,97 @@ static char *random_synopsis = "Conditionally branches, based upon a probability
|
||||
|
||||
static char *random_descrip =
|
||||
"Random([probability]:[[context|]extension|]priority)\n"
|
||||
" probability := INTEGER in the range 1 to 100\n"
|
||||
"DEPRECATED: Use GotoIf($[${RAND(1,100)} > <number>]?<label>)\n";
|
||||
" probability := INTEGER in the range 1 to 100\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int random_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
|
||||
char *s;
|
||||
char *exten, *pri, *context;
|
||||
char *prob;
|
||||
int probint;
|
||||
static int deprecated = 0;
|
||||
int probint, priorityint;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
LOCAL_USER_ADD(u);
|
||||
s = ast_strdupa((void *) data);
|
||||
|
||||
prob = strsep(&s,":");
|
||||
if ((!prob) || (sscanf(prob, "%d", &probint) != 1))
|
||||
probint = 0;
|
||||
|
||||
if (!deprecated) {
|
||||
deprecated = 1;
|
||||
ast_log(LOG_WARNING, "Random is deprecated in Asterisk 1.4. Replace with GotoIf($[${RAND(0,99)} + %d >= 100]?%s)\n", probint, s);
|
||||
}
|
||||
|
||||
if ((ast_random() % 100) + probint >= 100) {
|
||||
res = ast_parseable_goto(chan, s);
|
||||
if ((random() % 100) + probint > 100) {
|
||||
context = strsep(&s, "|");
|
||||
exten = strsep(&s, "|");
|
||||
if (!exten) {
|
||||
/* Only a priority */
|
||||
pri = context;
|
||||
exten = NULL;
|
||||
context = NULL;
|
||||
} else {
|
||||
pri = strsep(&s, "|");
|
||||
if (!pri) {
|
||||
pri = exten;
|
||||
exten = context;
|
||||
context = NULL;
|
||||
}
|
||||
}
|
||||
if (!pri) {
|
||||
ast_log(LOG_WARNING, "No label specified\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
} else if (sscanf(pri, "%d", &priorityint) != 1) {
|
||||
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
/* At this point we have a priority and */
|
||||
/* maybe an extension and a context */
|
||||
chan->priority = priorityint - 1;
|
||||
if (exten && strcasecmp(exten, "BYEXTENSION"))
|
||||
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
|
||||
if (context)
|
||||
strncpy(chan->context, context, sizeof(chan->context)-1);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n",
|
||||
chan->context,chan->exten, chan->priority+1);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_random);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app_random);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_random, random_exec, random_synopsis, random_descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Random goto");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
274
apps/app_read.c
274
apps/app_read.c
@@ -1,234 +1,144 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Trivial application to read a variable
|
||||
*
|
||||
* Copyright (C) 2003, Digium
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to read a variable
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/indications.h"
|
||||
|
||||
enum {
|
||||
OPT_SKIP = (1 << 0),
|
||||
OPT_INDICATION = (1 << 1),
|
||||
OPT_NOANSWER = (1 << 2),
|
||||
} read_option_flags;
|
||||
|
||||
AST_APP_OPTIONS(read_app_options, {
|
||||
AST_APP_OPTION('s', OPT_SKIP),
|
||||
AST_APP_OPTION('i', OPT_INDICATION),
|
||||
AST_APP_OPTION('n', OPT_NOANSWER),
|
||||
});
|
||||
static char *tdesc = "Read Variable Application";
|
||||
|
||||
static char *app = "Read";
|
||||
|
||||
static char *synopsis = "Read a variable";
|
||||
|
||||
static char *descrip =
|
||||
" Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n"
|
||||
"Reads a #-terminated string of digits a certain number of times from the\n"
|
||||
"user in to the given variable.\n"
|
||||
" filename -- file to play before reading digits or tone with option i\n"
|
||||
" Read(variable[|filename][|maxdigits][|option])\n\n"
|
||||
"Reads a #-terminated string of digits from the user in to the given variable,\n"
|
||||
"optionally playing a given filename first.\n"
|
||||
" maxdigits -- maximum acceptable number of digits. Stops reading after\n"
|
||||
" maxdigits have been entered (without requiring the user to\n"
|
||||
" press the '#' key).\n"
|
||||
" Defaults to 0 - no limit - wait for the user press the '#' key.\n"
|
||||
" Any value below 0 means the same. Max accepted value is 255.\n"
|
||||
" option -- options are 's' , 'i', 'n'\n"
|
||||
" 's' to return immediately if the line is not up,\n"
|
||||
" 'i' to play filename as an indication tone from your indications.conf\n"
|
||||
" 'n' to read digits even if the line is not up.\n"
|
||||
" attempts -- if greater than 1, that many attempts will be made in the \n"
|
||||
" event no data is entered.\n"
|
||||
" timeout -- An integer number of seconds to wait for a digit response. If greater\n"
|
||||
" than 0, that value will override the default timeout.\n\n"
|
||||
"Read should disconnect if the function fails or errors out.\n";
|
||||
" option -- may be 'skip' to return immediately if the line is not up,\n"
|
||||
" or 'noanswer' to read digits even if the line is not up.\n\n"
|
||||
"Returns -1 on hangup or error and 0 otherwise.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
#define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int read_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
char tmp[256] = "";
|
||||
int maxdigits = 255;
|
||||
int tries = 1, to = 0, x = 0;
|
||||
char *argcopy = NULL;
|
||||
struct tone_zone_sound *ts;
|
||||
struct ast_flags flags = {0};
|
||||
|
||||
AST_DECLARE_APP_ARGS(arglist,
|
||||
AST_APP_ARG(variable);
|
||||
AST_APP_ARG(filename);
|
||||
AST_APP_ARG(maxdigits);
|
||||
AST_APP_ARG(options);
|
||||
AST_APP_ARG(attempts);
|
||||
AST_APP_ARG(timeout);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
struct localuser *u;
|
||||
char tmp[256];
|
||||
char argdata[256] = "";
|
||||
char *varname;
|
||||
char *filename;
|
||||
char *stringp;
|
||||
char *maxdigitstr;
|
||||
char *options;
|
||||
int option_skip = 0;
|
||||
int option_noanswer = 0;
|
||||
int maxdigits=255;
|
||||
if (!data || ast_strlen_zero((char *)data)) {
|
||||
ast_log(LOG_WARNING, "Read requires an argument (variable)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
argcopy = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(arglist, argcopy);
|
||||
|
||||
if (!ast_strlen_zero(arglist.options)) {
|
||||
ast_app_parse_options(read_app_options, &flags, NULL, arglist.options);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(arglist.attempts)) {
|
||||
tries = atoi(arglist.attempts);
|
||||
if (tries <= 0)
|
||||
tries = 1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(arglist.timeout)) {
|
||||
to = atoi(arglist.timeout);
|
||||
if (to <= 0)
|
||||
to = 0;
|
||||
else
|
||||
to *= 1000;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(arglist.filename)) {
|
||||
arglist.filename = NULL;
|
||||
}
|
||||
if (!ast_strlen_zero(arglist.maxdigits)) {
|
||||
maxdigits = atoi(arglist.maxdigits);
|
||||
if ((maxdigits<1) || (maxdigits>255)) {
|
||||
maxdigits = 255;
|
||||
} else if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %d digits.\n", maxdigits);
|
||||
}
|
||||
if (ast_strlen_zero(arglist.variable)) {
|
||||
ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n");
|
||||
ast_module_user_remove(u);
|
||||
strncpy(argdata, (char *)data, sizeof(argdata)-1);
|
||||
stringp=argdata;
|
||||
varname = strsep(&stringp, "|");
|
||||
filename = strsep(&stringp, "|");
|
||||
maxdigitstr = strsep(&stringp,"|");
|
||||
options = strsep(&stringp, "|");
|
||||
if (options && !strcasecmp(options, "skip"))
|
||||
option_skip = 1;
|
||||
if (options && !strcasecmp(options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
if (!(filename) || ast_strlen_zero(filename))
|
||||
filename = NULL;
|
||||
if (maxdigitstr) {
|
||||
maxdigits = atoi(maxdigitstr);
|
||||
if ((maxdigits<1) || (maxdigits>255)) {
|
||||
maxdigits = 255;
|
||||
} else
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %i digits.\n", maxdigits);
|
||||
}
|
||||
if (!(varname) || ast_strlen_zero(varname)) {
|
||||
ast_log(LOG_WARNING, "Read requires an variable name\n");
|
||||
return -1;
|
||||
}
|
||||
ts=NULL;
|
||||
if (ast_test_flag(&flags,OPT_INDICATION)) {
|
||||
if (!ast_strlen_zero(arglist.filename)) {
|
||||
ts = ast_get_indication_tone(chan->zone,arglist.filename);
|
||||
}
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
if (ast_test_flag(&flags,OPT_SKIP)) {
|
||||
if (option_skip) {
|
||||
/* At the user's option, skip if the line is not up */
|
||||
pbx_builtin_setvar_helper(chan, arglist.variable, "\0");
|
||||
ast_module_user_remove(u);
|
||||
pbx_builtin_setvar_helper(chan, varname, "\0");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
} else if (!ast_test_flag(&flags,OPT_NOANSWER)) {
|
||||
} else if (!option_noanswer) {
|
||||
/* Otherwise answer unless we're supposed to read while on-hook */
|
||||
res = ast_answer(chan);
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
while (tries && !res) {
|
||||
ast_stopstream(chan);
|
||||
if (ts && ts->data[0]) {
|
||||
if (!to)
|
||||
to = chan->pbx ? chan->pbx->rtimeout * 1000 : 6000;
|
||||
res = ast_playtones_start(chan, 0, ts->data, 0);
|
||||
for (x = 0; x < maxdigits; ) {
|
||||
res = ast_waitfordigit(chan, to);
|
||||
ast_playtones_stop(chan);
|
||||
if (res < 1) {
|
||||
tmp[x]='\0';
|
||||
break;
|
||||
}
|
||||
tmp[x++] = res;
|
||||
if (tmp[x-1] == '#') {
|
||||
tmp[x-1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
res = ast_app_getdata(chan, arglist.filename, tmp, maxdigits, to);
|
||||
}
|
||||
if (res > -1) {
|
||||
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
|
||||
if (!ast_strlen_zero(tmp)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
|
||||
tries = 0;
|
||||
} else {
|
||||
tries--;
|
||||
if (option_verbose > 2) {
|
||||
if (tries)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User entered nothing, %d chance%s left\n", tries, (tries != 1) ? "s" : "");
|
||||
else
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User entered nothing.\n");
|
||||
}
|
||||
}
|
||||
res = 0;
|
||||
} else {
|
||||
pbx_builtin_setvar_helper(chan, arglist.variable, tmp);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
res = ast_app_getdata(chan, filename, tmp, maxdigits, 0);
|
||||
if (res > -1) {
|
||||
pbx_builtin_setvar_helper(chan, varname, tmp);
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
|
||||
res = 0;
|
||||
} else {
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
|
||||
}
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, read_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read Variable Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Matt O'Gorman <mogorman@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief ReadFile application -- Reads in a File for you.
|
||||
*
|
||||
* \author Matt O'Gorman <mogorman@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *app_readfile = "ReadFile";
|
||||
|
||||
static char *readfile_synopsis = "ReadFile(varname=file,length)";
|
||||
|
||||
static char *readfile_descrip =
|
||||
"ReadFile(varname=file,length)\n"
|
||||
" Varname - Result stored here.\n"
|
||||
" File - The name of the file to read.\n"
|
||||
" Length - Maximum number of characters to capture.\n";
|
||||
|
||||
|
||||
static int readfile_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct ast_module_user *u;
|
||||
char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL;
|
||||
int len=0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "ReadFile require an argument!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
|
||||
varname = strsep(&s, "=");
|
||||
file = strsep(&s, "|");
|
||||
length = s;
|
||||
|
||||
if (!varname || !file) {
|
||||
ast_log(LOG_ERROR, "No file or variable specified!\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length) {
|
||||
if ((sscanf(length, "%d", &len) != 1) || (len < 0)) {
|
||||
ast_log(LOG_WARNING, "%s is not a positive number, defaulting length to max\n", length);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((returnvar = ast_read_textfile(file))) {
|
||||
if (len > 0) {
|
||||
if (len < strlen(returnvar))
|
||||
returnvar[len]='\0';
|
||||
else
|
||||
ast_log(LOG_WARNING, "%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar));
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, varname, returnvar);
|
||||
free(returnvar);
|
||||
}
|
||||
ast_module_user_remove(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_readfile);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_readfile, readfile_exec, readfile_synopsis, readfile_descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stores output of file into a variable");
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Anthony Minessale <anthmct@yahoo.com>
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief RealTime App
|
||||
*
|
||||
* \author Anthony Minessale <anthmct@yahoo.com>
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/cli.h"
|
||||
|
||||
#define next_one(var) var = var->next
|
||||
#define crop_data(str) { *(str) = '\0' ; (str)++; }
|
||||
|
||||
static char *app = "RealTime";
|
||||
static char *uapp = "RealTimeUpdate";
|
||||
static char *synopsis = "Realtime Data Lookup";
|
||||
static char *usynopsis = "Realtime Data Rewrite";
|
||||
static char *USAGE = "RealTime(<family>|<colmatch>|<value>[|<prefix>])";
|
||||
static char *UUSAGE = "RealTimeUpdate(<family>|<colmatch>|<value>|<newcol>|<newval>)";
|
||||
static char *desc =
|
||||
"Use the RealTime config handler system to read data into channel variables.\n"
|
||||
"RealTime(<family>|<colmatch>|<value>[|<prefix>])\n\n"
|
||||
"All unique column names will be set as channel variables with optional prefix\n"
|
||||
"to the name. For example, a prefix of 'var_' would make the column 'name'\n"
|
||||
"become the variable ${var_name}. REALTIMECOUNT will be set with the number\n"
|
||||
"of values read.\n";
|
||||
static char *udesc = "Use the RealTime config handler system to update a value\n"
|
||||
"RealTimeUpdate(<family>|<colmatch>|<value>|<newcol>|<newval>)\n\n"
|
||||
"The column <newcol> in 'family' matching column <colmatch>=<value> will be\n"
|
||||
"updated to <newval>. REALTIMECOUNT will be set with the number of rows\n"
|
||||
"updated or -1 if an error occurs.\n";
|
||||
|
||||
|
||||
static int cli_realtime_load(int fd, int argc, char **argv)
|
||||
{
|
||||
char *header_format = "%30s %-30s\n";
|
||||
struct ast_variable *var=NULL;
|
||||
|
||||
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) {
|
||||
ast_cli(fd, header_format, "Column Name", "Column Value");
|
||||
ast_cli(fd, header_format, "--------------------", "--------------------");
|
||||
while(var) {
|
||||
ast_cli(fd, header_format, var->name, var->value);
|
||||
var = var->next;
|
||||
}
|
||||
} else {
|
||||
ast_cli(fd, "No rows found matching search criteria.\n");
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static int cli_realtime_update(int fd, int argc, char **argv) {
|
||||
int res = 0;
|
||||
|
||||
if(argc<7) {
|
||||
ast_cli(fd, "You must supply a family name, a column to update on, a new value, column to match, and value to to match.\n");
|
||||
ast_cli(fd, "Ex: realtime update sipfriends name bobsphone port 4343\n will execute SQL as UPDATE sipfriends SET port = 4343 WHERE name = bobsphone\n");
|
||||
return RESULT_FAILURE;
|
||||
}
|
||||
|
||||
res = ast_update_realtime(argv[2], argv[3], argv[4], argv[5], argv[6], NULL);
|
||||
|
||||
if(res < 0) {
|
||||
ast_cli(fd, "Failed to update. Check the debug log for possible SQL related entries.\n");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ast_cli(fd, "Updated %d RealTime record%s.\n", res, (res != 1) ? "s" : "");
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
static char cli_realtime_load_usage[] =
|
||||
"Usage: realtime load <family> <colmatch> <value>\n"
|
||||
" Prints out a list of variables using the RealTime driver.\n";
|
||||
|
||||
static char cli_realtime_update_usage[] =
|
||||
"Usage: realtime update <family> <colmatch> <value>\n"
|
||||
" Update a single variable using the RealTime driver.\n";
|
||||
|
||||
static struct ast_cli_entry cli_realtime[] = {
|
||||
{ { "realtime", "load", NULL, NULL },
|
||||
cli_realtime_load, "Used to print out RealTime variables.",
|
||||
cli_realtime_load_usage, NULL },
|
||||
|
||||
{ { "realtime", "update", NULL, NULL },
|
||||
cli_realtime_update, "Used to update RealTime variables.",
|
||||
cli_realtime_update_usage, NULL },
|
||||
};
|
||||
|
||||
static int realtime_update_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *family=NULL, *colmatch=NULL, *value=NULL, *newcol=NULL, *newval=NULL;
|
||||
struct ast_module_user *u;
|
||||
int res = 0, count = 0;
|
||||
char countc[13];
|
||||
|
||||
ast_log(LOG_WARNING, "The RealTimeUpdate application has been deprecated in favor of the REALTIME dialplan function.\n");
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
family = ast_strdupa(data);
|
||||
if ((colmatch = strchr(family,'|'))) {
|
||||
crop_data(colmatch);
|
||||
if ((value = strchr(colmatch,'|'))) {
|
||||
crop_data(value);
|
||||
if ((newcol = strchr(value,'|'))) {
|
||||
crop_data(newcol);
|
||||
if ((newval = strchr(newcol,'|')))
|
||||
crop_data(newval);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! (family && value && colmatch && newcol && newval) ) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
|
||||
res = -1;
|
||||
} else {
|
||||
count = ast_update_realtime(family,colmatch,value,newcol,newval,NULL);
|
||||
}
|
||||
|
||||
snprintf(countc, sizeof(countc), "%d", count);
|
||||
pbx_builtin_setvar_helper(chan, "REALTIMECOUNT", countc);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int realtime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0, count=0;
|
||||
struct ast_module_user *u;
|
||||
struct ast_variable *var, *itt;
|
||||
char *family=NULL, *colmatch=NULL, *value=NULL, *prefix=NULL, *vname=NULL;
|
||||
char countc[13];
|
||||
size_t len;
|
||||
|
||||
ast_log(LOG_WARNING, "The RealTime application has been deprecated in favor of the REALTIME dialplan function.\n");
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",USAGE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
family = ast_strdupa(data);
|
||||
if ((colmatch = strchr(family,'|'))) {
|
||||
crop_data(colmatch);
|
||||
if ((value = strchr(colmatch,'|'))) {
|
||||
crop_data(value);
|
||||
if ((prefix = strchr(value,'|')))
|
||||
crop_data(prefix);
|
||||
}
|
||||
}
|
||||
if (! (family && value && colmatch) ) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",USAGE);
|
||||
res = -1;
|
||||
} else {
|
||||
if (option_verbose > 3)
|
||||
ast_verbose(VERBOSE_PREFIX_4"Realtime Lookup: family:'%s' colmatch:'%s' value:'%s'\n",family,colmatch,value);
|
||||
if ((var = ast_load_realtime(family, colmatch, value, NULL))) {
|
||||
for (itt = var; itt; itt = itt->next) {
|
||||
if(prefix) {
|
||||
len = strlen(prefix) + strlen(itt->name) + 2;
|
||||
vname = alloca(len);
|
||||
snprintf(vname,len,"%s%s",prefix,itt->name);
|
||||
|
||||
} else
|
||||
vname = itt->name;
|
||||
|
||||
pbx_builtin_setvar_helper(chan, vname, itt->value);
|
||||
count++;
|
||||
}
|
||||
ast_variables_destroy(var);
|
||||
} else if (option_verbose > 3)
|
||||
ast_verbose(VERBOSE_PREFIX_4"No Realtime Matches Found.\n");
|
||||
}
|
||||
snprintf(countc, sizeof(countc), "%d", count);
|
||||
pbx_builtin_setvar_helper(chan, "REALTIMECOUNT", countc);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_cli_unregister_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
|
||||
res = ast_unregister_application(uapp);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
ast_cli_register_multiple(cli_realtime, sizeof(cli_realtime) / sizeof(struct ast_cli_entry));
|
||||
res = ast_register_application(uapp, realtime_update_exec, usynopsis, udesc);
|
||||
res |= ast_register_application(app, realtime_exec, synopsis, desc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Data Lookup/Rewrite");
|
||||
@@ -1,92 +1,67 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Trivial application to record a sound file
|
||||
*
|
||||
* Copyright (C) 2001, Linux Support Services, Inc.
|
||||
*
|
||||
* Matthew Fredrickson <creslin@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Matthew Fredrickson <creslin@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Trivial application to record a sound file
|
||||
*
|
||||
* \author Matthew Fredrickson <creslin@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/dsp.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Trivial Record Application";
|
||||
|
||||
static char *app = "Record";
|
||||
|
||||
static char *synopsis = "Record to a file";
|
||||
|
||||
static char *descrip =
|
||||
" Record(filename.format|silence[|maxduration][|options])\n\n"
|
||||
" Record(filename:format|silence[|maxduration][|option])\n\n"
|
||||
"Records from the channel into a given filename. If the file exists it will\n"
|
||||
"be overwritten.\n"
|
||||
"- 'format' is the format of the file type to be recorded (wav, gsm, etc).\n"
|
||||
"- 'silence' is the number of seconds of silence to allow before returning.\n"
|
||||
"- 'maxduration' is the maximum recording duration in seconds. If missing\n"
|
||||
"or 0 there is no maximum.\n"
|
||||
"- 'options' may contain any of the following letters:\n"
|
||||
" 'a' : append to existing recording rather than replacing\n"
|
||||
" 'n' : do not answer, but record anyway if line not yet answered\n"
|
||||
" 'q' : quiet (do not play a beep tone)\n"
|
||||
" 's' : skip recording if the line is not yet answered\n"
|
||||
" 't' : use alternate '*' terminator key (DTMF) instead of default '#'\n"
|
||||
" 'x' : ignore all terminator keys (DTMF) and keep recording until hangup\n"
|
||||
"\n"
|
||||
"- 'option' may be 'skip' to return immediately if the line is not up,\n"
|
||||
"or 'noanswer' to attempt to record even if the line is not up.\n\n"
|
||||
"If filename contains '%d', these characters will be replaced with a number\n"
|
||||
"incremented by one each time the file is recorded. A channel variable\n"
|
||||
"named RECORDED_FILE will also be set, which contains the final filemname.\n\n"
|
||||
"Use 'core show file formats' to see the available formats on your system\n\n"
|
||||
"incremented by one each time the file is recorded. \n\n"
|
||||
"Formats: g723, g729, gsm, h263, ulaw, alaw, vox, wav, WAV\n\n"
|
||||
"User can press '#' to terminate the recording and continue to the next priority.\n\n"
|
||||
"If the user should hangup during a recording, all data will be lost and the\n"
|
||||
"application will teminate. \n";
|
||||
"Returns -1 when the user hangs up.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int record_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int count = 0;
|
||||
int percentflag = 0;
|
||||
char *filename, *ext = NULL, *silstr, *maxstr, *options;
|
||||
char *vdata, *p;
|
||||
int i = 0;
|
||||
char fil[256];
|
||||
char tmp[256];
|
||||
char ext[10];
|
||||
char *vdata;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
struct ast_filestream *s = '\0';
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
struct ast_frame *f = NULL;
|
||||
|
||||
struct ast_dsp *sildet = NULL; /* silence detector dsp */
|
||||
@@ -94,134 +69,124 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
int dspsilence = 0;
|
||||
int silence = 0; /* amount of silence to allow */
|
||||
int gotsilence = 0; /* did we timeout for silence? */
|
||||
int maxduration = 0; /* max duration of recording in milliseconds */
|
||||
char silencestr[5];
|
||||
char durationstr[8];
|
||||
int maxduration = 0; /* max duration of recording */
|
||||
int gottimeout = 0; /* did we timeout for maxduration exceeded? */
|
||||
time_t timeout = 0;
|
||||
char option[16];
|
||||
int option_skip = 0;
|
||||
int option_noanswer = 0;
|
||||
int option_append = 0;
|
||||
int terminator = '#';
|
||||
int option_quiet = 0;
|
||||
int rfmt = 0;
|
||||
int flags;
|
||||
int waitres;
|
||||
struct ast_silence_generator *silgen = NULL;
|
||||
|
||||
char *end=NULL;
|
||||
char *p=NULL;
|
||||
|
||||
|
||||
|
||||
/* The next few lines of code parse out the filename and header from the input string */
|
||||
if (ast_strlen_zero(data)) { /* no data implies no filename or anything is present */
|
||||
if (!data) { /* no data implies no filename or anything is present */
|
||||
ast_log(LOG_WARNING, "Record requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* Yay for strsep being easy */
|
||||
vdata = ast_strdupa(data);
|
||||
|
||||
p = vdata;
|
||||
filename = strsep(&p, "|");
|
||||
silstr = strsep(&p, "|");
|
||||
maxstr = strsep(&p, "|");
|
||||
options = strsep(&p, "|");
|
||||
|
||||
if (filename) {
|
||||
if (strstr(filename, "%d"))
|
||||
percentflag = 1;
|
||||
ext = strrchr(filename, '.'); /* to support filename with a . in the filename, not format */
|
||||
if (!ext)
|
||||
ext = strchr(filename, ':');
|
||||
if (ext) {
|
||||
*ext = '\0';
|
||||
ext++;
|
||||
p = vdata;
|
||||
while(p && (p=strchr(p,':'))) {
|
||||
end=p;
|
||||
if(!strcasecmp(end,":end")) {
|
||||
*end='\0';
|
||||
end++;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
end=NULL;
|
||||
}
|
||||
if (!ext) {
|
||||
ast_log(LOG_WARNING, "No extension specified to filename!\n");
|
||||
ast_module_user_remove(u);
|
||||
|
||||
|
||||
for (; vdata[i] && (vdata[i] != ':') && (vdata[i] != '|'); i++ ) {
|
||||
if ((vdata[i] == '%') && (vdata[i+1] == 'd')) {
|
||||
percentflag = 1; /* the wildcard is used */
|
||||
}
|
||||
if (j < sizeof(fil) - 1)
|
||||
fil[j++] = vdata[i];
|
||||
}
|
||||
fil[j] = '\0';
|
||||
|
||||
if (vdata[i] != ':') {
|
||||
ast_log(LOG_WARNING, "No extension found\n");
|
||||
return -1;
|
||||
}
|
||||
if (silstr) {
|
||||
if ((sscanf(silstr, "%d", &i) == 1) && (i > -1)) {
|
||||
silence = i * 1000;
|
||||
} else if (!ast_strlen_zero(silstr)) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr);
|
||||
}
|
||||
i++;
|
||||
|
||||
j = 0;
|
||||
for (; vdata[i] && (vdata[i] != '|'); i++)
|
||||
if (j < sizeof(ext) - 1)
|
||||
ext[j++] = vdata[i];
|
||||
ext[j] = '\0';
|
||||
|
||||
if (vdata[i] == '|')
|
||||
i++;
|
||||
|
||||
j = 0;
|
||||
for (; vdata[i] && (vdata[i] != '|'); i++)
|
||||
if (j < sizeof(silencestr) - 1)
|
||||
silencestr[j++] = vdata[i];
|
||||
silencestr[j] = '\0';
|
||||
|
||||
if (j > 0) {
|
||||
silence = atoi(silencestr);
|
||||
if (silence > 0)
|
||||
silence *= 1000;
|
||||
}
|
||||
|
||||
if (maxstr) {
|
||||
if ((sscanf(maxstr, "%d", &i) == 1) && (i > -1))
|
||||
/* Convert duration to milliseconds */
|
||||
maxduration = i * 1000;
|
||||
else if (!ast_strlen_zero(maxstr))
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr);
|
||||
}
|
||||
if (options) {
|
||||
/* Retain backwards compatibility with old style options */
|
||||
if (!strcasecmp(options, "skip"))
|
||||
option_skip = 1;
|
||||
else if (!strcasecmp(options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
else {
|
||||
if (strchr(options, 's'))
|
||||
option_skip = 1;
|
||||
if (strchr(options, 'n'))
|
||||
option_noanswer = 1;
|
||||
if (strchr(options, 'a'))
|
||||
option_append = 1;
|
||||
if (strchr(options, 't'))
|
||||
terminator = '*';
|
||||
if (strchr(options, 'x'))
|
||||
terminator = 0;
|
||||
if (strchr(options, 'q'))
|
||||
option_quiet = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (vdata[i] == '|')
|
||||
i++;
|
||||
|
||||
j = 0;
|
||||
for (; vdata[i] && (vdata[i] != '|'); i++)
|
||||
if (j < sizeof(durationstr) - 1)
|
||||
durationstr[j++] = vdata[i];
|
||||
durationstr[j] = '\0';
|
||||
|
||||
if (j > 0)
|
||||
maxduration = atoi(durationstr);
|
||||
|
||||
if (vdata[i] == '|')
|
||||
i++;
|
||||
|
||||
j = 0;
|
||||
for (; vdata[i] && (vdata[i] != '|'); i++)
|
||||
if (j < sizeof(option) - 1)
|
||||
option[j++] = vdata[i];
|
||||
option[j] = '\0';
|
||||
|
||||
if (!strcasecmp(option, "skip"))
|
||||
option_skip = 1;
|
||||
if (!strcasecmp(option, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
|
||||
/* done parsing */
|
||||
|
||||
|
||||
/* these are to allow the use of the %d in the config file for a wild card of sort to
|
||||
create a new file with the inputed name scheme */
|
||||
if (percentflag) {
|
||||
AST_DECLARE_APP_ARGS(fname,
|
||||
AST_APP_ARG(piece)[100];
|
||||
);
|
||||
char *tmp2 = ast_strdupa(filename);
|
||||
char countstring[15];
|
||||
int i;
|
||||
|
||||
/* Separate each piece out by the format specifier */
|
||||
AST_NONSTANDARD_APP_ARGS(fname, tmp2, '%');
|
||||
do {
|
||||
int tmplen;
|
||||
/* First piece has no leading percent, so it's copied verbatim */
|
||||
ast_copy_string(tmp, fname.piece[0], sizeof(tmp));
|
||||
tmplen = strlen(tmp);
|
||||
for (i = 1; i < fname.argc; i++) {
|
||||
if (fname.piece[i][0] == 'd') {
|
||||
/* Substitute the count */
|
||||
snprintf(countstring, sizeof(countstring), "%d", count);
|
||||
ast_copy_string(tmp + tmplen, countstring, sizeof(tmp) - tmplen);
|
||||
tmplen += strlen(countstring);
|
||||
} else if (tmplen + 2 < sizeof(tmp)) {
|
||||
/* Unknown format specifier - just copy it verbatim */
|
||||
tmp[tmplen++] = '%';
|
||||
tmp[tmplen++] = fname.piece[i][0];
|
||||
}
|
||||
/* Copy the remaining portion of the piece */
|
||||
ast_copy_string(tmp + tmplen, &(fname.piece[i][1]), sizeof(tmp) - tmplen);
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), fil, count);
|
||||
count++;
|
||||
} while (ast_fileexists(tmp, ext, chan->language) > 0);
|
||||
} while ( ast_fileexists(tmp, ext, chan->language) != -1 );
|
||||
pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
|
||||
} else
|
||||
ast_copy_string(tmp, filename, sizeof(tmp));
|
||||
strncpy(tmp, fil, sizeof(tmp)-1);
|
||||
/* end of routine mentioned */
|
||||
|
||||
|
||||
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
if (option_skip) {
|
||||
/* At the user's option, skip if the line is not up */
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
} else if (!option_noanswer) {
|
||||
/* Otherwise answer unless we're supposed to record while on-hook */
|
||||
@@ -229,12 +194,7 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!option_quiet) {
|
||||
if (!res) {
|
||||
/* Some code to play a nice little beep to signify the start of the record operation */
|
||||
res = ast_streamfile(chan, "beep", chan->language);
|
||||
if (!res) {
|
||||
@@ -243,144 +203,138 @@ static int record_exec(struct ast_channel *chan, void *data)
|
||||
ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", chan->name);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
|
||||
/* The end of beep code. Now the recording starts */
|
||||
|
||||
if (silence > 0) {
|
||||
rfmt = chan->readformat;
|
||||
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
sildet = ast_dsp_new();
|
||||
if (!sildet) {
|
||||
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
ast_dsp_set_threshold(sildet, 256);
|
||||
}
|
||||
|
||||
|
||||
flags = option_append ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
|
||||
s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
|
||||
|
||||
if (!s) {
|
||||
ast_log(LOG_WARNING, "Could not create file %s\n", filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ast_opt_transmit_silence)
|
||||
silgen = ast_channel_start_silence_generator(chan);
|
||||
|
||||
/* Request a video update */
|
||||
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
|
||||
|
||||
if (maxduration <= 0)
|
||||
maxduration = -1;
|
||||
|
||||
while ((waitres = ast_waitfor(chan, maxduration)) > -1) {
|
||||
if (maxduration > 0) {
|
||||
if (waitres == 0) {
|
||||
gottimeout = 1;
|
||||
break;
|
||||
}
|
||||
maxduration = waitres;
|
||||
/* The end of beep code. Now the recording starts */
|
||||
|
||||
|
||||
if (silence > 0) {
|
||||
rfmt = chan->readformat;
|
||||
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
|
||||
return -1;
|
||||
}
|
||||
sildet = ast_dsp_new();
|
||||
if (!sildet) {
|
||||
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
|
||||
return -1;
|
||||
}
|
||||
ast_dsp_set_threshold(sildet, 256);
|
||||
}
|
||||
|
||||
f = ast_read(chan);
|
||||
if (!f) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
res = ast_writestream(s, f);
|
||||
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Problem writing frame\n");
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
|
||||
if (silence > 0) {
|
||||
dspsilence = 0;
|
||||
ast_dsp_silence(sildet, f, &dspsilence);
|
||||
if (dspsilence) {
|
||||
totalsilence = dspsilence;
|
||||
} else {
|
||||
totalsilence = 0;
|
||||
}
|
||||
if (totalsilence > silence) {
|
||||
/* Ended happily with silence */
|
||||
ast_frfree(f);
|
||||
gotsilence = 1;
|
||||
|
||||
|
||||
flags = end ? O_CREAT|O_APPEND|O_WRONLY : O_CREAT|O_TRUNC|O_WRONLY;
|
||||
s = ast_writefile( tmp, ext, NULL, flags , 0, 0644);
|
||||
|
||||
|
||||
if (s) {
|
||||
if (maxduration > 0)
|
||||
timeout = time(NULL) + (time_t)maxduration;
|
||||
|
||||
while (ast_waitfor(chan, -1) > -1) {
|
||||
if (maxduration > 0 && time(NULL) > timeout) {
|
||||
gottimeout = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (f->frametype == AST_FRAME_VIDEO) {
|
||||
res = ast_writestream(s, f);
|
||||
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Problem writing frame\n");
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
} else if ((f->frametype == AST_FRAME_DTMF) &&
|
||||
(f->subclass == terminator)) {
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
if (!f) {
|
||||
ast_log(LOG_DEBUG, "Got hangup\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (gotsilence) {
|
||||
ast_stream_rewind(s, silence-1000);
|
||||
ast_truncstream(s);
|
||||
} else if (!gottimeout) {
|
||||
/* Strip off the last 1/4 second of it */
|
||||
ast_stream_rewind(s, 250);
|
||||
ast_truncstream(s);
|
||||
}
|
||||
ast_closestream(s);
|
||||
|
||||
if (silgen)
|
||||
ast_channel_stop_silence_generator(chan, silgen);
|
||||
|
||||
out:
|
||||
f = ast_read(chan);
|
||||
if (!f) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
res = ast_writestream(s, f);
|
||||
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Problem writing frame\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (silence > 0) {
|
||||
dspsilence = 0;
|
||||
ast_dsp_silence(sildet, f, &dspsilence);
|
||||
if (dspsilence) {
|
||||
totalsilence = dspsilence;
|
||||
} else {
|
||||
totalsilence = 0;
|
||||
}
|
||||
if (totalsilence > silence) {
|
||||
/* Ended happily with silence */
|
||||
ast_frfree(f);
|
||||
gotsilence = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (f->frametype == AST_FRAME_VIDEO) {
|
||||
res = ast_writestream(s, f);
|
||||
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Problem writing frame\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((f->frametype == AST_FRAME_DTMF) &&
|
||||
(f->subclass == '#')) {
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
}
|
||||
if (!f) {
|
||||
ast_log(LOG_DEBUG, "Got hangup\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
if (gotsilence) {
|
||||
ast_stream_rewind(s, silence-1000);
|
||||
ast_truncstream(s);
|
||||
} else if (!gottimeout) {
|
||||
/* Strip off the last 1/4 second of it */
|
||||
ast_stream_rewind(s, 250);
|
||||
ast_truncstream(s);
|
||||
}
|
||||
ast_closestream(s);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Could not create file %s\n", fil);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if ((silence > 0) && rfmt) {
|
||||
res = ast_set_read_format(chan, rfmt);
|
||||
if (res)
|
||||
ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
|
||||
res = ast_set_read_format(chan, rfmt);
|
||||
if (res)
|
||||
ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
|
||||
if (sildet)
|
||||
ast_dsp_free(sildet);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, record_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
10591
apps/app_rpt.c
10591
apps/app_rpt.c
File diff suppressed because it is too large
Load Diff
@@ -1,47 +1,30 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (c) 2003, 2006 Tilghman Lesher. All rights reserved.
|
||||
* Copyright (c) 2006 Digium, Inc.
|
||||
* SayUnixTime application
|
||||
*
|
||||
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_sayunixtime__200309@the-tilghman.com>
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief SayUnixTime application
|
||||
*
|
||||
* \author Tilghman Lesher <app_sayunixtime__200309@the-tilghman.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/say.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Say time";
|
||||
|
||||
static char *app_sayunixtime = "SayUnixTime";
|
||||
static char *app_datetime = "DateTime";
|
||||
@@ -55,7 +38,8 @@ static char *sayunixtime_descrip =
|
||||
" timezone: timezone, see /usr/share/zoneinfo for a list.\n"
|
||||
" defaults to machine default.\n"
|
||||
" format: a format the time is to be said in. See voicemail.conf.\n"
|
||||
" defaults to \"ABdY 'digits/at' IMp\"\n";
|
||||
" defaults to \"ABdY 'digits/at' IMp\"\n"
|
||||
" Returns 0 or -1 on hangup.\n";
|
||||
static char *datetime_descrip =
|
||||
"DateTime([unixtime][|[timezone][|format]])\n"
|
||||
" unixtime: time, in seconds since Jan 1, 1970. May be negative.\n"
|
||||
@@ -63,64 +47,95 @@ static char *datetime_descrip =
|
||||
" timezone: timezone, see /usr/share/zoneinfo for a list.\n"
|
||||
" defaults to machine default.\n"
|
||||
" format: a format the time is to be said in. See voicemail.conf.\n"
|
||||
" defaults to \"ABdY 'digits/at' IMp\"\n";
|
||||
" defaults to \"ABdY 'digits/at' IMp\"\n"
|
||||
" Returns 0 or -1 on hangup.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int sayunixtime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(timeval);
|
||||
AST_APP_ARG(timezone);
|
||||
AST_APP_ARG(format);
|
||||
);
|
||||
char *parse;
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s,*zone=NULL,*timec;
|
||||
time_t unixtime;
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
char *format = "ABdY 'digits/at' IMp";
|
||||
struct timeval tv;
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
gettimeofday(&tv,NULL);
|
||||
unixtime = (time_t)tv.tv_sec;
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
if (data) {
|
||||
s = data;
|
||||
s = ast_strdupa(s);
|
||||
if (s) {
|
||||
timec = strsep(&s,"|");
|
||||
if ((timec) && (*timec != '\0')) {
|
||||
long timein;
|
||||
if (sscanf(timec,"%ld",&timein) == 1) {
|
||||
unixtime = (time_t)timein;
|
||||
}
|
||||
}
|
||||
if (s) {
|
||||
zone = strsep(&s,"|");
|
||||
if (zone && (*zone == '\0'))
|
||||
zone = NULL;
|
||||
if (s) {
|
||||
format = s;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory error\n");
|
||||
}
|
||||
}
|
||||
|
||||
ast_get_time_t(args.timeval, &unixtime, time(NULL), NULL);
|
||||
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
res = ast_answer(chan);
|
||||
|
||||
}
|
||||
if (!res)
|
||||
res = ast_say_date_with_format(chan, unixtime, AST_DIGIT_ANY,
|
||||
chan->language, args.format, args.timezone);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
res = ast_say_date_with_format(chan, unixtime, AST_DIGIT_ANY, chan->language, format, zone);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
res = ast_unregister_application(app_sayunixtime);
|
||||
res |= ast_unregister_application(app_datetime);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
if (! res)
|
||||
return ast_unregister_application(app_datetime);
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app_sayunixtime, sayunixtime_exec, sayunixtime_synopsis, sayunixtime_descrip);
|
||||
res |= ast_register_application(app_datetime, sayunixtime_exec, sayunixtime_synopsis, datetime_descrip);
|
||||
|
||||
if (! res)
|
||||
return ast_register_application(app_datetime, sayunixtime_exec, sayunixtime_synopsis, datetime_descrip);
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say time");
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,143 +1,84 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to send DTMF digits
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to send DTMF digits
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <asterisk/app.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/manager.h"
|
||||
static char *tdesc = "Send DTMF digits Application";
|
||||
|
||||
static char *app = "SendDTMF";
|
||||
|
||||
static char *synopsis = "Sends arbitrary DTMF digits";
|
||||
|
||||
static char *descrip =
|
||||
" SendDTMF(digits[|timeout_ms]): Sends DTMF digits on a channel. \n"
|
||||
" Accepted digits: 0-9, *#abcd, w (.5s pause)\n"
|
||||
" The application will either pass the assigned digits or terminate if it\n"
|
||||
" encounters an error.\n";
|
||||
" SendDTMF(digits): Sends DTMF digits on a channel. \n"
|
||||
" Accepted digits: 0-9, *#abcd\n"
|
||||
" Returns 0 on success or -1 on a hangup.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int senddtmf_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
char *digits = NULL, *to = NULL;
|
||||
int timeout = 250;
|
||||
struct localuser *u;
|
||||
char *digits = data;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!digits || ast_strlen_zero(digits)) {
|
||||
ast_log(LOG_WARNING, "SendDTMF requires an argument (digits or *#aAbBcCdD)\n");
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
digits = ast_strdupa(data);
|
||||
|
||||
if ((to = strchr(digits,'|'))) {
|
||||
*to = '\0';
|
||||
to++;
|
||||
timeout = atoi(to);
|
||||
}
|
||||
|
||||
if (timeout <= 0)
|
||||
timeout = 250;
|
||||
|
||||
res = ast_dtmf_stream(chan,NULL,digits,timeout);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
res = ast_dtmf_stream(chan,NULL,digits,250);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static char mandescr_playdtmf[] =
|
||||
"Description: Plays a dtmf digit on the specified channel.\n"
|
||||
"Variables: (all are required)\n"
|
||||
" Channel: Channel name to send digit to\n"
|
||||
" Digit: The dtmf digit to play\n";
|
||||
|
||||
static int manager_play_dtmf(struct mansession *s, const struct message *m)
|
||||
int unload_module(void)
|
||||
{
|
||||
const char *channel = astman_get_header(m, "Channel");
|
||||
const char *digit = astman_get_header(m, "Digit");
|
||||
struct ast_channel *chan = ast_get_channel_by_name_locked(channel);
|
||||
|
||||
if (!chan) {
|
||||
astman_send_error(s, m, "Channel not specified");
|
||||
return 0;
|
||||
}
|
||||
if (!digit) {
|
||||
astman_send_error(s, m, "No digit specified");
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_senddigit(chan, *digit);
|
||||
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
astman_send_ack(s, m, "DTMF successfully queued");
|
||||
|
||||
return 0;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
res |= ast_manager_unregister("PlayDTMF");
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
return ast_register_application(app, senddtmf_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_manager_register2( "PlayDTMF", EVENT_FLAG_CALL, manager_play_dtmf, "Play DTMF signal on a specific channel.", mandescr_playdtmf );
|
||||
res |= ast_register_application(app, senddtmf_exec, synopsis, descrip);
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send DTMF digits Application");
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,130 +1,94 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to transmit a text message
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to transmit a text message
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \note Requires support of sending text messages from channel driver
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/channel_pvt.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
static char *tdesc = "Send Text Applications";
|
||||
|
||||
static const char *app = "SendText";
|
||||
static char *app = "SendText";
|
||||
|
||||
static const char *synopsis = "Send a Text Message";
|
||||
static char *synopsis = "Send a Text Message";
|
||||
|
||||
static const char *descrip =
|
||||
" SendText(text[|options]): Sends text to current channel (callee).\n"
|
||||
"Result of transmission will be stored in the SENDTEXTSTATUS\n"
|
||||
"channel variable:\n"
|
||||
" SUCCESS Transmission succeeded\n"
|
||||
" FAILURE Transmission failed\n"
|
||||
" UNSUPPORTED Text transmission not supported by channel\n"
|
||||
"\n"
|
||||
"At this moment, text is supposed to be 7 bit ASCII in most channels.\n"
|
||||
"The option string many contain the following character:\n"
|
||||
"'j' -- jump to n+101 priority if the channel doesn't support\n"
|
||||
" text transport\n";
|
||||
static char *descrip =
|
||||
" SendText(text): Sends text to client. If the client\n"
|
||||
"does not support text transport, and there exists a step with\n"
|
||||
"priority n + 101, then execution will continue at that step.\n"
|
||||
"Otherwise, execution will continue at the next priority level.\n"
|
||||
"SendText only returns 0 if the text was sent correctly or if\n"
|
||||
"the channel does not support text transport, and -1 otherwise.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int sendtext_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u;
|
||||
char *status = "UNSUPPORTED";
|
||||
char *parse = NULL;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(text);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "SendText requires an argument (text[|options])\n");
|
||||
ast_module_user_remove(u);
|
||||
struct localuser *u;
|
||||
if (!data || !strlen((char *)data)) {
|
||||
ast_log(LOG_WARNING, "SendText requires an argument (text)\n");
|
||||
return -1;
|
||||
} else
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
ast_channel_lock(chan);
|
||||
if (!chan->tech->send_text) {
|
||||
ast_channel_unlock(chan);
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_mutex_lock(&chan->lock);
|
||||
if (!chan->pvt->send_text) {
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
/* Does not support transport */
|
||||
if (priority_jump || ast_opt_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
ast_module_user_remove(u);
|
||||
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
|
||||
chan->priority += 100;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
status = "FAILURE";
|
||||
ast_channel_unlock(chan);
|
||||
res = ast_sendtext(chan, args.text);
|
||||
if (!res)
|
||||
status = "SUCCESS";
|
||||
pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
res = ast_sendtext(chan, (char *)data);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, sendtext_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send Text Applications");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,56 +1,55 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* App to set callerid
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set callerid
|
||||
*
|
||||
* \author Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *app2 = "SetCallerPres";
|
||||
|
||||
static char *synopsis2 = "Set CallerID Presentation";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static struct {
|
||||
int val;
|
||||
char *name;
|
||||
} preses[] = {
|
||||
{ AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED, "allowed_not_screened" },
|
||||
{ AST_PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, "allowed_passed_screen" },
|
||||
{ AST_PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN, "allowed_failed_screen" },
|
||||
{ AST_PRES_ALLOWED_NETWORK_NUMBER, "allowed" },
|
||||
{ AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED , "prohib_not_screened" },
|
||||
{ AST_PRES_PROHIB_USER_NUMBER_PASSED_SCREEN, "prohib_passed_screen" },
|
||||
{ AST_PRES_PROHIB_USER_NUMBER_FAILED_SCREEN, "prohib_failed_screen" },
|
||||
{ AST_PRES_PROHIB_NETWORK_NUMBER, "prohib" },
|
||||
{ AST_PRES_NUMBER_NOT_AVAILABLE, "unavailable" },
|
||||
};
|
||||
|
||||
static char *descrip2 =
|
||||
" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n"
|
||||
" Valid presentations are:\n"
|
||||
" SetCallerPres(presentation): Set Caller*ID presentation on\n"
|
||||
"a call to a new value. Sets ANI as well if a flag is used.\n"
|
||||
"Always returns 0. Valid presentations are:\n"
|
||||
"\n"
|
||||
" allowed_not_screened : Presentation Allowed, Not Screened\n"
|
||||
" allowed_passed_screen : Presentation Allowed, Passed Screen\n"
|
||||
@@ -66,61 +65,56 @@ static char *descrip2 =
|
||||
|
||||
static int setcallerid_pres_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
int res = 0;
|
||||
char tmp[256] = "";
|
||||
struct localuser *u;
|
||||
int x;
|
||||
char *opts;
|
||||
int pres = -1;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* For interface consistency, permit the argument to be specified as a number */
|
||||
if (sscanf(data, "%d", &pres) != 1 || pres < 0 || pres > 255 || (pres & 0x9c)) {
|
||||
pres = ast_parse_caller_presentation(data);
|
||||
if (data)
|
||||
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
|
||||
opts = strchr(tmp, '|');
|
||||
if (opts) {
|
||||
*opts = '\0';
|
||||
opts++;
|
||||
}
|
||||
for (x=0;x<sizeof(preses) / sizeof(preses[0]);x++) {
|
||||
if (!strcasecmp(preses[x].name, tmp)) {
|
||||
pres = preses[x].val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pres < 0) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show application SetCallerPres')\n",
|
||||
(char *) data);
|
||||
ast_module_user_remove(u);
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show application SetCallerPres')\n", tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
chan->cid.cid_pres = pres;
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
LOCAL_USER_ADD(u);
|
||||
chan->callingpres = pres;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *tdesc = "Set CallerID Application";
|
||||
|
||||
static char *app = "SetCallerID";
|
||||
|
||||
static char *synopsis = "Set CallerID";
|
||||
|
||||
static char *descrip =
|
||||
" SetCallerID(clid[|a]): Set Caller*ID on a call to a new\n"
|
||||
"value. Sets ANI as well if a flag is used. \n";
|
||||
"value. Sets ANI as well if a flag is used. Always returns 0\n";
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
char *tmp = NULL;
|
||||
char name[256];
|
||||
char num[256];
|
||||
struct ast_module_user *u;
|
||||
char tmp[256] = "";
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
int anitoo = 0;
|
||||
static int dep_warning = 0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "SetCallerID requires an argument!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!dep_warning) {
|
||||
dep_warning = 1;
|
||||
ast_log(LOG_WARNING, "SetCallerID is deprecated. Please use Set(CALLERID(all)=...) or Set(CALLERID(ani)=...) instead.\n");
|
||||
}
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
|
||||
if (data)
|
||||
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
@@ -128,35 +122,38 @@ static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
if (*opt == 'a')
|
||||
anitoo = 1;
|
||||
}
|
||||
|
||||
ast_callerid_split(tmp, name, sizeof(name), num, sizeof(num));
|
||||
ast_set_callerid(chan, num, name, anitoo ? num : NULL);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_set_callerid(chan, strlen(tmp) ? tmp : NULL, anitoo);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
ast_unregister_application(app2);
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2);
|
||||
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app2);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
char *key()
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2);
|
||||
res |= ast_register_application(app, setcallerid_exec, synopsis, descrip);
|
||||
|
||||
return res;
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Application");
|
||||
|
||||
@@ -1,47 +1,30 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Applictions connected with CDR engine
|
||||
*
|
||||
* Copyright (C) 2003, Digium
|
||||
*
|
||||
* Justin Huff <jjhuff@mspin.net>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Applictions connected with CDR engine
|
||||
*
|
||||
* \author Justin Huff <jjhuff@mspin.net>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/cdr.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/manager.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/cdr.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/manager.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "CDR user field apps";
|
||||
|
||||
static char *setcdruserfield_descrip =
|
||||
"[Synopsis]\n"
|
||||
@@ -53,7 +36,7 @@ static char *setcdruserfield_descrip =
|
||||
" CDR records can be used for billing or storing other arbitrary data\n"
|
||||
" (I.E. telephone survey responses)\n"
|
||||
" Also see AppendCDRUserField().\n"
|
||||
"\nThis application is deprecated in favor of Set(CDR(userfield)=...)\n";
|
||||
" Always returns 0\n";
|
||||
|
||||
|
||||
static char *setcdruserfield_app = "SetCDRUserField";
|
||||
@@ -69,18 +52,21 @@ static char *appendcdruserfield_descrip =
|
||||
" CDR records can be used for billing or storing other arbitrary data\n"
|
||||
" (I.E. telephone survey responses)\n"
|
||||
" Also see SetCDRUserField().\n"
|
||||
"\nThis application is deprecated in favor of Set(CDR(userfield)=...)\n";
|
||||
" Always returns 0\n";
|
||||
|
||||
static char *appendcdruserfield_app = "AppendCDRUserField";
|
||||
static char *appendcdruserfield_synopsis = "Append to the CDR user field";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
static int action_setcdruserfield(struct mansession *s, const struct message *m)
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int action_setcdruserfield(struct mansession *s, struct message *m)
|
||||
{
|
||||
struct ast_channel *c = NULL;
|
||||
const char *userfield = astman_get_header(m, "UserField");
|
||||
const char *channel = astman_get_header(m, "Channel");
|
||||
const char *append = astman_get_header(m, "Append");
|
||||
char *userfield = astman_get_header(m, "UserField");
|
||||
char *channel = astman_get_header(m, "Channel");
|
||||
char *append = astman_get_header(m, "Append");
|
||||
|
||||
if (ast_strlen_zero(channel)) {
|
||||
astman_send_error(s, m, "No Channel specified");
|
||||
@@ -90,7 +76,13 @@ static int action_setcdruserfield(struct mansession *s, const struct message *m)
|
||||
astman_send_error(s, m, "No UserField specified");
|
||||
return 0;
|
||||
}
|
||||
c = ast_get_channel_by_name_locked(channel);
|
||||
c = ast_channel_walk_locked(NULL);
|
||||
while (c) {
|
||||
if (!strcasecmp(c->name, channel))
|
||||
break;
|
||||
ast_mutex_unlock(&c->lock);
|
||||
c = ast_channel_walk_locked(c);
|
||||
}
|
||||
if (!c) {
|
||||
astman_send_error(s, m, "No such channel");
|
||||
return 0;
|
||||
@@ -106,70 +98,68 @@ static int action_setcdruserfield(struct mansession *s, const struct message *m)
|
||||
|
||||
static int setcdruserfield_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
int res = 0;
|
||||
static int dep_warning = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (chan->cdr && data) {
|
||||
LOCAL_USER_ADD(u)
|
||||
if (chan->cdr && data)
|
||||
{
|
||||
ast_cdr_setuserfield(chan, (char*)data);
|
||||
}
|
||||
|
||||
if (!dep_warning) {
|
||||
dep_warning = 1;
|
||||
ast_log(LOG_WARNING, "SetCDRUserField is deprecated. Please use CDR(userfield) instead.\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int appendcdruserfield_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
struct localuser *u;
|
||||
int res = 0;
|
||||
static int dep_warning = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (chan->cdr && data) {
|
||||
LOCAL_USER_ADD(u)
|
||||
if (chan->cdr && data)
|
||||
{
|
||||
ast_cdr_appenduserfield(chan, (char*)data);
|
||||
}
|
||||
|
||||
if (!dep_warning) {
|
||||
dep_warning = 1;
|
||||
ast_log(LOG_WARNING, "AppendCDRUserField is deprecated. Please use CDR(userfield) instead.\n");
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
res = ast_unregister_application(setcdruserfield_app);
|
||||
res |= ast_unregister_application(appendcdruserfield_app);
|
||||
res |= ast_manager_unregister("SetCDRUserField");
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
ast_manager_unregister("SetCDRUserField");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(setcdruserfield_app, setcdruserfield_exec, setcdruserfield_synopsis, setcdruserfield_descrip);
|
||||
res |= ast_register_application(appendcdruserfield_app, appendcdruserfield_exec, appendcdruserfield_synopsis, appendcdruserfield_descrip);
|
||||
res |= ast_manager_register("SetCDRUserField", EVENT_FLAG_CALL, action_setcdruserfield, "Set the CDR UserField");
|
||||
|
||||
ast_manager_register("SetCDRUserField", EVENT_FLAG_CALL, action_setcdruserfield, "Set the CDR UserField");
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CDR user field apps");
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
107
apps/app_setcidname.c
Normal file
107
apps/app_setcidname.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* App to set callerid
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *tdesc = "Set CallerID Name";
|
||||
|
||||
static char *app = "SetCIDName";
|
||||
|
||||
static char *synopsis = "Set CallerID Name";
|
||||
|
||||
static char *descrip =
|
||||
" SetCIDName(cname[|a]): Set Caller*ID Name on a call to a new\n"
|
||||
"value, while preserving the original Caller*ID number. This is\n"
|
||||
"useful for providing additional information to the called\n"
|
||||
"party. Sets ANI as well if a flag is used. Always returns 0\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
char tmp[256] = "";
|
||||
char oldcid[256] = "", *l, *n;
|
||||
char newcid[256] = "";
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
int anitoo = 0;
|
||||
if (data)
|
||||
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
opt++;
|
||||
if (*opt == 'a')
|
||||
anitoo = 1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->callerid) {
|
||||
strncpy(oldcid, chan->callerid, sizeof(oldcid) - 1);
|
||||
ast_callerid_parse(oldcid, &n, &l);
|
||||
n = tmp;
|
||||
if (!ast_strlen_zero(n)) {
|
||||
if (l && !ast_strlen_zero(l))
|
||||
snprintf(newcid, sizeof(newcid), "\"%s\" <%s>", n, l);
|
||||
else
|
||||
strncpy(newcid, tmp, sizeof(newcid) - 1);
|
||||
} else if (l && !ast_strlen_zero(l)) {
|
||||
strncpy(newcid, l, sizeof(newcid) - 1);
|
||||
}
|
||||
} else
|
||||
strncpy(newcid, tmp, sizeof(newcid) - 1);
|
||||
ast_set_callerid(chan, !ast_strlen_zero(newcid) ? newcid : NULL, anitoo);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
108
apps/app_setcidnum.c
Normal file
108
apps/app_setcidnum.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* App to set callerid
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
* Oliver Daudey <traveler@xs4all.nl>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/lock.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/image.h>
|
||||
#include <asterisk/callerid.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *tdesc = "Set CallerID Number";
|
||||
|
||||
static char *app = "SetCIDNum";
|
||||
|
||||
static char *synopsis = "Set CallerID Number";
|
||||
|
||||
static char *descrip =
|
||||
" SetCIDNum(cnum[|a]): Set Caller*ID Number on a call to a new\n"
|
||||
"value, while preserving the original Caller*ID name. This is\n"
|
||||
"useful for providing additional information to the called\n"
|
||||
"party. Sets ANI as well if a flag is used. Always returns 0\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
char tmp[256] = "";
|
||||
char oldcid[256] = "", *l, *n;
|
||||
char newcid[256] = "";
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
int anitoo = 0;
|
||||
if (data)
|
||||
strncpy(tmp, (char *)data, sizeof(tmp) - 1);
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
opt++;
|
||||
if (*opt == 'a')
|
||||
anitoo = 1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
if (chan->callerid) {
|
||||
strncpy(oldcid, chan->callerid, sizeof(oldcid) - 1);
|
||||
ast_callerid_parse(oldcid, &n, &l);
|
||||
l = tmp;
|
||||
if (!ast_strlen_zero(l)) {
|
||||
if (n && !ast_strlen_zero(n))
|
||||
snprintf(newcid, sizeof(newcid), "\"%s\" <%s>", n, l);
|
||||
else
|
||||
strncpy(newcid, tmp, sizeof(newcid) - 1);
|
||||
} else if (n && !ast_strlen_zero(n)) {
|
||||
strncpy(newcid, n, sizeof(newcid) - 1);
|
||||
}
|
||||
} else
|
||||
strncpy(newcid, tmp, sizeof(newcid) - 1);
|
||||
ast_set_callerid(chan, !ast_strlen_zero(newcid) ? newcid : NULL, anitoo);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Frank Sautter, levigo holding gmbh, www.levigo.de
|
||||
*
|
||||
* Frank Sautter - asterisk+at+sautter+dot+com
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set the ISDN Transfer Capability
|
||||
*
|
||||
* \author Frank Sautter - asterisk+at+sautter+dot+com
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/transcap.h"
|
||||
|
||||
|
||||
static char *app = "SetTransferCapability";
|
||||
|
||||
static char *synopsis = "Set ISDN Transfer Capability";
|
||||
|
||||
|
||||
static struct { int val; char *name; } transcaps[] = {
|
||||
{ AST_TRANS_CAP_SPEECH, "SPEECH" },
|
||||
{ AST_TRANS_CAP_DIGITAL, "DIGITAL" },
|
||||
{ AST_TRANS_CAP_RESTRICTED_DIGITAL, "RESTRICTED_DIGITAL" },
|
||||
{ AST_TRANS_CAP_3_1K_AUDIO, "3K1AUDIO" },
|
||||
{ AST_TRANS_CAP_DIGITAL_W_TONES, "DIGITAL_W_TONES" },
|
||||
{ AST_TRANS_CAP_VIDEO, "VIDEO" },
|
||||
};
|
||||
|
||||
static char *descrip =
|
||||
" SetTransferCapability(transfercapability): Set the ISDN Transfer \n"
|
||||
"Capability of a call to a new value.\n"
|
||||
"Valid Transfer Capabilities are:\n"
|
||||
"\n"
|
||||
" SPEECH : 0x00 - Speech (default, voice calls)\n"
|
||||
" DIGITAL : 0x08 - Unrestricted digital information (data calls)\n"
|
||||
" RESTRICTED_DIGITAL : 0x09 - Restricted digital information\n"
|
||||
" 3K1AUDIO : 0x10 - 3.1kHz Audio (fax calls)\n"
|
||||
" DIGITAL_W_TONES : 0x11 - Unrestricted digital information with tones/announcements\n"
|
||||
" VIDEO : 0x18 - Video\n"
|
||||
"\n"
|
||||
"This application is deprecated in favor of Set(CHANNEL(transfercapability)=...)\n"
|
||||
;
|
||||
|
||||
static int settransfercapability_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *tmp = NULL;
|
||||
struct ast_module_user *u;
|
||||
int x;
|
||||
char *opts;
|
||||
int transfercapability = -1;
|
||||
static int dep_warning = 0;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (!dep_warning) {
|
||||
dep_warning = 1;
|
||||
ast_log(LOG_WARNING, "SetTransferCapability is deprecated. Please use CHANNEL(transfercapability) instead.\n");
|
||||
}
|
||||
|
||||
if (data)
|
||||
tmp = ast_strdupa(data);
|
||||
else
|
||||
tmp = "";
|
||||
|
||||
opts = strchr(tmp, '|');
|
||||
if (opts)
|
||||
*opts = '\0';
|
||||
|
||||
for (x = 0; x < (sizeof(transcaps) / sizeof(transcaps[0])); x++) {
|
||||
if (!strcasecmp(transcaps[x].name, tmp)) {
|
||||
transfercapability = transcaps[x].val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (transfercapability < 0) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid transfer capability (see 'show application SetTransferCapability')\n", tmp);
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
chan->transfercapability = (unsigned short)transfercapability;
|
||||
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Setting transfer capability to: 0x%.2x - %s.\n", transfercapability, tmp);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, settransfercapability_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set ISDN Transfer Capability");
|
||||
151
apps/app_skel.c
151
apps/app_skel.c
@@ -1,133 +1,74 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) <Year>, <Your Name Here>
|
||||
* Skeleton application
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* <Your Name Here> <<Your Email Here>>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Skeleton application
|
||||
*
|
||||
* \author <Your Name Here> <<Your Email Here>>
|
||||
*
|
||||
* This is a skeleton for development of an Asterisk application
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<defaultenabled>no</defaultenabled>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include <stdio.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *app = "Skel";
|
||||
static char *tdesc = "Trivial skeleton Application";
|
||||
static char *app = "skel";
|
||||
static char *synopsis =
|
||||
"Skeleton application.";
|
||||
static char *descrip = "This application is a template to build other applications from.\n"
|
||||
" It shows you the basic structure to create your own Asterisk applications.\n";
|
||||
" This is a skeleton application that shows you the basic structure to create your\n"
|
||||
"own asterisk applications.\n";
|
||||
|
||||
enum {
|
||||
OPTION_A = (1 << 0),
|
||||
OPTION_B = (1 << 1),
|
||||
OPTION_C = (1 << 2),
|
||||
} option_flags;
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
enum {
|
||||
OPTION_ARG_B = 0,
|
||||
OPTION_ARG_C = 1,
|
||||
/* This *must* be the last value in this enum! */
|
||||
OPTION_ARG_ARRAY_SIZE = 2,
|
||||
} option_args;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
AST_APP_OPTIONS(app_opts,{
|
||||
AST_APP_OPTION('a', OPTION_A),
|
||||
AST_APP_OPTION_ARG('b', OPTION_B, OPTION_ARG_B),
|
||||
AST_APP_OPTION_ARG('c', OPTION_C, OPTION_ARG_C),
|
||||
});
|
||||
|
||||
|
||||
static int app_exec(struct ast_channel *chan, void *data)
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_flags flags;
|
||||
struct ast_module_user *u;
|
||||
char *parse, *opts[OPTION_ARG_ARRAY_SIZE];
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(dummy);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n", app);
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
/* Do our thing here */
|
||||
|
||||
/* We need to make a copy of the input string if we are going to modify it! */
|
||||
parse = ast_strdupa(data);
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.argc == 2)
|
||||
ast_app_parse_options(app_opts, &flags, opts, args.options);
|
||||
|
||||
if (!ast_strlen_zero(args.dummy))
|
||||
ast_log(LOG_NOTICE, "Dummy value is : %s\n", args.dummy);
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_A))
|
||||
ast_log(LOG_NOTICE, "Option A is set\n");
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_B))
|
||||
ast_log(LOG_NOTICE, "Option B is set with : %s\n", opts[OPTION_ARG_B] ? opts[OPTION_ARG_B] : "<unspecified>");
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_C))
|
||||
ast_log(LOG_NOTICE, "Option C is set with : %s\n", opts[OPTION_ARG_C] ? opts[OPTION_ARG_C] : "<unspecified>");
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, skel_exec, synopsis, tdesc);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
res = ast_unregister_application(app);
|
||||
return res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
char *key()
|
||||
{
|
||||
return ast_register_application(app, app_exec, synopsis, descrip);
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Skeleton (sample) Application");
|
||||
|
||||
2384
apps/app_sms.c
2384
apps/app_sms.c
File diff suppressed because it is too large
Load Diff
@@ -1,121 +1,89 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* SoftHangup application
|
||||
*
|
||||
* Copyright (C) 1999, Mark Spencer
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
* Mark Spencer <markster@linux-support.net>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief 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/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *synopsis = "Soft Hangup Application";
|
||||
|
||||
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"
|
||||
"- 'options' may contain the following letter:\n"
|
||||
" 'a' : hang up all channels on a specified device instead of a single resource\n";
|
||||
static char *tdesc = "Hangs up the requested channel";
|
||||
|
||||
static char *desc = " SoftHangup(Technology/resource)\n"
|
||||
"Hangs up the requested channel. Always returns 0\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] = "";
|
||||
int all = 0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "SoftHangup requires an argument (Technology/resource)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
cdata = ast_strdupa(data);
|
||||
match = strsep(&cdata, "|");
|
||||
options = strsep(&cdata, "|");
|
||||
all = options && strchr(options,'a');
|
||||
LOCAL_USER_ADD(u);
|
||||
c = ast_channel_walk_locked(NULL);
|
||||
while (c) {
|
||||
ast_copy_string(name, c->name, sizeof(name));
|
||||
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"))
|
||||
cut = strrchr(name,'/');
|
||||
/* Basically everything else is Foo/Bar-Z */
|
||||
else
|
||||
cut = strchr(name,'-');
|
||||
/* Get rid of what we've cut */
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
}
|
||||
if (!strcasecmp(name, match)) {
|
||||
ast_log(LOG_WARNING, "Soft hanging %s up.\n",c->name);
|
||||
if (!strcasecmp(c->name, data)) {
|
||||
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
|
||||
if(!all)
|
||||
break;
|
||||
ast_mutex_unlock(&c->lock);
|
||||
break;
|
||||
}
|
||||
ast_mutex_unlock(&c->lock);
|
||||
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();
|
||||
|
||||
return res;
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,866 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2006, Digium, Inc.
|
||||
*
|
||||
* Joshua Colp <jcolp@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Speech Recognition Utility Applications
|
||||
*
|
||||
* \author Joshua Colp <jcolp@digium.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$");
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/speech.h"
|
||||
|
||||
/* Descriptions for each application */
|
||||
static char *speechcreate_descrip =
|
||||
"SpeechCreate(engine name)\n"
|
||||
"This application creates information to be used by all the other applications. It must be called before doing any speech recognition activities such as activating a grammar.\n"
|
||||
"It takes the engine name to use as the argument, if not specified the default engine will be used.\n";
|
||||
|
||||
static char *speechactivategrammar_descrip =
|
||||
"SpeechActivateGrammar(Grammar Name)\n"
|
||||
"This activates the specified grammar to be recognized by the engine. A grammar tells the speech recognition engine what to recognize, \n"
|
||||
"and how to portray it back to you in the dialplan. The grammar name is the only argument to this application.\n";
|
||||
|
||||
static char *speechstart_descrip =
|
||||
"SpeechStart()\n"
|
||||
"Tell the speech recognition engine that it should start trying to get results from audio being fed to it. This has no arguments.\n";
|
||||
|
||||
static char *speechbackground_descrip =
|
||||
"SpeechBackground(Sound File|Timeout)\n"
|
||||
"This application plays a sound file and waits for the person to speak. Once they start speaking playback of the file stops, and silence is heard.\n"
|
||||
"Once they stop talking the processing sound is played to indicate the speech recognition engine is working.\n"
|
||||
"Once results are available the application returns and results (score and text) are available using dialplan functions.\n"
|
||||
"The first text and score are ${SPEECH_TEXT(0)} AND ${SPEECH_SCORE(0)} while the second are ${SPEECH_TEXT(1)} and ${SPEECH_SCORE(1)}.\n"
|
||||
"The first argument is the sound file and the second is the timeout. Note the timeout will only start once the sound file has stopped playing.\n";
|
||||
|
||||
static char *speechdeactivategrammar_descrip =
|
||||
"SpeechDeactivateGrammar(Grammar Name)\n"
|
||||
"This deactivates the specified grammar so that it is no longer recognized. The only argument is the grammar name to deactivate.\n";
|
||||
|
||||
static char *speechprocessingsound_descrip =
|
||||
"SpeechProcessingSound(Sound File)\n"
|
||||
"This changes the processing sound that SpeechBackground plays back when the speech recognition engine is processing and working to get results.\n"
|
||||
"It takes the sound file as the only argument.\n";
|
||||
|
||||
static char *speechdestroy_descrip =
|
||||
"SpeechDestroy()\n"
|
||||
"This destroys the information used by all the other speech recognition applications.\n"
|
||||
"If you call this application but end up wanting to recognize more speech, you must call SpeechCreate\n"
|
||||
"again before calling any other application. It takes no arguments.\n";
|
||||
|
||||
static char *speechload_descrip =
|
||||
"SpeechLoadGrammar(Grammar Name|Path)\n"
|
||||
"Load a grammar only on the channel, not globally.\n"
|
||||
"It takes the grammar name as first argument and path as second.\n";
|
||||
|
||||
static char *speechunload_descrip =
|
||||
"SpeechUnloadGrammar(Grammar Name)\n"
|
||||
"Unload a grammar. It takes the grammar name as the only argument.\n";
|
||||
|
||||
/*! \brief Helper function used by datastores to destroy the speech structure upon hangup */
|
||||
static void destroy_callback(void *data)
|
||||
{
|
||||
struct ast_speech *speech = (struct ast_speech*)data;
|
||||
|
||||
if (speech == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Deallocate now */
|
||||
ast_speech_destroy(speech);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*! \brief Static structure for datastore information */
|
||||
static const struct ast_datastore_info speech_datastore = {
|
||||
.type = "speech",
|
||||
.destroy = destroy_callback
|
||||
};
|
||||
|
||||
/*! \brief Helper function used to find the speech structure attached to a channel */
|
||||
static struct ast_speech *find_speech(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_speech *speech = NULL;
|
||||
struct ast_datastore *datastore = NULL;
|
||||
|
||||
datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
|
||||
if (datastore == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
speech = datastore->data;
|
||||
|
||||
return speech;
|
||||
}
|
||||
|
||||
/* Helper function to find a specific speech recognition result by number and nbest alternative */
|
||||
static struct ast_speech_result *find_result(struct ast_speech_result *results, char *result_num)
|
||||
{
|
||||
struct ast_speech_result *result = results;
|
||||
char *tmp = NULL;
|
||||
int nbest_num = 0, wanted_num = 0, i = 0;
|
||||
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
if ((tmp = strchr(result_num, '/'))) {
|
||||
*tmp++ = '\0';
|
||||
nbest_num = atoi(result_num);
|
||||
wanted_num = atoi(tmp);
|
||||
} else {
|
||||
wanted_num = atoi(result_num);
|
||||
}
|
||||
|
||||
do {
|
||||
if (result->nbest_num != nbest_num)
|
||||
continue;
|
||||
if (i == wanted_num)
|
||||
break;
|
||||
i++;
|
||||
} while ((result = result->next));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*! \brief SPEECH_SCORE() Dialplan Function */
|
||||
static int speech_score(struct ast_channel *chan, char *cmd, char *data,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
struct ast_speech_result *result = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
char tmp[128] = "";
|
||||
|
||||
if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
|
||||
return -1;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%d", result->score);
|
||||
|
||||
ast_copy_string(buf, tmp, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function speech_score_function = {
|
||||
.name = "SPEECH_SCORE",
|
||||
.synopsis = "Gets the confidence score of a result.",
|
||||
.syntax = "SPEECH_SCORE([nbest number/]result number)",
|
||||
.desc =
|
||||
"Gets the confidence score of a result.\n",
|
||||
.read = speech_score,
|
||||
.write = NULL,
|
||||
};
|
||||
|
||||
/*! \brief SPEECH_TEXT() Dialplan Function */
|
||||
static int speech_text(struct ast_channel *chan, char *cmd, char *data,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
struct ast_speech_result *result = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
|
||||
return -1;
|
||||
|
||||
if (result->text != NULL)
|
||||
ast_copy_string(buf, result->text, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function speech_text_function = {
|
||||
.name = "SPEECH_TEXT",
|
||||
.synopsis = "Gets the recognized text of a result.",
|
||||
.syntax = "SPEECH_TEXT([nbest number/]result number)",
|
||||
.desc =
|
||||
"Gets the recognized text of a result.\n",
|
||||
.read = speech_text,
|
||||
.write = NULL,
|
||||
};
|
||||
|
||||
/*! \brief SPEECH_GRAMMAR() Dialplan Function */
|
||||
static int speech_grammar(struct ast_channel *chan, char *cmd, char *data,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
struct ast_speech_result *result = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
if (data == NULL || speech == NULL || !(result = find_result(speech->results, data)))
|
||||
return -1;
|
||||
|
||||
if (result->grammar != NULL)
|
||||
ast_copy_string(buf, result->grammar, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function speech_grammar_function = {
|
||||
.name = "SPEECH_GRAMMAR",
|
||||
.synopsis = "Gets the matched grammar of a result if available.",
|
||||
.syntax = "SPEECH_GRAMMAR([nbest number/]result number)",
|
||||
.desc =
|
||||
"Gets the matched grammar of a result if available.\n",
|
||||
.read = speech_grammar,
|
||||
.write = NULL,
|
||||
};
|
||||
|
||||
/*! \brief SPEECH_ENGINE() Dialplan Function */
|
||||
static int speech_engine_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
|
||||
{
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
if (data == NULL || speech == NULL)
|
||||
return -1;
|
||||
|
||||
ast_speech_change(speech, data, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function speech_engine_function = {
|
||||
.name = "SPEECH_ENGINE",
|
||||
.synopsis = "Change a speech engine specific attribute.",
|
||||
.syntax = "SPEECH_ENGINE(name)=value",
|
||||
.desc =
|
||||
"Changes a speech engine specific attribute.\n",
|
||||
.read = NULL,
|
||||
.write = speech_engine_write,
|
||||
};
|
||||
|
||||
/*! \brief SPEECH_RESULTS_TYPE() Dialplan Function */
|
||||
static int speech_results_type_write(struct ast_channel *chan, char *cmd, char *data, const char *value)
|
||||
{
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
if (data == NULL || speech == NULL)
|
||||
return -1;
|
||||
|
||||
if (!strcasecmp(value, "normal"))
|
||||
ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NORMAL);
|
||||
else if (!strcasecmp(value, "nbest"))
|
||||
ast_speech_change_results_type(speech, AST_SPEECH_RESULTS_TYPE_NBEST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function speech_results_type_function = {
|
||||
.name = "SPEECH_RESULTS_TYPE",
|
||||
.synopsis = "Sets the type of results that will be returned.",
|
||||
.syntax = "SPEECH_RESULTS_TYPE()=results type",
|
||||
.desc =
|
||||
"Sets the type of results that will be returned. Valid options are normal or nbest.",
|
||||
.read = NULL,
|
||||
.write = speech_results_type_write,
|
||||
};
|
||||
|
||||
/*! \brief SPEECH() Dialplan Function */
|
||||
static int speech_read(struct ast_channel *chan, char *cmd, char *data,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
int results = 0;
|
||||
struct ast_speech_result *result = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
char tmp[128] = "";
|
||||
|
||||
/* Now go for the various options */
|
||||
if (!strcasecmp(data, "status")) {
|
||||
if (speech != NULL)
|
||||
ast_copy_string(buf, "1", len);
|
||||
else
|
||||
ast_copy_string(buf, "0", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure we have a speech structure for everything else */
|
||||
if (speech == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check to see if they are checking for silence */
|
||||
if (!strcasecmp(data, "spoke")) {
|
||||
if (ast_test_flag(speech, AST_SPEECH_SPOKE))
|
||||
ast_copy_string(buf, "1", len);
|
||||
else
|
||||
ast_copy_string(buf, "0", len);
|
||||
} else if (!strcasecmp(data, "results")) {
|
||||
/* Count number of results */
|
||||
result = speech->results;
|
||||
while (result) {
|
||||
results++;
|
||||
result = result->next;
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), "%d", results);
|
||||
ast_copy_string(buf, tmp, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_custom_function speech_function = {
|
||||
.name = "SPEECH",
|
||||
.synopsis = "Gets information about speech recognition results.",
|
||||
.syntax = "SPEECH(argument)",
|
||||
.desc =
|
||||
"Gets information about speech recognition results.\n"
|
||||
"status: Returns 1 upon speech object existing, or 0 if not\n"
|
||||
"spoke: Returns 1 if spoker spoke, or 0 if not\n"
|
||||
"results: Returns number of results that were recognized\n",
|
||||
.read = speech_read,
|
||||
.write = NULL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*! \brief SpeechCreate() Dialplan Application */
|
||||
static int speech_create(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = NULL;
|
||||
struct ast_datastore *datastore = NULL;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
/* Request a speech object */
|
||||
speech = ast_speech_new(data, AST_FORMAT_SLINEAR);
|
||||
if (speech == NULL) {
|
||||
/* Not available */
|
||||
pbx_builtin_setvar_helper(chan, "ERROR", "1");
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
datastore = ast_channel_datastore_alloc(&speech_datastore, NULL);
|
||||
if (datastore == NULL) {
|
||||
ast_speech_destroy(speech);
|
||||
pbx_builtin_setvar_helper(chan, "ERROR", "1");
|
||||
ast_module_user_remove(u);
|
||||
return 0;
|
||||
}
|
||||
datastore->data = speech;
|
||||
ast_channel_datastore_add(chan, datastore);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief SpeechLoadGrammar(Grammar Name|Path) Dialplan Application */
|
||||
static int speech_load(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0, argc = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
char *argv[2], *args = NULL, *name = NULL, *path = NULL;
|
||||
|
||||
args = ast_strdupa(data);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse out arguments */
|
||||
argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
if (argc != 2) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
name = argv[0];
|
||||
path = argv[1];
|
||||
|
||||
/* Load the grammar locally on the object */
|
||||
res = ast_speech_grammar_load(speech, name, path);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief SpeechUnloadGrammar(Grammar Name) Dialplan Application */
|
||||
static int speech_unload(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Unload the grammar */
|
||||
res = ast_speech_grammar_unload(speech, data);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief SpeechDeactivateGrammar(Grammar Name) Dialplan Application */
|
||||
static int speech_deactivate(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Deactivate the grammar on the speech object */
|
||||
res = ast_speech_grammar_deactivate(speech, data);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief SpeechActivateGrammar(Grammar Name) Dialplan Application */
|
||||
static int speech_activate(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Activate the grammar on the speech object */
|
||||
res = ast_speech_grammar_activate(speech, data);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief SpeechStart() Dialplan Application */
|
||||
static int speech_start(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_speech_start(speech);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief SpeechProcessingSound(Sound File) Dialplan Application */
|
||||
static int speech_processing_sound(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (speech->processing_sound != NULL) {
|
||||
free(speech->processing_sound);
|
||||
speech->processing_sound = NULL;
|
||||
}
|
||||
|
||||
speech->processing_sound = strdup(data);
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief Helper function used by speech_background to playback a soundfile */
|
||||
static int speech_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
|
||||
{
|
||||
struct ast_filestream *fs = NULL;
|
||||
|
||||
if (!(fs = ast_openstream(chan, filename, preflang)))
|
||||
return -1;
|
||||
|
||||
if (ast_applystream(chan, fs))
|
||||
return -1;
|
||||
|
||||
ast_playstream(fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief SpeechBackground(Sound File|Timeout) Dialplan Application */
|
||||
static int speech_background(struct ast_channel *chan, void *data)
|
||||
{
|
||||
unsigned int timeout = 0;
|
||||
int res = 0, done = 0, argc = 0, started = 0, quieted = 0, max_dtmf_len = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
struct ast_frame *f = NULL;
|
||||
int oldreadformat = AST_FORMAT_SLINEAR;
|
||||
char dtmf[AST_MAX_EXTENSION] = "";
|
||||
time_t start, current;
|
||||
struct ast_datastore *datastore = NULL;
|
||||
char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
|
||||
const char *tmp2 = NULL;
|
||||
|
||||
args = ast_strdupa(data);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If channel is not already answered, then answer it */
|
||||
if (chan->_state != AST_STATE_UP && ast_answer(chan)) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Record old read format */
|
||||
oldreadformat = chan->readformat;
|
||||
|
||||
/* Change read format to be signed linear */
|
||||
if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse out options */
|
||||
argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
if (argc > 0) {
|
||||
/* Yay sound file */
|
||||
filename_tmp = ast_strdupa(argv[0]);
|
||||
if (!ast_strlen_zero(argv[1])) {
|
||||
if ((timeout = atoi(argv[1])) == 0)
|
||||
timeout = -1;
|
||||
} else
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
/* See if the maximum DTMF length variable is set... we use a variable in case they want to carry it through their entire dialplan */
|
||||
if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2))
|
||||
max_dtmf_len = atoi(tmp2);
|
||||
|
||||
/* See if a terminator is specified */
|
||||
if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) {
|
||||
if (ast_strlen_zero(tmp2))
|
||||
dtmf_terminator = '\0';
|
||||
else
|
||||
dtmf_terminator = tmp2[0];
|
||||
}
|
||||
|
||||
/* Before we go into waiting for stuff... make sure the structure is ready, if not - start it again */
|
||||
if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
|
||||
ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
|
||||
ast_speech_start(speech);
|
||||
}
|
||||
|
||||
/* Ensure no streams are currently running */
|
||||
ast_stopstream(chan);
|
||||
|
||||
/* Okay it's streaming so go into a loop grabbing frames! */
|
||||
while (done == 0) {
|
||||
/* If the filename is null and stream is not running, start up a new sound file */
|
||||
if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
|
||||
/* Discard old stream information */
|
||||
ast_stopstream(chan);
|
||||
/* Start new stream */
|
||||
speech_streamfile(chan, filename, chan->language);
|
||||
}
|
||||
|
||||
/* Run scheduled stuff */
|
||||
ast_sched_runq(chan->sched);
|
||||
|
||||
/* Yay scheduling */
|
||||
res = ast_sched_wait(chan->sched);
|
||||
if (res < 0) {
|
||||
res = 1000;
|
||||
}
|
||||
|
||||
/* If there is a frame waiting, get it - if not - oh well */
|
||||
if (ast_waitfor(chan, res) > 0) {
|
||||
f = ast_read(chan);
|
||||
if (f == NULL) {
|
||||
/* The channel has hung up most likely */
|
||||
done = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do timeout check (shared between audio/dtmf) */
|
||||
if ((!quieted || strlen(dtmf)) && started == 1) {
|
||||
time(¤t);
|
||||
if ((current-start) >= timeout) {
|
||||
done = 1;
|
||||
if (f)
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do checks on speech structure to see if it's changed */
|
||||
ast_mutex_lock(&speech->lock);
|
||||
if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
|
||||
if (chan->stream)
|
||||
ast_stopstream(chan);
|
||||
ast_clear_flag(speech, AST_SPEECH_QUIET);
|
||||
quieted = 1;
|
||||
}
|
||||
/* Check state so we can see what to do */
|
||||
switch (speech->state) {
|
||||
case AST_SPEECH_STATE_READY:
|
||||
/* If audio playback has stopped do a check for timeout purposes */
|
||||
if (chan->streamid == -1 && chan->timingfunc == NULL)
|
||||
ast_stopstream(chan);
|
||||
if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
|
||||
if (timeout == -1) {
|
||||
done = 1;
|
||||
if (f)
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
time(&start);
|
||||
started = 1;
|
||||
}
|
||||
/* Write audio frame out to speech engine if no DTMF has been received */
|
||||
if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
|
||||
ast_speech_write(speech, f->data, f->datalen);
|
||||
}
|
||||
break;
|
||||
case AST_SPEECH_STATE_WAIT:
|
||||
/* Cue up waiting sound if not already playing */
|
||||
if (!strlen(dtmf)) {
|
||||
if (chan->stream == NULL) {
|
||||
if (speech->processing_sound != NULL) {
|
||||
if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
|
||||
speech_streamfile(chan, speech->processing_sound, chan->language);
|
||||
}
|
||||
}
|
||||
} else if (chan->streamid == -1 && chan->timingfunc == NULL) {
|
||||
ast_stopstream(chan);
|
||||
if (speech->processing_sound != NULL) {
|
||||
if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
|
||||
speech_streamfile(chan, speech->processing_sound, chan->language);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AST_SPEECH_STATE_DONE:
|
||||
/* Now that we are done... let's switch back to not ready state */
|
||||
ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
|
||||
if (!strlen(dtmf)) {
|
||||
/* Copy to speech structure the results, if available */
|
||||
speech->results = ast_speech_results_get(speech);
|
||||
/* Break out of our background too */
|
||||
done = 1;
|
||||
/* Stop audio playback */
|
||||
if (chan->stream != NULL) {
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ast_mutex_unlock(&speech->lock);
|
||||
|
||||
/* Deal with other frame types */
|
||||
if (f != NULL) {
|
||||
/* Free the frame we received */
|
||||
switch (f->frametype) {
|
||||
case AST_FRAME_DTMF:
|
||||
if (dtmf_terminator != '\0' && f->subclass == dtmf_terminator) {
|
||||
done = 1;
|
||||
} else {
|
||||
if (chan->stream != NULL) {
|
||||
ast_stopstream(chan);
|
||||
}
|
||||
if (!started) {
|
||||
/* Change timeout to be 5 seconds for DTMF input */
|
||||
timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
|
||||
started = 1;
|
||||
}
|
||||
time(&start);
|
||||
snprintf(tmp, sizeof(tmp), "%c", f->subclass);
|
||||
strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1);
|
||||
/* If the maximum length of the DTMF has been reached, stop now */
|
||||
if (max_dtmf_len && strlen(dtmf) == max_dtmf_len)
|
||||
done = 1;
|
||||
}
|
||||
break;
|
||||
case AST_FRAME_CONTROL:
|
||||
switch (f->subclass) {
|
||||
case AST_CONTROL_HANGUP:
|
||||
/* Since they hung up we should destroy the speech structure */
|
||||
done = 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(dtmf)) {
|
||||
/* We sort of make a results entry */
|
||||
speech->results = ast_calloc(1, sizeof(*speech->results));
|
||||
if (speech->results != NULL) {
|
||||
ast_speech_dtmf(speech, dtmf);
|
||||
speech->results->score = 1000;
|
||||
speech->results->text = strdup(dtmf);
|
||||
speech->results->grammar = strdup("dtmf");
|
||||
}
|
||||
}
|
||||
|
||||
/* See if it was because they hung up */
|
||||
if (done == 3) {
|
||||
/* Destroy speech structure */
|
||||
ast_speech_destroy(speech);
|
||||
datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
|
||||
if (datastore != NULL) {
|
||||
ast_channel_datastore_remove(chan, datastore);
|
||||
}
|
||||
} else {
|
||||
/* Channel is okay so restore read format */
|
||||
ast_set_read_format(chan, oldreadformat);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief SpeechDestroy() Dialplan Application */
|
||||
static int speech_destroy(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_module_user *u = NULL;
|
||||
struct ast_speech *speech = find_speech(chan);
|
||||
struct ast_datastore *datastore = NULL;
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
if (speech == NULL) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Destroy speech structure */
|
||||
ast_speech_destroy(speech);
|
||||
|
||||
datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
|
||||
if (datastore != NULL) {
|
||||
ast_channel_datastore_remove(chan, datastore);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = ast_unregister_application("SpeechCreate");
|
||||
res |= ast_unregister_application("SpeechLoadGrammar");
|
||||
res |= ast_unregister_application("SpeechUnloadGrammar");
|
||||
res |= ast_unregister_application("SpeechActivateGrammar");
|
||||
res |= ast_unregister_application("SpeechDeactivateGrammar");
|
||||
res |= ast_unregister_application("SpeechStart");
|
||||
res |= ast_unregister_application("SpeechBackground");
|
||||
res |= ast_unregister_application("SpeechDestroy");
|
||||
res |= ast_unregister_application("SpeechProcessingSound");
|
||||
res |= ast_custom_function_unregister(&speech_function);
|
||||
res |= ast_custom_function_unregister(&speech_score_function);
|
||||
res |= ast_custom_function_unregister(&speech_text_function);
|
||||
res |= ast_custom_function_unregister(&speech_grammar_function);
|
||||
res |= ast_custom_function_unregister(&speech_engine_function);
|
||||
res |= ast_custom_function_unregister(&speech_results_type_function);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = ast_register_application("SpeechCreate", speech_create, "Create a Speech Structure", speechcreate_descrip);
|
||||
res |= ast_register_application("SpeechLoadGrammar", speech_load, "Load a Grammar", speechload_descrip);
|
||||
res |= ast_register_application("SpeechUnloadGrammar", speech_unload, "Unload a Grammar", speechunload_descrip);
|
||||
res |= ast_register_application("SpeechActivateGrammar", speech_activate, "Activate a Grammar", speechactivategrammar_descrip);
|
||||
res |= ast_register_application("SpeechDeactivateGrammar", speech_deactivate, "Deactivate a Grammar", speechdeactivategrammar_descrip);
|
||||
res |= ast_register_application("SpeechStart", speech_start, "Start recognizing voice in the audio stream", speechstart_descrip);
|
||||
res |= ast_register_application("SpeechBackground", speech_background, "Play a sound file and wait for speech to be recognized", speechbackground_descrip);
|
||||
res |= ast_register_application("SpeechDestroy", speech_destroy, "End speech recognition", speechdestroy_descrip);
|
||||
res |= ast_register_application("SpeechProcessingSound", speech_processing_sound, "Change background processing sound", speechprocessingsound_descrip);
|
||||
res |= ast_custom_function_register(&speech_function);
|
||||
res |= ast_custom_function_register(&speech_score_function);
|
||||
res |= ast_custom_function_register(&speech_text_function);
|
||||
res |= ast_custom_function_register(&speech_grammar_function);
|
||||
res |= ast_custom_function_register(&speech_engine_function);
|
||||
res |= ast_custom_function_register(&speech_results_type_function);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Dialplan Speech Applications");
|
||||
562
apps/app_sql_postgres.c
Normal file
562
apps/app_sql_postgres.c
Normal file
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Connect to PostgreSQL
|
||||
*
|
||||
* Copyright (C) 2002, Christos Ricudis
|
||||
*
|
||||
* Christos Ricudis <ricudis@itc.auth.gr>
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/linkedlists.h>
|
||||
#include <asterisk/chanvars.h>
|
||||
#include <asterisk/lock.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "libpq-fe.h"
|
||||
|
||||
#define EXTRA_LOG 0
|
||||
|
||||
|
||||
static char *tdesc = "Simple PostgreSQL Interface";
|
||||
|
||||
static char *app = "PGSQL";
|
||||
|
||||
static char *synopsis = "Do several SQLy things";
|
||||
|
||||
static char *descrip =
|
||||
"PGSQL(): Do several SQLy things\n"
|
||||
"Syntax:\n"
|
||||
" PGSQL(Connect var option-string)\n"
|
||||
" Connects to a database. Option string contains standard PostgreSQL\n"
|
||||
" parameters like host=, dbname=, user=. Connection identifer returned\n"
|
||||
" in ${var}\n"
|
||||
" PGSQL(Query var ${connection_identifier} query-string)\n"
|
||||
" Executes standard SQL query contained in query-string using established\n"
|
||||
" connection identified by ${connection_identifier}. Reseult of query is\n"
|
||||
" is stored in ${var}.\n"
|
||||
" PGSQL(Fetch statusvar ${result_identifier} var1 var2 ... varn)\n"
|
||||
" Fetches a single row from a result set contained in ${result_identifier}.\n"
|
||||
" Assigns returned fields to ${var1} ... ${varn}. ${statusvar} is set TRUE\n"
|
||||
" if additional rows exist in reseult set.\n"
|
||||
" PGSQL(Clear ${result_identifier})\n"
|
||||
" Frees memory and datastructures associated with result set.\n"
|
||||
" PGSQL(Disconnect ${connection_identifier})\n"
|
||||
" Disconnects from named connection to PostgreSQL.\n" ;
|
||||
|
||||
/*
|
||||
|
||||
Syntax of SQL commands :
|
||||
|
||||
Connect var option-string
|
||||
|
||||
Connects to a database using the option-string and stores the
|
||||
connection identifier in ${var}
|
||||
|
||||
|
||||
Query var ${connection_identifier} query-string
|
||||
|
||||
Submits query-string to database backend and stores the result
|
||||
identifier in ${var}
|
||||
|
||||
|
||||
Fetch statusvar ${result_identifier} var1 var2 var3 ... varn
|
||||
|
||||
Fetches a row from the query and stores end-of-table status in
|
||||
${statusvar} and columns in ${var1}..${varn}
|
||||
|
||||
|
||||
Clear ${result_identifier}
|
||||
|
||||
Clears data structures associated with ${result_identifier}
|
||||
|
||||
|
||||
Disconnect ${connection_identifier}
|
||||
|
||||
Disconnects from named connection
|
||||
|
||||
|
||||
EXAMPLES OF USE :
|
||||
|
||||
exten => s,2,PGSQL(Connect connid host=localhost user=asterisk dbname=credit)
|
||||
exten => s,3,PGSQL(Query resultid ${connid} SELECT username,credit FROM credit WHERE callerid=${CALLERIDNUM})
|
||||
exten => s,4,PGSQL(Fetch fetchid ${resultid} datavar1 datavar2)
|
||||
exten => s,5,GotoIf(${fetchid}?6:8)
|
||||
exten => s,6,Festival("User ${datavar1} currently has credit balance of ${datavar2} dollars.")
|
||||
exten => s,7,Goto(s,4)
|
||||
exten => s,8,PGSQL(Clear ${resultid})
|
||||
exten => s,9,PGSQL(Disconnect ${connid})
|
||||
|
||||
*/
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#define AST_PGSQL_ID_DUMMY 0
|
||||
#define AST_PGSQL_ID_CONNID 1
|
||||
#define AST_PGSQL_ID_RESID 2
|
||||
#define AST_PGSQL_ID_FETCHID 3
|
||||
|
||||
struct ast_PGSQL_id {
|
||||
int identifier_type; /* 0=dummy, 1=connid, 2=resultid */
|
||||
int identifier;
|
||||
void *data;
|
||||
AST_LIST_ENTRY(ast_PGSQL_id) entries;
|
||||
} *ast_PGSQL_id;
|
||||
|
||||
AST_LIST_HEAD(PGSQLidshead,ast_PGSQL_id) PGSQLidshead;
|
||||
|
||||
static void *find_identifier(int identifier,int identifier_type) {
|
||||
struct PGSQLidshead *headp;
|
||||
struct ast_PGSQL_id *i;
|
||||
void *res=NULL;
|
||||
int found=0;
|
||||
|
||||
headp=&PGSQLidshead;
|
||||
|
||||
if (AST_LIST_LOCK(headp)) {
|
||||
ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
|
||||
} else {
|
||||
AST_LIST_TRAVERSE(headp,i,entries) {
|
||||
if ((i->identifier==identifier) && (i->identifier_type==identifier_type)) {
|
||||
found=1;
|
||||
res=i->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ast_log(LOG_WARNING,"Identifier %d, identifier_type %d not found in identifier list\n",identifier,identifier_type);
|
||||
}
|
||||
AST_LIST_UNLOCK(headp);
|
||||
}
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
static int add_identifier(int identifier_type,void *data) {
|
||||
struct ast_PGSQL_id *i,*j;
|
||||
struct PGSQLidshead *headp;
|
||||
int maxidentifier=0;
|
||||
|
||||
headp=&PGSQLidshead;
|
||||
i=NULL;
|
||||
j=NULL;
|
||||
|
||||
if (AST_LIST_LOCK(headp)) {
|
||||
ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
|
||||
return(-1);
|
||||
} else {
|
||||
i=malloc(sizeof(struct ast_PGSQL_id));
|
||||
AST_LIST_TRAVERSE(headp,j,entries) {
|
||||
if (j->identifier>maxidentifier) {
|
||||
maxidentifier=j->identifier;
|
||||
}
|
||||
}
|
||||
|
||||
i->identifier=maxidentifier+1;
|
||||
i->identifier_type=identifier_type;
|
||||
i->data=data;
|
||||
AST_LIST_INSERT_HEAD(headp,i,entries);
|
||||
AST_LIST_UNLOCK(headp);
|
||||
}
|
||||
return(i->identifier);
|
||||
}
|
||||
|
||||
static int del_identifier(int identifier,int identifier_type) {
|
||||
struct ast_PGSQL_id *i;
|
||||
struct PGSQLidshead *headp;
|
||||
int found=0;
|
||||
|
||||
headp=&PGSQLidshead;
|
||||
|
||||
if (AST_LIST_LOCK(headp)) {
|
||||
ast_log(LOG_WARNING,"Unable to lock identifiers list\n");
|
||||
} else {
|
||||
AST_LIST_TRAVERSE(headp,i,entries) {
|
||||
if ((i->identifier==identifier) &&
|
||||
(i->identifier_type==identifier_type)) {
|
||||
AST_LIST_REMOVE(headp,i,ast_PGSQL_id,entries);
|
||||
free(i);
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_LIST_UNLOCK(headp);
|
||||
}
|
||||
|
||||
if (found==0) {
|
||||
ast_log(LOG_WARNING,"Could not find identifier %d, identifier_type %d in list to delete\n",identifier,identifier_type);
|
||||
return(-1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int aPGSQL_connect(struct ast_channel *chan, void *data) {
|
||||
|
||||
char *s1;
|
||||
char s[100] = "";
|
||||
char *optionstring;
|
||||
char *var;
|
||||
int l;
|
||||
int res;
|
||||
PGconn *karoto;
|
||||
int id;
|
||||
char *stringp=NULL;
|
||||
|
||||
|
||||
res=0;
|
||||
l=strlen(data)+2;
|
||||
s1=malloc(l);
|
||||
strncpy(s1, data, l -1);
|
||||
stringp=s1;
|
||||
strsep(&stringp," "); // eat the first token, we already know it :P
|
||||
var=strsep(&stringp," ");
|
||||
optionstring=strsep(&stringp,"\n");
|
||||
|
||||
karoto = PQconnectdb(optionstring);
|
||||
if (PQstatus(karoto) == CONNECTION_BAD) {
|
||||
ast_log(LOG_WARNING,"Connection to database using '%s' failed. postgress reports : %s\n", optionstring,
|
||||
PQerrorMessage(karoto));
|
||||
res=-1;
|
||||
} else {
|
||||
ast_log(LOG_WARNING,"adding identifier\n");
|
||||
id=add_identifier(AST_PGSQL_ID_CONNID,karoto);
|
||||
snprintf(s, sizeof(s), "%d", id);
|
||||
pbx_builtin_setvar_helper(chan,var,s);
|
||||
}
|
||||
|
||||
free(s1);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int aPGSQL_query(struct ast_channel *chan, void *data) {
|
||||
|
||||
|
||||
char *s1,*s2,*s3,*s4;
|
||||
char s[100] = "";
|
||||
char *querystring;
|
||||
char *var;
|
||||
int l;
|
||||
int res,nres;
|
||||
PGconn *karoto;
|
||||
PGresult *PGSQLres;
|
||||
int id,id1;
|
||||
char *stringp=NULL;
|
||||
|
||||
|
||||
res=0;
|
||||
l=strlen(data)+2;
|
||||
s1=malloc(l);
|
||||
s2=malloc(l);
|
||||
strncpy(s1, data, l - 1);
|
||||
stringp=s1;
|
||||
strsep(&stringp," "); // eat the first token, we already know it :P
|
||||
s3=strsep(&stringp," ");
|
||||
while (1) { // ugly trick to make branches with break;
|
||||
var=s3;
|
||||
s4=strsep(&stringp," ");
|
||||
id=atoi(s4);
|
||||
querystring=strsep(&stringp,"\n");
|
||||
if ((karoto=find_identifier(id,AST_PGSQL_ID_CONNID))==NULL) {
|
||||
ast_log(LOG_WARNING,"Invalid connection identifier %d passed in aPGSQL_query\n",id);
|
||||
res=-1;
|
||||
break;
|
||||
}
|
||||
PGSQLres=PQexec(karoto,querystring);
|
||||
if (PGSQLres==NULL) {
|
||||
ast_log(LOG_WARNING,"aPGSQL_query: Connection Error (connection identifier = %d, error message : %s)\n",id,PQerrorMessage(karoto));
|
||||
res=-1;
|
||||
break;
|
||||
}
|
||||
if (PQresultStatus(PGSQLres) == PGRES_BAD_RESPONSE ||
|
||||
PQresultStatus(PGSQLres) == PGRES_NONFATAL_ERROR ||
|
||||
PQresultStatus(PGSQLres) == PGRES_FATAL_ERROR) {
|
||||
ast_log(LOG_WARNING,"aPGSQL_query: Query Error (connection identifier : %d, error message : %s)\n",id,PQcmdStatus(PGSQLres));
|
||||
res=-1;
|
||||
break;
|
||||
}
|
||||
nres=PQnfields(PGSQLres);
|
||||
id1=add_identifier(AST_PGSQL_ID_RESID,PGSQLres);
|
||||
snprintf(s, sizeof(s), "%d", id1);
|
||||
pbx_builtin_setvar_helper(chan,var,s);
|
||||
break;
|
||||
}
|
||||
|
||||
free(s1);
|
||||
free(s2);
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
|
||||
static int aPGSQL_fetch(struct ast_channel *chan, void *data) {
|
||||
|
||||
char *s1,*s2,*fetchid_var,*s4,*s5,*s6,*s7;
|
||||
char s[100];
|
||||
char *var;
|
||||
int l;
|
||||
int res;
|
||||
PGresult *PGSQLres;
|
||||
int id,id1,i,j,fnd;
|
||||
int *lalares=NULL;
|
||||
int nres;
|
||||
struct ast_var_t *variables;
|
||||
struct varshead *headp;
|
||||
char *stringp=NULL;
|
||||
|
||||
headp=&chan->varshead;
|
||||
|
||||
res=0;
|
||||
l=strlen(data)+2;
|
||||
s7=NULL;
|
||||
s1=malloc(l);
|
||||
s2=malloc(l);
|
||||
strncpy(s1, data, l - 1);
|
||||
stringp=s1;
|
||||
strsep(&stringp," "); // eat the first token, we already know it :P
|
||||
fetchid_var=strsep(&stringp," ");
|
||||
while (1) { // ugly trick to make branches with break;
|
||||
var=fetchid_var; // fetchid
|
||||
fnd=0;
|
||||
|
||||
AST_LIST_TRAVERSE(headp,variables,entries) {
|
||||
if (strncasecmp(ast_var_name(variables),fetchid_var,strlen(fetchid_var))==0) {
|
||||
s7=ast_var_value(variables);
|
||||
fnd=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fnd==0) {
|
||||
s7="0";
|
||||
pbx_builtin_setvar_helper(chan,fetchid_var,s7);
|
||||
}
|
||||
|
||||
s4=strsep(&stringp," ");
|
||||
id=atoi(s4); // resultid
|
||||
if ((PGSQLres=find_identifier(id,AST_PGSQL_ID_RESID))==NULL) {
|
||||
ast_log(LOG_WARNING,"Invalid result identifier %d passed in aPGSQL_fetch\n",id);
|
||||
res=-1;
|
||||
break;
|
||||
}
|
||||
id=atoi(s7); //fetchid
|
||||
if ((lalares=find_identifier(id,AST_PGSQL_ID_FETCHID))==NULL) {
|
||||
i=0; // fetching the very first row
|
||||
} else {
|
||||
i=*lalares;
|
||||
free(lalares);
|
||||
del_identifier(id,AST_PGSQL_ID_FETCHID); // will re-add it a bit later
|
||||
}
|
||||
|
||||
if (i<PQntuples(PGSQLres)) {
|
||||
nres=PQnfields(PGSQLres);
|
||||
ast_log(LOG_WARNING,"ast_PGSQL_fetch : nres = %d i = %d ;\n",nres,i);
|
||||
for (j=0;j<nres;j++) {
|
||||
s5=strsep(&stringp," ");
|
||||
if (s5==NULL) {
|
||||
ast_log(LOG_WARNING,"ast_PGSQL_fetch : More tuples (%d) than variables (%d)\n",nres,j);
|
||||
break;
|
||||
}
|
||||
s6=PQgetvalue(PGSQLres,i,j);
|
||||
if (s6==NULL) {
|
||||
ast_log(LOG_WARNING,"PWgetvalue(res,%d,%d) returned NULL in ast_PGSQL_fetch\n",i,j);
|
||||
break;
|
||||
}
|
||||
ast_log(LOG_WARNING,"===setting variable '%s' to '%s'\n",s5,s6);
|
||||
pbx_builtin_setvar_helper(chan,s5,s6);
|
||||
}
|
||||
lalares=malloc(sizeof(int));
|
||||
*lalares = ++i; // advance to the next row
|
||||
id1 = add_identifier(AST_PGSQL_ID_FETCHID,lalares);
|
||||
} else {
|
||||
ast_log(LOG_WARNING,"ast_PGSQL_fetch : EOF\n");
|
||||
id1 = 0; // no more rows
|
||||
}
|
||||
snprintf(s, sizeof(s), "%d", id1);
|
||||
ast_log(LOG_WARNING,"Setting var '%s' to value '%s'\n",fetchid_var,s);
|
||||
pbx_builtin_setvar_helper(chan,fetchid_var,s);
|
||||
break;
|
||||
}
|
||||
|
||||
free(s1);
|
||||
free(s2);
|
||||
return(res);
|
||||
}
|
||||
|
||||
static int aPGSQL_reset(struct ast_channel *chan, void *data) {
|
||||
|
||||
char *s1,*s3;
|
||||
int l;
|
||||
PGconn *karoto;
|
||||
int id;
|
||||
char *stringp=NULL;
|
||||
|
||||
|
||||
l=strlen(data)+2;
|
||||
s1=malloc(l);
|
||||
strncpy(s1, data, l - 1);
|
||||
stringp=s1;
|
||||
strsep(&stringp," "); // eat the first token, we already know it :P
|
||||
s3=strsep(&stringp," ");
|
||||
id=atoi(s3);
|
||||
if ((karoto=find_identifier(id,AST_PGSQL_ID_CONNID))==NULL) {
|
||||
ast_log(LOG_WARNING,"Invalid connection identifier %d passed in aPGSQL_reset\n",id);
|
||||
} else {
|
||||
PQreset(karoto);
|
||||
}
|
||||
free(s1);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
static int aPGSQL_clear(struct ast_channel *chan, void *data) {
|
||||
|
||||
char *s1,*s3;
|
||||
int l;
|
||||
PGresult *karoto;
|
||||
int id;
|
||||
char *stringp=NULL;
|
||||
|
||||
|
||||
l=strlen(data)+2;
|
||||
s1=malloc(l);
|
||||
strncpy(s1, data, l - 1);
|
||||
stringp=s1;
|
||||
strsep(&stringp," "); // eat the first token, we already know it :P
|
||||
s3=strsep(&stringp," ");
|
||||
id=atoi(s3);
|
||||
if ((karoto=find_identifier(id,AST_PGSQL_ID_RESID))==NULL) {
|
||||
ast_log(LOG_WARNING,"Invalid result identifier %d passed in aPGSQL_clear\n",id);
|
||||
} else {
|
||||
PQclear(karoto);
|
||||
del_identifier(id,AST_PGSQL_ID_RESID);
|
||||
}
|
||||
free(s1);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int aPGSQL_disconnect(struct ast_channel *chan, void *data) {
|
||||
|
||||
char *s1,*s3;
|
||||
int l;
|
||||
PGconn *karoto;
|
||||
int id;
|
||||
char *stringp=NULL;
|
||||
|
||||
|
||||
l=strlen(data)+2;
|
||||
s1=malloc(l);
|
||||
strncpy(s1, data, l - 1);
|
||||
stringp=s1;
|
||||
strsep(&stringp," "); // eat the first token, we already know it :P
|
||||
s3=strsep(&stringp," ");
|
||||
id=atoi(s3);
|
||||
if ((karoto=find_identifier(id,AST_PGSQL_ID_CONNID))==NULL) {
|
||||
ast_log(LOG_WARNING,"Invalid connection identifier %d passed in aPGSQL_disconnect\n",id);
|
||||
} else {
|
||||
PQfinish(karoto);
|
||||
del_identifier(id,AST_PGSQL_ID_CONNID);
|
||||
}
|
||||
free(s1);
|
||||
return(0);
|
||||
|
||||
}
|
||||
|
||||
static int aPGSQL_debug(struct ast_channel *chan, void *data) {
|
||||
ast_log(LOG_WARNING,"Debug : %s\n",(char *)data);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int PGSQL_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
int result;
|
||||
|
||||
#if EXTRA_LOG
|
||||
printf("PRSQL_exec: data=%s\n",(char*)data);
|
||||
#endif
|
||||
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "APP_PGSQL requires an argument (see manual)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
result=0;
|
||||
|
||||
if (strncasecmp("connect",data,strlen("connect"))==0) {
|
||||
result=(aPGSQL_connect(chan,data));
|
||||
} else if (strncasecmp("query",data,strlen("query"))==0) {
|
||||
result=(aPGSQL_query(chan,data));
|
||||
} else if (strncasecmp("fetch",data,strlen("fetch"))==0) {
|
||||
result=(aPGSQL_fetch(chan,data));
|
||||
} else if (strncasecmp("reset",data,strlen("reset"))==0) {
|
||||
result=(aPGSQL_reset(chan,data));
|
||||
} else if (strncasecmp("clear",data,strlen("clear"))==0) {
|
||||
result=(aPGSQL_clear(chan,data));
|
||||
} else if (strncasecmp("debug",data,strlen("debug"))==0) {
|
||||
result=(aPGSQL_debug(chan,data));
|
||||
} else if (strncasecmp("disconnect",data,strlen("disconnect"))==0) {
|
||||
result=(aPGSQL_disconnect(chan,data));
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Unknown APP_PGSQL argument : %s\n",(char *)data);
|
||||
result=-1;
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
struct PGSQLidshead *headp;
|
||||
|
||||
headp=&PGSQLidshead;
|
||||
|
||||
AST_LIST_HEAD_INIT(headp);
|
||||
return ast_register_application(app, PGSQL_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
174
apps/app_stack.c
174
apps/app_stack.c
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2004-2006 Tilghman Lesher <app_stack_v002@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.
|
||||
*
|
||||
* 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 Stack applications Gosub, Return, etc.
|
||||
*
|
||||
* \author Tilghman Lesher <app_stack_v002@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/options.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/chanvars.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/config.h"
|
||||
|
||||
#define STACKVAR "~GOSUB~STACK~"
|
||||
|
||||
|
||||
static const char *app_gosub = "Gosub";
|
||||
static const char *app_gosubif = "GosubIf";
|
||||
static const char *app_return = "Return";
|
||||
static const char *app_pop = "StackPop";
|
||||
|
||||
static const char *gosub_synopsis = "Jump to label, saving return address";
|
||||
static const char *gosubif_synopsis = "Conditionally jump to label, saving return address";
|
||||
static const char *return_synopsis = "Return from gosub routine";
|
||||
static const char *pop_synopsis = "Remove one address from gosub stack";
|
||||
|
||||
static const char *gosub_descrip =
|
||||
"Gosub([[context|]exten|]priority)\n"
|
||||
" Jumps to the label specified, saving the return address.\n";
|
||||
static const char *gosubif_descrip =
|
||||
"GosubIf(condition?labeliftrue[:labeliffalse])\n"
|
||||
" If the condition is true, then jump to labeliftrue. If false, jumps to\n"
|
||||
"labeliffalse, if specified. In either case, a jump saves the return point\n"
|
||||
"in the dialplan, to be returned to with a Return.\n";
|
||||
static const char *return_descrip =
|
||||
"Return()\n"
|
||||
" Jumps to the last label on the stack, removing it.\n";
|
||||
static const char *pop_descrip =
|
||||
"StackPop()\n"
|
||||
" Removes last label on the stack, discarding it.\n";
|
||||
|
||||
|
||||
static int pop_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
pbx_builtin_setvar_helper(chan, STACKVAR, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int return_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
const char *label = pbx_builtin_getvar_helper(chan, STACKVAR);
|
||||
|
||||
if (ast_strlen_zero(label)) {
|
||||
ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
|
||||
return -1;
|
||||
} else if (ast_parseable_goto(chan, label)) {
|
||||
ast_log(LOG_WARNING, "No next statement after Gosub?\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, STACKVAR, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gosub_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char newlabel[AST_MAX_EXTENSION * 2 + 3 + 11];
|
||||
struct ast_module_user *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR, "%s requires an argument: %s([[context|]exten|]priority)\n", app_gosub, app_gosub);
|
||||
return -1;
|
||||
}
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
snprintf(newlabel, sizeof(newlabel), "%s|%s|%d", chan->context, chan->exten, chan->priority + 1);
|
||||
|
||||
if (ast_parseable_goto(chan, data)) {
|
||||
ast_module_user_remove(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pbx_builtin_pushvar_helper(chan, STACKVAR, newlabel);
|
||||
ast_module_user_remove(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gosubif_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct ast_module_user *u;
|
||||
char *condition="", *label1, *label2, *args;
|
||||
int res=0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "GosubIf requires an argument\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
args = ast_strdupa(data);
|
||||
|
||||
u = ast_module_user_add(chan);
|
||||
|
||||
condition = strsep(&args, "?");
|
||||
label1 = strsep(&args, ":");
|
||||
label2 = args;
|
||||
|
||||
if (pbx_checkcondition(condition)) {
|
||||
if (!ast_strlen_zero(label1)) {
|
||||
res = gosub_exec(chan, label1);
|
||||
}
|
||||
} else if (!ast_strlen_zero(label2)) {
|
||||
res = gosub_exec(chan, label2);
|
||||
}
|
||||
|
||||
ast_module_user_remove(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
ast_unregister_application(app_return);
|
||||
ast_unregister_application(app_pop);
|
||||
ast_unregister_application(app_gosubif);
|
||||
ast_unregister_application(app_gosub);
|
||||
|
||||
ast_module_user_hangup_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip);
|
||||
ast_register_application(app_return, return_exec, return_synopsis, return_descrip);
|
||||
ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip);
|
||||
ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Stack Routines");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user