Compare commits

..

3 Commits

Author SHA1 Message Date
Kevin P. Fleming
4f72b2febe remove extraneous svn:executable properties
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/0.1.11@7221 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-29 18:24:39 +00:00
Kevin P. Fleming
a1bf01718e automatic tag renames
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/0.1.11@7201 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2005-11-27 17:18:34 +00:00
Admin Commit
0a5d88d0f8 This commit was manufactured by cvs2svn to create tag 'v0-1-11'.
git-svn-id: https://origsvn.digium.com/svn/asterisk/tags/v0-1-11@428 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2002-03-15 14:58:01 +00:00
1100 changed files with 56411 additions and 413246 deletions

View File

@@ -1 +0,0 @@
28

View File

@@ -1 +0,0 @@
28

View File

@@ -1 +0,0 @@
1.4.5

58
BUGS
View File

@@ -1,22 +1,48 @@
Asterisk Bug Tracking Information
=================================
* EVERYTHING MARKED WITH "XXX" IN THE SOURCE REPRESENTS A BUG! Sometimes
these bugs are in asterisk, and sometimes they relate to the products
that asterisk uses.
To learn about and report Asterisk bugs, please visit
the official Asterisk Bug Tracker at:
* In general Asterisk is a very new program, and there are liable to be
many bugs yet to be discovered, so if you think you've found one, please
be sure to report it.
http://bugs.digium.com
* When you flip to call waiting on a tormenta channel while you have a
three way call up, the parties in the three way cannot hear one another
in the general case.
For more information on using the bug tracker, or to
learn how you can contribute by acting as a bug marshall
please see:
* No auto-reload in chan_zap yet
http://www.asterisk.org/developers/bug-guidelines
* Must be able to call park with flash-hook transfer
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:
======================================================================
Short report on the voicemail system
======================================================================
Stuff We Need:
http://lists.digium.com
Thank you!
-Date/Time (conversion on the fly for different locales)
-A more fleshed/emphasized Main Menu
-Mailbox Options
-useful for allowing user to set certain options
-Notification of new vs. old messages
-Notification of first and last messages (old and new)
and a return to the Main Menu @ the end
**-Better handling of lack of user input, specifically...
infinite loops...
currently found in: vm-instructions
vm-msginstruct
System MUST disconnect user for inactivity
-Mid message menu w/
pause/unpause
seeking
callback option
option to get caller's number if available
option to leave message directly on caller's voicemail
if he/she has account on system
-Also redesign the End Of Message Menu
-Efficienty Question...
Better to always rename msgs to being @ 0001
or...
Better to append new msgs numerically @ the
end and use software to traverse them in
order...saving cpu cycles on renaming files
..could get messy w/ lots of users

486
CHANGES
View File

@@ -1,341 +1,145 @@
Changes since Asterisk 1.2:
* over 4,000 commits since 1.2
* queue member naming
* CLI commands rework
o Change the way CLI commands are structured.
o Most commands are now <module> <verb> <args>
* chan_h323 update
* RTP packetization
* SLA (Shared Line Appearance) support
* T.38 Passthrough Support for faxing in SIP
* Generic channel jitterbuffer (spawned from RTP)
* Variable Length DTMF for better DTMF compatibility
* Improved chan_iax2 scalability by using multithreading
* AEL2 has replaced the original implementation of AEL. The "2" is removed. For more details,
read: http://www.voip-info.org/wiki/view/Asterisk+AEL2
AEL is no longer considered experimental.
* New sounds; English, Spanish, and French prompts, as well as music on hold files, in
multiple Asterisk native formats.
* IMAP storage of voicemail
* Jabber/GoogleTalk integration
* New speech recognition API for interfacing to different Voice Recognition software packages
* much more customizable and portable build system
o also for asterisk-addons
* Radius CDR logging
* SNMP support
* SMDI (Simplified Message Desk Interface) support
* Redesign of MusicOnHold configuration settings
* Manager over HTTP
* Significant chan_skinny updates
* Significant chan_misdn updates
* Improved SIP transfers
* SIP MWI subscription support
* Much improved support for SIP video
* Control over SIP transfers and subscriptions (enable/disable per device)
* ChanSpy whisper mode (Whisper Paging)
* Configurable language support for saying dates and times
* Significant architecture improvements for memory usage and performance
* Media-only IAX2 transfers
* Updates to the Radio Repeater app code
* Deprecation of AgentCallbackLogin in favor of a dialplan-based solution
* uClibc builds supported
* Work done for freeBSD portability
* Work done for Solaris portability
* FreeTDS-based database can be used with Realtime
* New internal data structure, stringfields, is implemented in IAX and SIP, reducing memory consumption by about 50%.
* Use of thread local storage for reduced memory allocation/freeing and lower stack consumption
* Reorganized files into docs/ main/ configs/, including name changes in some cases
* Much effort was expended in arranging documentation in source files in doxygen format
* Improved IP TOS support for IAX and SIP
* Builtin mini HTTP server
* Added support for Sigma Designs cards.
* Frame header caching to reduce memory allocation/freeing
* Passthrough and record/playback support for G.722 wideband audio
* using mpg123 to play MP3 files for music-on-hold will be deprecated in 1.4 (start using the "native support")
* New Apps:
1. AMD() ;; Answering Machine Detection
2. ChannelRedirect() ;; asynch goto, redirect chan to context/exten/priority
3. ContinueWhile() ;; Addition to the While() suite. Acts like "continue".
4. ExitWhile() ;; Addition to the While() suite. Acts like "break".
5. ExtenSpy() ;; A close cousin to ChanSpy().
6. FollowMe() ;; findme/followme call redirect app
7. Log() ;; Send a message to the log, based on severity level.
8. MacroExclusive() ;; No more than one invocation of this macro allowed at any one time.
9. MorseCode() ;; turns strings into dits and dahs. A playground for ham radio licensees!
10. OSPAuth() ;; OSP authentication
11. QueueLog() ;; allows you to write your own events into the queue log
12. SLAStation() ;; Shared Line Appearance
13. SLATrunk() ;; Shared Line Appearance
14. SpeechCreate() ;; Voice Recognition Engine interface...
15. SpeechActivateGrammar()
16. SpeechStart()
17. SpeechBackground
18. SpeechDeactivateGrammar()
19. SpeechProcessingSound()
20. SpeechDestroy()
21. SpeechLoadGrammar()
22. SpeechUnloadGrammar()
23. StopMixMonitor() ;; to stop the MixMonitor App.
24. TryExec() ;; execute dialplan app without fatal consequences
* Apps removed:
1. CheckGroup -- do a comparison to ${GROUP()}
2. Curl -- use the function CURL() instead
3. Cut -- use the function CUT() instead
4. DateTime -- use sayunixtime() app instead.
5. DBget -- deprecated in 1.2, now removed.
6. DBput -- deprecated in 1.2, now removed.
7. Enumlookup -- use the function ENUMLOOKUP() instead
8. Eval -- use the function EVAL() instead
9. GetGroupCount -- use the function GROUP_COUNT() instead
10. GetGroupMatchCount -- use the function GROUP_MATCH_COUNT() instead
11. Intercom -- use the chan_oss module instead
12. Math -- use the function MATH() instead
13. MD5 -- use the function MD5() instead
14. SetCIDname -- use the function CALLERID(name) instead
15. SetCIDnum -- use the function CALLERID(number) instead
16. SetGroup -- use Set(GROUP=group) instead
17. SetRDNIS -- use the function CALLERID(rdnis) instead
18. Sql_postgres -- was deprecated in 1.2, now removed
19. Txtcidname -- use the function TXTCIDNAME instead
* New Dialplan Functions:
1. ARRAY()
2. BASE_64_DECODE()
3. BASE_64_ENCODE()
4. CHANNEL()
5. CURL()
6. CUT()
7. DB_DELETE()
8. FILTER()
9. GLOBAL()
10. IFTIME()
11. KEYPADHASH()
12. ODBC()
13. QUOTE()
14. RAND()
15. REALTIME()
16. SHA1()
17. SORT()
18. SPRINTF()
19. SQL_ESC()
20. STAT()
21. STRPTIME()
* 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
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
View File

@@ -1,341 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

171
CREDITS
View File

@@ -1,177 +1,18 @@
=== DEVELOPMENT SUPPORT ===
We'd like to thank the following companies for helping fund development of
Asterisk:
Pilosoft, Inc. - for supporting ADSI development in Asterisk
Asterlink, Inc. - for supporting broad Asterisk development
GFS - for supporting ALSA development
Telesthetic - for supporting SIP development
Christos Ricudis - for substantial code contributions
nic.at - ENUM support in Asterisk
Paul Bagyenda, Digital Solutions - for initial Voicetronix driver development
=== WISHLIST CONTRIBUTERS ===
Jeremy McNamara - SpeeX support
Nick Seraphin - RDNIS support
Gary - Phonejack ADSI (in progress)
Wasim - Hangup detect
=== HARDWARE DONORS ===
* Thanks to QuickNet Technologies for their donation of an Internet
PhoneJack and Linejack card to the project. (http://www.quicknet.net)
* Thanks to VoipSupply for their donation of Sipura ATAs to the project for
T.38 testing. (http://www.voipsupply.com)
* Thanks to Grandstream for their donation of ATAs to the project for
T.38 testing. (http://www.grandstream.com)
=== DEVELOPMENT SUPPORT ===
I'd like to thank the following companies for helping fund development of
Asterisk:
=== MISCELLANEOUS PATCHES ===
Jim Dixon - Zapata Telephony and app_rpt
http://www.zapatatelephony.org/app_rpt.html
Pilosoft, Inc. - for supporting ADSI development in Asterisk
Russell Bryant - Asterisk 1.0 maintainer and misc. enhancements
russelb@clemson.edu
Anthony Minessale II - Countless big and small fixes, and relentless forward push
ChanSpy, ForkCDR, ControlPlayback, While/EndWhile, DumpChan, Dictate,
MacroIf, ExecIf, ExecIfTime, RetryDial, MixMonitor applications; many realtime
concepts and implementation pieces, including res_config_odbc; format_slin;
cdr_custom; several features in Dial including L(), G() and enhancements to
M() and D(); several CDR enhancements including CDR variables; attended
transfer; one touch record; native MOH; manager eventmask; command line '-t'
flag to allow recording/voicemail on nfs shares; #exec command and multiline
comments in config files; setvar in iax and sip configs.
anthmct@yahoo.com http://www.asterlink.com
James Golovich - Innumerable contributions
You can find him and asterisk-perl at http://asterisk.gnuinter.net
Andre Bierwirth - Extension hints and status
Oliver Daudey - ISDN4Linux fixes
Pauline Middelink - ISDN4Linux patches and some general patches.
She can be found at http://www.polyware.nl/~middelink/En/
Jean-Denis Girard - Various contributions from the South Pacific Islands
jd-girard@esoft.pf http://www.esoft.pf
William Jordan / Vonage - MySQL enhancements to Voicemail
wjordan@vonage.com
Jac Kersing - Various fixes
Steven Critchfield - Seek and Trunc functions for playback and recording
critch@basesys.com
Jefferson Noxon - app_lookupcidname, app_db, and various other contributions
Klaus-Peter Junghanns - in-band DTMF on SIP and MGCP
Ross Finlayson - Dynamic RTP payload support
Mahmut Fettahlioglu - Audio recording, music-on-hold changes, alaw file
format, and various fixes. Can be contacted at mahmut@oa.com.au
James Dennis - Cisco SIP compatibility patches to work with SIP service
providers. Can be contacted at asterisk@jdennis.net
Tilghman Lesher - ast_localtime(); ast_say_date_with_format();
GotoIfTime, Random, SayUnixTime, HasNewVoicemail applications;
CUT, SORT, EVAL, CURL, FIELDQTY, STRFTIME, QUEUEAGENT* functions;
and other innumerable bug fixes. http://asterisk.drunkcoder.com/
Jayson Vantuyl - Manager protocol changes, various other bugs.
jvantuyl@computingedge.net
Thorsten Lockert - OpenBSD, FreeBSD ports, making MacOS X port run on 10.3,
dialplan include verification, route lookup on OpenBSD, SNMP agent
support (res_snmp), various other bugs. tholo@sigmasoft.com
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 +37,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,

8322
ChangeLog

File diff suppressed because it is too large Load Diff

390
LICENSE
View File

@@ -1,69 +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.
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.546.8963 (via telephone in the USA)
+1.256.428.6000 (via telephone outside the USA)
+1.256.864.0464 (via FAX inside or outside the USA)
IAX2/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.
150 West Park Loop
Suite 100
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.

735
Makefile
View File

@@ -3,475 +3,110 @@
#
# Top level Makefile
#
# Copyright (C) 1999-2006, Digium, Inc.
# 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
#
# All Makefiles use the following variables:
#
# ASTCFLAGS - compiler options
# ASTLDFLAGS - linker flags (not libraries)
# AST_LIBS - libraries to build binaries XXX
# LIBS - additional libraries, at top-level for all links,
# on a single object just for that object
# SOLINK - linker flags used only for creating shared objects (.so files),
# used for all .so links
#
# Default values fo ASTCFLAGS and ASTLDFLAGS can be specified in the
# environment when running make, as follows:
#
# $ ASTCFLAGS="-Werror" make
export ASTTOPDIR
export ASTERISKVERSION
export ASTERISKVERSIONNUM
export INSTALL_PATH
export ASTETCDIR
export ASTVARRUNDIR
export MODULES_DIR
export ASTSPOOLDIR
export ASTVARLIBDIR
export ASTDATADIR
export ASTLOGDIR
export ASTLIBDIR
export ASTMANDIR
export ASTHEADERDIR
export ASTBINDIR
export ASTSBINDIR
export AGI_DIR
export ASTCONFPATH
export NOISY_BUILD
export MENUSELECT_CFLAGS
export CC
export CXX
export AR
export RANLIB
export HOST_CC
export STATIC_BUILD
export INSTALL
export DESTDIR
export PROC
export SOLINK
export STRIP
export DOWNLOAD
export OSARCH
export CURSES_DIR
export NCURSES_DIR
export TERMCAP_DIR
export TINFO_DIR
export GTK2_LIB
export GTK2_INCLUDE
.EXPORT_ALL_VARIABLES:
# even though we could use '-include makeopts' here, use a wildcard
# lookup anyway, so that make won't try to build makeopts if it doesn't
# exist (other rules will force it to be built if needed)
ifneq ($(wildcard makeopts),)
include makeopts
endif
INSTALL_PREFIX=
#Uncomment this to see all build commands instead of 'quiet' output
#NOISY_BUILD=yes
MODULES_DIR=$(INSTALL_PREFIX)/usr/lib/asterisk/modules
AGI_DIR=$(INSTALL_PREFIX)/var/lib/asterisk/agi-bin
# Create OPTIONS variable
OPTIONS=
# Pentium Pro Optimize
#PROC=i686
# Pentium Optimize
PROC=i586
ASTTOPDIR:=$(shell pwd)
DEBUG=-g #-pg
INCLUDE=-Iinclude -I../include
CFLAGS=-pipe -Wall -Wmissing-prototypes -Wmissing-declarations -O6 $(DEBUG) $(INCLUDE) -D_REENTRANT
#CFLAGS+=-Werror
CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
ASTERISKVERSION=$(shell if [ -f .version ]; then cat .version; fi)
RPMVERSION=$(shell sed 's/[-\/:]/_/g' .version)
CFLAGS+=-DASTERISK_VERSION=\"$(ASTERISKVERSION)\"
# Optional debugging parameters
CFLAGS+= -DDO_CRASH -DDEBUG_THREADS
# Uncomment next one to enable ast_frame tracing (for debugging)
#CLFAGS+= -DTRACE_FRAMES
CFLAGS+=# -fomit-frame-pointer
SUBDIRS=res channels pbx apps codecs formats agi cdr
LIBS=-ldl -lpthread -lreadline -lncurses -lm
OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
translate.o file.o say.o pbx.o cli.o md5.o \
ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
cdr.o tdd.o asterisk.o
CC=gcc
INSTALL=install
# Overwite config files on "make samples"
OVERWRITE=y
# Include debug and macro symbols in the executables (-g) and profiling info (-pg)
DEBUG=-g3
# Staging directory
# Files are copied here temporarily during the install process
# For example, make DESTDIR=/tmp/asterisk woud put things in
# /tmp/asterisk/etc/asterisk
# !!! Watch out, put no spaces or comments after the value !!!
#DESTDIR?=/tmp/asterisk
# Define standard directories for various platforms
# These apply if they are not redefined in asterisk.conf
ifeq ($(OSARCH),SunOS)
ASTETCDIR=/var/etc/asterisk
ASTLIBDIR=/opt/asterisk/lib
ASTVARLIBDIR=/var/opt/asterisk
ASTSPOOLDIR=/var/spool/asterisk
ASTLOGDIR=/var/log/asterisk
ASTHEADERDIR=/opt/asterisk/include
ASTBINDIR=/opt/asterisk/bin
ASTSBINDIR=/opt/asterisk/sbin
ASTVARRUNDIR=/var/run/asterisk
ASTMANDIR=/opt/asterisk/man
else
ASTETCDIR=$(sysconfdir)/asterisk
ASTLIBDIR=$(libdir)/asterisk
ASTHEADERDIR=$(includedir)/asterisk
ASTBINDIR=$(bindir)
ASTSBINDIR=$(sbindir)
ASTSPOOLDIR=$(localstatedir)/spool/asterisk
ASTLOGDIR=$(localstatedir)/log/asterisk
ASTVARRUNDIR=$(localstatedir)/run
ASTMANDIR=$(mandir)
ifeq ($(OSARCH),FreeBSD)
ASTVARLIBDIR=$(prefix)/share/asterisk
else
ASTVARLIBDIR=$(localstatedir)/lib/asterisk
endif
endif
ifeq ($(ASTDATADIR),)
ASTDATADIR:=$(ASTVARLIBDIR)
endif
# Asterisk.conf is located in ASTETCDIR or by using the -C flag
# when starting Asterisk
ASTCONFPATH=$(ASTETCDIR)/asterisk.conf
MODULES_DIR=$(ASTLIBDIR)/modules
AGI_DIR=$(ASTDATADIR)/agi-bin
# If you use Apache, you may determine by a grep 'DocumentRoot' of your httpd.conf file
HTTP_DOCSDIR=/var/www/html
# Determine by a grep 'ScriptAlias' of your Apache httpd.conf file
HTTP_CGIDIR=/var/www/cgi-bin
# Uncomment this to use the older DSP routines
#ASTCFLAGS+=-DOLD_DSP_ROUTINES
# If the file .asterisk.makeopts is present in your home directory, you can
# include all of your favorite menuselect options so that every time you download
# a new version of Asterisk, you don't have to run menuselect to set them.
# The file /etc/asterisk.makeopts will also be included but can be overridden
# by the file in your home directory.
GLOBAL_MAKEOPTS=$(wildcard /etc/asterisk.makeopts)
USER_MAKEOPTS=$(wildcard ~/.asterisk.makeopts)
MOD_SUBDIR_CFLAGS=-I$(ASTTOPDIR)/include
OTHER_SUBDIR_CFLAGS=-I$(ASTTOPDIR)/include
ifeq ($(OSARCH),linux-gnu)
ifeq ($(PROC),x86_64)
# You must have GCC 3.4 to use k8, otherwise use athlon
PROC=k8
#PROC=athlon
endif
ifeq ($(PROC),sparc64)
#The problem with sparc is the best stuff is in newer versions of gcc (post 3.0) only.
#This works for even old (2.96) versions of gcc and provides a small boost either way.
#A ultrasparc cpu is really v9 but the stock debian stable 3.0 gcc doesn't support it.
#So we go lowest common available by gcc and go a step down, still a step up from
#the default as we now have a better instruction set to work with. - Belgarath
PROC=ultrasparc
OPTIONS+=$(shell if $(CC) -mtune=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mtune=$(PROC)"; fi)
OPTIONS+=$(shell if $(CC) -mcpu=v8 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mcpu=v8"; fi)
OPTIONS+=-fomit-frame-pointer
endif
ifeq ($(PROC),arm)
# The Cirrus logic is the only heavily shipping arm processor with a real floating point unit
ifeq ($(SUB_PROC),maverick)
OPTIONS+=-fsigned-char -mcpu=ep9312
else
ifeq ($(SUB_PROC),xscale)
OPTIONS+=-fsigned-char -mcpu=xscale
else
OPTIONS+=-fsigned-char
endif
endif
endif
endif
ASTCFLAGS+=-pipe -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG)
ASTCFLAGS+=-include $(ASTTOPDIR)/include/asterisk/autoconfig.h
ifeq ($(AST_DEVMODE),yes)
ASTCFLAGS+=-Werror -Wunused
endif
ifneq ($(findstring BSD,$(OSARCH)),)
ASTCFLAGS+=-I/usr/local/include
ASTLDFLAGS+=-L/usr/local/lib
endif
ifneq ($(PROC),ultrasparc)
ASTCFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
endif
ifeq ($(PROC),ppc)
ASTCFLAGS+=-fsigned-char
endif
ifeq ($(OSARCH),FreeBSD)
# -V is understood by BSD Make, not by GNU make.
BSDVERSION=$(shell make -V OSVERSION -f /usr/share/mk/bsd.port.subdir.mk)
ASTCFLAGS+=$(shell if test $(BSDVERSION) -lt 500016 ; then echo "-D_THREAD_SAFE"; fi)
AST_LIBS+=$(shell if test $(BSDVERSION) -lt 502102 ; then echo "-lc_r"; else echo "-pthread"; fi)
endif
ifeq ($(OSARCH),NetBSD)
ASTCFLAGS+=-pthread -I/usr/pkg/include
endif
ifeq ($(OSARCH),OpenBSD)
ASTCFLAGS+=-pthread
endif
ifeq ($(OSARCH),SunOS)
ASTCFLAGS+=-Wcast-align -DSOLARIS -I../include/solaris-compat -I/opt/ssl/include -I/usr/local/ssl/include
endif
ASTERISKVERSION:=$(shell build_tools/make_version .)
ifneq ($(wildcard .version),)
ASTERISKVERSIONNUM:=$(shell awk -F. '{printf "%01d%02d%02d", $$1, $$2, $$3}' .version)
RPMVERSION:=$(shell sed 's/[-\/:]/_/g' .version)
else
RPMVERSION=unknown
endif
ifneq ($(wildcard .svn),)
ASTERISKVERSIONNUM=999999
endif
ASTCFLAGS+=$(MALLOC_DEBUG)$(BUSYDETECT)$(OPTIONS)
MOD_SUBDIRS:=res channels pbx apps codecs formats cdr funcs main
OTHER_SUBDIRS:=utils agi
SUBDIRS:=$(OTHER_SUBDIRS) $(MOD_SUBDIRS)
SUBDIRS_INSTALL:=$(SUBDIRS:%=%-install)
SUBDIRS_CLEAN:=$(SUBDIRS:%=%-clean)
SUBDIRS_UNINSTALL:=$(SUBDIRS:%=%-uninstall)
MOD_SUBDIRS_EMBED_LDSCRIPT:=$(MOD_SUBDIRS:%=%-embed-ldscript)
MOD_SUBDIRS_EMBED_LDFLAGS:=$(MOD_SUBDIRS:%=%-embed-ldflags)
MOD_SUBDIRS_EMBED_LIBS:=$(MOD_SUBDIRS:%=%-embed-libs)
ifneq ($(findstring darwin,$(OSARCH)),)
ASTCFLAGS+=-D__Darwin__
AUDIO_LIBS=-framework CoreAudio
SOLINK=-dynamic -bundle -undefined suppress -force_flat_namespace
else
# These are used for all but Darwin
SOLINK=-shared -Xlinker -x
ifneq ($(findstring BSD,$(OSARCH)),)
LDFLAGS+=-L/usr/local/lib
endif
endif
ifeq ($(OSARCH),SunOS)
SOLINK=-shared -fpic -L/usr/local/ssl/lib
endif
# This is used when generating the doxygen documentation
ifneq ($(DOT),:)
HAVEDOT=yes
else
HAVEDOT=no
endif
all: _all
_all: all
@echo " +--------- Asterisk Build Complete ---------+"
@echo " + Asterisk has successfully been built, and +"
@echo " + can be installed by running: +"
@echo " + Asterisk has successfully been built, but +"
@echo " + cannot be run before being installed by +"
@echo " + running: +"
@echo " + +"
@echo " + $(MAKE) install +"
@echo " + make install +"
@echo " +-------------------------------------------+"
_all: cleantest $(SUBDIRS)
all: asterisk subdirs
makeopts: configure
@echo "****"
@echo "**** The configure script must be executed before running '$(MAKE)'."
@echo "**** Please run \"./configure\"."
@echo "****"
@exit 1
_version:
if [ -d CVS ] && ! [ -f .version ]; then echo "CVS-`date +"%D-%T"`" > .version; fi
menuselect.makeopts: menuselect/menuselect menuselect-tree
menuselect/menuselect --check-deps $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts
.version: _version
$(MOD_SUBDIRS_EMBED_LDSCRIPT):
@echo "EMBED_LDSCRIPTS+="`$(MAKE) --quiet --no-print-directory -C $(@:-embed-ldscript=) SUBDIR=$(@:-embed-ldscript=) __embed_ldscript` >> makeopts.embed_rules
build.h:
./make_build_h
$(MOD_SUBDIRS_EMBED_LDFLAGS):
@echo "EMBED_LDFLAGS+="`$(MAKE) --quiet --no-print-directory -C $(@:-embed-ldflags=) SUBDIR=$(@:-embed-ldflags=) __embed_ldflags` >> makeopts.embed_rules
asterisk: .version build.h $(OBJS)
gcc -o asterisk -rdynamic $(OBJS) $(LIBS)
$(MOD_SUBDIRS_EMBED_LIBS):
@echo "EMBED_LIBS+="`$(MAKE) --quiet --no-print-directory -C $(@:-embed-libs=) SUBDIR=$(@:-embed-libs=) __embed_libs` >> makeopts.embed_rules
subdirs:
for x in $(SUBDIRS); do $(MAKE) -C $$x || exit 1 ; done
makeopts.embed_rules: menuselect.makeopts
@echo "Generating embedded module rules ..."
@rm -f $@
@$(MAKE) --no-print-directory $(MOD_SUBDIRS_EMBED_LDSCRIPT)
@$(MAKE) --no-print-directory $(MOD_SUBDIRS_EMBED_LDFLAGS)
@$(MAKE) --no-print-directory $(MOD_SUBDIRS_EMBED_LIBS)
clean:
for x in $(SUBDIRS); do $(MAKE) -C $$x clean || exit 1 ; done
rm -f *.o *.so asterisk
rm -f build.h
$(SUBDIRS): include/asterisk/version.h include/asterisk/buildopts.h defaults.h makeopts.embed_rules
# ensure that all module subdirectories are processed before 'main' during
# a parallel build, since if there are modules selected to be embedded the
# directories containing them must be completed before the main Asterisk
# binary can be built
main: $(filter-out main,$(MOD_SUBDIRS))
$(MOD_SUBDIRS):
@ASTCFLAGS="$(MOD_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" AST_LIBS="$(AST_LIBS)" $(MAKE) --no-print-directory --no-builtin-rules -C $@ SUBDIR=$@ all
$(OTHER_SUBDIRS):
@ASTCFLAGS="$(OTHER_SUBDIR_CFLAGS) $(ASTCFLAGS)" ASTLDFLAGS="$(ASTLDFLAGS)" AUDIO_LIBS="$(AUDIO_LIBS)" $(MAKE) --no-print-directory --no-builtin-rules -C $@ SUBDIR=$@ all
defaults.h: makeopts
@build_tools/make_defaults_h > $@.tmp
@if cmp -s $@.tmp $@ ; then : ; else \
mv $@.tmp $@ ; \
fi
@rm -f $@.tmp
include/asterisk/version.h:
@build_tools/make_version_h > $@.tmp
@if cmp -s $@.tmp $@ ; then : ; else \
mv $@.tmp $@ ; \
fi
@rm -f $@.tmp
include/asterisk/buildopts.h: menuselect.makeopts
@build_tools/make_buildopts_h > $@.tmp
@if cmp -s $@.tmp $@ ; then : ; else \
mv $@.tmp $@ ; \
fi
@rm -f $@.tmp
$(SUBDIRS_CLEAN):
@$(MAKE) --no-print-directory -C $(@:-clean=) clean
clean: $(SUBDIRS_CLEAN)
rm -f defaults.h
rm -f include/asterisk/build.h
rm -f include/asterisk/version.h
@$(MAKE) -C menuselect clean
cp -f .cleancount .lastclean
dist-clean: distclean
distclean: clean
@$(MAKE) -C menuselect dist-clean
@$(MAKE) -C sounds dist-clean
rm -f menuselect.makeopts makeopts menuselect-tree menuselect.makedeps
rm -f makeopts.embed_rules
rm -f config.log config.status
rm -rf autom4te.cache
rm -f include/asterisk/autoconfig.h
rm -f include/asterisk/buildopts.h
rm -rf doc/api
rm -f build_tools/menuselect-deps
datafiles: _all
if [ x`$(ID) -un` = xroot ]; then CFLAGS="$(ASTCFLAGS)" sh build_tools/mkpkgconfig $(DESTDIR)/usr/lib/pkgconfig; fi
# Should static HTTP be installed during make samples or even with its own target ala
# webvoicemail? There are portions here that *could* be customized but might also be
# improved a lot. I'll put it here for now.
mkdir -p $(DESTDIR)$(ASTDATADIR)/static-http
for x in static-http/*; do \
$(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/static-http ; \
datafiles: all
mkdir -p $(INSTALL_PREFIX)/var/lib/asterisk/sounds/digits
for x in sounds/digits/*; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/sounds/digits ; \
done
mkdir -p $(DESTDIR)$(ASTDATADIR)/images
for x in sounds/vm-* sounds/transfer* sounds/pbx-* sounds/ss-* sounds/beep* sounds/dir-*; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/sounds ; \
done
mkdir -p $(INSTALL_PREFIX)/var/lib/asterisk/images
for x in images/*.jpg; do \
$(INSTALL) -m 644 $$x $(DESTDIR)$(ASTDATADIR)/images ; \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/images ; \
done
mkdir -p $(DESTDIR)$(AGI_DIR)
$(MAKE) -C sounds install
mkdir -p $(AGI_DIR)
update:
@if [ -d .svn ]; then \
echo "Updating from Subversion..." ; \
svn update | tee update.out; \
rm -f .version; \
if [ `grep -c ^C update.out` -gt 0 ]; then \
echo ; echo "The following files have conflicts:" ; \
grep ^C update.out | cut -b4- ; \
fi ; \
rm -f update.out; \
else \
echo "Not under version control"; \
fi
NEWHEADERS=$(notdir $(wildcard include/asterisk/*.h))
OLDHEADERS=$(filter-out $(NEWHEADERS),$(notdir $(wildcard $(DESTDIR)$(ASTHEADERDIR)/*.h)))
bininstall: _all
mkdir -p $(DESTDIR)$(MODULES_DIR)
mkdir -p $(DESTDIR)$(ASTSBINDIR)
mkdir -p $(DESTDIR)$(ASTETCDIR)
mkdir -p $(DESTDIR)$(ASTBINDIR)
mkdir -p $(DESTDIR)$(ASTVARRUNDIR)
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/dictate
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/system
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/tmp
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/meetme
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/monitor
$(INSTALL) -m 755 main/asterisk $(DESTDIR)$(ASTSBINDIR)/
$(LN) -sf asterisk $(DESTDIR)$(ASTSBINDIR)/rasterisk
$(INSTALL) -m 755 contrib/scripts/astgenkey $(DESTDIR)$(ASTSBINDIR)/
$(INSTALL) -m 755 contrib/scripts/autosupport $(DESTDIR)$(ASTSBINDIR)/
if [ ! -f $(DESTDIR)$(ASTSBINDIR)/safe_asterisk ]; then \
cat contrib/scripts/safe_asterisk | sed 's|__ASTERISK_SBIN_DIR__|$(ASTSBINDIR)|;s|__ASTERISK_VARRUN_DIR__|$(ASTVARRUNDIR)|;' > $(DESTDIR)$(ASTSBINDIR)/safe_asterisk ;\
chmod 755 $(DESTDIR)$(ASTSBINDIR)/safe_asterisk;\
fi
$(INSTALL) -d $(DESTDIR)$(ASTHEADERDIR)
$(INSTALL) -m 644 include/asterisk.h $(DESTDIR)$(includedir)
$(INSTALL) -m 644 include/asterisk/*.h $(DESTDIR)$(ASTHEADERDIR)
if [ -n "$(OLDHEADERS)" ]; then \
rm -f $(addprefix $(DESTDIR)$(ASTHEADERDIR)/,$(OLDHEADERS)) ;\
fi
mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-csv
mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-custom
mkdir -p $(DESTDIR)$(ASTDATADIR)/keys
mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware
mkdir -p $(DESTDIR)$(ASTDATADIR)/firmware/iax
mkdir -p $(DESTDIR)$(ASTMANDIR)/man8
$(INSTALL) -m 644 keys/iaxtel.pub $(DESTDIR)$(ASTDATADIR)/keys
$(INSTALL) -m 644 keys/freeworlddialup.pub $(DESTDIR)$(ASTDATADIR)/keys
$(INSTALL) -m 644 doc/asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8
$(INSTALL) -m 644 contrib/scripts/astgenkey.8 $(DESTDIR)$(ASTMANDIR)/man8
$(INSTALL) -m 644 contrib/scripts/autosupport.8 $(DESTDIR)$(ASTMANDIR)/man8
$(INSTALL) -m 644 contrib/scripts/safe_asterisk.8 $(DESTDIR)$(ASTMANDIR)/man8
if [ -f contrib/firmware/iax/iaxy.bin ] ; then \
$(INSTALL) -m 644 contrib/firmware/iax/iaxy.bin $(DESTDIR)$(ASTDATADIR)/firmware/iax/iaxy.bin; \
fi
$(SUBDIRS_INSTALL):
@DESTDIR="$(DESTDIR)" ASTSBINDIR="$(ASTSBINDIR)" $(MAKE) -C $(@:-install=) install
NEWMODS=$(notdir $(wildcard */*.so))
OLDMODS=$(filter-out $(NEWMODS),$(notdir $(wildcard $(DESTDIR)$(MODULES_DIR)/*.so)))
oldmodcheck:
@if [ -n "$(OLDMODS)" ]; then \
echo " WARNING WARNING WARNING" ;\
echo "" ;\
echo " Your Asterisk modules directory, located at" ;\
echo " $(DESTDIR)$(MODULES_DIR)" ;\
echo " contains modules that were not installed by this " ;\
echo " version of Asterisk. Please ensure that these" ;\
echo " modules are compatible with this version before" ;\
echo " attempting to run Asterisk." ;\
echo "" ;\
for f in $(OLDMODS); do \
echo " $$f" ;\
done ;\
echo "" ;\
echo " WARNING WARNING WARNING" ;\
fi
install: datafiles bininstall $(SUBDIRS_INSTALL)
@if [ -x /usr/sbin/asterisk-post-install ]; then \
/usr/sbin/asterisk-post-install $(DESTDIR) . ; \
fi
install: all datafiles
mkdir -p $(MODULES_DIR)
mkdir -p $(INSTALL_PREFIX)/usr/sbin
install -m 755 asterisk $(INSTALL_PREFIX)/usr/sbin/
install -m 755 astgenkey $(INSTALL_PREFIX)/usr/sbin/
for x in $(SUBDIRS); do $(MAKE) -C $$x install || exit 1 ; done
install -d $(INSTALL_PREFIX)/usr/include/asterisk
install include/asterisk/*.h $(INSTALL_PREFIX)/usr/include/asterisk
rm -f $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm
mkdir -p $(INSTALL_PREFIX)/var/spool/asterisk/vm
rm -f $(INSTALL_PREFIX)/usr/lib/asterisk/modules/chan_ixj.so
rm -f $(INSTALL_PREFIX)/usr/lib/asterisk/modules/chan_tor.so
mkdir -p $(INSTALL_PREFIX)/var/lib/asterisk/sounds
mkdir -p $(INSTALL_PREFIX)/var/log/asterisk/cdr-csv
mkdir -p $(INSTALL_PREFIX)/var/lib/asterisk/keys
install -m 644 keys/iaxtel.pub $(INSTALL_PREFIX)/var/lib/asterisk/keys
( cd $(INSTALL_PREFIX)/var/lib/asterisk/sounds ; ln -s ../../../spool/asterisk/vm . )
@echo " +---- Asterisk Installation Complete -------+"
@echo " + +"
@echo " + YOU MUST READ THE SECURITY DOCUMENT +"
@@ -481,210 +116,58 @@ install: datafiles bininstall $(SUBDIRS_INSTALL)
@echo " + configuration files (overwriting any +"
@echo " + existing config files), run: +"
@echo " + +"
@echo " + $(MAKE) samples +"
@echo " + make samples +"
@echo " + +"
@echo " +----------------- or ---------------------+"
@echo " + +"
@echo " + You can go ahead and install the asterisk +"
@echo " + program documentation now or later run: +"
@echo " + +"
@echo " + $(MAKE) progdocs +"
@echo " + make progdocs +"
@echo " + +"
@echo " + **Note** This requires that you have +"
@echo " + doxygen installed on your local system +"
@echo " +-------------------------------------------+"
@$(MAKE) -s oldmodcheck
upgrade: bininstall
adsi:
mkdir -p $(DESTDIR)$(ASTETCDIR)
for x in configs/*.adsi; do \
if [ ! -f $(DESTDIR)$(ASTETCDIR)/$$x ]; then \
$(INSTALL) -m 644 $$x $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x` ; \
fi ; \
done
samples: adsi
mkdir -p $(DESTDIR)$(ASTETCDIR)
samples: all datafiles
mkdir -p $(INSTALL_PREFIX)/etc/asterisk
for x in configs/*.sample; do \
if [ -f $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample` ]; then \
if [ "$(OVERWRITE)" = "y" ]; then \
if cmp -s $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample` $$x ; then \
echo "Config file $$x is unchanged"; \
continue; \
fi ; \
mv -f $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample` $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample`.old ; \
else \
echo "Skipping config file $$x"; \
continue; \
fi ;\
if [ -f $(INSTALL_PREFIX)/etc/asterisk/`basename $$x .sample` ]; then \
mv -f $(INSTALL_PREFIX)/etc/asterisk/`basename $$x .sample` $(INSTALL_PREFIX)/etc/asterisk/`basename $$x .sample`.old ; \
fi ; \
$(INSTALL) -m 644 $$x $(DESTDIR)$(ASTETCDIR)/`$(BASENAME) $$x .sample` ;\
install $$x $(INSTALL_PREFIX)/etc/asterisk/`basename $$x .sample` ;\
done
if [ "$(OVERWRITE)" = "y" ] || [ ! -f $(DESTDIR)$(ASTCONFPATH) ]; then \
( \
echo "[directories]" ; \
echo "astetcdir => $(ASTETCDIR)" ; \
echo "astmoddir => $(MODULES_DIR)" ; \
echo "astvarlibdir => $(ASTVARLIBDIR)" ; \
echo "astdatadir => $(ASTDATADIR)" ; \
echo "astagidir => $(AGI_DIR)" ; \
echo "astspooldir => $(ASTSPOOLDIR)" ; \
echo "astrundir => $(ASTVARRUNDIR)" ; \
echo "astlogdir => $(ASTLOGDIR)" ; \
echo "" ; \
echo ";[options]" ; \
echo ";internal_timing = yes" ; \
echo ";systemname = my_system_name ; prefix uniqueid with a system name for global uniqueness issues" ; \
echo "; Changing the following lines may compromise your security." ; \
echo ";[files]" ; \
echo ";astctlpermissions = 0660" ; \
echo ";astctlowner = root" ; \
echo ";astctlgroup = apache" ; \
echo ";astctl = asterisk.ctl" ; \
) > $(DESTDIR)$(ASTCONFPATH) ; \
else \
echo "Skipping asterisk.conf creation"; \
fi
mkdir -p $(DESTDIR)$(ASTSPOOLDIR)/voicemail/default/1234/INBOX
build_tools/make_sample_voicemail $(DESTDIR)/$(ASTDATADIR) $(DESTDIR)/$(ASTSPOOLDIR)
webvmail:
@[ -d $(DESTDIR)$(HTTP_DOCSDIR)/ ] || ( printf "http docs directory not found.\nUpdate assignment of variable HTTP_DOCSDIR in Makefile!\n" && exit 1 )
@[ -d $(DESTDIR)$(HTTP_CGIDIR) ] || ( printf "cgi-bin directory not found.\nUpdate assignment of variable HTTP_CGIDIR in Makefile!\n" && exit 1 )
$(INSTALL) -m 4755 -o root -g root contrib/scripts/vmail.cgi $(DESTDIR)$(HTTP_CGIDIR)/vmail.cgi
mkdir -p $(DESTDIR)$(HTTP_DOCSDIR)/_asterisk
for x in images/*.gif; do \
$(INSTALL) -m 644 $$x $(DESTDIR)$(HTTP_DOCSDIR)/_asterisk/; \
for x in sounds/demo-*; do \
install $$x $(INSTALL_PREFIX)/var/lib/asterisk/sounds; \
done
mkdir -p $(INSTALL_PREFIX)/var/spool/asterisk/vm/1234/INBOX
:> $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm/1234/unavail.gsm
for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isunavail; do \
cat $(INSTALL_PREFIX)/var/lib/asterisk/sounds/$$x.gsm >> $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm/1234/unavail.gsm ; \
done
:> $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm/1234/busy.gsm
for x in vm-theperson digits/1 digits/2 digits/3 digits/4 vm-isonphone; do \
cat $(INSTALL_PREFIX)/var/lib/asterisk/sounds/$$x.gsm >> $(INSTALL_PREFIX)/var/lib/asterisk/sounds/vm/1234/busy.gsm ; \
done
@echo " +--------- Asterisk Web Voicemail ----------+"
@echo " + +"
@echo " + Asterisk Web Voicemail is installed in +"
@echo " + your cgi-bin directory: +"
@echo " + $(DESTDIR)$(HTTP_CGIDIR)"
@echo " + IT USES A SETUID ROOT PERL SCRIPT, SO +"
@echo " + IF YOU DON'T LIKE THAT, UNINSTALL IT! +"
@echo " + +"
@echo " + Other static items have been stored in: +"
@echo " + $(DESTDIR)$(HTTP_DOCSDIR)"
@echo " + +"
@echo " + If these paths do not match your httpd +"
@echo " + installation, correct the definitions +"
@echo " + in your Makefile of HTTP_CGIDIR and +"
@echo " + HTTP_DOCSDIR +"
@echo " + +"
@echo " +-------------------------------------------+"
spec:
sed "s/^Version:.*/Version: $(RPMVERSION)/g" redhat/asterisk.spec > asterisk.spec ; \
mailbox:
./addmailbox
rpm: __rpm
__rpm: include/asterisk/version.h include/asterisk/buildopts.h spec
__rpm: _version
rm -rf /tmp/asterisk ; \
mkdir -p /tmp/asterisk/redhat/RPMS/i386 ; \
$(MAKE) DESTDIR=/tmp/asterisk install ; \
$(MAKE) DESTDIR=/tmp/asterisk samples ; \
make INSTALL_PREFIX=/tmp/asterisk install ; \
make INSTALL_PREFIX=/tmp/asterisk samples ; \
mkdir -p /tmp/asterisk/etc/rc.d/init.d ; \
cp -f contrib/init.d/rc.redhat.asterisk /tmp/asterisk/etc/rc.d/init.d/asterisk ; \
rpmbuild --rcfile /usr/lib/rpm/rpmrc:redhat/rpmrc -bb asterisk.spec
cp -f redhat/asterisk /tmp/asterisk/etc/rc.d/init.d/ ; \
cp -f redhat/rpmrc /tmp/asterisk/ ; \
cp -f redhat/rpmmacros /tmp/asterisk/ ; \
sed "s/Version:/Version: $(RPMVERSION)/g" redhat/asterisk.spec > /tmp/asterisk/asterisk.spec ; \
rpm --rcfile /usr/lib/rpm/rpmrc:/tmp/asterisk/rpmrc -bb /tmp/asterisk/asterisk.spec ; \
mv /tmp/asterisk/redhat/RPMS/i386/asterisk* ./ ; \
rm -rf /tmp/asterisk
progdocs:
(cat contrib/asterisk-ng-doxygen; echo "HAVE_DOT=$(HAVEDOT)"; \
echo "PROJECT_NUMBER=$(ASTERISKVERSION)") | doxygen -
config:
@if [ "${OSARCH}" = "linux-gnu" ]; then \
if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then \
$(INSTALL) -m 755 contrib/init.d/rc.redhat.asterisk /etc/rc.d/init.d/asterisk; \
/sbin/chkconfig --add asterisk; \
elif [ -f /etc/debian_version ]; then \
$(INSTALL) -m 755 contrib/init.d/rc.debian.asterisk /etc/init.d/asterisk; \
/usr/sbin/update-rc.d asterisk start 10 2 3 4 5 . stop 91 2 3 4 5 .; \
elif [ -f /etc/gentoo-release ]; then \
$(INSTALL) -m 755 contrib/init.d/rc.gentoo.asterisk /etc/init.d/asterisk; \
/sbin/rc-update add asterisk default; \
elif [ -f /etc/mandrake-release ]; then \
$(INSTALL) -m 755 contrib/init.d/rc.mandrake.asterisk /etc/rc.d/init.d/asterisk; \
/sbin/chkconfig --add asterisk; \
elif [ -f /etc/SuSE-release -o -f /etc/novell-release ]; then \
$(INSTALL) -m 755 contrib/init.d/rc.suse.asterisk /etc/init.d/asterisk; \
/sbin/chkconfig --add asterisk; \
elif [ -f /etc/slackware-version ]; then \
echo "Slackware is not currently supported, although an init script does exist for it." \
else \
echo "We could not install init scripts for your distribution."; \
fi \
else \
echo "We could not install init scripts for your operating system."; \
fi
sounds:
$(MAKE) -C sounds all
# If the cleancount has been changed, force a make clean.
# .cleancount is the global clean count, and .lastclean is the
# last clean count we had
cleantest:
@if ! cmp -s .cleancount .lastclean ; then \
$(MAKE) clean;\
fi
$(SUBDIRS_UNINSTALL):
@$(MAKE) --no-print-directory -C $(@:-uninstall=) uninstall
_uninstall: $(SUBDIRS_UNINSTALL)
rm -f $(DESTDIR)$(MODULES_DIR)/*
rm -f $(DESTDIR)$(ASTSBINDIR)/*asterisk*
rm -f $(DESTDIR)$(ASTSBINDIR)/astgenkey
rm -f $(DESTDIR)$(ASTSBINDIR)/autosupport
rm -rf $(DESTDIR)$(ASTHEADERDIR)
rm -rf $(DESTDIR)$(ASTDATADIR)/firmware
rm -rf $(DESTDIR)$(ASTMANDIR)/man8
$(MAKE) -C sounds uninstall
uninstall: _uninstall
@echo " +--------- Asterisk Uninstall Complete -----+"
@echo " + Asterisk binaries, sounds, man pages, +"
@echo " + headers, modules, and firmware builds, +"
@echo " + have all been uninstalled. +"
@echo " + +"
@echo " + To remove ALL traces of Asterisk, +"
@echo " + including configuration, spool +"
@echo " + directories, and logs, run the following +"
@echo " + command: +"
@echo " + +"
@echo " + $(MAKE) uninstall-all +"
@echo " +-------------------------------------------+"
uninstall-all: _uninstall
rm -rf $(DESTDIR)$(ASTLIBDIR)
rm -rf $(DESTDIR)$(ASTVARLIBDIR)
rm -rf $(DESTDIR)$(ASTDATADIR)
rm -rf $(DESTDIR)$(ASTSPOOLDIR)
rm -rf $(DESTDIR)$(ASTETCDIR)
rm -rf $(DESTDIR)$(ASTLOGDIR)
menuconfig: menuselect
gmenuconfig: gmenuselect
menuselect: menuselect/menuselect menuselect-tree
-@menuselect/menuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
gmenuselect: menuselect/gmenuselect menuselect-tree
-@menuselect/gmenuselect $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
menuselect/menuselect: makeopts menuselect/menuselect.c menuselect/menuselect_curses.c menuselect/menuselect_stub.c menuselect/menuselect.h menuselect/linkedlists.h makeopts
@CC="$(HOST_CC)" LD="" AR="" RANLIB="" CFLAGS="" $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
menuselect/gmenuselect: makeopts menuselect/menuselect.c menuselect/menuselect_gtk.c menuselect/menuselect_stub.c menuselect/menuselect.h menuselect/linkedlists.h makeopts
@CC="$(HOST_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" CFLAGS="" $(MAKE) -C menuselect _gmenuselect CONFIGURE_SILENT="--silent"
menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml sounds/sounds.xml build_tools/embed_modules.xml
@echo "Generating input for menuselect ..."
@build_tools/prep_moduledeps > $@
.PHONY: menuselect main sounds clean dist-clean distclean all prereqs cleantest uninstall _uninstall uninstall-all dont-optimize $(SUBDIRS_INSTALL) $(SUBDIRS_CLEAN) $(SUBDIRS_UNINSTALL) $(SUBDIRS) $(MOD_SUBDIRS_EMBED_LDSCRIPT) $(MOD_SUBDIRS_EMBED_LDFLAGS) $(MOD_SUBDIRS_EMBED_LIBS) menuselect.makeopts
doxygen asterisk-ng-doxygen

View File

@@ -1,84 +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
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
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::
ifneq ($(wildcard .*.d),)
include .*.d
endif

View File

@@ -1,81 +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
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] $< -> $@"
ifeq ($(AST_DEVMODE),yes)
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
else
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS)
endif
%.o: %.s
$(ECHO_PREFIX) echo " [AS] $< -> $@"
ifeq ($(AST_DEVMODE),yes)
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
else
$(CMD_PREFIX) $(CC) -o $@ -c $< $(PTHREAD_CFLAGS) $(ASTCFLAGS)
endif
%.oo: %.cc
$(ECHO_PREFIX) echo " [CXX] $< -> $@"
ifeq ($(AST_DEVMODE),yes)
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations,$(ASTCFLAGS)) -MMD -MT $@ -MF .$(subst /,_,$@).d -MP
else
$(CMD_PREFIX) $(CXX) -o $@ -c $< $(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations,$(ASTCFLAGS))
endif
%.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)

244
README
View File

@@ -1,155 +1,98 @@
The Asterisk(R) Open Source PBX
by Mark Spencer <markster@digium.com>
and the Asterisk.org developer community
Copyright (C) 2001-2006 Digium, Inc.
and other copyright holders.
The Asterisk Open Source PBX
by Mark Spencer <markster@linux-support.net>
Copyright (C) 2001, Linux Support Services, Inc.
================================================================
* 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
on the project itself, please visit the Asterisk home page at:
http://www.asterisk.org
http://www.asteriskpbx.com
In addition you'll find lots of information compiled by the Asterisk
community on this Wiki:
* LICENSING
Asterisk is distributed under GNU General Public License. The GPL also
must apply to all loadable modules as well, except as defined below.
http://www.voip-info.org/wiki-Asterisk
Linux Support Services, Inc. retains copyright to all of the core
Asterisk system, and therefore can grant, at its sole discression, 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. At
this time (5/21/2001) the only component of Asterisk which is covered
under GPL and not under our Copyright is the Xing MP3 decoder.
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.
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 excemption that we do).
* SUPPORTED OPERATING SYSTEMS
If you have any questions, whatsoever, regarding our licensing policy,
please contact us.
* 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
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.
First, be sure you've got supported hardware. To use Asterisk right now,
you will need one of the following:
Supported telephony hardware includes:
* All Wildcard (tm) products from Digium (www.digium.com)
* All Wildcard (tm) products from LSS (www.linux-support.net)
* 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.
Assuming you have one of these (most likely the third) you're ready to
proceed:
* UPGRADING FROM AN EARLIER VERSION
1) Run "make"
2) Run "make install"
If you are updating from a previous version of Asterisk, make sure you
read the UPGRADE.txt file in the source directory. There are some files
and configuration options that you will have to change, even though we
made every effort possible to maintain backwards compatibility.
In order to discover new features to use, please check the configuration
examples in the /configs directory of the source code distribution.
To discover the major new features of Asterisk 1.2, please visit
http://edvina.net/asterisk1-2/
* NEW INSTALLATIONS
Ensure that your system contains a compatible compiler and development
libraries. Asterisk requires either the GNU Compiler Collection (GCC) version
3.0 or higher, or a compiler that supports the C99 specification and some of
the gcc language extensions. In addition, your system needs to have the C
library headers available, and the headers and libraries for OpenSSL,
ncurses and zlib.
On many distributions, these files are installed by packages with names like
'glibc-devel', 'ncurses-devel', 'openssl-devel' and 'zlib-devel' or similar.
So let's proceed:
1) Read this README file.
There are more documents than this one in the doc/ directory.
You may also want to check the configuration files that contain
examples and reference guides. They are all in the configs/
directory.
2) Run "./configure"
Execute the configure script to guess values for system-dependent
variables used during compilation.
3) Run "make menuselect" [optional]
This is needed if you want to select the modules that will be
compiled and to check modules dependencies.
4) Run "make"
Assuming the build completes successfully:
5) Run "make install"
Each time you update or checkout from the repository, you are strongly
encouraged to ensure all previous object files are removed to avoid internal
inconsistency in Asterisk. Normally, this is automatically done with
the presence of the file .cleancount, which increments each time a 'make clean'
is required, and the file .lastclean, which contains the last .cleancount used.
If this is your first time working with Asterisk, you may wish to install
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.
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 +101,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,89 +117,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
large jumps in time. Manually changing the system time using date(1)
(or other similar commands) may cause SIP registrations and other
internal processes to fail. If your system cannot keep accurate time
by itself use NTP (http://www.ntp.org/) to keep the system clock
synchronized to "real time". NTP is designed to keep the system clock
synchronized by speeding up or slowing down the system clock until it
is synchronized to "real time" rather than by jumping the time and
causing discontinuities. Most Linux distributions include precompiled
versions of NTP. Beware of some time synchronization methods that get
the correct real time periodically and then manually set the system
clock.
Apparent time changes due to daylight savings time are just that,
apparent. The use of daylight savings time in a Linux system is
purely a user interface issue and does not affect the operation of the
Linux kernel or Asterisk. The system clock on Linux kernels operates
on UTC. UTC does not use daylight savings time.
Also note that this issue is separate from the clocking of TDM
channels, and is known to at least affect SIP registrations.
* FILE DESCRIPTORS
Depending on the size of your system and your configuration,
Asterisk can consume a large number of file descriptors. In UNIX,
file descriptors are used for more than just files on disk. File
descriptors are also used for handling network communication
(e.g. SIP, IAX2, or H.323 calls) and hardware access (e.g. analog and
digital trunk hardware). Asterisk accesses many on-disk files for
everything from configuration information to voicemail storage.
Most systems limit the number of file descriptors that Asterisk can
have open at one time. This can limit the number of simultaneous
calls that your system can handle. For example, if the limit is set
at 1024 (a common default value) Asterisk can handle approxiately 150
SIP calls simultaneously. To change the number of file descriptors
follow the instructions for your system below:
== PAM-based Linux System ==
If your system uses PAM (Pluggable Authentication Modules) edit
/etc/security/limits.conf. Add these lines to the bottom of the file:
root soft nofile 4096
root hard nofile 8196
asterisk soft nofile 4096
asterisk hard nofile 8196
(adjust the numbers to taste). You may need to reboot the system for
these changes to take effect.
== Generic UNIX System ==
If there are no instructions specifically adapted to your system
above you can try adding the command "ulimit -n 8192" to the script
that starts Asterisk.
* MORE INFORMATION
See the doc directory for more documentation on various features. Again,
please read all the configuration samples that include documentation on
the configuration options.
Finally, you may wish to visit the web site and join the mailing list if
Finally, you may wish to visit the web site and join the mailing list if
you're interested in getting more information.
http://www.asterisk.org/support
Welcome to the growing worldwide community of Asterisk users!
Mark Spencer
----
Asterisk is a trademark belonging to Digium, inc
Mark

14
README.cdr Normal file
View File

@@ -0,0 +1,14 @@
Asterisk now generates Call Detail Records. See include/asterisk/cdr.h for
all the fields which are recorded. By default, records in comma-separated
values will be created in /var/log/asterisk/cdr-csv. You can specify
account codes and AMA (Automated Machine Accounting) flags on a per-channel
(Zaptel et al) or per-user (IAX) basis to help with accounting. Look
at the top of cdr/cdr_csv.c to see the format for the records.
ONE IMPORTANT NOTE: If you are trying to collect records on IAX to IAX calls
you need to be aware that by default, IAX will attempt to transfer calls
in this situation (if DTMF is not required). When the transfer is completed
the call is dumped from the middle machine and thus the call detail records
will report a short call time. If you want detailed records you must
turn off IAX transfer, but unless your servers are very close together, you
will definitely get a latency hit from doing so.

View File

@@ -31,7 +31,7 @@ and H.323, some of which are:
* High performance, low overhead protocol
When running on low-bandwidth connections, or when running
large numbers of calls, optimized bandwidth utilization is
imperative. IAX uses only 4 bytes of overhead
imperitive. IAX uses only 4 bytes of overhead
* Internationalization support
IAX transmits language information, so that remote PBX
@@ -133,12 +133,10 @@ The first line of the "general" section is always:
Following the first line are a number of other possibilities:
> bindport = <portnum>
> port = <portnum>
This sets the port that IAX will bind to. The default IAX version 1
port number is 5036. For IAX version 2, that is now the default in
Asterisk, the default port is 4569.
It is recommended that this value not be altered in general.
This sets the port that IAX will bind to. The default IAX port number is
5036. It is recommended that this value not be altered in general.
> bindaddr = <ipaddr>
@@ -172,15 +170,12 @@ disallow the LPC10 codec just because it doesn't sound very good.
These parameters control the operation of the jitter buffer. The
jitterbuffer should always be enabled unless you expect all your
connections to be over a LAN.
* drop count is the maximum number of voice packets to allow to drop
(out of 100). Useful values are 3-10.
* maxjitterbuffer is the maximum amount of jitter buffer to permit to be
used.
* maxexcessbuffer is the maximum amount of excess jitter buffer
that is permitted before the jitter buffer is slowly shrunk to eliminate
latency.
* minexcessbuffer is the minimum amount of excess jitter buffer
connections to be over a LAN. The drop count is the maximum number of
voice packets to allow to drop (out of 100). Useful values are 3-10. The
maxjitterbuffer is the maximum amount of jitter buffer to permit to be
used. The "maxexcessbuffer" is the maximum amount of excess jitter buffer
that is permitted before the jitter buffer is slowly shrunk to eliminate
latency.
> accountcode = <code>
> amaflags = [default|omit|billing|documentation]
@@ -203,7 +198,7 @@ these packets, improving voice quality.
> register => <name>[:<secret>]@<host>[:port]
Any number of registry entries may be instantiated in the general
Any number of registery entries may be instantiated in the general
section. Registration allows Asterisk to notify a remote Asterisk server
(with a fixed address) what our current address is. In order for
registration to work, the remote Asterisk server will need to have a
@@ -213,20 +208,13 @@ The name is a required field, and is the remote peer name that we wish to
identify ourselves as. A secret may be provided as well. The secret is
generally a shared password between the local server and the remote
server. However, if the secret is in square brackets ([]'s) then it is
interpreted as the name of a RSA key to use. In that case, the local Asterisk
interpreted as the name of a key to use. In that case, the local Asterisk
server must have the *private* key (/var/lib/asterisk/keys/<name>.key) and
the remote server will have to have the corresponding public key.
The "host" is a required field and is the hostname or IP address of the
remote Asterisk server. The port specification is optional and is by
default 4569 for iax2 if not specified.
> notransfer = yes | no
If an IAX phone calls another IAX phone by using a Asterisk server,
Asterisk will transfer the call to go peer to peer. If you do not
want this, turn on notransfer with a "yes". This is also settable
for peers and users.
default 5036 if not specified.
-------------
@@ -244,7 +232,7 @@ should be an alphanumeric string.
> type = [user|peer|friend]
This line tells Asterisk how to interpret this entity. Users are things
that connect to us, while peers are phones we connect to, and a friend is
that connect to us, while peers are people we connect to, and a friend is
shorthand for creating a user and a peer with identical information
----------------
@@ -256,7 +244,7 @@ One or more context lines may be specified in a user, thus giving the user
access to place calls in the given contexts. Contexts are used by
Asterisk to divide dialing plans into logical units each with the ability
to have numbers interpreted differently, have their own security model,
auxiliary switch handling, and include other contexts. Most users are
auxilliary switch handling, and include other contexts. Most users are
given access to the default context. Trusted users could be given access
to the local context for example.
@@ -274,10 +262,10 @@ the final result being the decision. For example:
would deny anyone in 192.168.0.0 with a netmask of 24 bits (class C),
whereas:
> deny = 192.168.0.0/24
> permit = 0.0.0.0/0
> deny = 192.168.0.0/255.255.255.0
> permit = 0.0.0.0/0.0.0.0
would not deny anyone since the final rule would permit anyone, thus
would not deny anyone since the final rule would permit anyone, thsu
overriding the denial.
If no permit/deny rules are listed, it is assumed that someone may connect
@@ -293,9 +281,9 @@ perspective of your server.
You may select which authentication methods are permitted to be used by
the user to authenticate to us. Multiple methods may be specified,
separated by commas. If md5 or plaintext authentication is selected, a
secret must be provided. If RSA authentication is specified, then one or
more key names must be specified with "inkeys"
separated by commas. If md5 or plaintext authentication is selected, a
secret must be provided. If RSA authentication is specified, then one or
more key names must be specifed with "inkeys"
If no secret is specified and no authentication method is specified, then
no authentication will be required.
@@ -335,35 +323,4 @@ If the host uses dynamic registration, Asterisk may still be given a
default IP address to use when dynamic registration has not been performed
or has timed out.
> peercontext = <context>
Specifies the context name to be passed to the peer for it to use when routing
the call through its dial plan. This entry will be used only if a context
is not included in the IAX2 channel name passed to the Dial command.
> qualify = [yes | no | <value>]
Qualify turns on checking of availability of the remote peer. If the
peer becomes unavailable, no calls are placed to the peer until
it is reachable again. This is also helpful in certain NAT situations.
> jitterbuffer = [yes | no]
Turns on or off the jitterbuffer for this peer
> mailbox = <mailbox>[@mailboxcontext]
Specifies a mailbox to check for voicemail notification.
> permit = <ipaddr>/<netmask>
> deny = <ipaddr>/<netmask>
Permit and deny rules may be applied to users, allowing them to connect
from certain IP addresses and not others. The permit and deny rules are
interpreted in sequence and all are evaluated on a given IP address, with
the final result being the decision. See the user section above
for examples.
----------------------------------------------------------------------
For more examples of a configuration, please see the iax.conf.sample in
your the /configs directory of you source code distribution

41
SECURITY Normal file
View File

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

View File

@@ -1,461 +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.
* 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'.
* 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:
* 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

View File

@@ -1,939 +0,0 @@
# AST_GCC_ATTRIBUTE([attribute name])
AC_DEFUN([AST_GCC_ATTRIBUTE],
[
AC_MSG_CHECKING(for compiler 'attribute $1' support)
AC_COMPILE_IFELSE(
AC_LANG_PROGRAM([static int __attribute__(($1)) test(void) {}],
[]),
AC_MSG_RESULT(yes)
AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
AC_MSG_RESULT(no))
])
# 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
])
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=
if test "${PWLIBDIR:-unset}" != "unset" ; then
AC_CHECK_FILE(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
fi
if test "${HAS_PWLIB:-unset}" = "unset" ; then
if test "${OPENH323DIR:-unset}" != "unset"; then
AC_CHECK_FILE(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
fi
if test "${HAS_PWLIB:-unset}" != "unset" ; then
PWLIBDIR="${OPENH323DIR}/../pwlib"
else
AC_CHECK_FILE(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
if test "${HAS_PWLIB:-unset}" != "unset" ; then
PWLIBDIR="${HOME}/pwlib"
else
AC_CHECK_FILE(/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_FILE(/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_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=
if test "${OPENH323DIR:-unset}" != "unset" ; then
AC_CHECK_FILE(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
fi
if test "${HAS_OPENH323:-unset}" = "unset" ; then
AC_CHECK_FILE(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
if test "${HAS_OPENH323:-unset}" != "unset" ; then
OPENH323DIR="${PWLIBDIR}/../openh323"
AC_CHECK_FILE(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}")
else
AC_CHECK_FILE(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
if test "${HAS_OPENH323:-unset}" != "unset" ; then
OPENH323DIR="${HOME}/openh323"
else
AC_CHECK_FILE(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
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
AC_CHECK_FILE(/usr/include/openh323/h323.h, HAS_OPENH323=1, )
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_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

20
addmailbox Normal file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
VMHOME=/var/spool/asterisk/vm
SNDHOME=/var/lib/asterisk/sounds
echo -n "Enter mailbox number: "
read mailbox
mkdir -p ${VMHOME}/${mailbox}
mkdir -p ${VMHOME}/${mailbox}/INBOX
cat ${SNDHOME}/vm-theperson.gsm > ${VMHOME}/${mailbox}/unavail.gsm
cat ${SNDHOME}/vm-theperson.gsm > ${VMHOME}/${mailbox}/busy.gsm
cat ${SNDHOME}/vm-extension.gsm > ${VMHOME}/${mailbox}/greet.gsm
nums=`echo $mailbox | sed 's/./ \0/g'`
for x in $nums; do
cat ${SNDHOME}/digits/${x}.gsm >> ${VMHOME}/${mailbox}/unavail.gsm
cat ${SNDHOME}/digits/${x}.gsm >> ${VMHOME}/${mailbox}/busy.gsm
cat ${SNDHOME}/digits/${x}.gsm >> ${VMHOME}/${mailbox}/greet.gsm
done
cat ${SNDHOME}/vm-isunavail.gsm >> ${VMHOME}/${mailbox}/unavail.gsm
cat ${SNDHOME}/vm-isonphone.gsm >> ${VMHOME}/${mailbox}/busy.gsm

View File

@@ -1,82 +0,0 @@
#!/usr/bin/perl
#
# Simple AGI application to play mp3's selected by a user both using
# xmms and over the phone itself.
#
$|=1;
while(<STDIN>) {
chomp;
last unless length($_);
if (/^agi_(\w+)\:\s+(.*)$/) {
$AGI{$1} = $2;
}
}
print STDERR "AGI Environment Dump:\n";
foreach $i (sort keys %AGI) {
print STDERR " -- $i = $AGI{$i}\n";
}
dbmopen(%DIGITS, "/var/lib/asterisk/mp3list", 0644) || die("Unable to open mp3list");;
sub checkresult {
my ($res) = @_;
my $retval;
$tests++;
chomp $res;
if ($res =~ /^200/) {
$res =~ /result=(-?[\w\*\#]+)/;
return $1;
} else {
return -1;
}
}
#print STDERR "1. Playing beep...\n";
#print "STREAM FILE beep \"\"\n";
#$result = <STDIN>;
#checkresult($result);
print STDERR "2. Getting song name...\n";
print "GET DATA demo-enterkeywords\n";
$result = <STDIN>;
$digitstr = checkresult($result);
if ($digitstr < 0) {
exit(1);
}
$digitstr =~ s/\*/ /g;
print STDERR "Resulting songname is $digitstr\n";
@searchwords = split (/\s+/, $digitstr);
print STDERR "Searchwords: " . join(':', @searchwords) . "\n";
foreach $key (sort keys %DIGITS) {
@words = split(/\s+/, $DIGITS{$key});
$match = 1;
foreach $search (@searchwords) {
$match = 0 unless grep(/$search/, @words);
}
if ($match > 0) {
print STDERR "File $key matches\n";
# Play a beep
print "STREAM FILE beep \"\"\n";
system("xmms", $key);
$result = <STDIN>;
if (&checkresult($result) < 0) {
exit 0;
}
print "EXEC MP3Player \"$key\"\n";
# print "WAIT FOR DIGIT 60000\n";
$result = <STDIN>;
if (&checkresult($result) < 0) {
exit 0;
}
print STDERR "Got here...\n";
}
}
print STDERR "4. Testing 'saynumber' of $digitstr...\n";
print "STREAM FILE demo-nomatch\"\"\n";
$result = <STDIN>;
checkresult($result);

View File

@@ -1,47 +1,27 @@
#
# 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
AGIS=agi-test.agi eagi-test eagi-sphinx-test jukebox.agi
ifeq ($(OSARCH),SunOS)
LIBS+=-lsocket -lnsl
endif
include $(ASTTOPDIR)/Makefile.rules
CFLAGS+=
all: $(AGIS)
strcompat.c: ../main/strcompat.c
@cp $< $@
eagi-test: eagi-test.o strcompat.o
eagi-sphinx-test: eagi-sphinx-test.o
install: all
mkdir -p $(DESTDIR)$(AGI_DIR)
for x in $(AGIS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(AGI_DIR) ; done
uninstall:
for x in $(AGIS); do rm -f $(DESTDIR)$(AGI_DIR)/$$x ; done
for x in $(AGIS); do $(INSTALL) -m 755 $$x $(AGI_DIR) ; done
clean:
rm -f *.so *.o look eagi-test eagi-sphinx-test
rm -f .*.o.d .*.oo.d
rm -f strcompat.c
rm -f *.so *.o look
ifneq ($(wildcard .*.d),)
include .*.d
endif
%.so : %.o
$(CC) -shared -Xlinker -x -o $@ $<

View File

@@ -1,11 +1,5 @@
#!/usr/bin/perl
use strict;
$|=1;
# Setup some variables
my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
while(<STDIN>) {
chomp;
last unless length($_);
@@ -15,7 +9,7 @@ while(<STDIN>) {
}
print STDERR "AGI Environment Dump:\n";
foreach my $i (sort keys %AGI) {
foreach $i (sort keys %AGI) {
print STDERR " -- $i = $AGI{$i}\n";
}
@@ -41,38 +35,38 @@ sub checkresult {
print STDERR "1. Testing 'sendfile'...";
print "STREAM FILE beep \"\"\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "2. Testing 'sendtext'...";
print "SEND TEXT \"hello world\"\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "3. Testing 'sendimage'...";
print "SEND IMAGE asterisk-image\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "4. Testing 'saynumber'...";
print "SAY NUMBER 192837465 \"\"\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "5. Testing 'waitdtmf'...";
print "WAIT FOR DIGIT 1000\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "6. Testing 'record'...";
print "RECORD FILE testagi gsm 1234 3000\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "6a. Testing 'record' playback...";
print "STREAM FILE testagi \"\"\n";
my $result = <STDIN>;
&checkresult($result);
$result = <STDIN>;
checkresult($result);
print STDERR "================== Complete ======================\n";
print STDERR "$tests tests completed, $pass passed, $fail failed\n";

View File

@@ -1,222 +0,0 @@
/*
* Extended AGI test application
*
* This code is released into public domain
* without any warranty of any kind.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "asterisk.h"
#include "asterisk/compat.h"
#define AUDIO_FILENO (STDERR_FILENO + 1)
#define SPHINX_HOST "192.168.1.108"
#define SPHINX_PORT 3460
static int sphinx_sock = -1;
static int connect_sphinx(void)
{
struct hostent *hp;
struct sockaddr_in sin;
int res;
hp = gethostbyname(SPHINX_HOST);
if (!hp) {
fprintf(stderr, "Unable to resolve '%s'\n", SPHINX_HOST);
return -1;
}
sphinx_sock = socket(PF_INET, SOCK_STREAM, 0);
if (sphinx_sock < 0) {
fprintf(stderr, "Unable to allocate socket: %s\n", strerror(errno));
return -1;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(SPHINX_PORT);
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
if (connect(sphinx_sock, (struct sockaddr *)&sin, sizeof(sin))) {
fprintf(stderr, "Unable to connect on socket: %s\n", strerror(errno));
close(sphinx_sock);
sphinx_sock = -1;
return -1;
}
res = fcntl(sphinx_sock, F_GETFL);
if ((res < 0) || (fcntl(sphinx_sock, F_SETFL, res | O_NONBLOCK) < 0)) {
fprintf(stderr, "Unable to set flags on socket: %s\n", strerror(errno));
close(sphinx_sock);
sphinx_sock = -1;
return -1;
}
return 0;
}
static int read_environment(void)
{
char buf[256];
char *val;
/* Read environment */
for(;;) {
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '\0';
/* Check for end of environment */
if (!strlen(buf))
return 0;
val = strchr(buf, ':');
if (!val) {
fprintf(stderr, "Invalid environment: '%s'\n", buf);
return -1;
}
*val = '\0';
val++;
val++;
/* Skip space */
fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
/* Load into normal environment */
setenv(buf, val, 1);
}
/* Never reached */
return 0;
}
static char *wait_result(void)
{
fd_set fds;
int res;
int max;
static char astresp[256];
static char sphinxresp[256];
char audiobuf[4096];
for (;;) {
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
FD_SET(AUDIO_FILENO, &fds);
max = AUDIO_FILENO;
if (sphinx_sock > -1) {
FD_SET(sphinx_sock, &fds);
if (sphinx_sock > max)
max = sphinx_sock;
}
/* Wait for *some* sort of I/O */
res = select(max + 1, &fds, NULL, NULL, NULL);
if (res < 0) {
fprintf(stderr, "Error in select: %s\n", strerror(errno));
return NULL;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
fgets(astresp, sizeof(astresp), stdin);
if (feof(stdin)) {
fprintf(stderr, "Got hungup on apparently\n");
return NULL;
}
astresp[strlen(astresp) - 1] = '\0';
fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
return astresp;
}
if (FD_ISSET(AUDIO_FILENO, &fds)) {
res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
if (res > 0) {
if (sphinx_sock > -1)
write(sphinx_sock, audiobuf, res);
}
}
if ((sphinx_sock > -1) && FD_ISSET(sphinx_sock, &fds)) {
res = read(sphinx_sock, sphinxresp, sizeof(sphinxresp));
if (res > 0) {
fprintf(stderr, "Oooh, Sphinx found a token: '%s'\n", sphinxresp);
return sphinxresp;
} else if (res == 0) {
fprintf(stderr, "Hrm, lost sphinx, guess we're on our own\n");
close(sphinx_sock);
sphinx_sock = -1;
}
}
}
}
static char *run_command(char *command)
{
fprintf(stdout, "%s\n", command);
return wait_result();
}
static int run_script(void)
{
char *res;
res = run_command("STREAM FILE demo-enterkeywords 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "1. Result is '%s'\n", res);
res = run_command("STREAM FILE demo-nomatch 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "2. Result is '%s'\n", res);
res = run_command("SAY NUMBER 23452345 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "3. Result is '%s'\n", res);
res = run_command("GET DATA demo-enterkeywords");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "4. Result is '%s'\n", res);
res = run_command("STREAM FILE auth-thankyou \"\"");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "5. Result is '%s'\n", res);
return 0;
}
int main(int argc, char *argv[])
{
char *tmp;
int ver = 0;
int subver = 0;
/* Setup stdin/stdout for line buffering */
setlinebuf(stdin);
setlinebuf(stdout);
if (read_environment()) {
fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
exit(1);
}
connect_sphinx();
tmp = getenv("agi_enhanced");
if (tmp) {
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
if (ver < 1) {
fprintf(stderr, "No enhanced AGI services available. Use EAGI, not AGI\n");
exit(1);
}
if (run_script())
return -1;
exit(0);
}

View File

@@ -1,165 +0,0 @@
/*
* Extended AGI test application
*
* This code is released into the public domain
* with no warranty of any kind
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#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)
{
char buf[256];
char *val;
/* Read environment */
for(;;) {
fgets(buf, sizeof(buf), stdin);
if (feof(stdin))
return -1;
buf[strlen(buf) - 1] = '\0';
/* Check for end of environment */
if (!strlen(buf))
return 0;
val = strchr(buf, ':');
if (!val) {
fprintf(stderr, "Invalid environment: '%s'\n", buf);
return -1;
}
*val = '\0';
val++;
val++;
/* Skip space */
fprintf(stderr, "Environment: '%s' is '%s'\n", buf, val);
/* Load into normal environment */
setenv(buf, val, 1);
}
/* Never reached */
return 0;
}
static char *wait_result(void)
{
fd_set fds;
int res;
int bytes = 0;
static char astresp[256];
char audiobuf[4096];
for (;;) {
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
FD_SET(AUDIO_FILENO, &fds);
/* Wait for *some* sort of I/O */
res = select(AUDIO_FILENO + 1, &fds, NULL, NULL, NULL);
if (res < 0) {
fprintf(stderr, "Error in select: %s\n", strerror(errno));
return NULL;
}
if (FD_ISSET(STDIN_FILENO, &fds)) {
fgets(astresp, sizeof(astresp), stdin);
if (feof(stdin)) {
fprintf(stderr, "Got hungup on apparently\n");
return NULL;
}
astresp[strlen(astresp) - 1] = '\0';
fprintf(stderr, "Ooh, got a response from Asterisk: '%s'\n", astresp);
return astresp;
}
if (FD_ISSET(AUDIO_FILENO, &fds)) {
res = read(AUDIO_FILENO, audiobuf, sizeof(audiobuf));
if (res > 0) {
/* XXX Process the audio with sphinx here XXX */
#if 0
fprintf(stderr, "Got %d/%d bytes of audio\n", res, bytes);
#endif
bytes += res;
/* Prentend we detected some audio after 3 seconds */
if (bytes > 16000 * 3) {
return "Sample Message";
bytes = 0;
}
}
}
}
}
static char *run_command(char *command)
{
fprintf(stdout, "%s\n", command);
return wait_result();
}
static int run_script(void)
{
char *res;
res = run_command("STREAM FILE demo-enterkeywords 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "1. Result is '%s'\n", res);
res = run_command("STREAM FILE demo-nomatch 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "2. Result is '%s'\n", res);
res = run_command("SAY NUMBER 23452345 0123456789*#");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "3. Result is '%s'\n", res);
res = run_command("GET DATA demo-enterkeywords");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "4. Result is '%s'\n", res);
res = run_command("STREAM FILE auth-thankyou \"\"");
if (!res) {
fprintf(stderr, "Failed to execute command\n");
return -1;
}
fprintf(stderr, "5. Result is '%s'\n", res);
return 0;
}
int main(int argc, char *argv[])
{
char *tmp;
int ver = 0;
int subver = 0;
/* Setup stdin/stdout for line buffering */
setlinebuf(stdin);
setlinebuf(stdout);
if (read_environment()) {
fprintf(stderr, "Failed to read environment: %s\n", strerror(errno));
exit(1);
}
tmp = getenv("agi_enhanced");
if (tmp) {
if (sscanf(tmp, "%d.%d", &ver, &subver) != 2)
ver = 0;
}
if (ver < 1) {
fprintf(stderr, "No enhanced AGI services available. Use EAGI, not AGI\n");
exit(1);
}
if (run_script())
return -1;
exit(0);
}

View File

@@ -1,94 +0,0 @@
#!/usr/bin/perl
use strict;
use Socket;
use Carp;
use IO::Handle;
my $port = 4573;
$|=1;
# Setup some variables
my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
sub checkresult {
my ($res) = @_;
my $retval;
$tests++;
chomp $res;
if ($res =~ /^200/) {
$res =~ /result=(-?\d+)/;
if (!length($1)) {
print STDERR "FAIL ($res)\n";
$fail++;
} else {
print STDERR "PASS ($1)\n";
$pass++;
}
} else {
print STDERR "FAIL (unexpected result '$res')\n";
$fail++;
}
}
socket(SERVER, PF_INET, SOCK_STREAM, 0);
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1));
bind(SERVER, sockaddr_in($port, INADDR_ANY)) || die("can't bind\n");
listen(SERVER, SOMAXCONN);
for(;;) {
my $raddr = accept(CLIENT, SERVER);
my ($s, $p) = sockaddr_in($raddr);
CLIENT->autoflush(1);
while(<CLIENT>) {
chomp;
last unless length($_);
if (/^agi_(\w+)\:\s+(.*)$/) {
$AGI{$1} = $2;
}
}
print STDERR "AGI Environment Dump from $s:$p --\n";
foreach my $i (sort keys %AGI) {
print STDERR " -- $i = $AGI{$i}\n";
}
print STDERR "1. Testing 'sendfile'...";
print CLIENT "STREAM FILE beep \"\"\n";
my $result = <CLIENT>;
&checkresult($result);
print STDERR "2. Testing 'sendtext'...";
print CLIENT "SEND TEXT \"hello world\"\n";
my $result = <CLIENT>;
&checkresult($result);
print STDERR "3. Testing 'sendimage'...";
print CLIENT "SEND IMAGE asterisk-image\n";
my $result = <CLIENT>;
&checkresult($result);
print STDERR "4. Testing 'saynumber'...";
print CLIENT "SAY NUMBER 192837465 \"\"\n";
my $result = <CLIENT>;
&checkresult($result);
print STDERR "5. Testing 'waitdtmf'...";
print CLIENT "WAIT FOR DIGIT 1000\n";
my $result = <CLIENT>;
&checkresult($result);
print STDERR "6. Testing 'record'...";
print CLIENT "RECORD FILE testagi gsm 1234 3000\n";
my $result = <CLIENT>;
&checkresult($result);
print STDERR "6a. Testing 'record' playback...";
print CLIENT "STREAM FILE testagi \"\"\n";
my $result = <CLIENT>;
&checkresult($result);
close(CLIENT);
print STDERR "================== Complete ======================\n";
print STDERR "$tests tests completed, $pass passed, $fail failed\n";
print STDERR "==================================================\n";
}

View File

@@ -1,488 +0,0 @@
#!/usr/bin/perl
#
# Jukebox 0.2
#
# A music manager for Asterisk.
#
# Copyright (C) 2005-2006, Justin Tunney
#
# Justin Tunney <jesuscyborg@gmail.com>
#
# This program is free software, distributed under the terms of the
# GNU General Public License v2.
#
# Keep it open source pigs
#
# --------------------------------------------------------------------
#
# Uses festival to list off all your MP3 music files over a channel in
# a hierarchical fashion. Put this file in your agi-bin folder which
# is located at: /var/lib/asterisk/agi-bin Be sure to chmod +x it!
#
# Invocation Example:
# exten => 68742,1,Answer()
# exten => 68742,2,agi,jukebox.agi|/home/justin/Music
# exten => 68742,3,Hangup()
#
# exten => 68742,1,Answer()
# exten => 68742,2,agi,jukebox.agi|/home/justin/Music|pm
# exten => 68742,3,Hangup()
#
# Options:
# p - Precache text2wave outputs for every possible filename.
# It is much better to set this option because if a caller
# presses a key during a cache operation, it will be ignored.
# m - Go back to menu after playing song
# g - Do not play the greeting message
#
# Usage Instructions:
# - Press '*' to go up a directory. If you are in the root music
# folder you will be exitted from the script.
# - If you have a really long list of files, you can filter the list
# at any time by pressing '#' and spelling out a few letters you
# expect the files to start with. For example, if you wanted to
# know what extension 'Requiem For A Dream' was, you'd type:
# '#737'. Note, phone keypads don't include Q and Z. Q is 7 and
# Z is 9.
#
# Notes:
# - This AGI script uses the MP3Player command which uses the
# mpg123 Program. Grab yourself a copy of this program by
# going to http://www.mpg123.de/cgi-bin/sitexplorer.cgi?/mpg123/
# Be sure to download mpg123-0.59r.tar.gz because it is known to
# work with Asterisk and hopefully isn't the release with that
# awful security problem. If you're using Fedora Core 3 with
# Alsa like me, make linux-alsa isn't going to work. Do make
# linux-devel and you're peachy keen.
#
# - You won't get nifty STDERR debug messages if you're using a
# remote asterisk shell.
#
# - For some reason, caching certain files will generate the
# error: 'using default diphone ax-ax for y-pau'. Example:
# # echo "Depeche Mode - CUW - 05 - The Meaning of Love" | text2wave -o /var/jukeboxcache/jukeboxcache/Depeche_Mode/Depeche_Mode_-_CUW_-_05_-_The_Meaning_of_Love.mp3.ul -otype ulaw -
# The temporary work around is to just touch these files.
#
# - The background app doesn't like to get more than 2031 chars
# of input.
#
use strict;
$|=1;
# Setup some variables
my %AGI; my $tests = 0; my $fail = 0; my $pass = 0;
my @masterCacheList = ();
my $maxNumber = 10;
while (<STDIN>) {
chomp;
last unless length($_);
if (/^agi_(\w+)\:\s+(.*)$/) {
$AGI{$1} = $2;
}
}
# setup options
my $SHOWGREET = 1;
my $PRECACHE = 0;
my $MENUAFTERSONG = 0;
$PRECACHE = 1 if $ARGV[1] =~ /p/;
$MENUAFTERSONG = 1 if $ARGV[1] =~ /m/;
$SHOWGREET = 0 if $ARGV[1] =~ /g/;
# setup folders
my $MUSIC = $ARGV[0];
$MUSIC = &rmts($MUSIC);
my $FESTIVALCACHE = "/var/jukeboxcache";
if (! -e $FESTIVALCACHE) {
`mkdir -p -m0776 $FESTIVALCACHE`;
}
# make sure we have some essential files
if (! -e "$FESTIVALCACHE/jukebox_greet.ul") {
`echo "Welcome to the Asterisk Jukebox" | text2wave -o $FESTIVALCACHE/jukebox_greet.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_press.ul") {
`echo "Press" | text2wave -o $FESTIVALCACHE/jukebox_press.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_for.ul") {
`echo "For" | text2wave -o $FESTIVALCACHE/jukebox_for.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_toplay.ul") {
`echo "To play" | text2wave -o $FESTIVALCACHE/jukebox_toplay.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_nonefound.ul") {
`echo "There were no music files found in this folder" | text2wave -o $FESTIVALCACHE/jukebox_nonefound.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_percent.ul") {
`echo "Percent" | text2wave -o $FESTIVALCACHE/jukebox_percent.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_generate.ul") {
`echo "Please wait while Astrisk Jukebox cashes the files of your music collection" | text2wave -o $FESTIVALCACHE/jukebox_generate.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_invalid.ul") {
`echo "You have entered an invalid selection" | text2wave -o $FESTIVALCACHE/jukebox_invalid.ul -otype ulaw -`;
}
if (! -e "$FESTIVALCACHE/jukebox_thankyou.ul") {
`echo "Thank you for using Astrisk Jukebox, Goodbye" | text2wave -o $FESTIVALCACHE/jukebox_thankyou.ul -otype ulaw -`;
}
# greet the user
if ($SHOWGREET) {
print "EXEC Playback \"$FESTIVALCACHE/jukebox_greet\"\n";
my $result = <STDIN>; &check_result($result);
}
# go through the directories
music_dir_cache() if $PRECACHE;
music_dir_menu('/');
exit 0;
##########################################################################
sub music_dir_menu {
my $dir = shift;
# generate a list of mp3's and directories and assign each one it's
# own selection number. Then make sure that we've got a sound clip
# for the file name
if (!opendir(THEDIR, rmts($MUSIC.$dir))) {
print STDERR "Failed to open music directory: $dir\n";
exit 1;
}
my @files = sort readdir THEDIR;
my $cnt = 1;
my @masterBgList = ();
foreach my $file (@files) {
chomp($file);
if ($file ne '.' && $file ne '..' && $file ne 'festivalcache') { # ignore special files
my $real_version = &rmts($MUSIC.$dir).'/'.$file;
my $cache_version = &rmts($FESTIVALCACHE.$dir).'/'.$file.'.ul';
my $cache_version2 = &rmts($FESTIVALCACHE.$dir).'/'.$file;
my $cache_version_esc = &clean_file($cache_version);
my $cache_version2_esc = &clean_file($cache_version2);
if (-d $real_version) {
# 0:id 1:type 2:text2wav-file 3:for-filtering 4:the-directory 5:text2wav echo
push(@masterBgList, [$cnt++, 1, $cache_version2_esc, &remove_special_chars($file), $file, "for the $file folder"]);
} elsif ($real_version =~ /\.mp3$/) {
# 0:id 1:type 2:text2wav-file 3:for-filtering 4:the-mp3
push(@masterBgList, [$cnt++, 2, $cache_version2_esc, &remove_special_chars($file), $real_version, "to play $file"]);
}
}
}
close(THEDIR);
my @filterList = @masterBgList;
if (@filterList == 0) {
print "EXEC Playback \"$FESTIVALCACHE/jukebox_nonefound\"\n";
my $result = <STDIN>; &check_result($result);
return 0;
}
for (;;) {
MYCONTINUE:
# play bg selections and figure out their selection
my $digit = '';
my $digitstr = '';
for (my $n=0; $n<@filterList; $n++) {
&cache_speech(&remove_file_extension($filterList[$n][5]), "$filterList[$n][2].ul") if ! -e "$filterList[$n][2].ul";
&cache_speech("Press $filterList[$n][0]", "$FESTIVALCACHE/jukebox_$filterList[$n][0].ul") if ! -e "$FESTIVALCACHE/jukebox_$filterList[$n][0].ul";
print "EXEC Background \"$filterList[$n][2]&$FESTIVALCACHE/jukebox_$filterList[$n][0]\"\n";
my $result = <STDIN>;
$digit = &check_result($result);
if ($digit > 0) {
$digitstr .= chr($digit);
last;
}
}
for (;;) {
print "WAIT FOR DIGIT 3000\n";
my $result = <STDIN>;
$digit = &check_result($result);
last if $digit <= 0;
$digitstr .= chr($digit);
}
# see if it's a valid selection
print STDERR "Digits Entered: '$digitstr'\n";
exit 0 if $digitstr eq '';
my $found = 0;
goto EXITSUB if $digitstr =~ /\*/;
# filter the list
if ($digitstr =~ /^\#\d+/) {
my $regexp = '';
for (my $n=1; $n<length($digitstr); $n++) {
my $d = substr($digitstr, $n, 1);
if ($d == 2) {
$regexp .= '[abc]';
} elsif ($d == 3) {
$regexp .= '[def]';
} elsif ($d == 4) {
$regexp .= '[ghi]';
} elsif ($d == 5) {
$regexp .= '[jkl]';
} elsif ($d == 6) {
$regexp .= '[mno]';
} elsif ($d == 7) {
$regexp .= '[pqrs]';
} elsif ($d == 8) {
$regexp .= '[tuv]';
} elsif ($d == 9) {
$regexp .= '[wxyz]';
}
}
@filterList = ();
for (my $n=1; $n<@masterBgList; $n++) {
push(@filterList, $masterBgList[$n]) if $masterBgList[$n][3] =~ /^$regexp/i;
}
goto MYCONTINUE;
}
for (my $n=0; $n<@masterBgList; $n++) {
if ($digitstr == $masterBgList[$n][0]) {
if ($masterBgList[$n][1] == 1) { # a folder
&music_dir_menu(rmts($dir).'/'.$masterBgList[$n][4]);
@filterList = @masterBgList;
goto MYCONTINUE;
} elsif ($masterBgList[$n][1] == 2) { # a file
# because *'s scripting language is crunk and won't allow us to escape
# funny filenames, we need to create a temporary symlink to the mp3
# file
my $mp3 = &escape_file($masterBgList[$n][4]);
my $link = `mktemp`;
chomp($link);
$link .= '.mp3';
print STDERR "ln -s $mp3 $link\n";
my $cmdr = `ln -s $mp3 $link`;
chomp($cmdr);
print "Failed to create symlink to mp3: $cmdr\n" if $cmdr ne '';
print "EXEC MP3Player \"$link\"\n";
my $result = <STDIN>; &check_result($result);
`rm $link`;
if (!$MENUAFTERSONG) {
print "EXEC Playback \"$FESTIVALCACHE/jukebox_thankyou\"\n";
my $result = <STDIN>; &check_result($result);
exit 0;
} else {
goto MYCONTINUE;
}
}
}
}
print "EXEC Playback \"$FESTIVALCACHE/jukebox_invalid\"\n";
my $result = <STDIN>; &check_result($result);
}
EXITSUB:
}
sub cache_speech {
my $speech = shift;
my $file = shift;
my $theDir = extract_file_dir($file);
`mkdir -p -m0776 $theDir`;
print STDERR "echo \"$speech\" | text2wave -o $file -otype ulaw -\n";
my $cmdr = `echo "$speech" | text2wave -o $file -otype ulaw -`;
chomp($cmdr);
if ($cmdr =~ /using default diphone/) {
# temporary bug work around....
`touch $file`;
} elsif ($cmdr ne '') {
print STDERR "Command Failed\n";
exit 1;
}
}
sub music_dir_cache {
# generate list of text2speech files to generate
if (!music_dir_cache_genlist('/')) {
print STDERR "Horrible Dreadful Error: No Music Found in $MUSIC!";
exit 1;
}
# add to list how many 'number' files we have to generate. We can't
# use the SayNumber app in Asterisk because we want to chain all
# talking in one Background command. We also want a consistent
# voice...
for (my $n=1; $n<=$maxNumber; $n++) {
push(@masterCacheList, [3, "Press $n", "$FESTIVALCACHE/jukebox_$n.ul"]) if ! -e "$FESTIVALCACHE/jukebox_$n.ul";
}
# now generate all these darn text2speech files
if (@masterCacheList > 5) {
print "EXEC Playback \"$FESTIVALCACHE/jukebox_generate\"\n";
my $result = <STDIN>; &check_result($result);
}
my $theTime = time();
for (my $n=0; $n < @masterCacheList; $n++) {
my $cmdr = '';
if ($masterCacheList[$n][0] == 1) { # directory
&cache_speech("for folder $masterCacheList[$n][1]", $masterCacheList[$n][2]);
} elsif ($masterCacheList[$n][0] == 2) { # file
&cache_speech("to play $masterCacheList[$n][1]", $masterCacheList[$n][2]);
} elsif ($masterCacheList[$n][0] == 3) { # number
&cache_speech($masterCacheList[$n][1], $masterCacheList[$n][2]);
}
if (time() >= $theTime + 30) {
my $percent = int($n / @masterCacheList * 100);
print "SAY NUMBER $percent \"\"\n";
my $result = <STDIN>; &check_result($result);
print "EXEC Playback \"$FESTIVALCACHE/jukebox_percent\"\n";
my $result = <STDIN>; &check_result($result);
$theTime = time();
}
}
}
# this function will fill the @masterCacheList of all the files that
# need to have text2speeced ulaw files of their names generated
sub music_dir_cache_genlist {
my $dir = shift;
if (!opendir(THEDIR, rmts($MUSIC.$dir))) {
print STDERR "Failed to open music directory: $dir\n";
exit 1;
}
my @files = sort readdir THEDIR;
my $foundFiles = 0;
my $tmpMaxNum = 0;
foreach my $file (@files) {
chomp;
if ($file ne '.' && $file ne '..' && $file ne 'festivalcache') { # ignore special files
my $real_version = &rmts($MUSIC.$dir).'/'.$file;
my $cache_version = &rmts($FESTIVALCACHE.$dir).'/'.$file.'.ul';
my $cache_version2 = &rmts($FESTIVALCACHE.$dir).'/'.$file;
my $cache_version_esc = &clean_file($cache_version);
my $cache_version2_esc = &clean_file($cache_version2);
if (-d $real_version) {
if (music_dir_cache_genlist(rmts($dir).'/'.$file)) {
$tmpMaxNum++;
$maxNumber = $tmpMaxNum if $tmpMaxNum > $maxNumber;
push(@masterCacheList, [1, $file, $cache_version_esc]) if ! -e $cache_version_esc;
$foundFiles = 1;
}
} elsif ($real_version =~ /\.mp3$/) {
$tmpMaxNum++;
$maxNumber = $tmpMaxNum if $tmpMaxNum > $maxNumber;
push(@masterCacheList, [2, &remove_file_extension($file), $cache_version_esc]) if ! -e $cache_version_esc;
$foundFiles = 1;
}
}
}
close(THEDIR);
return $foundFiles;
}
sub rmts { # remove trailing slash
my $hog = shift;
$hog =~ s/\/$//;
return $hog;
}
sub extract_file_name {
my $hog = shift;
$hog =~ /\/?([^\/]+)$/;
return $1;
}
sub extract_file_dir {
my $hog = shift;
return $hog if ! ($hog =~ /\//);
$hog =~ /(.*)\/[^\/]*$/;
return $1;
}
sub remove_file_extension {
my $hog = shift;
return $hog if ! ($hog =~ /\./);
$hog =~ /(.*)\.[^.]*$/;
return $1;
}
sub clean_file {
my $hog = shift;
$hog =~ s/\\/_/g;
$hog =~ s/ /_/g;
$hog =~ s/\t/_/g;
$hog =~ s/\'/_/g;
$hog =~ s/\"/_/g;
$hog =~ s/\(/_/g;
$hog =~ s/\)/_/g;
$hog =~ s/&/_/g;
$hog =~ s/\[/_/g;
$hog =~ s/\]/_/g;
$hog =~ s/\$/_/g;
$hog =~ s/\|/_/g;
$hog =~ s/\^/_/g;
return $hog;
}
sub remove_special_chars {
my $hog = shift;
$hog =~ s/\\//g;
$hog =~ s/ //g;
$hog =~ s/\t//g;
$hog =~ s/\'//g;
$hog =~ s/\"//g;
$hog =~ s/\(//g;
$hog =~ s/\)//g;
$hog =~ s/&//g;
$hog =~ s/\[//g;
$hog =~ s/\]//g;
$hog =~ s/\$//g;
$hog =~ s/\|//g;
$hog =~ s/\^//g;
return $hog;
}
sub escape_file {
my $hog = shift;
$hog =~ s/\\/\\\\/g;
$hog =~ s/ /\\ /g;
$hog =~ s/\t/\\\t/g;
$hog =~ s/\'/\\\'/g;
$hog =~ s/\"/\\\"/g;
$hog =~ s/\(/\\\(/g;
$hog =~ s/\)/\\\)/g;
$hog =~ s/&/\\&/g;
$hog =~ s/\[/\\\[/g;
$hog =~ s/\]/\\\]/g;
$hog =~ s/\$/\\\$/g;
$hog =~ s/\|/\\\|/g;
$hog =~ s/\^/\\\^/g;
return $hog;
}
sub check_result {
my ($res) = @_;
my $retval;
$tests++;
chomp $res;
if ($res =~ /^200/) {
$res =~ /result=(-?\d+)/;
if (!length($1)) {
print STDERR "FAIL ($res)\n";
$fail++;
exit 1;
} else {
print STDERR "PASS ($1)\n";
return $1;
}
} else {
print STDERR "FAIL (unexpected result '$res')\n";
exit 1;
}
}

View File

@@ -1,44 +0,0 @@
#!/usr/bin/perl
#
# Build a database linking filenames to their numerical representations
# using a keypad for the DialAnMp3 application
#
$mp3dir="/usr/media/mpeg3";
dbmopen(%DIGITS, "/var/lib/asterisk/mp3list", 0644) || die("Unable to open mp3list");;
sub process_dir {
my ($dir) = @_;
my $file;
my $digits;
my @entries;
opendir(DIR, $dir);
@entries = readdir(DIR);
closedir(DIR);
foreach $_ (@entries) {
if (!/^\./) {
$file = "$dir/$_";
if (-d "$file") {
process_dir("$file");
} else {
$digits = $_;
$digits =~ s/[^ \w]+//g;
$digits =~ s/\_/ /g;
$digits =~ tr/[a-z]/[A-Z]/;
$digits =~ tr/[A-C]/2/;
$digits =~ tr/[D-F]/3/;
$digits =~ tr/[G-I]/4/;
$digits =~ tr/[J-L]/5/;
$digits =~ tr/[M-O]/6/;
$digits =~ tr/[P-S]/7/;
$digits =~ tr/[T-V]/8/;
$digits =~ tr/[W-Z]/9/;
$digits =~ s/\s+/ /;
print "File: $file, digits: $digits\n";
$DIGITS{$file} = $digits;
}
}
}
}
process_dir($mp3dir);

View File

@@ -1,33 +1,17 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* u-Law to Signed linear conversion
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
* the GNU General Public License
*/
/*! \file
*
* \brief u-Law to Signed linear conversion
*
* \author Mark Spencer <markster@digium.com>
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/alaw.h"
#include <asterisk/alaw.h>
#define AMI_MASK 0x55

43
app.c Normal file
View File

@@ -0,0 +1,43 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Channel Management
*
* 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 <pthread.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <asterisk/channel.h>
#include <asterisk/file.h>
#include <asterisk/app.h>
/* set timeout to 0 for "standard" timeouts. Set timeout to -1 for
"ludicrous time" (essentially never times out) */
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
{
int res,to,fto;
if (prompt) {
res = ast_streamfile(c, prompt, c->language);
if (res < 0)
return res;
}
fto = 6000;
to = 2000;
if (timeout > 0) fto = to = timeout;
if (timeout < 0) fto = to = 1000000000;
res = ast_readstring(c, s, maxlen, to, fto, "#");
return res;
}

View File

@@ -1,41 +1,42 @@
#
# 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
#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_intercom.so app_mp3.so \
app_system.so app_echo.so app_record.so app_image.so app_url.so app_disa.so \
app_agi.so app_qcall.so
C_MODS:=$(filter-out $(MENUSELECT_APPS),$(patsubst %.c,%,$(wildcard app_*.c)))
CC_MODS:=$(filter-out $(MENUSELECT_APPS),$(patsubst %.cc,%,$(wildcard app_*.cc)))
APPS+=$(shell if [ -f /usr/include/zap.h ]; then echo "app_zapras.so" ; fi)
LOADABLE_MODS:=$(C_MODS) $(CC_MODS)
CFLAGS+=
ifneq ($(findstring apps,$(MENUSELECT_EMBED)),)
EMBEDDED_MODS:=$(LOADABLE_MODS)
LOADABLE_MODS:=
endif
all: $(APPS)
MENUSELECT_OPTS_app_directory:=$(MENUSELECT_OPTS_app_voicemail)
ifneq ($(findstring ODBC_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_ODBC_STORAGE)
endif
ifneq ($(findstring IMAP_STORAGE,$(MENUSELECT_OPTS_app_voicemail)),)
MENUSELECT_DEPENDS_app_voicemail+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_IMAP_STORAGE)
endif
clean:
rm -f *.so *.o look
ifeq (SunOS,$(shell uname))
MENUSELECT_DEPENDS_app_chanspy+=RT
RT_LIB=-lrt
endif
%.so : %.o
$(CC) -shared -Xlinker -x -o $@ $<
all: _all
install: all
for x in $(APPS); do $(INSTALL) -m 755 $$x $(MODULES_DIR) ; done
include $(ASTTOPDIR)/Makefile.moddir_rules
app_todd.o: app_todd.c
gcc -pipe -O6 -g -Iinclude -I../include -D_REENTRANT -march=i586 -DDO_CRASH -DDEBUG_THREADS -c -o app_todd.o app_todd.c
app_todd.so: app_todd.o
$(CC) -shared -Xlinker -x -o $@ $< -L/usr/local/ssl/lib -lssl -lcrypto
look: look.c
gcc -pipe -O6 -g look.c -o look -lncurses

File diff suppressed because it is too large Load Diff

873
apps/app_agi.c Normal file
View File

@@ -0,0 +1,873 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Asterisk Gateway Interface
*
* 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/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <sys/time.h>
#include <asterisk/cli.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/image.h>
#include <asterisk/say.h>
#include "../asterisk.h"
#include <pthread.h>
#define MAX_ARGS 128
/* Recycle some stuff from the CLI interface */
#define fdprintf ast_cli
typedef struct agi_command {
/* Null terminated list of the words of the command */
char *cmda[AST_MAX_CMD_LEN];
/* Handler for the command (fd for output, # of arguments, argument list).
Returns RESULT_SHOWUSAGE for improper arguments */
int (*handler)(struct ast_channel *chan, int fd, int argc, char *argv[]);
/* Summary of the command (< 60 characters) */
char *summary;
/* Detailed usage information */
char *usage;
} agi_command;
static char *tdesc = "Asterisk Gateway Interface (AGI)";
static char *app = "AGI";
static char *synopsis = "Executes an AGI compliant application";
static char *descrip =
" AGI(command|args): Executes an Asterisk Gateway Interface compliant\n"
"program on a channel. AGI allows Asterisk to launch external programs\n"
"written in any language to control a telephony channel, play audio,\n"
"read DTMF digits, etc. by communicating with the AGI protocol on stdin\n"
"and stdout. Returns -1 on hangup or if application requested hangup, or\n"
"0 on non-hangup exit.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
#define TONE_BLOCK_SIZE 200
static float loudness = 8192.0;
unsigned char linear2ulaw(short sample);
static void make_tone_block(unsigned char *data, float f1, int *x);
static void make_tone_block(unsigned char *data, float f1, int *x)
{
int i;
float val;
for(i = 0; i < TONE_BLOCK_SIZE; i++)
{
val = loudness * sin((f1 * 2.0 * M_PI * (*x)++)/8000.0);
data[i] = linear2ulaw((int)val);
}
/* wrap back around from 8000 */
if (*x >= 8000) *x = 0;
return;
}
static int launch_script(char *script, char *args, int *fds, int *opid)
{
char tmp[256];
int pid;
int toast[2];
int fromast[2];
int x;
if (script[0] != '/') {
snprintf(tmp, sizeof(tmp), "%s/%s", AST_AGI_DIR, script);
script = tmp;
}
if (pipe(toast)) {
ast_log(LOG_WARNING, "Unable to create toast pipe: %s\n",strerror(errno));
return -1;
}
if (pipe(fromast)) {
ast_log(LOG_WARNING, "unable to create fromast pipe: %s\n", strerror(errno));
close(toast[0]);
close(toast[1]);
return -1;
}
pid = fork();
if (pid < 0) {
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
return -1;
}
if (!pid) {
/* Redirect stdin and out */
dup2(fromast[0], STDIN_FILENO);
dup2(toast[1], STDOUT_FILENO);
/* Close everything but stdin/out/error */
for (x=STDERR_FILENO + 1;x<1024;x++)
close(x);
/* Execute script */
execl(script, script, args, NULL);
ast_log(LOG_WARNING, "Failed to execute '%s': %s\n", script, strerror(errno));
exit(1);
}
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Launched AGI Script %s\n", script);
fds[0] = toast[0];
fds[1] = fromast[1];
/* close what we're not using in the parent */
close(toast[1]);
close(fromast[0]);
*opid = pid;
return 0;
}
static void setup_env(struct ast_channel *chan, char *request, int fd)
{
/* Print initial environment, with agi_request always being the first
thing */
fdprintf(fd, "agi_request: %s\n", request);
fdprintf(fd, "agi_channel: %s\n", chan->name);
fdprintf(fd, "agi_language: %s\n", chan->language);
fdprintf(fd, "agi_type: %s\n", chan->type);
/* ANI/DNIS */
fdprintf(fd, "agi_callerid: %s\n", chan->callerid ? chan->callerid : "");
fdprintf(fd, "agi_dnid: %s\n", chan->dnid ? chan->dnid : "");
/* Context information */
fdprintf(fd, "agi_context: %s\n", chan->context);
fdprintf(fd, "agi_extension: %s\n", chan->exten);
fdprintf(fd, "agi_priority: %d\n", chan->priority);
/* End with empty return */
fdprintf(fd, "\n");
}
static int handle_waitfordigit(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
int to;
if (argc != 4)
return RESULT_SHOWUSAGE;
if (sscanf(argv[3], "%i", &to) != 1)
return RESULT_SHOWUSAGE;
res = ast_waitfordigit(chan, to);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_sendtext(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
if (argc != 3)
return RESULT_SHOWUSAGE;
/* At the moment, the parser (perhaps broken) returns with
the last argument PLUS the newline at the end of the input
buffer. This probably needs to be fixed, but I wont do that
because other stuff may break as a result. The right way
would probably be to strip off the trailing newline before
parsing, then here, add a newline at the end of the string
before sending it to ast_sendtext --DUDE */
res = ast_sendtext(chan, argv[2]);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_recvchar(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
if (argc != 3)
return RESULT_SHOWUSAGE;
res = ast_recvchar(chan,atoi(argv[2]));
if (res == 0) {
fdprintf(fd, "200 result=%d (timeout)\n", res);
return RESULT_SUCCESS;
}
if (res > 0) {
fdprintf(fd, "200 result=%d\n", res);
return RESULT_SUCCESS;
}
else {
fdprintf(fd, "200 result=%d (hangup)\n", res);
return RESULT_FAILURE;
}
}
static int handle_tddmode(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res,x;
if (argc != 3)
return RESULT_SHOWUSAGE;
if (!strncasecmp(argv[2],"on",2)) x = 1; else x = 0;
res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_sendimage(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
if (argc != 3)
return RESULT_SHOWUSAGE;
res = ast_send_image(chan, argv[2]);
if (!ast_check_hangup(chan))
res = 0;
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_streamfile(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
if (argc != 4)
return RESULT_SHOWUSAGE;
res = ast_streamfile(chan, argv[2],chan->language);
if (res) {
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SHOWUSAGE;
else
return RESULT_FAILURE;
}
res = ast_waitstream(chan, argv[3]);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_saynumber(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
int num;
if (argc != 4)
return RESULT_SHOWUSAGE;
if (sscanf(argv[2], "%i", &num) != 1)
return RESULT_SHOWUSAGE;
res = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout);
static int handle_getdata(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
char data[50];
int max;
int timeout;
if (argc < 3)
return RESULT_SHOWUSAGE;
if (argc >= 4) timeout = atoi(argv[3]); else timeout = 0;
if (argc >= 5) max = atoi(argv[4]); else max = 50;
res = ast_app_getdata(chan, argv[2], data, max, timeout);
if (res == 1)
fdprintf(fd, "200 result=%s (timeout)\n", data);
else
fdprintf(fd, "200 result=%s\n", data);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_setcontext(struct ast_channel *chan, int fd, int argc, char *argv[])
{
if (argc != 3)
return RESULT_SHOWUSAGE;
strncpy(chan->context, argv[2], sizeof(chan->context)-1);
fdprintf(fd, "200 result=0\n");
return RESULT_SUCCESS;
}
static int handle_setextension(struct ast_channel *chan, int fd, int argc, char **argv)
{
if (argc != 3)
return RESULT_SHOWUSAGE;
strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
fdprintf(fd, "200 result=0\n");
return RESULT_SUCCESS;
}
static int handle_setpriority(struct ast_channel *chan, int fd, int argc, char **argv)
{
int pri;
if (argc != 3)
return RESULT_SHOWUSAGE;
if (sscanf(argv[2], "%i", &pri) != 1)
return RESULT_SHOWUSAGE;
chan->priority = pri - 1;
fdprintf(fd, "200 result=0\n");
return RESULT_SUCCESS;
}
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 int handle_recordfile(struct ast_channel *chan, int fd, int argc, char *argv[])
{
struct ast_filestream *fs;
struct ast_frame *f,wf;
struct timeval tv, start, lastout, now, notime = { 0,0 } ;
fd_set readfds;
unsigned char tone_block[TONE_BLOCK_SIZE];
int res = -1;
int ms,i,j;
if (argc < 6)
return RESULT_SHOWUSAGE;
if (sscanf(argv[5], "%i", &ms) != 1)
return RESULT_SHOWUSAGE;
if (argc > 6) { /* if to beep */
i = 0;
lastout.tv_sec = lastout.tv_usec = 0;
for(j = 0; j < 13; j++)
{
do gettimeofday(&now,NULL);
while (lastout.tv_sec &&
(ms_diff(&now,&lastout) < 25));
lastout.tv_sec = now.tv_sec;
lastout.tv_usec = now.tv_usec;
wf.frametype = AST_FRAME_VOICE;
wf.subclass = AST_FORMAT_ULAW;
wf.offset = AST_FRIENDLY_OFFSET;
wf.mallocd = 0;
wf.data = tone_block;
wf.datalen = TONE_BLOCK_SIZE;
/* make this tone block */
make_tone_block(tone_block,1000.0,&i);
wf.timelen = wf.datalen / 8;
if (ast_write(chan, &wf)) {
fdprintf(fd, "200 result=%d (hangup)\n", 0);
return RESULT_FAILURE;
}
FD_ZERO(&readfds);
FD_SET(chan->fds[0],&readfds);
/* if no read avail, do send again */
if (select(chan->fds[0] + 1,&readfds,NULL,
NULL,&notime) < 1) continue;
f = ast_read(chan);
if (!f) {
fdprintf(fd, "200 result=%d (hangup)\n", 0);
return RESULT_FAILURE;
}
switch(f->frametype) {
case AST_FRAME_DTMF:
if (strchr(argv[4], f->subclass)) {
/* This is an interrupting chracter */
fdprintf(fd, "200 result=%d (dtmf)\n", f->subclass);
ast_frfree(f);
return RESULT_SUCCESS;
}
break;
case AST_FRAME_VOICE:
break; /* throw it away */
}
ast_frfree(f);
}
/* suck in 5 voice frames to make up for echo of beep, etc */
for(i = 0; i < 5; i++) {
f = ast_read(chan);
if (!f) {
fdprintf(fd, "200 result=%d (hangup)\n", 0);
return RESULT_FAILURE;
}
switch(f->frametype) {
case AST_FRAME_DTMF:
if (strchr(argv[4], f->subclass)) {
/* This is an interrupting chracter */
fdprintf(fd, "200 result=%d (dtmf)\n", f->subclass);
ast_frfree(f);
return RESULT_SUCCESS;
}
break;
case AST_FRAME_VOICE:
break; /* throw it away */
}
ast_frfree(f);
}
}
fs = ast_writefile(argv[2], argv[3], NULL, O_CREAT | O_TRUNC | O_WRONLY, 0, 0644);
if (!fs) {
fdprintf(fd, "200 result=%d (writefile)\n", res);
return RESULT_FAILURE;
}
gettimeofday(&start, NULL);
gettimeofday(&tv, NULL);
while ((ms < 0) || (((tv.tv_sec - start.tv_sec) * 1000 + (tv.tv_usec - start.tv_usec)/1000) < ms)) {
res = ast_waitfor(chan, -1);
if (res < 0) {
ast_closestream(fs);
fdprintf(fd, "200 result=%d (waitfor)\n", res);
return RESULT_FAILURE;
}
f = ast_read(chan);
if (!f) {
fdprintf(fd, "200 result=%d (hangup)\n", 0);
ast_closestream(fs);
return RESULT_FAILURE;
}
switch(f->frametype) {
case AST_FRAME_DTMF:
if (strchr(argv[4], f->subclass)) {
/* This is an interrupting chracter */
fdprintf(fd, "200 result=%d (dtmf)\n", f->subclass);
ast_closestream(fs);
ast_frfree(f);
return RESULT_SUCCESS;
}
break;
case AST_FRAME_VOICE:
ast_writestream(fs, f);
break;
};
ast_frfree(f);
gettimeofday(&tv, NULL);
}
fdprintf(fd, "200 result=%d (timeout)\n", 0);
ast_closestream(fs);
return RESULT_SUCCESS;
}
static char usage_waitfordigit[] =
" Usage: WAIT FOR DIGIT <timeout>\n"
" Waits up to 'timeout' seconds for channel to receive a DTMF digit.\n"
" Returns -1 on channel failure, 0 if no digit is received in the timeout, or\n"
" the numerical value of the ascii of the digit if one is received. Use -1\n"
" for the timeout value if you desire the call to block indefinitely.\n";
static char usage_sendtext[] =
" Usage: SEND TEXT \"<text to send>\"\n"
" Sends the given text on a channel. Most channels do not support the\n"
" transmission of text. Returns 0 if text is sent, or if the channel does not\n"
" support text transmission. Returns -1 only on error/hangup. Text\n"
" consisting of greater than one word should be placed in quotes since the\n"
" command only accepts a single argument.\n";
static char usage_recvchar[] =
" Usage: RECEIVE CHAR <timeout>\n"
" Receives a character of text on a channel. Specify timeout to be the\n"
" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
" do not support the reception of text. Returns the decimal value of the character\n"
" if one is received, or 0 if the channel does not support text reception. Returns\n"
" -1 only on error/hangup.\n";
static char usage_tddmode[] =
" Usage: TDD MODE <on|off>\n"
" Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
" successful, or 0 if channel is not TDD-capable.\n";
static char usage_sendimage[] =
" Usage: SEND IMAGE <image>\n"
" Sends the given image on a channel. Most channels do not support the\n"
" transmission of images. Returns 0 if image is sent, or if the channel does not\n"
" support image transmission. Returns -1 only on error/hangup. Image names\n"
" should not include extensions.\n";
static char usage_streamfile[] =
" Usage: STREAM FILE <filename> <escape digits>\n"
" Send the given file, allowing playback to be interrupted by the given\n"
" digits, if any. Use double quotes for the digits if you wish none to be\n"
" permitted. Returns 0 if playback completes without a digit being pressed, or\n"
" the ASCII numerical value of the digit if one was pressed, or -1 on error or\n"
" if the channel was disconnected. Remember, the file extension must not be\n"
" included in the filename.\n";
static char usage_saynumber[] =
" Usage: SAY NUMBER <number> <escape digits>\n"
" Say a given number, returning early if any of the given DTMF digits\n"
" are received on the channel. Returns 0 if playback completes without a digit\n"
" being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
" -1 on error/hangup.\n";
static char usage_getdata[] =
" Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
" Stream the given file, and recieve DTMF data. Returns the digits recieved\n"
"from the channel at the other end.\n";
static char usage_setcontext[] =
" Usage: SET CONTEXT <desired context>\n"
" Sets the context for continuation upon exiting the application.\n";
static char usage_setextension[] =
" Usage: SET EXTENSION <new extension>\n"
" Changes the extension for continuation upon exiting the application.\n";
static char usage_setpriority[] =
" Usage: SET PRIORITY <num>\n"
" Changes the priority for continuation upon exiting the application.\n";
static char usage_recordfile[] =
" Usage: RECORD FILE <filename> <format> <escape digits> <timeout> [BEEP]\n"
" Record to a file until a given dtmf digit in the sequence is received\n"
" Returns -1 on hangup or error. The format will specify what kind of file\n"
" will be recorded. The timeout is the maximum record time in milliseconds, or\n"
" -1 for no timeout\n";
agi_command commands[] = {
{ { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
{ { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
{ { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
{ { "tdd", "mode", NULL }, handle_tddmode, "Sends text to channels supporting it", usage_tddmode },
{ { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
{ { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
{ { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
{ { "get", "data", NULL }, handle_getdata, "Gets data on a channel", usage_getdata },
{ { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
{ { "set", "extension", NULL }, handle_setextension, "Changes channel extension", usage_setextension },
{ { "set", "priority", NULL }, handle_setpriority, "Prioritizes the channel", usage_setpriority },
{ { "record", "file", NULL }, handle_recordfile, "Records to a given file", usage_recordfile }
};
static agi_command *find_command(char *cmds[])
{
int x;
int y;
int match;
for (x=0;x < sizeof(commands) / sizeof(commands[0]);x++) {
/* start optimistic */
match = 1;
for (y=0;match && cmds[y]; y++) {
/* If there are no more words in the command (and we're looking for
an exact match) or there is a difference between the two words,
then this is not a match */
if (!commands[x].cmda[y])
break;
if (strcasecmp(commands[x].cmda[y], cmds[y]))
match = 0;
}
/* If more words are needed to complete the command then this is not
a candidate (unless we're looking for a really inexact answer */
if (commands[x].cmda[y])
match = 0;
if (match)
return &commands[x];
}
return NULL;
}
static int parse_args(char *s, int *max, char *argv[])
{
int x=0;
int quoted=0;
int escaped=0;
int whitespace=1;
char *cur;
cur = s;
while(*s) {
switch(*s) {
case '"':
/* If it's escaped, put a literal quote */
if (escaped)
goto normal;
else
quoted = !quoted;
if (quoted && whitespace) {
/* If we're starting a quote, coming off white space start a new word, too */
argv[x++] = cur;
whitespace=0;
}
escaped = 0;
break;
case ' ':
case '\t':
if (!quoted && !escaped) {
/* If we're not quoted, mark this as whitespace, and
end the previous argument */
whitespace = 1;
*(cur++) = '\0';
} else
/* Otherwise, just treat it as anything else */
goto normal;
break;
case '\\':
/* If we're escaped, print a literal, otherwise enable escaping */
if (escaped) {
goto normal;
} else {
escaped=1;
}
break;
default:
normal:
if (whitespace) {
if (x >= MAX_ARGS -1) {
ast_log(LOG_WARNING, "Too many arguments, truncating\n");
break;
}
/* Coming off of whitespace, start the next argument */
argv[x++] = cur;
whitespace=0;
}
*(cur++) = *s;
escaped=0;
}
s++;
}
/* Null terminate */
*(cur++) = '\0';
argv[x] = NULL;
*max = x;
return 0;
}
static int agi_handle_command(struct ast_channel *chan, int fd, char *buf)
{
char *argv[MAX_ARGS];
int argc = 0;
int res;
agi_command *c;
argc = MAX_ARGS;
parse_args(buf, &argc, argv);
#if 0
{ int x;
for (x=0;x<argc;x++)
fprintf(stderr, "Got Arg%d: %s\n", x, argv[x]); }
#endif
c = find_command(argv);
if (c) {
res = c->handler(chan, fd, argc, argv);
switch(res) {
case RESULT_SHOWUSAGE:
fdprintf(fd, "520-Invalid command syntax. Proper usage follows:\n");
fdprintf(fd, c->usage);
fdprintf(fd, "520 End of proper usage.\n");
break;
case RESULT_FAILURE:
/* They've already given the failure. We've been hung up on so handle this
appropriately */
return -1;
}
} else {
fdprintf(fd, "510 Invalid or unknown command\n");
}
return 0;
}
static int run_agi(struct ast_channel *chan, char *request, int *fds, int pid)
{
struct ast_channel *c;
int outfd;
int ms;
int returnstatus = 0;
struct ast_frame *f;
char buf[2048];
FILE *readf;
if (!(readf = fdopen(fds[0], "r"))) {
ast_log(LOG_WARNING, "Unable to fdopen file descriptor\n");
kill(pid, SIGHUP);
return -1;
}
setlinebuf(readf);
setup_env(chan, request, fds[1]);
for (;;) {
ms = -1;
c = ast_waitfor_nandfds(&chan, 1, &fds[0], 1, NULL, &outfd, &ms);
if (c) {
/* Idle the channel until we get a command */
f = ast_read(c);
if (!f) {
ast_log(LOG_DEBUG, "%s hungup\n", chan->name);
returnstatus = -1;
break;
} else {
ast_frfree(f);
}
} else if (outfd > -1) {
if (!fgets(buf, sizeof(buf), readf)) {
/* Program terminated */
if (returnstatus)
returnstatus = -1;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
/* No need to kill the pid anymore, since they closed us */
pid = -1;
break;
}
#if 0
/* Un-comment this code to fix the problem with
the newline being included in the parsed
command string(s) output --DUDE */
/* get rid of trailing newline, if any */
if (*buf && buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0;
#endif
returnstatus |= agi_handle_command(chan, fds[1], buf);
/* If the handle_command returns -1, we need to stop */
if (returnstatus < 0) {
break;
}
} else {
ast_log(LOG_WARNING, "No channel, no fd?\n");
returnstatus = -1;
break;
}
}
/* Notify process */
if (pid > -1)
kill(pid, SIGHUP);
fclose(readf);
return returnstatus;
}
static int agi_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
char *args,*ringy;
char tmp[256];
int fds[2];
int pid;
if (!data || !strlen(data)) {
ast_log(LOG_WARNING, "AGI requires an argument (script)\n");
return -1;
}
strncpy(tmp, data, sizeof(tmp)-1);
strtok(tmp, "|");
args = strtok(NULL, "|");
ringy = strtok(NULL,"|");
if (!args)
args = "";
LOCAL_USER_ADD(u);
/* Answer if need be */
if (chan->state != AST_STATE_UP) {
if (ringy) { /* if for ringing first */
/* a little ringy-dingy first */
ast_indicate(chan, AST_CONTROL_RINGING);
sleep(3);
}
if (ast_answer(chan)) {
LOCAL_USER_REMOVE(u);
return -1;
}
}
res = launch_script(tmp, args, fds, &pid);
if (!res) {
res = run_agi(chan, tmp, fds, pid);
close(fds[0]);
close(fds[1]);
}
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, agi_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}
#define CLIP 32635
#define BIAS 0x84
unsigned char
linear2ulaw(sample)
short sample; {
static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
int sign, exponent, mantissa;
unsigned char ulawbyte;
/* Get the sample into sign-magnitude. */
sign = (sample >> 8) & 0x80; /* set aside the sign */
if (sign != 0) sample = -sample; /* get magnitude */
if (sample > CLIP) sample = CLIP; /* clip the magnitude */
/* Convert from 16 bit linear to ulaw. */
sample = sample + BIAS;
exponent = exp_lut[(sample >> 7) & 0xFF];
mantissa = (sample >> (exponent + 3)) & 0x0F;
ulawbyte = ~(sign | (exponent << 4) | mantissa);
#ifdef ZEROTRAP
if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
#endif
return(ulawbyte);
}

View File

@@ -1,841 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2004 - 2005 Steve Rodgers
*
* Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
* \brief Central Station Alarm receiver for Ademco Contact ID
* \author Steve Rodgers <hwstar@rodgers.sdcoxmail.com>
*
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
*
* Use at your own risk. Please consult the GNU GPL license document included with Asterisk. *
*
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sys/wait.h>
#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"
struct event_node{
char data[17];
struct event_node *next;
};
typedef struct event_node event_node_t;
static char *app = "AlarmReceiver";
static char *synopsis = "Provide support for receiving alarm reports from a burglar or fire alarm panel";
static char *descrip =
" AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n"
"Contact ID. This application should be called whenever there is an alarm\n"
"panel calling in to dump its events. The application will handshake with the\n"
"alarm panel, and receive events, validate them, handshake them, and store them\n"
"until the panel hangs up. Once the panel hangs up, the application will run the\n"
"system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n"
"the events to the standard input of the application. The configuration file also\n"
"contains settings for DTMF timing, and for the loudness of the acknowledgement\n"
"tones.\n";
/* Config Variables */
static int fdtimeout = 2000;
static int sdtimeout = 200;
static int toneloudness = 4096;
static int log_individual_events = 0;
static char event_spool_dir[128] = {'\0'};
static char event_app[128] = {'\0'};
static char db_family[128] = {'\0'};
static char time_stamp_format[128] = {"%a %b %d, %Y @ %H:%M:%S %Z"};
/* Misc variables */
static char event_file[14] = "/event-XXXXXX";
/*
* Attempt to access a database variable and increment it,
* provided that the user defined db-family in alarmreceiver.conf
* The alarmreceiver app will write statistics to a few variables
* in this family if it is defined. If the new key doesn't exist in the
* family, then create it and set its value to 1.
*/
static void database_increment( char *key )
{
int res = 0;
unsigned v;
char value[16];
if (ast_strlen_zero(db_family))
return; /* If not defined, don't do anything */
res = ast_db_get(db_family, key, value, sizeof(value) - 1);
if(res){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Creating database entry %s and setting to 1\n", key);
/* Guess we have to create it */
res = ast_db_put(db_family, key, "1");
return;
}
sscanf(value, "%u", &v);
v++;
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: New value for %s: %u\n", key, v);
snprintf(value, sizeof(value), "%u", v);
res = ast_db_put(db_family, key, value);
if((res)&&(option_verbose >= 4))
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: database_increment write error\n");
return;
}
/*
* Build a MuLaw data block for a single frequency tone
*/
static void make_tone_burst(unsigned char *data, float freq, float loudness, int len, int *x)
{
int i;
float val;
for(i = 0; i < len; i++){
val = loudness * sin((freq * 2.0 * M_PI * (*x)++)/8000.0);
data[i] = AST_LIN2MU((int)val);
}
/* wrap back around from 8000 */
if (*x >= 8000) *x = 0;
return;
}
/*
* Send a single tone burst for a specifed duration and frequency.
* Returns 0 if successful
*/
static int send_tone_burst(struct ast_channel *chan, float freq, int duration, int tldn)
{
int res = 0;
int i = 0;
int x = 0;
struct ast_frame *f, wf;
struct {
unsigned char offset[AST_FRIENDLY_OFFSET];
unsigned char buf[640];
} tone_block;
for(;;)
{
if (ast_waitfor(chan, -1) < 0){
res = -1;
break;
}
f = ast_read(chan);
if (!f){
res = -1;
break;
}
if (f->frametype == AST_FRAME_VOICE) {
wf.frametype = AST_FRAME_VOICE;
wf.subclass = AST_FORMAT_ULAW;
wf.offset = AST_FRIENDLY_OFFSET;
wf.mallocd = 0;
wf.data = tone_block.buf;
wf.datalen = f->datalen;
wf.samples = wf.datalen;
make_tone_burst(tone_block.buf, freq, (float) tldn, wf.datalen, &x);
i += wf.datalen / 8;
if (i > duration) {
ast_frfree(f);
break;
}
if (ast_write(chan, &wf)){
if(option_verbose >= 4)
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;
}
}
ast_frfree(f);
}
return res;
}
/*
* Receive a string of DTMF digits where the length of the digit string is known in advance. Do not give preferential
* treatment to any digit value, and allow separate time out values to be specified for the first digit and all subsequent
* digits.
*
* Returns 0 if all digits successfully received.
* Returns 1 if a digit time out occurred
* Returns -1 if the caller hung up or there was a channel error.
*
*/
static int receive_dtmf_digits(struct ast_channel *chan, char *digit_string, int length, int fdto, int sdto)
{
int res = 0;
int i = 0;
int r;
struct ast_frame *f;
struct timeval lastdigittime;
lastdigittime = ast_tvnow();
for(;;){
/* if outa time, leave */
if (ast_tvdiff_ms(ast_tvnow(), lastdigittime) >
((i > 0) ? sdto : fdto)){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: DTMF Digit Timeout on %s\n", chan->name);
ast_log(LOG_DEBUG,"AlarmReceiver: DTMF timeout on chan %s\n",chan->name);
res = 1;
break;
}
if ((r = ast_waitfor(chan, -1) < 0)) {
ast_log(LOG_DEBUG, "Waitfor returned %d\n", r);
continue;
}
f = ast_read(chan);
if (f == NULL){
res = -1;
break;
}
/* If they hung up, leave */
if ((f->frametype == AST_FRAME_CONTROL) &&
(f->subclass == AST_CONTROL_HANGUP)){
ast_frfree(f);
res = -1;
break;
}
/* if not DTMF, just do it again */
if (f->frametype != AST_FRAME_DTMF){
ast_frfree(f);
continue;
}
digit_string[i++] = f->subclass; /* save digit */
ast_frfree(f);
/* If we have all the digits we expect, leave */
if(i >= length)
break;
lastdigittime = ast_tvnow();
}
digit_string[i] = '\0'; /* Nul terminate the end of the digit string */
return res;
}
/*
* Write the metadata to the log file
*/
static int write_metadata( FILE *logfile, char *signalling_type, struct ast_channel *chan)
{
int res = 0;
time_t t;
struct tm now;
char *cl,*cn;
char workstring[80];
char timestamp[80];
/* Extract the caller ID location */
if (chan->cid.cid_num)
ast_copy_string(workstring, chan->cid.cid_num, sizeof(workstring));
workstring[sizeof(workstring) - 1] = '\0';
ast_callerid_parse(workstring, &cn, &cl);
if (cl)
ast_shrink_phone_number(cl);
/* Get the current time */
time(&t);
ast_localtime(&t, &now, NULL);
/* Format the time */
strftime(timestamp, sizeof(timestamp), time_stamp_format, &now);
res = fprintf(logfile, "\n\n[metadata]\n\n");
if(res >= 0)
res = fprintf(logfile, "PROTOCOL=%s\n", signalling_type);
if(res >= 0)
res = fprintf(logfile, "CALLINGFROM=%s\n", (!cl) ? "<unknown>" : cl);
if(res >- 0)
res = fprintf(logfile, "CALLERNAME=%s\n", (!cn) ? "<unknown>" : cn);
if(res >= 0)
res = fprintf(logfile, "TIMESTAMP=%s\n\n", timestamp);
if(res >= 0)
res = fprintf(logfile, "[events]\n\n");
if(res < 0){
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't write metadata\n");
ast_log(LOG_DEBUG,"AlarmReceiver: can't write metadata\n");
}
else
res = 0;
return res;
}
/*
* Write a single event to the log file
*/
static int write_event( FILE *logfile, event_node_t *event)
{
int res = 0;
if( fprintf(logfile, "%s\n", event->data) < 0)
res = -1;
return res;
}
/*
* If we are configured to log events, do so here.
*
*/
static int log_events(struct ast_channel *chan, char *signalling_type, event_node_t *event)
{
int res = 0;
char workstring[sizeof(event_spool_dir)+sizeof(event_file)] = "";
int fd;
FILE *logfile;
event_node_t *elp = event;
if (!ast_strlen_zero(event_spool_dir)) {
/* Make a template */
ast_copy_string(workstring, event_spool_dir, sizeof(workstring));
strncat(workstring, event_file, sizeof(workstring) - strlen(workstring) - 1);
/* Make the temporary file */
fd = mkstemp(workstring);
if(fd == -1){
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: can't make temporary file\n");
ast_log(LOG_DEBUG,"AlarmReceiver: can't make temporary file\n");
res = -1;
}
if(!res){
logfile = fdopen(fd, "w");
if(logfile){
/* Write the file */
res = write_metadata(logfile, signalling_type, chan);
if(!res)
while((!res) && (elp != NULL)){
res = write_event(logfile, elp);
elp = elp->next;
}
if(!res){
if(fflush(logfile) == EOF)
res = -1;
if(!res){
if(fclose(logfile) == EOF)
res = -1;
}
}
}
else
res = -1;
}
}
return res;
}
/*
* This function implements the logic to receive the Ademco contact ID format.
*
* The function will return 0 when the caller hangs up, else a -1 if there was a problem.
*/
static int receive_ademco_contact_id( struct ast_channel *chan, void *data, int fdto, int sdto, int tldn, event_node_t **ehead)
{
int i,j;
int res = 0;
int checksum;
char event[17];
event_node_t *enew, *elp;
int got_some_digits = 0;
int events_received = 0;
int ack_retries = 0;
static char digit_map[15] = "0123456789*#ABC";
static unsigned char digit_weights[15] = {10,1,2,3,4,5,6,7,8,9,11,12,13,14,15};
database_increment("calls-received");
/* Wait for first event */
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for first event from panel\n");
while(res >= 0){
if(got_some_digits == 0){
/* Send ACK tone sequence */
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 1400Hz 100ms burst (ACK)\n");
res = send_tone_burst(chan, 1400.0, 100, tldn);
if(!res)
res = ast_safe_sleep(chan, 100);
if(!res){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Sending 2300Hz 100ms burst (ACK)\n");
res = send_tone_burst(chan, 2300.0, 100, tldn);
}
}
if( res >= 0)
res = receive_dtmf_digits(chan, event, sizeof(event) - 1, fdto, sdto);
if (res < 0){
if(events_received == 0)
/* Hangup with no events received should be logged in the DB */
database_increment("no-events-received");
else{
if(ack_retries){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: ACK retries during this call: %d\n", ack_retries);
database_increment("ack-retries");
}
}
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: App exiting...\n");
res = -1;
break;
}
if(res != 0){
/* Didn't get all of the digits */
if(option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Incomplete string: %s, trying again...\n", event);
if(!got_some_digits){
got_some_digits = (!ast_strlen_zero(event)) ? 1 : 0;
ack_retries++;
}
continue;
}
got_some_digits = 1;
if(option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Received Event %s\n", event);
ast_log(LOG_DEBUG, "AlarmReceiver: Received event: %s\n", event);
/* Calculate checksum */
for(j = 0, checksum = 0; j < 16; j++){
for(i = 0 ; i < sizeof(digit_map) ; i++){
if(digit_map[i] == event[j])
break;
}
if(i == 16)
break;
checksum += digit_weights[i];
}
if(i == 16){
if(option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Bad DTMF character %c, trying again\n", event[j]);
continue; /* Bad character */
}
/* Checksum is mod(15) of the total */
checksum = checksum % 15;
if (checksum) {
database_increment("checksum-errors");
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 */
if(strncmp(event + 4, "18", 2)){
if(strncmp(event + 4, "98", 2)){
database_increment("format-errors");
if(option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "AlarmReceiver: Wrong message type\n");
ast_log(LOG_DEBUG, "AlarmReceiver: Wrong message type\n");
continue;
}
}
events_received++;
/* Queue the Event */
if (!(enew = ast_calloc(1, sizeof(*enew)))) {
res = -1;
break;
}
enew->next = NULL;
ast_copy_string(enew->data, event, sizeof(enew->data));
/*
* Insert event onto end of list
*/
if(*ehead == NULL){
*ehead = enew;
}
else{
for(elp = *ehead; elp->next != NULL; elp = elp->next)
;
elp->next = enew;
}
if(res > 0)
res = 0;
/* Let the user have the option of logging the single event before sending the kissoff tone */
if((res == 0) && (log_individual_events))
res = log_events(chan, ADEMCO_CONTACT_ID, enew);
/* Wait 200 msec before sending kissoff */
if(res == 0)
res = ast_safe_sleep(chan, 200);
/* Send the kissoff tone */
if(res == 0)
res = send_tone_burst(chan, 1400.0, 900, tldn);
}
return res;
}
/*
* This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
* This function will always return 0.
*/
static int alarmreceiver_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
event_node_t *elp, *efree;
char signalling_type[64] = "";
event_node_t *event_head = NULL;
u = ast_module_user_add(chan);
/* Set write and read formats to ULAW */
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Setting read and write formats to ULAW\n");
if (ast_set_write_format(chan,AST_FORMAT_ULAW)){
ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",chan->name);
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));
/* Answer the channel if it is not already */
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Answering channel\n");
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
if (res) {
ast_module_user_remove(u);
return -1;
}
}
/* Wait for the connection to settle post-answer */
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: Waiting for connection to stabilize\n");
res = ast_safe_sleep(chan, 1250);
/* Attempt to receive the events */
if(!res){
/* Determine the protocol to receive in advance */
/* Note: Ademco contact is the only one supported at this time */
/* Others may be added later */
if(!strcmp(signalling_type, ADEMCO_CONTACT_ID))
receive_ademco_contact_id(chan, data, fdtimeout, sdtimeout, toneloudness, &event_head);
else
res = -1;
}
/* Events queued by receiver, write them all out here if so configured */
if((!res) && (log_individual_events == 0)){
res = log_events(chan, signalling_type, event_head);
}
/*
* Do we exec a command line at the end?
*/
if((!res) && (!ast_strlen_zero(event_app)) && (event_head)){
ast_log(LOG_DEBUG,"Alarmreceiver: executing: %s\n", event_app);
ast_safe_system(event_app);
}
/*
* Free up the data allocated in our linked list
*/
for(elp = event_head; (elp != NULL);){
efree = elp;
elp = elp->next;
free(efree);
}
ast_module_user_remove(u);
return 0;
}
/*
* Load the configuration from the configuration file
*/
static int load_config(void)
{
struct ast_config *cfg;
const char *p;
/* Read in the config file */
cfg = ast_config_load(ALMRCV_CONFIG);
if(!cfg){
if(option_verbose >= 4)
ast_verbose(VERBOSE_PREFIX_4 "AlarmReceiver: No config file\n");
return 0;
}
else{
p = ast_variable_retrieve(cfg, "general", "eventcmd");
if(p){
ast_copy_string(event_app, p, sizeof(event_app));
event_app[sizeof(event_app) - 1] = '\0';
}
p = ast_variable_retrieve(cfg, "general", "loudness");
if(p){
toneloudness = atoi(p);
if(toneloudness < 100)
toneloudness = 100;
if(toneloudness > 8192)
toneloudness = 8192;
}
p = ast_variable_retrieve(cfg, "general", "fdtimeout");
if(p){
fdtimeout = atoi(p);
if(fdtimeout < 1000)
fdtimeout = 1000;
if(fdtimeout > 10000)
fdtimeout = 10000;
}
p = ast_variable_retrieve(cfg, "general", "sdtimeout");
if(p){
sdtimeout = atoi(p);
if(sdtimeout < 110)
sdtimeout = 110;
if(sdtimeout > 4000)
sdtimeout = 4000;
}
p = ast_variable_retrieve(cfg, "general", "logindividualevents");
if(p){
log_individual_events = ast_true(p);
}
p = ast_variable_retrieve(cfg, "general", "eventspooldir");
if(p){
ast_copy_string(event_spool_dir, p, sizeof(event_spool_dir));
event_spool_dir[sizeof(event_spool_dir) - 1] = '\0';
}
p = ast_variable_retrieve(cfg, "general", "timestampformat");
if(p){
ast_copy_string(time_stamp_format, p, sizeof(time_stamp_format));
time_stamp_format[sizeof(time_stamp_format) - 1] = '\0';
}
p = ast_variable_retrieve(cfg, "general", "db-family");
if(p){
ast_copy_string(db_family, p, sizeof(db_family));
db_family[sizeof(db_family) - 1] = '\0';
}
ast_config_destroy(cfg);
}
return 1;
}
/*
* These functions are required to implement an Asterisk App.
*/
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
if(load_config())
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
else
return AST_MODULE_LOAD_DECLINE;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Alarm Receiver for Asterisk");

View File

@@ -1,398 +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;
static void isAnsweringMachine(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_frame *f = NULL;
struct ast_dsp *silenceDetector = NULL;
int dspsilence = 0, readFormat, framelength;
int inInitialSilence = 1;
int inGreeting = 0;
int voiceDuration = 0;
int silenceDuration = 0;
int iTotalTime = 0;
int iWordsCount = 0;
int currentState = STATE_IN_SILENCE;
int previousState = STATE_IN_SILENCE;
int consecutiveVoiceDuration = 0;
char amdCause[256] = "", amdStatus[256] = "";
char *parse = ast_strdupa(data);
/* Lets set the initial values of the variables that will control the algorithm.
The initial values are the default ones. If they are passed as arguments
when invoking the application, then the default values will be overwritten
by the ones passed as parameters. */
int initialSilence = dfltInitialSilence;
int greeting = dfltGreeting;
int afterGreetingSilence = dfltAfterGreetingSilence;
int totalAnalysisTime = dfltTotalAnalysisTime;
int minimumWordLength = dfltMinimumWordLength;
int betweenWordsSilence = dfltBetweenWordsSilence;
int maximumNumberOfWords = dfltMaximumNumberOfWords;
int silenceThreshold = dfltSilenceThreshold;
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");
/* 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, totalAnalysisTime)) > -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) {
/* If the total time exceeds the analysis time then give up as we are not too sure */
framelength = (ast_codec_get_samples(f) / DEFAULT_SAMPLES_PER_MS);
iTotalTime += framelength;
if (iTotalTime >= totalAnalysisTime) {
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 */
dspsilence = 0;
ast_dsp_silence(silenceDetector, f, &dspsilence);
if (dspsilence) {
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);
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);
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);
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);
break;
}
if (voiceDuration >= minimumWordLength ) {
silenceDuration = 0;
inInitialSilence = 0;
inGreeting = 1;
}
}
}
ast_frfree(f);
}
if (!res) {
/* It took too long to get a frame back. Giving up. */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD: Channel [%s]. Too long...\n", chan->name);
strcpy(amdStatus , "NOTSURE");
sprintf(amdCause , "TOOLONG-%d", iTotalTime);
}
/* Set the status and cause on the channel */
pbx_builtin_setvar_helper(chan , "AMDSTATUS" , amdStatus);
pbx_builtin_setvar_helper(chan , "AMDCAUSE" , amdCause);
/* Restore channel read format */
if (readFormat && ast_set_read_format(chan, readFormat))
ast_log(LOG_WARNING, "AMD: Unable to restore read format on '%s'\n", chan->name);
/* Free the DSP used to detect silence */
ast_dsp_free(silenceDetector);
return;
}
static int amd_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u = NULL;
u = ast_module_user_add(chan);
isAnsweringMachine(chan, data);
ast_module_user_remove(u);
return 0;
}
static void load_config(void)
{
struct ast_config *cfg = NULL;
char *cat = NULL;
struct ast_variable *var = NULL;
if (!(cfg = ast_config_load("amd.conf"))) {
ast_log(LOG_ERROR, "Configuration file amd.conf missing.\n");
return;
}
cat = ast_category_browse(cfg, NULL);
while (cat) {
if (!strcasecmp(cat, "general") ) {
var = ast_variable_browse(cfg, cat);
while (var) {
if (!strcasecmp(var->name, "initial_silence")) {
dfltInitialSilence = atoi(var->value);
} else if (!strcasecmp(var->name, "greeting")) {
dfltGreeting = atoi(var->value);
} else if (!strcasecmp(var->name, "after_greeting_silence")) {
dfltAfterGreetingSilence = atoi(var->value);
} else if (!strcasecmp(var->name, "silence_threshold")) {
dfltSilenceThreshold = atoi(var->value);
} else if (!strcasecmp(var->name, "total_analysis_time")) {
dfltTotalAnalysisTime = atoi(var->value);
} else if (!strcasecmp(var->name, "min_word_length")) {
dfltMinimumWordLength = atoi(var->value);
} else if (!strcasecmp(var->name, "between_words_silence")) {
dfltBetweenWordsSilence = atoi(var->value);
} else if (!strcasecmp(var->name, "maximum_number_of_words")) {
dfltMaximumNumberOfWords = atoi(var->value);
} else {
ast_log(LOG_WARNING, "%s: Cat:%s. Unknown keyword %s at line %d of amd.conf\n",
app, cat, var->name, var->lineno);
}
var = var->next;
}
}
cat = ast_category_browse(cfg, cat);
}
ast_config_destroy(cfg);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AMD defaults: initialSilence [%d] greeting [%d] afterGreetingSilence [%d] "
"totalAnalysisTime [%d] minimumWordLength [%d] betweenWordsSilence [%d] maximumNumberOfWords [%d] silenceThreshold [%d] \n",
dfltInitialSilence, dfltGreeting, dfltAfterGreetingSilence, dfltTotalAnalysisTime,
dfltMinimumWordLength, dfltBetweenWordsSilence, dfltMaximumNumberOfWords, dfltSilenceThreshold );
return;
}
static int unload_module(void)
{
ast_module_user_hangup_all();
return ast_unregister_application(app);
}
static int load_module(void)
{
load_config();
return ast_register_application(app, amd_exec, synopsis, descrip);
}
static int reload(void)
{
load_config();
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Answering Machine Detection Application",
.load = load_module,
.unload = unload_module,
.reload = reload,
);

View File

@@ -1,250 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Execute arbitrary authenticate commands
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include "asterisk/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 *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"
;
static int auth_exec(struct ast_channel *chan, void *data)
{
int res=0;
int retries;
struct ast_module_user *u;
char passwd[256];
char *prompt;
int maxdigits;
char *argcopy =NULL;
struct ast_flags flags = {0};
AST_DECLARE_APP_ARGS(arglist,
AST_APP_ARG(password);
AST_APP_ARG(options);
AST_APP_ARG(maxdigits);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
return -1;
}
u = ast_module_user_add(chan);
if (chan->_state != AST_STATE_UP) {
res = ast_answer(chan);
if (res) {
ast_module_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;
}
/* Start asking for password */
prompt = "agent-pass";
for (retries = 0; retries < 3; retries++) {
res = ast_app_getdata(chan, prompt, passwd, maxdigits, 0);
if (res < 0)
break;
res = 0;
if (arglist.password[0] == '/') {
if (ast_test_flag(&flags,OPT_DATABASE)) {
char tmp[256];
/* Compare against a database key */
if (!ast_db_get(arglist.password + 1, passwd, tmp, sizeof(tmp))) {
/* It's a good password */
if (ast_test_flag(&flags,OPT_REMOVE)) {
ast_db_del(arglist.password + 1, passwd);
}
break;
}
} else {
/* Compare against a file */
FILE *f;
f = fopen(arglist.password, "r");
if (f) {
char buf[256] = "";
char md5passwd[33] = "";
char *md5secret = NULL;
while (!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f) && !ast_strlen_zero(buf)) {
buf[strlen(buf) - 1] = '\0';
if (ast_test_flag(&flags,OPT_MULTIPLE)) {
md5secret = strchr(buf, ':');
if (md5secret == NULL)
continue;
*md5secret = '\0';
md5secret++;
ast_md5_hash(md5passwd, passwd);
if (!strcmp(md5passwd, md5secret)) {
if (ast_test_flag(&flags,OPT_ACCOUNT))
ast_cdr_setaccount(chan, buf);
break;
}
} else {
if (!strcmp(passwd, buf)) {
if (ast_test_flag(&flags,OPT_ACCOUNT))
ast_cdr_setaccount(chan, buf);
break;
}
}
}
}
fclose(f);
if (!ast_strlen_zero(buf)) {
if (ast_test_flag(&flags,OPT_MULTIPLE)) {
if (md5secret && !strcmp(md5passwd, md5secret))
break;
} else {
if (!strcmp(passwd, buf))
break;
}
}
} else
ast_log(LOG_WARNING, "Unable to open file '%s' for authentication: %s\n", arglist.password, strerror(errno));
}
} else {
/* Compare against a fixed password */
if (!strcmp(passwd, arglist.password))
break;
}
prompt="auth-incorrect";
}
if ((retries < 3) && !res) {
if (ast_test_flag(&flags,OPT_ACCOUNT) && !ast_test_flag(&flags,OPT_MULTIPLE))
ast_cdr_setaccount(chan, passwd);
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;
}
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
ast_module_user_hangup_all();
res = ast_unregister_application(app);
return res;
}
static int load_module(void)
{
return ast_register_application(app, auth_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Authentication Application");

View File

@@ -1,78 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Martin Pycko <martinp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Applications connected with CDR engine
*
* Martin Pycko <martinp@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
#include <stdlib.h>
#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
static char *nocdr_descrip =
" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n"
"current call.\n";
static char *nocdr_app = "NoCDR";
static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call";
static int nocdr_exec(struct ast_channel *chan, void *data)
{
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_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(nocdr_app);
ast_module_user_hangup_all();
return res;
}
static 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");

View File

@@ -1,173 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
* James Golovich <james@gnuinter.net>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Check if Channel is Available
*
* \author Mark Spencer <markster@digium.com>
* \author James Golovich <james@gnuinter.net>
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/devicestate.h"
#include "asterisk/options.h"
static char *app = "ChanIsAvail";
static char *synopsis = "Check channel availability";
static char *descrip =
" ChanIsAvail(Technology/resource[&Technology2/resource2...][|options]): \n"
"This application will check to see if any of the specified channels are\n"
"available. 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";
static int chanavail_exec(struct ast_channel *chan, void *data)
{
int res=-1, inuse=-1, option_state=0, priority_jump=0;
int status;
struct ast_module_user *u;
char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur;
struct ast_channel *tempchan;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(reqchans);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
return -1;
}
u = ast_module_user_add(chan);
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;
if (peers) {
cur = peers;
do {
/* remember where to start next time */
rest = strchr(cur, '&');
if (rest) {
*rest = 0;
rest++;
}
tech = cur;
number = strchr(tech, '/');
if (!number) {
ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
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))) {
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;
}
}
}
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int res = 0;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, chanavail_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Check channel availability");

View File

@@ -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");

View File

@@ -1,745 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005 Anthony Minessale II (anthmct@yahoo.com)
* Copyright (C) 2005 - 2006, Digium, Inc.
*
* A license has been granted to Digium (via disclaimer) for the use of
* this code.
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief ChanSpy: Listen in on any channel.
*
* \author Anthony Minessale II <anthmct@yahoo.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <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/chanspy.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_channel_spy spy;
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;
if (csth->spy.status != CHANSPY_RUNNING)
/* Channel is already gone more than likely */
return -1;
ast_mutex_lock(&csth->spy.lock);
f = ast_channel_spy_read_frame(&csth->spy, samples);
ast_mutex_unlock(&csth->spy.lock);
if (!f)
return 0;
if (ast_write(chan, f)) {
ast_frfree(f);
return -1;
}
if (csth->fd)
write(csth->fd, f->data, f->datalen);
ast_frfree(f);
return 0;
}
static struct ast_generator spygen = {
.alloc = spy_alloc,
.release = spy_release,
.generate = spy_generate,
};
static int start_spying(struct ast_channel *chan, struct ast_channel *spychan, struct ast_channel_spy *spy)
{
int res;
struct ast_channel *peer;
ast_log(LOG_NOTICE, "Attaching %s to %s\n", spychan->name, chan->name);
ast_channel_lock(chan);
res = ast_channel_spy_add(chan, spy);
ast_channel_unlock(chan);
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
return res;
}
/* Map 'volume' levels from -4 through +4 into
decibel (dB) settings for channel drivers
*/
static signed char volfactor_map[] = {
-24,
-18,
-12,
-6,
0,
6,
12,
18,
24,
};
/* attempt to set the desired gain adjustment via the channel driver;
if successful, clear it out of the csth structure so the
generator will not attempt to do the adjustment itself
*/
static void set_volume(struct ast_channel *chan, struct chanspy_translation_helper *csth)
{
signed char volume_adjust = volfactor_map[csth->volfactor + 4];
if (!ast_channel_setoption(chan, AST_OPTION_TXGAIN, &volume_adjust, sizeof(volume_adjust), 0))
csth->volfactor = 0;
csth->spy.read_vol_adjustment = csth->volfactor;
csth->spy.write_vol_adjustment = csth->volfactor;
}
static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, 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;
if (ast_check_hangup(chan) || ast_check_hangup(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_set_flag(&csth.spy, CHANSPY_FORMAT_AUDIO);
ast_set_flag(&csth.spy, CHANSPY_TRIGGER_NONE);
ast_set_flag(&csth.spy, CHANSPY_MIXAUDIO);
csth.spy.type = "ChanSpy";
csth.spy.status = CHANSPY_RUNNING;
csth.spy.read_queue.format = AST_FORMAT_SLINEAR;
csth.spy.write_queue.format = AST_FORMAT_SLINEAR;
ast_mutex_init(&csth.spy.lock);
csth.volfactor = *volfactor;
set_volume(chan, &csth);
if (csth.volfactor) {
ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
csth.spy.read_vol_adjustment = csth.volfactor;
ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
csth.spy.write_vol_adjustment = csth.volfactor;
}
csth.fd = fd;
if (start_spying(spyee, chan, &csth.spy)) {
ast_mutex_destroy(&csth.spy.lock);
return 0;
}
if (ast_test_flag(flags, OPTION_WHISPER)) {
struct ast_filestream *beepstream;
int old_write_format = 0;
ast_channel_whisper_start(csth.spy.chan);
old_write_format = chan->writeformat;
if ((beepstream = ast_openstream_full(chan, "beep", chan->language, 1))) {
struct ast_frame *f;
while ((f = ast_readframe(beepstream))) {
ast_channel_whisper_feed(csth.spy.chan, f);
ast_frfree(f);
}
ast_closestream(beepstream);
chan->stream = NULL;
}
if (old_write_format)
ast_set_write_format(chan, old_write_format);
}
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.status == CHANSPY_RUNNING &&
csth.spy.chan) {
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_channel_whisper_feed(csth.spy.chan, f);
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;
set_volume(chan, &csth);
if (csth.volfactor) {
ast_set_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
csth.spy.read_vol_adjustment = csth.volfactor;
ast_set_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
csth.spy.write_vol_adjustment = csth.volfactor;
} else {
ast_clear_flag(&csth.spy, CHANSPY_READ_VOLADJUST);
ast_clear_flag(&csth.spy, CHANSPY_WRITE_VOLADJUST);
}
} else if (res >= '0' && res <= '9') {
inp[x++] = res;
}
}
if (ast_test_flag(flags, OPTION_WHISPER) && csth.spy.chan)
ast_channel_whisper_stop(csth.spy.chan);
if (ast_test_flag(flags, OPTION_PRIVATE))
ast_channel_stop_silence_generator(chan, silgen);
else
ast_deactivate_generator(chan);
/* If a channel still exists on our spy structure then we need to remove ourselves */
if (csth.spy.chan) {
csth.spy.status = CHANSPY_DONE;
ast_channel_lock(csth.spy.chan);
ast_channel_spy_remove(csth.spy.chan, &csth.spy);
ast_channel_unlock(csth.spy.chan);
}
ast_channel_spy_free(&csth.spy);
if (option_verbose >= 2)
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
return running;
}
static struct ast_channel *next_channel(const struct ast_channel *last, const char *spec,
const char *exten, const char *context)
{
struct ast_channel *this;
redo:
if (spec)
this = ast_walk_channel_by_name_prefix_locked(last, spec, strlen(spec));
else if (exten)
this = ast_walk_channel_by_exten_locked(last, exten, context);
else
this = ast_channel_walk_locked(last);
if (this) {
ast_channel_unlock(this);
if (!strncmp(this->name, "Zap/pseudo", 10))
goto redo;
}
return this;
}
static int common_exec(struct ast_channel *chan, const struct ast_flags *flags,
int volfactor, const int fd, const char *mygroup, const char *spec,
const char *exten, const char *context)
{
struct ast_channel *peer, *prev, *next;
char nameprefix[AST_NAME_STRLEN];
char peer_name[AST_NAME_STRLEN + 5];
signed char zero_volume = 0;
int waitms;
int res;
char *ptr;
int num;
if (chan->_state != AST_STATE_UP)
ast_answer(chan);
ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
waitms = 100;
for (;;) {
if (!ast_test_flag(flags, OPTION_QUIET)) {
res = ast_streamfile(chan, "beep", chan->language);
if (!res)
res = ast_waitstream(chan, "");
else if (res < 0) {
ast_clear_flag(chan, AST_FLAG_SPYING);
break;
}
}
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;
peer = prev = next = NULL;
for (peer = next_channel(peer, spec, exten, context);
peer;
prev = peer, peer = next ? next : next_channel(peer, spec, exten, context), next = NULL) {
const char *group;
int igrp = !mygroup;
char *groups[25];
int num_groups = 0;
char *dup_group;
int x;
char *s;
if (peer == prev)
break;
if (peer == chan)
continue;
if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(peer))
continue;
if (ast_check_hangup(peer) || ast_test_flag(peer, AST_FLAG_SPYING))
continue;
if (mygroup) {
if ((group = pbx_builtin_getvar_helper(peer, "SPYGROUP"))) {
dup_group = ast_strdupa(group);
num_groups = ast_app_separate_args(dup_group, ':', groups,
sizeof(groups) / sizeof(groups[0]));
}
for (x = 0; x < num_groups; x++) {
if (!strcmp(mygroup, groups[x])) {
igrp = 1;
break;
}
}
}
if (!igrp)
continue;
strcpy(peer_name, "spy-");
strncat(peer_name, peer->name, AST_NAME_STRLEN);
ptr = strchr(peer_name, '/');
*ptr++ = '\0';
for (s = peer_name; s < ptr; s++)
*s = tolower(*s);
if (!ast_test_flag(flags, OPTION_QUIET)) {
if (ast_fileexists(peer_name, NULL, NULL) != -1) {
res = ast_streamfile(chan, peer_name, chan->language);
if (!res)
res = ast_waitstream(chan, "");
if (res)
break;
} else
res = ast_say_character_str(chan, peer_name, "", chan->language);
if ((num = atoi(ptr)))
ast_say_digits(chan, atoi(ptr), "", chan->language);
}
waitms = 5000;
res = channel_spy(chan, peer, &volfactor, fd, flags);
if (res == -1) {
break;
} else if (res > 1 && spec) {
snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);
if ((next = ast_get_channel_by_name_prefix_locked(nameprefix, strlen(nameprefix)))) {
ast_channel_unlock(next);
} else {
/* stay on this channel */
next = peer;
}
peer = NULL;
}
}
if (res == -1)
break;
}
ast_clear_flag(chan, AST_FLAG_SPYING);
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
return res;
}
static int chanspy_exec(struct ast_channel *chan, void *data)
{
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);
}
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[512];
snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 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);
}
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[512];
snprintf(filename, sizeof(filename), "%s/%s.%d.raw", ast_config_AST_MONITOR_DIR, recbase, (int) time(NULL));
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) <= 0) {
ast_log(LOG_WARNING, "Cannot open '%s' for recording\n", filename);
fd = 0;
}
}
res = common_exec(chan, &flags, volfactor, fd, mygroup, NULL, exten, context);
if (fd)
close(fd);
if (oldwf && ast_set_write_format(chan, oldwf) < 0)
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res = 0;
res |= ast_unregister_application(app_chan);
res |= ast_unregister_application(app_ext);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res = 0;
res |= ast_register_application(app_chan, chanspy_exec, tdesc, desc_chan);
res |= ast_register_application(app_ext, extenspy_exec, tdesc, desc_ext);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Listen to the audio of an active channel");

View File

@@ -1,168 +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 Trivial application to control playback of a sound file
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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 const char *app = "ControlPlayback";
static const char *synopsis = "Play a file with fast forward and rewind";
static const char *descrip =
" ControlPlayback(file[|skipms[|ff[|rew[|stop[|pause[|restart|options]]]]]]]):\n"
"This application will play back the given filename. By default, the '*' key\n"
"can be used to rewind, and the '#' key can be used to fast-forward.\n"
"Parameters:\n"
" skipms - This is number of milliseconds to skip when rewinding or\n"
" fast-forwarding.\n"
" ff - Fast-forward when this DTMF digit is received.\n"
" rew - Rewind when this DTMF digit is received.\n"
" stop - Stop playback when this DTMF digit is received.\n"
" pause - Pause playback when this DTMF digit is received.\n"
" restart - Restart playback when this DTMF digit is received.\n"
"Options:\n"
" 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 int is_on_phonepad(char key)
{
return key == 35 || key == 42 || (key >= 48 && key <= 57);
}
static int controlplayback_exec(struct ast_channel *chan, void *data)
{
int res = 0, priority_jump = 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)) {
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));
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;
}
skipms = argv[arg_skip] ? atoi(argv[arg_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 (argv[options]) {
if (strchr(argv[options], 'j'))
priority_jump = 1;
}
res = ast_control_streamfile(chan, argv[arg_file], argv[arg_fwd], argv[arg_rev], argv[arg_stop], argv[arg_pause], argv[arg_restart], skipms);
/* If we stopped on one of our stop keys, return 0 */
if (argv[arg_stop] && strchr(argv[arg_stop], res)) {
res = 0;
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "USERSTOPPED");
} else {
if (res < 0) {
if (priority_jump || ast_opt_priority_jumping) {
if (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 res;
res = ast_unregister_application(app);
return res;
}
static int load_module(void)
{
return ast_register_application(app, controlplayback_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Control Playback Application");

View File

@@ -1,167 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Copyright (C) 2003, Jefferson Noxon
*
* Mark Spencer <markster@digium.com>
* Jefferson Noxon <jeff@debian.org>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Database access functions
*
* \author Mark Spencer <markster@digium.com>
* \author Jefferson Noxon <jeff@debian.org>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <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 "asterisk/options.h"
/*! \todo XXX Remove this application after 1.4 is relased */
static char *d_descrip =
" DBdel(family/key): This application will delete a key from the Asterisk\n"
"database.\n"
" This application has been DEPRECATED in favor of the DB_DELETE function.\n";
static char *dt_descrip =
" DBdeltree(family[/keytree]): This application will delete a family or keytree\n"
"from the Asterisk database\n";
static char *d_app = "DBdel";
static char *dt_app = "DBdeltree";
static char *d_synopsis = "Delete a key from the database";
static char *dt_synopsis = "Delete a family or keytree from the database";
static int deltree_exec(struct ast_channel *chan, void *data)
{
char *argv, *family, *keytree;
struct ast_module_user *u;
u = ast_module_user_add(chan);
argv = ast_strdupa(data);
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);
return 0;
}
if (ast_strlen_zero(keytree))
keytree = 0;
} else {
family = argv;
keytree = 0;
}
if (option_verbose > 2) {
if (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);
}
if (ast_db_deltree(family, keytree)) {
if (option_verbose > 2)
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)
{
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");
}
argv = ast_strdupa(data);
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);
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)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "DBdel: Error deleting key from database.\n");
}
} else {
ast_log(LOG_DEBUG, "Ignoring, no parameters\n");
}
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int retval;
retval = ast_unregister_application(dt_app);
retval |= ast_unregister_application(d_app);
return retval;
}
static int load_module(void)
{
int retval;
retval = ast_register_application(d_app, del_exec, d_synopsis, d_descrip);
retval |= ast_register_application(dt_app, deltree_exec, dt_synopsis, dt_descrip);
return retval;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database Access Functions");

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,181 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2005, Joshua Colp
*
* Joshua Colp <jcolp@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Directed Call Pickup Support
*
* \author Joshua Colp <jcolp@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/options.h"
#define PICKUPMARK "PICKUPMARK"
static const char *app = "Pickup";
static const char *synopsis = "Directed Call Pickup";
static const char *descrip =
" Pickup(extension[@context][&extension2@context...]): This application can pickup any ringing channel\n"
"that is calling the specified extension. If no context is specified, the current\n"
"context will be used. If you use the special string \"PICKUPMARK\" for the context parameter, for example\n"
"10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n"
"as \"extension\".";
/* Perform actual pickup between two channels */
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
{
int res = 0;
if (option_debug)
ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
if ((res = ast_answer(chan))) {
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
return -1;
}
if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
return -1;
}
if ((res = ast_channel_masquerade(target, chan))) {
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
return -1;
}
return res;
}
/* Helper function that determines whether a channel is capable of being picked up */
static int can_pickup(struct ast_channel *chan)
{
if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING))
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");

View File

@@ -1,194 +1,59 @@
/*
* 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/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 <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
#include "../asterisk.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(context): Presents the user with a directory of extensions from\n"
"which they may select by name. The list of names and extensions is\n"
"discovered from voicemail.conf. The context argument is required, and\n"
"specifies the context in which to interpret the extensions\n. Returns 0\n"
"unless the user hangs up. It also sets up the channel on exit to enter the\n"
"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
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;
LOCAL_USER_DECL;
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);
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");
break;
}
snprintf(sql, sizeof(sql), "SELECT recording FROM %s WHERE dir=? AND msgnum=-1", odbc_table);
res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
break;
}
SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
res = ast_odbc_smart_execute(obj, stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
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)) {
@@ -245,6 +110,7 @@ static char *convert(const char *lastname)
case 'Z':
tmp[lcount++] = '9';
break;
default:
}
lastname++;
}
@@ -253,190 +119,19 @@ static char *convert(const char *lastname)
return tmp;
}
/* play name of mailbox owner.
* returns: -1 for bad or missing extension
* '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)
{
int res = 0;
int loop;
char fn[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
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
if (ast_fileexists(fn, NULL, chan->language) > 0) {
res = ast_stream_and_wait(chan, fn, chan->language, 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 {
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);
}
}
#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)
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 == '*') /* Skip to next match in list */
break;
/* Not '1', or '*', so decrement number of tries */
res = 0;
}
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 digit)
{
/* Read in the first three digits.. "digit" is the first digit, already read */
char ext[NUMDIGITS + 1], *cat;
char name[80] = "";
char ext[NUMDIGITS + 1];
struct ast_variable *v;
int res;
int found=0;
int lastuserchoice = 0;
char *start, *conv, *stringp = NULL;
const char *pos;
if (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;
}
}
char *start, *pos, *conv;
char fn[256];
memset(ext, 0, sizeof(ext));
ext[0] = digit;
res = 0;
if (ast_readstring(chan, ext + 1, NUMDIGITS - 1, 3000, 3000, "#") < 0) res = -1;
if (ast_readstring(chan, ext + 1, NUMDIGITS, 3000, 3000, "#") < 0) res = -1;
if (!res) {
/* Search for all names which start with those digits */
v = ast_variable_browse(cfg, context);
@@ -445,18 +140,16 @@ 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")) {
stringp=start;
strsep(&stringp, ",");
pos = strsep(&stringp, ",");
if (start) {
strtok(start, ",");
pos = strtok(NULL, ",");
if (pos) {
ast_copy_string(name, pos, sizeof(name));
/* Grab the last name */
if (last && strrchr(pos,' '))
if (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);
@@ -470,95 +163,51 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, struct
}
v = v->next;
}
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);
switch (res) {
case -1:
/* user pressed '1' but extension does not exist, or
* user hungup
*/
lastuserchoice = 0;
break;
case '1':
/* user pressed '1' and extensions exists;
play_mailbox_owner will already have done
a goto() on the channel
*/
lastuserchoice = res;
break;
case '*':
/* user pressed '*' to skip something found */
lastuserchoice = res;
snprintf(fn, sizeof(fn), "%s/vm/%s/greet", AST_SPOOL_DIR, v->name);
if (ast_fileexists(fn, NULL, chan->language)) {
res = ast_streamfile(chan, fn, chan->language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
res = ast_say_digit_str(chan, v->name, AST_DIGIT_ANY, chan->language);
}
ahem:
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 > -1) {
if (res == '1') {
strncpy(chan->exten, v->name, sizeof(chan->exten)-1);
chan->priority = 0;
strncpy(chan->context, context, sizeof(chan->context)-1);
res = 0;
break;
default:
break;
}
v = v->next;
}
}
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;
break;
case '1':
/* user pressed '1' and extensions exists;
play_mailbox_owner will already have done
a goto() on the channel
*/
lastuserchoice = res;
break;
case '*':
/* user pressed '*' to skip something found */
lastuserchoice = res;
res = 0;
break;
default:
break;
}
free(conv);
break;
}
free(conv);
} else if (res == '*') {
res = 0;
v = v->next;
} else {
res = 0;
goto ahem;
}
}
} else {
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;
}
}
if (lastuserchoice != '1') {
res = ast_streamfile(chan, found ? "dir-nomore" : "dir-nomatch", chan->language);
if (!res)
res = 1;
return res;
}
return 0;
}
return res;
}
@@ -566,113 +215,65 @@ 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;
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);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
struct localuser *u;
struct ast_config *cfg;
if (!data) {
ast_log(LOG_WARNING, "directory requires an argument (context)\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))
dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
if (ast_strlen_zero(dirintro))
dirintro = last ? "dir-intro" : "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);
LOCAL_USER_ADD(u);
top:
if (!res)
res = ast_streamfile(chan, "dir-intro", 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, (char *)data, res);
if (res > 0) {
res = do_directory(chan, cfg, ucfg, args.vmcontext, args.dialcontext, res, last, readext, fromappvm);
if (res > 0) {
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res >= 0)
continue;
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
if (res >= 0) {
goto top;
}
}
break;
}
if (ucfg)
ast_config_destroy(ucfg);
ast_config_destroy(cfg);
ast_module_user_remove(u);
ast_destroy(cfg);
LOCAL_USER_REMOVE(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
#ifdef ODBC_STORAGE
struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG);
const char *tmp;
if (cfg) {
if ((tmp = ast_variable_retrieve(cfg, "general", "odbcstorage"))) {
ast_copy_string(odbc_database, tmp, sizeof(odbc_database));
}
if ((tmp = ast_variable_retrieve(cfg, "general", "odbctable"))) {
ast_copy_string(odbc_table, tmp, sizeof(odbc_table));
}
if ((tmp = ast_variable_retrieve(cfg, "general", "format"))) {
ast_copy_string(vmfmts, tmp, sizeof(vmfmts));
}
ast_config_destroy(cfg);
} else
ast_log(LOG_WARNING, "Unable to load " VOICEMAIL_CONFIG " - ODBC defaults will be used\n");
#endif
return ast_register_application(app, directory_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Directory");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,389 +1,406 @@
/*
* 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.
*
*
* 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.
* Jim Dixon <jim@lambdatel.com>
*
* 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/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 <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <pthread.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"
#define TONE_BLOCK_SIZE 200
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"
"lines, or comments starting with \"#\" or \";\". In addition, the\n"
"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"
"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";
"lines, or comments starting with \"#\" or \";\".\n\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 float loudness=8192.0;
int firstdigittimeout = 10000; /* 10 seconds first digit timeout */
int digittimeout = 5000; /* 5 seconds subsequent digit timeout */
static void make_tone_block(unsigned char *data, float f1, float f2, int *x);
static void make_tone_block(unsigned char *data, float f1, float f2, int *x)
{
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");
if (ts)
ast_playtones_start(chan, 0, ts->data, 0);
else
ast_tonepair_start(chan, 350, 440, 0, 0);
int i;
float val;
for(i = 0; i < TONE_BLOCK_SIZE; i++)
{
val = loudness * sin((f1 * 2.0 * M_PI * (*x))/8000.0);
val += loudness * sin((f2 * 2.0 * M_PI * (*x)++)/8000.0);
data[i] = AST_LIN2MU((int)val);
}
/* wrap back around from 8000 */
if (*x >= 8000) *x = 0;
return;
}
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 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];
struct ast_frame *f;
struct timeval lastdigittime;
int res;
time_t rstart;
int i,j,k,x;
struct localuser *u;
char tmp[256],exten[AST_MAX_EXTENSION],acctcode[20];
unsigned char tone_block[TONE_BLOCK_SIZE],sil_block[TONE_BLOCK_SIZE];
char *ourcontext;
struct ast_frame *f,wf;
fd_set readfds;
int waitfor_notime;
struct timeval notime = { 0,0 }, lastout, now, lastdigittime;
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);
);
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;
/* make block of silence */
memset(sil_block,0x7f,TONE_BLOCK_SIZE);
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);
strtok(tmp, "|");
ourcontext = strtok(NULL, "|");
/* if context not specified, use "disa" */
if (!ourcontext) 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);
if (!strcasecmp(args.passcode, "no-password")) {
k |= 1; /* We have the password */
if (!strcasecmp(tmp, "no-password"))
{
k = 1;
ast_log(LOG_DEBUG, "DISA no-password login success\n");
}
lastdigittime = ast_tvnow();
play_dialtone(chan, args.mailbox);
for (;;) {
gettimeofday(&lastdigittime,NULL);
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) ? digittimeout : firstdigittimeout))
{
ast_log(LOG_DEBUG,"DISA %s entry timeout on chan %s\n",
((k&1) ? "extension" : "password"),chan->name);
break;
((k) ? "extension" : "password"),chan->name);
goto reorder;
}
if ((res = ast_waitfor(chan, -1) < 0)) {
ast_log(LOG_DEBUG, "Waitfor returned %d\n", res);
continue;
/* if first digit or ignore, send dialtone */
if ((!i) || (ast_ignore_pattern(ourcontext,exten) && k))
{
gettimeofday(&now,NULL);
if (lastout.tv_sec &&
(ms_diff(&now,&lastout) < 25)) continue;
lastout.tv_sec = now.tv_sec;
lastout.tv_usec = now.tv_usec;
wf.frametype = AST_FRAME_VOICE;
wf.subclass = AST_FORMAT_ULAW;
wf.offset = AST_FRIENDLY_OFFSET;
wf.mallocd = 0;
wf.data = tone_block;
wf.datalen = TONE_BLOCK_SIZE;
/* make this tone block */
make_tone_block(tone_block,350.0,440.0,&x);
wf.timelen = wf.datalen / 8;
if (ast_write(chan, &wf))
{
ast_log(LOG_WARNING, "DISA Failed to write frame on %s\n",chan->name);
LOCAL_USER_REMOVE(u);
return -1;
}
}
waitfor_notime = notime.tv_usec + notime.tv_sec * 1000;
if (!ast_waitfor_nandfds(&chan, 1, &(chan->fds[0]), 1, NULL, NULL,
&waitfor_notime)) continue;
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) {
/* if not DTMF, just do it again */
if (f->frametype != AST_FRAME_DTMF)
{
ast_frfree(f);
continue;
}
/* 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) {
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) /* 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))
{
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;
strtok(tmp, "|");
ourcontext = strtok(NULL, "|");
/* 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);
k|=1; /* In number mode */
k = 1;
i = 0; /* re-set buffer pointer */
exten[sizeof(acctcode)] = 0;
ast_copy_string(acctcode, exten, sizeof(acctcode));
strcpy(acctcode,exten);
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;
}
}
exten[i++] = j; /* save digit */
exten[i] = 0;
if (!(k&1))
continue; /* if getting password, continue doing it */
/* if this exists */
if (ast_ignore_pattern(args.context, exten)) {
play_dialtone(chan, "");
did_ignore = 1;
} else
if (did_ignore) {
ast_playtones_stop(chan);
did_ignore = 0;
}
/* if can do some more, do it */
if (!ast_matchmore_extension(chan,args.context,exten,1, chan->cid.cid_num)) {
break;
if (!k) continue; /* if getting password, continue doing it */
/* if this exists */
if (ast_exists_extension(chan,ourcontext,exten,1, chan->callerid))
{
strcpy(chan->exten,exten);
strcpy(chan->context,ourcontext);
strcpy(chan->accountcode,acctcode);
chan->priority = 0;
ast_cdr_init(chan->cdr,chan);
LOCAL_USER_REMOVE(u);
return 0;
}
/* if can do some more, do it */
if (ast_canmatch_extension(chan,ourcontext,exten,1, chan->callerid)) continue;
}
}
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;
}
}
/* 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) {
if (ast_waitfor(chan, -1) < 0)
break;
f = ast_read(chan);
if (!f)
break;
ast_frfree(f);
/* something is invalid, give em reorder forever */
x = 0;
for(;;)
{
for(i = 0; i < 10; i++)
{
do gettimeofday(&now,NULL);
while (lastout.tv_sec &&
(ms_diff(&now,&lastout) < 25)) ;
lastout.tv_sec = now.tv_sec;
lastout.tv_usec = now.tv_usec;
wf.frametype = AST_FRAME_VOICE;
wf.subclass = AST_FORMAT_ULAW;
wf.offset = AST_FRIENDLY_OFFSET;
wf.mallocd = 0;
wf.data = tone_block;
wf.datalen = TONE_BLOCK_SIZE;
/* make this tone block */
make_tone_block(tone_block,480.0,620.0,&x);
wf.timelen = wf.datalen / 8;
if (ast_write(chan, &wf))
{
ast_log(LOG_WARNING, "DISA Failed to write frame on %s\n",chan->name);
LOCAL_USER_REMOVE(u);
return -1;
}
FD_ZERO(&readfds);
FD_SET(chan->fds[0],&readfds);
/* if no read avail, do send again */
if (select(chan->fds[0] + 1,&readfds,NULL,
NULL,&notime) < 1) continue;
/* read frame */
f = ast_read(chan);
if (f == NULL)
{
LOCAL_USER_REMOVE(u);
return -1;
}
if ((f->frametype == AST_FRAME_CONTROL) &&
(f->subclass == AST_CONTROL_HANGUP))
{
ast_frfree(f);
LOCAL_USER_REMOVE(u);
return -1;
}
ast_frfree(f);
}
for(i = 0; i < 10; i++)
{
do gettimeofday(&now,NULL);
while (lastout.tv_sec &&
(ms_diff(&now,&lastout) < 25)) ;
lastout.tv_sec = now.tv_sec;
lastout.tv_usec = now.tv_usec;
wf.frametype = AST_FRAME_VOICE;
wf.subclass = AST_FORMAT_ULAW;
wf.offset = AST_FRIENDLY_OFFSET;
wf.mallocd = 0;
wf.data = sil_block;
wf.datalen = TONE_BLOCK_SIZE;
wf.timelen = wf.datalen / 8;
if (ast_write(chan, &wf))
{
ast_log(LOG_WARNING, "DISA Failed to write frame on %s\n",chan->name);
LOCAL_USER_REMOVE(u);
return -1;
}
FD_ZERO(&readfds);
FD_SET(chan->fds[0],&readfds);
/* if no read avail, do send again */
if (select(chan->fds[0] + 1,&readfds,NULL,
NULL,&notime) < 1) continue;
/* read frame */
f = ast_read(chan);
if (f == NULL)
{
LOCAL_USER_REMOVE(u);
return -1;
}
if ((f->frametype == AST_FRAME_CONTROL) &&
(f->subclass == AST_CONTROL_HANGUP))
{
ast_frfree(f);
LOCAL_USER_REMOVE(u);
return -1;
}
ast_frfree(f);
}
}
}
ast_playtones_stop(chan);
ast_module_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()
{
return ASTERISK_GPL_KEY;
}

View File

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

View File

@@ -1,104 +1,94 @@
/*
* 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/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"
#include <pthread.h>
static char *tdesc = "Simple Echo Application";
static char *app = "Echo";
static char *synopsis = "Echo audio, video, or DTMF back to the calling party";
static char *synopsis = "Echo audio read back to the user";
static char *descrip =
" Echo(): This application will echo any audio, video, or DTMF frames read from\n"
"the calling channel back to itself. If the DTMF digit '#' is received, the\n"
"application will exit.\n";
" Echo(): Echo audio read from channel back to the channel. Returns 0\n"
"if the user exits with the '#' key, or -1 if the user hangs up.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int echo_exec(struct ast_channel *chan, void *data)
{
int res = -1;
int format;
struct ast_module_user *u;
u = ast_module_user_add(chan);
format = ast_best_codec(chan->nativeformats);
ast_set_write_format(chan, format);
ast_set_read_format(chan, format);
while (ast_waitfor(chan, -1) > -1) {
struct ast_frame *f = ast_read(chan);
if (!f)
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;
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((f = ast_read(chan))) {
if (f->frametype == AST_FRAME_VOICE) {
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;
}

View File

@@ -1,221 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
* Portions copyright (c) 2006, Philipp Dunkel.
*
* Tilghman Lesher <app_exec__v002@the-tilghman.com>
*
* 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"
/* 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 *app_exec = "Exec";
static char *exec_synopsis = "Executes dialplan application";
static char *exec_descrip =
"Usage: Exec(appname(arguments))\n"
" Allows an arbitrary application to be invoked even when not\n"
"hardcoded into the dialplan. If the underlying application\n"
"terminates the dialplan, or if the application cannot be found,\n"
"Exec will terminate the dialplan.\n"
" To invoke external applications, see the application System.\n"
" If you would like to catch any error instead, see TryExec.\n";
static char *app_tryexec = "TryExec";
static char *tryexec_synopsis = "Executes dialplan application, always returning";
static char *tryexec_descrip =
"Usage: TryExec(appname(arguments))\n"
" Allows an arbitrary application to be invoked even when not\n"
"hardcoded into the dialplan. To invoke external applications\n"
"see the application System. Always returns to the dialplan.\n"
"The channel variable TRYSTATUS will be set to:\n"
" SUCCESS if the application returned zero\n"
" FAILED if the application returned non-zero\n"
" NOAPP if the application was not found or was not specified\n";
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";
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 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);
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
res = -1;
}
}
}
ast_module_user_remove(u);
return res;
}
static int tryexec_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
char *s, *appname, *endargs, args[MAXRESULT] = "";
struct ast_app *app;
u = ast_module_user_add(chan);
/* Check and parse arguments */
if (data) {
s = ast_strdupa(data);
appname = strsep(&s, "(");
if (s) {
endargs = strrchr(s, ')');
if (endargs)
*endargs = '\0';
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
}
if (appname) {
app = pbx_findapp(appname);
if (app) {
res = pbx_exec(chan, app, args);
pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
} else {
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
pbx_builtin_setvar_helper(chan, "TRYSTATUS", "NOAPP");
}
}
}
ast_module_user_remove(u);
return 0;
}
static int execif_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *myapp = NULL;
char *mydata = NULL;
char *expr = NULL;
struct ast_app *app = NULL;
u = ast_module_user_add(chan);
expr = ast_strdupa(data);
if ((myapp = strchr(expr,'|'))) {
*myapp = '\0';
myapp++;
if ((mydata = strchr(myapp,'|'))) {
*mydata = '\0';
mydata++;
} else
mydata = "";
if (pbx_checkcondition(expr)) {
if ((app = pbx_findapp(myapp))) {
res = pbx_exec(chan, app, mydata);
} else {
ast_log(LOG_WARNING, "Count not find application! (%s)\n", myapp);
res = -1;
}
}
} else {
ast_log(LOG_ERROR,"Invalid Syntax.\n");
res = -1;
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_exec);
res |= ast_unregister_application(app_tryexec);
res |= ast_unregister_application(app_execif);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res = ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
res |= ast_register_application(app_tryexec, tryexec_exec, tryexec_synopsis, tryexec_descrip);
res |= ast_register_application(app_execif, execif_exec, execif_synopsis, execif_descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Executes dialplan applications");

View File

@@ -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 an process to run the supplied command,\n"
"and starts a generator on the channel. The generator's play list is\n"
"controlled by the external application, which can add and clear entries\n"
"via simple commands issued over its stdout. The external application\n"
"will receive all DTMF events received on the channel, and notification\n"
"if the channel is hung up. The application will not be forcibly terminated\n"
"when the channel is hung up.\n"
"See doc/externalivr.txt for a protocol specification.\n";
/* 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");

View File

@@ -1,553 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* 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.
*/
/*! \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 <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#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 *app = "Festival";
static char *synopsis = "Say text to the user";
static char *descrip =
" Festival(text[|intkeys]): Connect to Festival, send the argument, get back the waveform,"
"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";
static char *socket_receive_file_to_buff(int fd,int *size)
{
/* Receive file (probably a waveform file) from socket using */
/* Festival key stuff technique, but long winded I know, sorry */
/* but will receive any file without closeing the stream or */
/* using OOB data */
static char *file_stuff_key = "ft_StUfF_key"; /* must == Festival's key */
char *buff;
int bufflen;
int n,k,i;
char c;
bufflen = 1024;
if (!(buff = ast_malloc(bufflen)))
{
/* TODO: Handle memory allocation failure */
}
*size=0;
for (k=0; file_stuff_key[k] != '\0';)
{
n = read(fd,&c,1);
if (n==0) break; /* hit stream eof before end of file */
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 */
}
}
if (file_stuff_key[k] == c)
k++;
else if ((c == 'X') && (file_stuff_key[k+1] == '\0'))
{ /* It looked like the key but wasn't */
for (i=0; i < k; i++,(*size)++)
buff[*size] = file_stuff_key[i];
k=0;
/* omit the stuffed 'X' */
}
else
{
for (i=0; i < k; i++,(*size)++)
buff[*size] = file_stuff_key[i];
k=0;
buff[*size] = c;
(*size)++;
}
}
return buff;
}
static int send_waveform_to_fd(char *waveform, int length, int fd) {
int res;
int x;
#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);
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 */
#ifdef __PPC__
for( x=0; x<length; x+=2)
{
c = *(waveform+x+1);
*(waveform+x+1)=*(waveform+x);
*(waveform+x)=c;
}
#endif
write(fd,waveform,length);
close(fd);
exit(0);
}
static int send_waveform_to_channel(struct ast_channel *chan, char *waveform, int length, char *intkeys) {
int res=0;
int fds[2];
int ms = -1;
int pid = -1;
int needed = 0;
int owriteformat;
struct ast_frame *f;
struct myframe {
struct ast_frame f;
char offset[AST_FRIENDLY_OFFSET];
char frdata[2048];
} myf = {
.f = { 0, },
};
if (pipe(fds)) {
ast_log(LOG_WARNING, "Unable to create pipe\n");
return -1;
}
/* Answer if it's not already going */
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) {
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
return -1;
}
res=send_waveform_to_fd(waveform,length,fds[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 = 1000;
res = ast_waitfor(chan, ms);
if (res < 1) {
res = -1;
break;
}
f = ast_read(chan);
if (!f) {
ast_log(LOG_WARNING, "Null frame == hangup() detected\n");
res = -1;
break;
}
if (f->frametype == AST_FRAME_DTMF) {
ast_log(LOG_DEBUG, "User pressed a key\n");
if (intkeys && strchr(intkeys, f->subclass)) {
res = f->subclass;
ast_frfree(f);
break;
}
}
if (f->frametype == AST_FRAME_VOICE) {
/* Treat as a generator */
needed = f->samples * 2;
if (needed > sizeof(myf.frdata)) {
ast_log(LOG_WARNING, "Only able to deliver %d of %d requested samples\n",
(int)sizeof(myf.frdata) / 2, needed/2);
needed = sizeof(myf.frdata);
}
res = read(fds[0], myf.frdata, needed);
if (res > 0) {
myf.f.frametype = AST_FRAME_VOICE;
myf.f.subclass = AST_FORMAT_SLINEAR;
myf.f.datalen = res;
myf.f.samples = res / 2;
myf.f.offset = AST_FRIENDLY_OFFSET;
myf.f.src = __PRETTY_FUNCTION__;
myf.f.data = myf.frdata;
if (ast_write(chan, &myf.f) < 0) {
res = -1;
ast_frfree(f);
break;
}
if (res < needed) { /* last frame */
ast_log(LOG_DEBUG, "Last frame\n");
res=0;
ast_frfree(f);
break;
}
} else {
ast_log(LOG_DEBUG, "No more waveform\n");
res = 0;
}
}
ast_frfree(f);
}
}
close(fds[0]);
close(fds[1]);
/* if (pid > -1) */
/* kill(pid, SIGKILL); */
if (!res && owriteformat)
ast_set_write_format(chan, owriteformat);
return res;
}
#define MAXLEN 180
#define MAXFESTLEN 2048
static int festival_exec(struct ast_channel *chan, void *vdata)
{
int usecache;
int res=0;
struct ast_module_user *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;
int port=1314;
int n;
char ack[4];
char *waveform;
int filesize;
int wave;
char bigstring[MAXFESTLEN];
int i;
struct MD5Context md5ctx;
unsigned char MD5Res[16];
char MD5Hex[33] = "";
char koko[4] = "";
char cachefile[MAXFESTLEN]="";
int readcache=0;
int writecache=0;
int strln;
int fdesc = -1;
char buffer[16384];
int seekpos = 0;
char *data;
char *intstr;
struct ast_config *cfg;
char *newfestivalcommand;
if (ast_strlen_zero(vdata)) {
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
return -1;
}
u = ast_module_user_add(chan);
cfg = ast_config_load(FESTIVAL_CONFIG);
if (!cfg) {
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
ast_module_user_remove(u);
return -1;
}
if (!(host = ast_variable_retrieve(cfg, "general", "host"))) {
host = "localhost";
}
if (!(temp = ast_variable_retrieve(cfg, "general", "port"))) {
port = 1314;
} else {
port = atoi(temp);
}
if (!(temp = ast_variable_retrieve(cfg, "general", "usecache"))) {
usecache=0;
} else {
usecache = ast_true(temp);
}
if (!(cachedir = ast_variable_retrieve(cfg, "general", "cachedir"))) {
cachedir = "/tmp/";
}
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) {
*intstr = '\0';
intstr++;
if (!strcasecmp(intstr, "any"))
intstr = AST_DIGIT_ANY;
}
ast_log(LOG_DEBUG, "Text passed to festival server : %s\n",(char *)data);
/* Connect to local festival server */
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) {
ast_log(LOG_WARNING,"festival_client: can't get socket\n");
ast_config_destroy(cfg);
ast_module_user_remove(u);
return -1;
}
memset(&serv_addr, 0, sizeof(serv_addr));
if ((serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) {
/* its a name rather than an ipnum */
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);
return -1;
}
memmove(&serv_addr.sin_addr,serverhost->h_addr, serverhost->h_length);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
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);
return -1;
}
/* Compute MD5 sum of string */
MD5Init(&md5ctx);
MD5Update(&md5ctx,(unsigned char const *)data,strlen(data));
MD5Final(MD5Res,&md5ctx);
MD5Hex[0] = '\0';
/* Convert to HEX and look if there is any matching file in the cache
directory */
for (i=0;i<16;i++) {
snprintf(koko, sizeof(koko), "%X",MD5Res[i]);
strncat(MD5Hex, koko, sizeof(MD5Hex) - strlen(MD5Hex) - 1);
}
readcache=0;
writecache=0;
if (strlen(cachedir)+strlen(MD5Hex)+1<=MAXFESTLEN && (usecache==-1)) {
snprintf(cachefile, sizeof(cachefile), "%s/%s", cachedir, MD5Hex);
fdesc=open(cachefile,O_RDWR);
if (fdesc==-1) {
fdesc=open(cachefile,O_CREAT|O_RDWR,0777);
if (fdesc!=-1) {
writecache=1;
strln=strlen((char *)data);
ast_log(LOG_DEBUG,"line length : %d\n",strln);
write(fdesc,&strln,sizeof(int));
write(fdesc,data,strln);
seekpos=lseek(fdesc,0,SEEK_CUR);
ast_log(LOG_DEBUG,"Seek position : %d\n",seekpos);
}
} else {
read(fdesc,&strln,sizeof(int));
ast_log(LOG_DEBUG,"Cache file exists, strln=%d, strlen=%d\n",strln,(int)strlen((char *)data));
if (strlen((char *)data)==strln) {
ast_log(LOG_DEBUG,"Size OK\n");
read(fdesc,&bigstring,strln);
bigstring[strln] = 0;
if (strcmp(bigstring,data)==0) {
readcache=1;
} else {
ast_log(LOG_WARNING,"Strings do not match\n");
}
} else {
ast_log(LOG_WARNING,"Size mismatch\n");
}
}
}
if (readcache==1) {
close(fd);
fd=fdesc;
ast_log(LOG_DEBUG,"Reading from cache...\n");
} else {
ast_log(LOG_DEBUG,"Passing text to festival...\n");
fs=fdopen(dup(fd),"wb");
fprintf(fs,festivalcommand,(char *)data);
fflush(fs);
fclose(fs);
}
/* Write to cache and then pass it down */
if (writecache==1) {
ast_log(LOG_DEBUG,"Writing result to cache...\n");
while ((strln=read(fd,buffer,16384))!=0) {
write(fdesc,buffer,strln);
}
close(fd);
close(fdesc);
fd=open(cachefile,O_RDWR);
lseek(fd,seekpos,SEEK_SET);
}
ast_log(LOG_DEBUG,"Passing data to channel...\n");
/* Read back info from server */
/* 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;
}
ack[3] = '\0';
if (strcmp(ack,"WV\n") == 0) { /* receive a waveform */
ast_log(LOG_DEBUG,"Festival WV command\n");
waveform = socket_receive_file_to_buff(fd,&filesize);
res = send_waveform_to_channel(chan,waveform,filesize, intstr);
free(waveform);
break;
}
else if (strcmp(ack,"LP\n") == 0) { /* receive an s-expr */
ast_log(LOG_DEBUG,"Festival LP command\n");
waveform = socket_receive_file_to_buff(fd,&filesize);
waveform[filesize]='\0';
ast_log(LOG_WARNING,"Festival returned LP : %s\n",waveform);
free(waveform);
} else if (strcmp(ack,"ER\n") == 0) { /* server got an error */
ast_log(LOG_WARNING,"Festival returned ER\n");
res=-1;
break;
}
} while (strcmp(ack,"OK\n") != 0);
close(fd);
ast_config_destroy(cfg);
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)
{
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");

View File

@@ -1,124 +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 App to flash a zap trunk
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<depend>zaptel</depend>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <zaptel/zaptel.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 *app = "Flash";
static char *synopsis = "Flashes a Zap Trunk";
static char *descrip =
" Flash(): Sends a flash on a zap trunk. This is only a hack for\n"
"people who want to perform transfers and such via AGI and is generally\n"
"quite useless oths application will only work on Zap trunks.\n";
static inline int zt_wait_event(int fd)
{
/* Avoid the silly zt_waitevent which ignores a bunch of events */
int i,j=0;
i = ZT_IOMUX_SIGEVENT;
if (ioctl(fd, ZT_IOMUX, &i) == -1) return -1;
if (ioctl(fd, ZT_GETEVENT, &j) == -1) return -1;
return j;
}
static int flash_exec(struct ast_channel *chan, void *data)
{
int res = -1;
int x;
struct ast_module_user *u;
struct zt_params ztp;
u = ast_module_user_add(chan);
if (!strcasecmp(chan->tech->type, "Zap")) {
memset(&ztp, 0, sizeof(ztp));
res = ioctl(chan->fds[0], ZT_GET_PARAMS, &ztp);
if (!res) {
if (ztp.sigtype & __ZT_SIG_FXS) {
x = ZT_FLASH;
res = ioctl(chan->fds[0], ZT_HOOK, &x);
if (!res || (errno == EINPROGRESS)) {
if (res) {
/* Wait for the event to finish */
zt_wait_event(chan->fds[0]);
}
res = ast_safe_sleep(chan, 1000);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Flashed channel %s\n", chan->name);
} else
ast_log(LOG_WARNING, "Unable to flash channel %s: %s\n", chan->name, strerror(errno));
} else
ast_log(LOG_WARNING, "%s is not an FXO Channel\n", chan->name);
} else
ast_log(LOG_WARNING, "Unable to get parameters of %s: %s\n", chan->name, strerror(errno));
} else
ast_log(LOG_WARNING, "%s is not a Zap channel\n", chan->name);
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, flash_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Flash channel application");

File diff suppressed because it is too large Load Diff

View File

@@ -1,114 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, 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
*/
#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/cdr.h"
#include "asterisk/module.h"
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";
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 };
cdr = chan->cdr;
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 int forkcdr_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *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);
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, forkcdr_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Fork The CDR into 2 separate entities");

View File

@@ -1,148 +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 Get ADSI CPE ID
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/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 *app = "GetCPEID";
static char *synopsis = "Get ADSI CPE ID";
static char *descrip =
" GetCPEID: Obtains and displays ADSI CPE ID and other information in order\n"
"to properly setup zapata.conf for on-hook operations.\n";
static int cpeid_setstatus(struct ast_channel *chan, char *stuff[], int voice)
{
int justify[5] = { ADSI_JUST_CENT, ADSI_JUST_LEFT, ADSI_JUST_LEFT, ADSI_JUST_LEFT };
char *tmp[5];
int x;
for (x=0;x<4;x++)
tmp[x] = stuff[x];
tmp[4] = NULL;
return ast_adsi_print(chan, tmp, justify, voice);
}
static int cpeid_exec(struct ast_channel *chan, void *idata)
{
int res=0;
struct ast_module_user *u;
unsigned char cpeid[4];
int gotgeometry = 0;
int gotcpeid = 0;
int width, height, buttons;
char *data[4];
unsigned int x;
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);
if (res > 0) {
cpeid_setstatus(chan, data, 0);
res = ast_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);
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);
gotgeometry = 1;
}
}
if (res > -1) {
if (gotcpeid)
snprintf(data[1], 80, "CPEID: %02x:%02x:%02x:%02x", cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
else
strcpy(data[1], "CPEID Unknown");
if (gotgeometry)
snprintf(data[2], 80, "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);
for(;;) {
res = ast_waitfordigit(chan, 1000);
if (res < 0)
break;
if (res == '#') {
res = 0;
break;
}
}
ast_adsi_unload_session(chan);
}
}
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, cpeid_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Get ADSI CPE ID");

View File

@@ -1,222 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Changes Copyright (c) 2004 - 2006 Todd Freeman <freeman@andrews.edu>
*
* 95% based on HasNewVoicemail by:
*
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
*
* 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.
*
* 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 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 "asterisk/app.h"
#include "asterisk/options.h"
static char *app_hasvoicemail = "HasVoicemail";
static char *hasvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
static char *hasvoicemail_descrip =
"HasVoicemail(vmbox[/folder][@context][|varname[|options]])\n"
" 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";
static char *app_hasnewvoicemail = "HasNewVoicemail";
static char *hasnewvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
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";
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 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");
return -1;
}
u = ast_module_user_add(chan);
input = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, input);
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))
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);
);
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";
}
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;
}
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 res;
res = ast_custom_function_unregister(&acf_vmcount);
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 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_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.");

View File

@@ -1,223 +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 Stream to an icecast server via ICES (see contrib/asterisk-ices.xml)
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#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"
#define ICES "/usr/bin/ices"
#define LOCAL_ICES "/usr/local/bin/ices"
static char *app = "ICES";
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";
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);
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++) {
if ((x != STDIN_FILENO) && (x != STDOUT_FILENO))
close(x);
}
/* Most commonly installed in /usr/local/bin */
execl(ICES, "ices", filename, (char *)NULL);
/* But many places has it in /usr/bin */
execl(LOCAL_ICES, "ices", filename, (char *)NULL);
/* As a last-ditch effort, try to use PATH */
execlp("ices", "ices", filename, (char *)NULL);
ast_log(LOG_WARNING, "Execute of ices failed\n");
_exit(0);
}
static int ices_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
int fds[2];
int ms = -1;
int pid = -1;
int flags;
int oreadformat;
struct timeval last;
struct ast_frame *f;
char filename[256]="";
char *c;
if (ast_strlen_zero(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);
ast_stopstream(chan);
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (res) {
close(fds[0]);
close(fds[1]);
ast_log(LOG_WARNING, "Answer failed!\n");
ast_module_user_remove(u);
return -1;
}
oreadformat = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
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));
else
snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
/* Placeholder for options */
c = strchr(filename, '|');
if (c)
*c = '\0';
res = icesencode(filename, fds[0]);
close(fds[0]);
if (res >= 0) {
pid = res;
for (;;) {
/* Wait for audio, and stream */
ms = ast_waitfor(chan, -1);
if (ms < 0) {
ast_log(LOG_DEBUG, "Hangup detected\n");
res = -1;
break;
}
f = ast_read(chan);
if (!f) {
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
res = -1;
break;
}
if (f->frametype == AST_FRAME_VOICE) {
res = write(fds[1], f->data, f->datalen);
if (res < 0) {
if (errno != EAGAIN) {
ast_log(LOG_WARNING, "Write failed to pipe: %s\n", strerror(errno));
res = -1;
ast_frfree(f);
break;
}
}
}
ast_frfree(f);
}
}
close(fds[1]);
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 res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static 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");

View File

@@ -1,125 +1,89 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to transmit an image
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief App to transmit an image
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
* the GNU General Public License
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <asterisk/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 <pthread.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;
}

196
apps/app_intercom.c Normal file
View File

@@ -0,0 +1,196 @@
/*
* 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/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 <pthread.h>
#include <sys/time.h>
#include <linux/soundcard.h>
#include <netinet/in.h>
#define DEV_DSP "/dev/dsp"
/* 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;
static pthread_mutex_t sound_lock = PTHREAD_MUTEX_INITIALIZER;
static int sound = -1;
static int write_audio(short *data, int len)
{
int res;
struct audio_buf_info info;
ast_pthread_mutex_lock(&sound_lock);
if (sound < 0) {
ast_log(LOG_WARNING, "Sound device closed?\n");
ast_pthread_mutex_unlock(&sound_lock);
return -1;
}
if (ioctl(sound, SNDCTL_DSP_GETOSPACE, &info)) {
ast_log(LOG_WARNING, "Unable to read output space\n");
ast_pthread_mutex_unlock(&sound_lock);
return -1;
}
res = write(sound, data, len);
ast_pthread_mutex_unlock(&sound_lock);
return res;
}
static int create_audio()
{
int fmt, desired, res, fd;
fd = open(DEV_DSP, O_WRONLY);
if (fd < 0) {
ast_log(LOG_WARNING, "Unable to open %s: %s\n", DEV_DSP, strerror(errno));
close(fd);
return -1;
}
fmt = AFMT_S16_LE;
res = ioctl(fd, SNDCTL_DSP_SETFMT, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set format to 16-bit signed\n");
close(fd);
return -1;
}
fmt = 0;
res = ioctl(fd, SNDCTL_DSP_STEREO, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
close(fd);
return -1;
}
/* 8000 Hz desired */
desired = 8000;
fmt = desired;
res = ioctl(fd, SNDCTL_DSP_SPEED, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to set audio device to mono\n");
close(fd);
return -1;
}
if (fmt != desired) {
ast_log(LOG_WARNING, "Requested %d Hz, got %d Hz -- sound may be choppy\n", desired, fmt);
}
#if 1
/* 2 bytes * 15 units of 2^5 = 32 bytes per buffer */
fmt = ((BUFFER_SIZE) << 16) | (0x0005);
res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fmt);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set fragment size -- sound may be choppy\n");
}
#endif
sound = fd;
return 0;
}
static int intercom_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct localuser *u;
struct ast_frame *f;
int oreadformat;
LOCAL_USER_ADD(u);
/* Remember original read format */
oreadformat = chan->readformat;
/* Set mode to signed linear */
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
return -1;
}
/* Read packets from the channel */
while(!res) {
res = ast_waitfor(chan, -1);
if (res > 0) {
res = 0;
f = ast_read(chan);
if (f) {
if (f->frametype == AST_FRAME_DTMF) {
ast_frfree(f);
break;
} else {
if (f->frametype == AST_FRAME_VOICE) {
if (f->subclass == AST_FORMAT_SLINEAR) {
res = write_audio(f->data, f->datalen);
if (res > 0)
res = 0;
} else
ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
}
}
ast_frfree(f);
} else
res = -1;
}
}
LOCAL_USER_REMOVE(u);
if (!res)
ast_set_read_format(chan, oreadformat);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
if (sound > -1)
close(sound);
return ast_unregister_application(app);
}
int load_module(void)
{
if (create_audio())
return -1;
return ast_register_application(app, intercom_exec, synopsis, descrip);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,132 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief IVR Demo application
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
/*** MODULEINFO
<defaultenabled>no</defaultenabled>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
static char *tdesc = "IVR Demo Application";
static char *app = "IVRDemo";
static char *synopsis =
" This is a skeleton application that shows you the basic structure to create your\n"
"own asterisk applications and demonstrates the IVR demo.\n";
static int ivr_demo_func(struct ast_channel *chan, void *data)
{
ast_verbose("IVR Demo, data is %s!\n", (char *)data);
return 0;
}
AST_IVR_DECLARE_MENU(ivr_submenu, "IVR Demo Sub Menu", 0,
{
{ "s", AST_ACTION_BACKGROUND, "demo-abouttotry" },
{ "s", AST_ACTION_WAITOPTION },
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
{ "1", AST_ACTION_RESTART },
{ "2", AST_ACTION_PLAYLIST, "digits/2;digits/3" },
{ "3", AST_ACTION_CALLBACK, ivr_demo_func },
{ "4", AST_ACTION_TRANSFER, "demo|s|1" },
{ "*", AST_ACTION_REPEAT },
{ "#", AST_ACTION_UPONE },
{ NULL }
});
AST_IVR_DECLARE_MENU(ivr_demo, "IVR Demo Main Menu", 0,
{
{ "s", AST_ACTION_BACKGROUND, "demo-congrats" },
{ "g", AST_ACTION_BACKGROUND, "demo-instruct" },
{ "g", AST_ACTION_WAITOPTION },
{ "1", AST_ACTION_PLAYBACK, "digits/1" },
{ "1", AST_ACTION_RESTART },
{ "2", AST_ACTION_MENU, &ivr_submenu },
{ "2", AST_ACTION_RESTART },
{ "i", AST_ACTION_PLAYBACK, "invalid" },
{ "i", AST_ACTION_REPEAT, (void *)(unsigned long)2 },
{ "#", AST_ACTION_EXIT },
{ NULL },
});
static int skel_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
/* Do our thing here */
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (!res)
res = ast_ivr_menu_run(chan, &ivr_demo, data);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, skel_exec, tdesc, synopsis);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "IVR Demo Application");

View File

@@ -1,160 +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 App to lookup the callerid number, and see if it is blacklisted
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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 *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";
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,
};
static int
lookupblacklist_exec (struct ast_channel *chan, void *data)
{
char blacklist[1];
struct ast_module_user *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))) {
if (option_verbose > 2)
ast_log(LOG_NOTICE, "Blacklisted number %s found\n",chan->cid.cid_num);
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);
return 0;
}
static 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;
}
static int load_module(void)
{
int res = ast_custom_function_register(&blacklist_function);
res |= ast_register_application (app, lookupblacklist_exec, synopsis,descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Look up Caller*ID name/number from blacklist database");

View File

@@ -1,103 +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 App to set callerid name from database, based on directory number
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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 *app = "LookupCIDName";
static char *synopsis = "Look up CallerID Name from local database";
static char *descrip =
" LookupCIDName: Looks up the Caller*ID number on the active\n"
"channel in the Asterisk database (family 'cidname') and sets the\n"
"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";
static int lookupcidname_exec (struct ast_channel *chan, void *data)
{
char dbname[64];
struct ast_module_user *u;
static int dep_warning = 0;
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");
}
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;
}
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, lookupcidname_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Look up CallerID Name from local database");

View File

@@ -1,557 +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 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"
#define MAX_ARGS 80
/* special result value used to force macro exit */
#define MACRO_EXIT_RESULT 1024
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"
"${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";
static char *app = "Macro";
static char *if_app = "MacroIf";
static char *exclusive_app = "MacroExclusive";
static char *exit_app = "MacroExit";
static char *synopsis = "Macro Implementation";
static char *if_synopsis = "Conditional Macro Implementation";
static char *exclusive_synopsis = "Exclusive Macro Implementation";
static char *exit_synopsis = "Exit From Macro";
static 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_lock_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;
}
static int macro_exec(struct ast_channel *chan, void *data)
{
return _macro_exec(chan, data, 0);
}
static int macroexclusive_exec(struct ast_channel *chan, void *data)
{
return _macro_exec(chan, data, 1);
}
static int macroif_exec(struct ast_channel *chan, void *data)
{
char *expr = NULL, *label_a = NULL, *label_b = NULL;
int res = 0;
struct ast_module_user *u;
u = ast_module_user_add(chan);
if (!(expr = ast_strdupa(data))) {
ast_module_user_remove(u);
return -1;
}
if ((label_a = strchr(expr, '?'))) {
*label_a = '\0';
label_a++;
if ((label_b = strchr(label_a, ':'))) {
*label_b = '\0';
label_b++;
}
if (pbx_checkcondition(expr))
macro_exec(chan, label_a);
else if (label_b)
macro_exec(chan, label_b);
} else
ast_log(LOG_WARNING, "Invalid Syntax.\n");
ast_module_user_remove(u);
return res;
}
static int macro_exit_exec(struct ast_channel *chan, void *data)
{
return MACRO_EXIT_RESULT;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(if_app);
res |= ast_unregister_application(exit_app);
res |= ast_unregister_application(app);
res |= ast_unregister_application(exclusive_app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application(exit_app, macro_exit_exec, exit_synopsis, exit_descrip);
res |= ast_register_application(if_app, macroif_exec, if_synopsis, if_descrip);
res |= ast_register_application(exclusive_app, macroexclusive_exec, exclusive_synopsis, exclusive_descrip);
res |= ast_register_application(app, macro_exec, synopsis, descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros");

File diff suppressed because it is too large Load Diff

View File

@@ -1,153 +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 Digital Milliwatt Test
*
* \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 <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 *app = "Milliwatt";
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";
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));
}
static void milliwatt_release(struct ast_channel *chan, void *data)
{
free(data);
return;
}
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__,
};
/* 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;
}
len = samples * sizeof (buf[0]);
wf.datalen = len;
wf.samples = samples;
/* create a buffer containing the digital milliwatt pattern */
for(i = 0; i < len; i++)
{
buf[AST_FRIENDLY_OFFSET + i] = digital_milliwatt[(*indexp)++];
*indexp &= 7;
}
if (ast_write(chan,&wf) < 0)
{
ast_log(LOG_WARNING,"Failed to write frame to '%s': %s\n",chan->name,strerror(errno));
return -1;
}
return 0;
}
static struct ast_generator milliwattgen =
{
alloc: milliwatt_alloc,
release: milliwatt_release,
generate: milliwatt_generate,
} ;
static int milliwatt_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
u = ast_module_user_add(chan);
ast_set_write_format(chan, AST_FORMAT_ULAW);
ast_set_read_format(chan, AST_FORMAT_ULAW);
if (chan->_state != AST_STATE_UP)
{
ast_answer(chan);
}
if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0)
{
ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
ast_module_user_remove(u);
return -1;
}
while(!ast_safe_sleep(chan, 10000));
ast_deactivate_generator(chan);
ast_module_user_remove(u);
return -1;
}
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, milliwatt_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Digital Milliwatt (mu-law) Test Application");

View File

@@ -1,463 +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/chanspy.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} and \n"
"all variables will be evaluated at that time.\n"
"The variable MIXMONITOR_FILENAME will contain the filename used to record.\n"
"";
static const char *stop_app = "StopMixMonitor";
static const char *stop_synopsis = "Stop recording a call through MixMonitor";
static const char *stop_desc = ""
" StopMixMonitor()\n\n"
"Stops the audio recording that was started with a call to MixMonitor()\n"
"on the current channel.\n"
"";
struct module_symbols *me;
static const char *mixmonitor_spy_type = "MixMonitor";
struct mixmonitor {
struct ast_channel_spy spy;
char *filename;
char *post_process;
char *name;
unsigned int flags;
};
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_channel_spy *spy)
{
struct ast_channel *peer;
int res;
if (!chan)
return -1;
ast_channel_lock(chan);
res = ast_channel_spy_add(chan, spy);
ast_channel_unlock(chan);
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_frame *f = NULL;
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_mutex_lock(&mixmonitor->spy.lock);
while (mixmonitor->spy.chan) {
struct ast_frame *next;
int write;
ast_channel_spy_trigger_wait(&mixmonitor->spy);
if (!mixmonitor->spy.chan || mixmonitor->spy.status != CHANSPY_RUNNING)
break;
while (1) {
if (!(f = ast_channel_spy_read_frame(&mixmonitor->spy, SAMPLES_PER_FRAME)))
break;
write = (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) ||
ast_bridged_channel(mixmonitor->spy.chan));
/* it is possible for ast_channel_spy_read_frame() to return a chain
of frames if a queue flush was necessary, so process them
*/
for (; f; f = next) {
next = AST_LIST_NEXT(f, frame_list);
if (write && errflag == 0) {
if (!fs) {
/* Determine creation flags and filename plus extension for filestream */
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";
/* Move onto actually creating the filestream */
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;
}
}
if (fs)
ast_writestream(fs, f);
}
ast_frame_free(f, 0);
}
}
}
ast_mutex_unlock(&mixmonitor->spy.lock);
ast_channel_spy_free(&mixmonitor->spy);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
if (mixmonitor->post_process) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
ast_safe_system(mixmonitor->post_process);
}
if (fs)
ast_closestream(fs);
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->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 */
ast_set_flag(&mixmonitor->spy, CHANSPY_FORMAT_AUDIO);
ast_set_flag(&mixmonitor->spy, CHANSPY_MIXAUDIO);
mixmonitor->spy.type = mixmonitor_spy_type;
mixmonitor->spy.status = CHANSPY_RUNNING;
mixmonitor->spy.read_queue.format = AST_FORMAT_SLINEAR;
mixmonitor->spy.write_queue.format = AST_FORMAT_SLINEAR;
if (readvol) {
ast_set_flag(&mixmonitor->spy, CHANSPY_READ_VOLADJUST);
mixmonitor->spy.read_vol_adjustment = readvol;
}
if (writevol) {
ast_set_flag(&mixmonitor->spy, CHANSPY_WRITE_VOLADJUST);
mixmonitor->spy.write_vol_adjustment = writevol;
}
ast_mutex_init(&mixmonitor->spy.lock);
if (startmon(chan, &mixmonitor->spy)) {
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_mutex_destroy(&mixmonitor->spy.lock);
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_channel_lock(chan);
ast_channel_spy_stop_by_type(chan, mixmonitor_spy_type);
ast_channel_unlock(chan);
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_channel_spy_stop_by_type(chan, mixmonitor_spy_type);
ast_channel_unlock(chan);
return RESULT_SUCCESS;
}
static char *complete_mixmonitor_cli(const char *line, const char *word, int pos, int state)
{
return ast_complete_channels(line, word, pos, state, 2);
}
static struct ast_cli_entry cli_mixmonitor[] = {
{ { "mixmonitor", NULL, NULL },
mixmonitor_cli, "Execute a MixMonitor command.",
"mixmonitor <start|stop> <chan_name> [args]\n\n"
"The optional arguments are passed to the\n"
"MixMonitor application when the 'start' command is used.\n",
complete_mixmonitor_cli },
};
static int unload_module(void)
{
int res;
ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
res = ast_unregister_application(stop_app);
res |= ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");

View File

@@ -1,178 +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++) {
char *dahdit;
if (*digit < 0) {
continue;
}
for (dahdit = morsecode[(int)*digit]; *dahdit; dahdit++) {
if (*dahdit == '-') {
playtone(chan, tone, 3 * ditlen);
} else if (*dahdit == '.') {
playtone(chan, tone, 1 * ditlen);
} else {
/* Account for ditlen of silence immediately following */
playtone(chan, 0, 2 * ditlen);
}
/* Pause slightly between each dit and dah */
playtone(chan, 0, 1 * ditlen);
}
/* Pause between characters */
playtone(chan, 0, 2 * ditlen);
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_morsecode);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app_morsecode, morsecode_exec, morsecode_synopsis, morsecode_descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Morse code");

View File

@@ -1,192 +1,172 @@
/*
* 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, 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 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/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>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.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);
}
/* Execute mpg123, but buffer if it's a net connection */
if (!strncasecmp(filename, "http://", 7)) {
/* Most commonly installed in /usr/local/bin */
execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
/* But many places has it in /usr/bin */
execl(MPG_123, "mpg123", "-q", "-s", "-b", "1024","-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
/* As a last-ditch effort, try to use PATH */
execlp("mpg123", "mpg123", "-q", "-s", "-b", "1024", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
}
else {
/* Most commonly installed in /usr/local/bin */
execl(MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
/* But many places has it in /usr/bin */
execl(LOCAL_MPG_123, "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
/* As a last-ditch effort, try to use PATH */
execlp("mpg123", "mpg123", "-q", "-s", "-f", "8192", "--mono", "-r", "8000", filename, (char *)NULL);
}
if (strncmp(filename, "http://", 7))
execl(MPG_123, MPG_123, "-q", "-s", "-b", "1024", "--mono", "-r", "8000", filename, NULL);
else
execl(MPG_123, MPG_123, "-q", "-s", "--mono", "-r", "8000", filename, NULL);
ast_log(LOG_WARNING, "Execute of mpg123 failed\n");
_exit(0);
}
static int timed_read(int fd, void *data, int datalen, int timeout)
{
int res;
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
res = poll(fds, 1, timeout);
if (res < 1) {
ast_log(LOG_NOTICE, "Poll timed out/errored out with %d\n", res);
return -1;
}
return read(fd, data, datalen);
return -1;
}
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 rfds[1 + AST_MAX_FDS];
int ms = -1;
int pid = -1;
int us;
int exception;
int owriteformat;
int timeout = 2000;
struct timeval next;
struct timeval tv;
struct timeval last;
struct ast_frame *f;
int x;
struct myframe {
struct ast_frame f;
char offset[AST_FRIENDLY_OFFSET];
short frdata[160];
char frdata[160];
} myf;
if (ast_strlen_zero(data)) {
last.tv_usec = 0;
last.tv_sec = 0;
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;
}
res = mp3play((char *)data, fds[1]);
if (!strncasecmp((char *)data, "http://", 7)) {
timeout = 10000;
}
/* Wait 1000 ms first */
next = ast_tvnow();
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 */
rfds[AST_MAX_FDS] = fds[0];
for (;;) {
ms = ast_tvdiff_ms(next, ast_tvnow());
if (ms <= 0) {
res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata), timeout);
CHECK_BLOCKING(chan);
for (x=0;x<AST_MAX_FDS;x++)
rfds[x] = chan->fds[x];
res = ast_waitfor_n_fd(rfds, AST_MAX_FDS+1, &ms, &exception);
chan->blocking = 0;
if (res < 1) {
ast_log(LOG_DEBUG, "Hangup detected\n");
res = -1;
break;
}
for(x=0;x<AST_MAX_FDS;x++)
if (res == chan->fds[x])
break;
if (x < AST_MAX_FDS) {
if (exception)
chan->exception = 1;
f = ast_read(chan);
if (!f) {
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
res = -1;
break;
}
if (f->frametype == AST_FRAME_DTMF) {
ast_log(LOG_DEBUG, "User pressed a key\n");
ast_frfree(f);
res = 0;
break;
}
ast_frfree(f);
} else if (res == fds[0]) {
gettimeofday(&tv, NULL);
if (last.tv_sec || last.tv_usec) {
/* We should wait at least a frame length */
us = sizeof(myf.frdata) / 16 * 1000;
/* Subtract 1,000,000 us for each second late we've passed */
us -= (tv.tv_sec - last.tv_sec) * 1000000;
/* And one for each us late we've passed */
us -= (tv.tv_usec - last.tv_usec);
/* Sleep that long if needed */
if (us > 0)
usleep(us);
}
last = tv;
res = read(fds[0], myf.frdata, sizeof(myf.frdata));
if (res > 0) {
myf.f.frametype = AST_FRAME_VOICE;
myf.f.subclass = AST_FORMAT_SLINEAR;
myf.f.datalen = res;
myf.f.samples = res / 2;
myf.f.timelen = res / 16;
myf.f.mallocd = 0;
myf.f.offset = AST_FRIENDLY_OFFSET;
myf.f.src = __PRETTY_FUNCTION__;
myf.f.delivery.tv_sec = 0;
myf.f.delivery.tv_usec = 0;
myf.f.data = myf.frdata;
if (ast_write(chan, &myf.f) < 0) {
res = -1;
@@ -195,61 +175,48 @@ static int mp3_exec(struct ast_channel *chan, void *data)
} else {
ast_log(LOG_DEBUG, "No more mp3\n");
res = 0;
break;
}
next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
} else {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_DEBUG, "Hangup detected\n");
res = -1;
break;
}
if (ms) {
f = ast_read(chan);
if (!f) {
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
res = -1;
break;
}
if (f->frametype == AST_FRAME_DTMF) {
ast_log(LOG_DEBUG, "User pressed a key\n");
ast_frfree(f);
res = 0;
break;
}
ast_frfree(f);
}
ast_log(LOG_DEBUG, "HuhHHH?\n");
res = -1;
break;
}
}
}
close(fds[0]);
close(fds[1]);
LOCAL_USER_REMOVE(u);
if (pid > -1)
kill(pid, SIGKILL);
if (!res && owriteformat)
ast_set_write_format(chan, owriteformat);
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, mp3_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly MP3 Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,237 +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 Silly application to play an NBScat file -- uses nbscat8k
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#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 *app = "NBScat";
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.";
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);
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++) {
if (x != STDOUT_FILENO)
close(x);
}
/* Most commonly installed in /usr/local/bin */
execl(NBSCAT, "nbscat8k", "-d", (char *)NULL);
execl(LOCAL_NBSCAT, "nbscat8k", "-d", (char *)NULL);
ast_log(LOG_WARNING, "Execute of nbscat8k failed\n");
_exit(0);
}
static int timed_read(int fd, void *data, int datalen)
{
int res;
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
res = poll(fds, 1, 2000);
if (res < 1) {
ast_log(LOG_NOTICE, "Selected timed out/errored out with %d\n", res);
return -1;
}
return read(fd, data, datalen);
}
static int NBScat_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
int fds[2];
int ms = -1;
int pid = -1;
int owriteformat;
struct timeval 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;
}
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.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());
if (ms <= 0) {
res = timed_read(fds[0], myf.frdata, sizeof(myf.frdata));
if (res > 0) {
myf.f.frametype = AST_FRAME_VOICE;
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.delivery.tv_sec = 0;
myf.f.delivery.tv_usec = 0;
myf.f.data = myf.frdata;
if (ast_write(chan, &myf.f) < 0) {
res = -1;
break;
}
} else {
ast_log(LOG_DEBUG, "No more mp3\n");
res = 0;
break;
}
next = ast_tvadd(next, ast_samp2tv(myf.f.samples, 8000));
} else {
ms = ast_waitfor(chan, ms);
if (ms < 0) {
ast_log(LOG_DEBUG, "Hangup detected\n");
res = -1;
break;
}
if (ms) {
f = ast_read(chan);
if (!f) {
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
res = -1;
break;
}
if (f->frametype == AST_FRAME_DTMF) {
ast_log(LOG_DEBUG, "User pressed a key\n");
ast_frfree(f);
res = 0;
break;
}
ast_frfree(f);
}
}
}
}
close(fds[0]);
close(fds[1]);
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 res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
return ast_register_application(app, NBScat_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Silly NBS Stream Application");

File diff suppressed because it is too large Load Diff

View File

@@ -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");

View File

@@ -1,260 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2006, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
*
* Author: Ben Miller <bgmiller@dccinc.com>
* With TONS of help from Mark!
*
* 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 ParkAndAnnounce application for Asterisk
*
* \author Ben Miller <bgmiller@dccinc.com>
* \arg With TONS of help from Mark!
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "asterisk/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 *app = "ParkAndAnnounce";
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";
static int parkandannounce_exec(struct ast_channel *chan, void *data)
{
int res=0;
char *return_context;
int 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;
struct ast_channel *dchan;
struct outgoing_helper oh;
int outstate;
struct ast_module_user *u;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
return -1;
}
u = ast_module_user_add(chan);
s = ast_strdupa(data);
template=strsep(&s,"|");
if(! template) {
ast_log(LOG_WARNING, "PARK: An announce template must be defined\n");
ast_module_user_remove(u);
return -1;
}
if(s) {
timeout = atoi(strsep(&s, "|"));
timeout *= 1000;
}
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);
return -1;
} else {
dialtech=strsep(&dial, "/");
dialstr=dial;
ast_verbose( VERBOSE_PREFIX_3 "Dial Tech,String: (%s,%s)\n", dialtech,dialstr);
}
return_context = s;
if(return_context != NULL) {
/* set the return context. Code borrowed from the Goto builtin */
working = return_context;
context = strsep(&working, "|");
exten = strsep(&working, "|");
if(!exten) {
/* Only a priority in this one */
priority = context;
exten = NULL;
context = NULL;
} else {
priority = strsep(&working, "|");
if(!priority) {
/* Only an extension and priority in this one */
priority = exten;
exten = context;
context = NULL;
}
}
if(atoi(priority) < 0) {
ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
ast_module_user_remove(u);
return -1;
}
/* At this point we have a priority and maybe an extension and a context */
chan->priority = atoi(priority);
if (exten)
ast_copy_string(chan->exten, exten, sizeof(chan->exten));
if (context)
ast_copy_string(chan->context, context, sizeof(chan->context));
} 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 "Warning: Return Context Invalid, call will return to default|s\n");
}
}
/* 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. */
ast_masq_park_call(chan, NULL, timeout, &lot);
res=-1;
ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
/* Now place the call to the extention */
snprintf(buf, sizeof(buf), "%d", lot);
memset(&oh, 0, sizeof(oh));
oh.parent_channel = chan;
oh.vars = ast_variable_new("_PARKEDAT", buf);
dchan = __ast_request_and_dial(dialtech, AST_FORMAT_SLINEAR, dialstr,30000, &outstate, chan->cid.cid_num, chan->cid.cid_name, &oh);
if(dchan) {
if(dchan->_state == AST_STATE_UP) {
if(option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", dchan->name);
} else {
if(option_verbose > 3)
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);
return -1;
}
} else {
ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
ast_module_user_remove(u);
return -1;
}
ast_stopstream(dchan);
/* now we have the call placed and are ready to play stuff to it */
ast_verbose(VERBOSE_PREFIX_4 "Announce Template:%s\n", template);
tpl_working = template;
tpl_current=strsep(&tpl_working, ":");
while(tpl_current && looptemp < sizeof(tmp)) {
tmp[looptemp]=tpl_current;
looptemp++;
tpl_current=strsep(&tpl_working,":");
}
for(i=0; i<looptemp; i++) {
ast_verbose(VERBOSE_PREFIX_4 "Announce:%s\n", tmp[i]);
if(!strcmp(tmp[i], "PARKED")) {
ast_say_digits(dchan, lot, "", dchan->language);
} else {
dres = ast_streamfile(dchan, tmp[i], dchan->language);
if(!dres) {
dres = ast_waitstream(dchan, "");
} else {
ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], dchan->name);
dres = 0;
}
}
}
ast_stopstream(dchan);
ast_hangup(dchan);
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, park_exec); */
return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Call Parking and Announce Application");

View File

@@ -1,492 +1,113 @@
/*
* 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/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.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"
"specified, the application will return immediately should the channel not be\n"
"off hook. Otherwise, unless 'noanswer' is specified, the 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"
;
" Playback(filename[|option]): Plays back a given filename (do not put\n"
"extension). Options may also be included following a pipe symbol. The only\n"
"defined option at this time is 'skip', which causes the playback of the\n"
"message to be skipped if the channel is not in the 'up' state (i.e. it\n"
"hasn't been answered yet. If 'skip' is specified, the application will\n"
"return immediately should the channel not be off hook. Otherwise, unless\n"
"'noanswer' is specified, the channel channel will be answered before the sound\n"
"is played. Not all channels support playing messages while on hook. Returns -1\n"
"if the channel was hung up, or if the 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;
ast_log(LOG_WARNING, "string <%s> depth <%d>\n", s, depth);
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 */
ast_log(LOG_WARNING, "try <%s> in <%s>\n", s, a->language);
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;
ast_log(LOG_WARNING, "value is <%s>\n", s);
n = ast_var_assign("SAY", s);
AST_LIST_INSERT_HEAD(&head, n, entries);
/* scan the body, one piece at a time */
while ( ret <= 0 && (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));
ast_log(LOG_WARNING, "doing [%s]\n", 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);
}
}
}
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",
"say load new|old" },
};
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)) {
if (!data || !strlen((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;
}
if (chan->_state != AST_STATE_UP) {
strncpy(tmp, (char *)data, sizeof(tmp)-1);
strtok(tmp, "|");
options = strtok(NULL, "|");
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);
ast_stopstream(chan);
}
done:
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", mres ? "FAILED" : "SUCCESS");
ast_module_user_remove(u);
LOCAL_USER_REMOVE(u);
return res;
}
static int reload(void)
int unload_module(void)
{
if (say_cfg) {
ast_config_destroy(say_cfg);
ast_log(LOG_NOTICE, "Reloading say.conf\n");
}
say_cfg = ast_config_load("say.conf");
/*
* XXX here we should sort rules according to the same order
* we have in pbx.c so we have the same matching behaviour.
*/
return 0;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int unload_module(void)
int load_module(void)
{
int res;
res = ast_unregister_application(app);
ast_cli_unregister_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
ast_module_user_hangup_all();
if (say_cfg)
ast_config_destroy(say_cfg);
return res;
}
static int load_module(void)
{
say_cfg = ast_config_load("say.conf");
ast_cli_register_multiple(cli_playback, sizeof(cli_playback) / sizeof(struct ast_cli_entry));
return ast_register_application(app, playback_exec, synopsis, descrip);
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Sound File Playback Application",
.load = load_module,
.unload = unload_module,
.reload = reload,
);
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,232 +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 Block all calls without Caller*ID, require phone # to be entered
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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"
#define PRIV_CONFIG "privacy.conf"
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"
;
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);
);
u = ast_module_user_add(chan);
if (!ast_strlen_zero(chan->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
} 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);
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);
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);
if (!res)
res = ast_streamfile(chan, "privacy-unident", chan->language);
if (!res)
res = ast_waitstream(chan, "");
/*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, "#");
if (res < 0)
break;
/*Make sure we get at least digits*/
if (strlen(phone) >= minlength )
break;
else {
res = ast_streamfile(chan, "privacy-incorrect", chan->language);
if (!res)
res = ast_waitstream(chan, "");
}
}
/*Got a number, play sounds and send them on their way*/
if ((retries < maxretries) && res >= 0 ) {
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");
} 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");
}
if (cfg)
ast_config_destroy(cfg);
}
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, privacy_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Require phone number to be entered, if no CallerID sent");

370
apps/app_qcall.c Normal file
View File

@@ -0,0 +1,370 @@
/** @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).
*
* 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".
*
* 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/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 <pthread.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>
const char *qdir="/var/spool/asterisk/qcall";
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 20 /* 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;
sprintf(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_ctime)
{ /* 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 (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],dialstr[300],extstr[300],ident[300],reqinp[300],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 */
strcpy(fname,(char *)arg);
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);
}
strcpy(reqinp,"1"); /* default required input for acknowledgement */
if (fscanf(fp,"%s %s %s %d %s %s",dialstr,clid,
extstr,&maxsecs,ident,reqinp) < 5)
{
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);
channel->callerid = NULL;
channel->ani = NULL;
#ifdef OURCLID
channel->callerid = strdup(OURCLID);
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 (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");
ast_frfree(f);
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);
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);
strcat(ident,"-ok");
/* if file existant, play it */
if (!ast_streamfile(channel,ident,0))
{
ast_waitstream(channel,"");
ast_stopstream(channel);
}
channel->callerid = strdup(clid);
channel->ani = strdup(clid);
channel->language[0] = 0;
channel->dnid = strdup(extstr);
#ifdef AMAFLAGS
channel->amaflags = AMAFLAGS;
#endif
#ifdef ACCTCODE
strcpy(channel->accountcode,ACCTCODE);
#else
channel->accountcode[0] = 0;
#endif
if (maxsecs) /* if finite length call */
{
time(&channel->whentohangup);
channel->whentohangup += maxsecs;
}
strcpy(channel->exten,extstr);
strcpy(channel->context,context);
channel->priority = 1;
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)
{
mkdir(qdir,0660);
pthread_create(&qcall_thread,NULL,qcall,NULL);
return 0;
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,108 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2003 - 2005 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <asterisk__app_random__200508@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 <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 *app_random = "Random";
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";
static int random_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
char *s;
char *prob;
int probint;
static int deprecated = 0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n");
return -1;
}
u = ast_module_user_add(chan);
s = ast_strdupa(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 (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n",
chan->context,chan->exten, chan->priority+1);
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_random);
ast_module_user_hangup_all();
return res;
}
static 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");

View File

@@ -1,234 +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 Trivial application to read a variable
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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 *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"
" 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";
#define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
static int read_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char tmp[256] = "";
int maxdigits = 255;
int tries = 1, to = 0, x = 0;
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)) {
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);
return -1;
}
ts=NULL;
if (ast_test_flag(&flags,OPT_INDICATION)) {
if (!ast_strlen_zero(arglist.filename)) {
ts = ast_get_indication_tone(chan->zone,arglist.filename);
}
}
if (chan->_state != AST_STATE_UP) {
if (ast_test_flag(&flags,OPT_SKIP)) {
/* 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);
return 0;
} else if (!ast_test_flag(&flags,OPT_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_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, read_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read Variable Application");

View File

@@ -1,120 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Matt O'Gorman <mogorman@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief ReadFile application -- Reads in a File for you.
*
* \author Matt O'Gorman <mogorman@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
static char *app_readfile = "ReadFile";
static char *readfile_synopsis = "ReadFile(varname=file,length)";
static char *readfile_descrip =
"ReadFile(varname=file,length)\n"
" Varname - Result stored here.\n"
" File - The name of the file to read.\n"
" Length - Maximum number of characters to capture.\n";
static int readfile_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
char *s, *varname=NULL, *file=NULL, *length=NULL, *returnvar=NULL;
int len=0;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "ReadFile require an argument!\n");
return -1;
}
u = ast_module_user_add(chan);
s = ast_strdupa(data);
varname = strsep(&s, "=");
file = strsep(&s, "|");
length = s;
if (!varname || !file) {
ast_log(LOG_ERROR, "No file or variable specified!\n");
ast_module_user_remove(u);
return -1;
}
if (length) {
if ((sscanf(length, "%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");

View File

@@ -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");

View File

@@ -1,386 +1,174 @@
/*
* 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/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.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"
"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"
"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"
"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";
" Record(filename:extension): Records from the channel into a given\n"
"filename. If the file exists it will be overwritten. The 'extension'\n"
"is the extension of the file type to be recorded (wav, gsm, etc).\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; /* Used so I don't have to typecast every use of *data */
int i = 0;
int j = 0;
struct ast_filestream *s = '\0';
struct ast_module_user *u;
struct ast_frame *f = NULL;
struct localuser *u;
struct ast_frame *f;
struct ast_dsp *sildet = NULL; /* silence detector dsp */
int totalsilence = 0;
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 */
int gottimeout = 0; /* did we timeout for maxduration exceeded? */
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;
vdata = data; /* explained above */
/* 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 (!vdata) { /* 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++;
for (; vdata[i] && (vdata[i] != ':') ; i++ ) {
if ((vdata[i] == '%') && (vdata[i+1] == 'd')) {
percentflag = 1; /* the wildcard is used */
}
}
if (!ext) {
ast_log(LOG_WARNING, "No extension specified to filename!\n");
ast_module_user_remove(u);
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);
if (i == strlen(vdata) ) {
ast_log(LOG_WARNING, "No extension found\n");
return -1;
}
fil[i] = vdata[i];
}
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;
}
}
fil[i++] = '\0';
for (; j < 10 && i < strlen(data); i++, j++)
ext[j] = vdata[i];
ext[j] = '\0';
/* 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, 256, fil, count);
count++;
} while (ast_fileexists(tmp, ext, chan->language) > 0);
pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
} while ( ast_fileexists(tmp, ext, chan->language) != -1 );
} else
ast_copy_string(tmp, filename, sizeof(tmp));
strncpy(tmp, fil, 256-1);
/* end of routine mentioned */
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);
return 0;
} else if (!option_noanswer) {
/* Otherwise answer unless we're supposed to record while on-hook */
res = ast_answer(chan);
}
LOCAL_USER_ADD(u);
if (chan->state != AST_STATE_UP) {
res = ast_answer(chan); /* Shouldn't need this, but checking to see if channel is already answered
* Theoretically asterisk should already have answered before running the app */
}
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) {
printf("Waiting on stream\n");
res = ast_waitstream(chan, "");
} else {
printf("streamfile failed\n");
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);
/* The end of beep code. Now the recording starts */
s = ast_writefile( tmp, ext, NULL, O_CREAT|O_TRUNC|O_WRONLY , 0, 0644);
/* 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;
}
if (s) {
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;
while ((f = ast_read(chan))) {
if (f->frametype == AST_FRAME_VOICE) {
res = ast_writestream(s, f);
if (res) {
ast_log(LOG_WARNING, "Problem writing frame\n");
break;
}
}
if (totalsilence > silence) {
/* Ended happily with silence */
if ((f->frametype == AST_FRAME_DTMF) &&
(f->subclass == '#')) {
ast_frfree(f);
gotsilence = 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:
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);
if (sildet)
ast_dsp_free(sildet);
}
ast_module_user_remove(u);
if (!f) {
ast_log(LOG_DEBUG, "Got hangup\n");
res = -1;
}
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);
return res;
}
static int unload_module(void)
int unload_module(void)
{
int res;
res = ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int load_module(void)
int load_module(void)
{
return ast_register_application(app, record_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial Record Application");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,126 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2003, 2006 Tilghman Lesher. All rights reserved.
* Copyright (c) 2006 Digium, Inc.
*
* 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/app.h"
static char *app_sayunixtime = "SayUnixTime";
static char *app_datetime = "DateTime";
static char *sayunixtime_synopsis = "Says a specified time in a custom format";
static char *sayunixtime_descrip =
"SayUnixTime([unixtime][|[timezone][|format]])\n"
" unixtime: time, in seconds since Jan 1, 1970. May be negative.\n"
" defaults to now.\n"
" 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";
static char *datetime_descrip =
"DateTime([unixtime][|[timezone][|format]])\n"
" unixtime: time, in seconds since Jan 1, 1970. May be negative.\n"
" defaults to now.\n"
" 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";
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;
time_t unixtime;
if (!data)
return 0;
parse = ast_strdupa(data);
u = ast_module_user_add(chan);
AST_STANDARD_APP_ARGS(args, parse);
ast_get_time_t(args.timeval, &unixtime, time(NULL), NULL);
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);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_sayunixtime);
res |= ast_unregister_application(app_datetime);
ast_module_user_hangup_all();
return res;
}
static 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);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Say time");

View File

@@ -1,143 +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 App to send DTMF digits
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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 *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";
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;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SendDTMF requires an argument (digits or *#aAbBcCdD)\n");
return 0;
}
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);
return res;
}
static char mandescr_playdtmf[] =
"Description: Plays a dtmf digit on the specified channel.\n"
"Variables: (all are required)\n"
" Channel: Channel name to send digit to\n"
" Digit: The dtmf digit to play\n";
static int manager_play_dtmf(struct mansession *s, const struct message *m)
{
const char *channel = astman_get_header(m, "Channel");
const char *digit = astman_get_header(m, "Digit");
struct ast_channel *chan = ast_get_channel_by_name_locked(channel);
if (!chan) {
astman_send_error(s, m, "Channel not specified");
return 0;
}
if (!digit) {
astman_send_error(s, m, "No digit specified");
ast_mutex_unlock(&chan->lock);
return 0;
}
ast_senddigit(chan, *digit);
ast_mutex_unlock(&chan->lock);
astman_send_ack(s, m, "DTMF successfully queued");
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app);
res |= ast_manager_unregister("PlayDTMF");
ast_module_user_hangup_all();
return res;
}
static int load_module(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);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send DTMF digits Application");

View File

@@ -1,130 +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 App to transmit a text message
*
* \author Mark Spencer <markster@digium.com>
*
* \note Requires support of sending text messages from channel driver
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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 const char *app = "SendText";
static const 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 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);
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);
/* 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);
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;
}
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, sendtext_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send Text Applications");

View File

@@ -1,159 +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 App to set callerid
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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"
static char *app2 = "SetCallerPres";
static char *synopsis2 = "Set CallerID Presentation";
static char *descrip2 =
" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n"
" Valid presentations are:\n"
"\n"
" allowed_not_screened : Presentation Allowed, Not Screened\n"
" allowed_passed_screen : Presentation Allowed, Passed Screen\n"
" allowed_failed_screen : Presentation Allowed, Failed Screen\n"
" allowed : Presentation Allowed, Network Number\n"
" prohib_not_screened : Presentation Prohibited, Not Screened\n"
" prohib_passed_screen : Presentation Prohibited, Passed Screen\n"
" prohib_failed_screen : Presentation Prohibited, Failed Screen\n"
" prohib : Presentation Prohibited, Network Number\n"
" unavailable : Number Unavailable\n"
"\n"
;
static int setcallerid_pres_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
int pres = -1;
u = ast_module_user_add(chan);
pres = ast_parse_caller_presentation(data);
if (pres < 0) {
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show application SetCallerPres')\n",
(char *) data);
ast_module_user_remove(u);
return 0;
}
chan->cid.cid_pres = pres;
ast_module_user_remove(u);
return 0;
}
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";
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 *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);
opt = strchr(tmp, '|');
if (opt) {
*opt = '\0';
opt++;
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);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app2);
res |= ast_unregister_application(app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application(app2, setcallerid_pres_exec, synopsis2, descrip2);
res |= ast_register_application(app, setcallerid_exec, synopsis, descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Set CallerID Application");

View File

@@ -1,175 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* 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.
*/
/*! \file
*
* \brief Applictions connected with CDR engine
*
* \author Justin Huff <jjhuff@mspin.net>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "asterisk/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 *setcdruserfield_descrip =
"[Synopsis]\n"
"SetCDRUserField(value)\n\n"
"[Description]\n"
"SetCDRUserField(value): Set the CDR 'user field' to value\n"
" The Call Data Record (CDR) user field is an extra field you\n"
" can use for data not stored anywhere else in the record.\n"
" CDR records can be used for billing or storing other arbitrary data\n"
" (I.E. telephone survey responses)\n"
" Also see AppendCDRUserField().\n"
"\nThis application is deprecated in favor of Set(CDR(userfield)=...)\n";
static char *setcdruserfield_app = "SetCDRUserField";
static char *setcdruserfield_synopsis = "Set the CDR user field";
static char *appendcdruserfield_descrip =
"[Synopsis]\n"
"AppendCDRUserField(value)\n\n"
"[Description]\n"
"AppendCDRUserField(value): Append value to the CDR user field\n"
" The Call Data Record (CDR) user field is an extra field you\n"
" can use for data not stored anywhere else in the record.\n"
" CDR records can be used for billing or storing other arbitrary data\n"
" (I.E. telephone survey responses)\n"
" Also see SetCDRUserField().\n"
"\nThis application is deprecated in favor of Set(CDR(userfield)=...)\n";
static char *appendcdruserfield_app = "AppendCDRUserField";
static char *appendcdruserfield_synopsis = "Append to the CDR user field";
static int action_setcdruserfield(struct mansession *s, const 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");
if (ast_strlen_zero(channel)) {
astman_send_error(s, m, "No Channel specified");
return 0;
}
if (ast_strlen_zero(userfield)) {
astman_send_error(s, m, "No UserField specified");
return 0;
}
c = ast_get_channel_by_name_locked(channel);
if (!c) {
astman_send_error(s, m, "No such channel");
return 0;
}
if (ast_true(append))
ast_cdr_appenduserfield(c, userfield);
else
ast_cdr_setuserfield(c, userfield);
ast_mutex_unlock(&c->lock);
astman_send_ack(s, m, "CDR Userfield Set");
return 0;
}
static int setcdruserfield_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
int res = 0;
static int dep_warning = 0;
u = ast_module_user_add(chan);
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);
return res;
}
static int appendcdruserfield_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
int res = 0;
static int dep_warning = 0;
u = ast_module_user_add(chan);
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);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(setcdruserfield_app);
res |= ast_unregister_application(appendcdruserfield_app);
res |= ast_manager_unregister("SetCDRUserField");
ast_module_user_hangup_all();
return res;
}
static 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");
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CDR user field apps");

View File

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

View File

@@ -1,133 +1,75 @@
/*
* 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 <stdlib.h>
#include <unistd.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/lock.h"
#include "asterisk/app.h"
static char *app = "Skel";
static char *synopsis =
"Skeleton application.";
static char *descrip = "This application is a template to build other applications from.\n"
" It shows you the basic structure to create your own Asterisk applications.\n";
enum {
OPTION_A = (1 << 0),
OPTION_B = (1 << 1),
OPTION_C = (1 << 2),
} option_flags;
enum {
OPTION_ARG_B = 0,
OPTION_ARG_C = 1,
/* This *must* be the last value in this enum! */
OPTION_ARG_ARRAY_SIZE = 2,
} option_args;
AST_APP_OPTIONS(app_opts,{
AST_APP_OPTION('a', OPTION_A),
AST_APP_OPTION_ARG('b', OPTION_B, OPTION_ARG_B),
AST_APP_OPTION_ARG('c', OPTION_C, OPTION_ARG_C),
});
#include <pthread.h>
static int app_exec(struct ast_channel *chan, void *data)
static char *tdesc = "Trivial skeleton Application";
static char *app = "skel";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
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);
}
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");

File diff suppressed because it is too large Load Diff

View File

@@ -1,121 +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 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"
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 *app = "SoftHangup";
static int softhangup_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
struct ast_channel *c=NULL;
char *options, *cut, *cdata, *match;
char name[AST_CHANNEL_NAME] = "";
int all = 0;
if (ast_strlen_zero(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');
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);
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
if(!all)
break;
}
c = ast_channel_walk_locked(c);
}
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, softhangup_exec, synopsis, desc);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Hangs up the requested channel");

View File

@@ -1,858 +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;
if (ast_playstream(fs))
return -1;
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] = "";
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);
/* 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(&current);
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 (f->subclass == '#') {
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));
/* 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) {
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");

View File

@@ -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 (label1) {
res = gosub_exec(chan, label1);
}
} else if (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");

View File

@@ -1,158 +1,96 @@
/*
* 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, 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 system commands
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#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/module.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.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/app.h"
#include "asterisk/options.h"
#include <pthread.h>
static char *tdesc = "Generic System() application";
static char *app = "System";
static char *app2 = "TrySystem";
static char *synopsis = "Execute a system command";
static char *synopsis2 = "Try executing a system command";
static char *chanvar = "SYSTEMSTATUS";
static char *descrip =
" System(command): Executes a command by using system(). If the command\n"
"fails, the console should report a fallthrough. \n"
"Result of execution is returned in the SYSTEMSTATUS channel variable:\n"
" FAILURE Could not execute the specified command\n"
" SUCCESS Specified command successfully executed\n"
"\n"
"Old behaviour:\n"
"If the command itself executes but is in error, and if there exists\n"
"a priority n + 101, where 'n' is the priority of the current instance,\n"
"then the channel will be setup to continue at that priority level.\n"
"Note that this jump functionality has been deprecated and will only occur\n"
"if the global priority jumping option is enabled in extensions.conf.\n";
" System(command): Executes a command by using system(). Returns -1 on\n"
"failure to execute the specified command. If the command itself executes\n"
"but is in error, and if there exists a priority n + 101, where 'n' is the\n"
"priority of the current instance, then the channel will be setup to\n"
"continue at that priority level. Otherwise, System returns 0.\n";
static char *descrip2 =
" TrySystem(command): Executes a command by using system().\n"
"on any situation.\n"
"Result of execution is returned in the SYSTEMSTATUS channel variable:\n"
" FAILURE Could not execute the specified command\n"
" SUCCESS Specified command successfully executed\n"
" APPERROR Specified command successfully executed, but returned error code\n"
"\n"
"Old behaviour:\nIf the command itself executes but is in error, and if\n"
"there exists a priority n + 101, where 'n' is the priority of the current\n"
"instance, then the channel will be setup to continue at that\n"
"priority level. Otherwise, System will terminate.\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int system_exec_helper(struct ast_channel *chan, void *data, int failmode)
static int skel_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct ast_module_user *u;
if (ast_strlen_zero(data)) {
struct localuser *u;
if (!data) {
ast_log(LOG_WARNING, "System requires an argument(command)\n");
pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
return failmode;
return -1;
}
u = ast_module_user_add(chan);
LOCAL_USER_ADD(u);
/* Do our thing here */
res = ast_safe_system((char *)data);
if ((res < 0) && (errno != ECHILD)) {
ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
res = failmode;
res = system((char *)data);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to execute '%s'\n", data);
res = -1;
} else if (res == 127) {
ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
pbx_builtin_setvar_helper(chan, chanvar, "FAILURE");
res = failmode;
ast_log(LOG_WARNING, "Unable to execute '%s'\n", data);
res = -1;
} else {
if (res < 0)
res = 0;
if (ast_opt_priority_jumping && res)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
if (res != 0)
pbx_builtin_setvar_helper(chan, chanvar, "APPERROR");
else
pbx_builtin_setvar_helper(chan, chanvar, "SUCCESS");
if (res && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority+=100;
res = 0;
}
ast_module_user_remove(u);
}
LOCAL_USER_REMOVE(u);
return res;
}
static int system_exec(struct ast_channel *chan, void *data)
int unload_module(void)
{
return system_exec_helper(chan, data, -1);
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
static int trysystem_exec(struct ast_channel *chan, void *data)
int load_module(void)
{
return system_exec_helper(chan, data, 0);
return ast_register_application(app, skel_exec, synopsis, descrip);
}
static int unload_module(void)
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
res = ast_unregister_application(app);
res |= ast_unregister_application(app2);
ast_module_user_hangup_all();
STANDARD_USECOUNT(res);
return res;
}
static int load_module(void)
char *key()
{
int res;
res = ast_register_application(app2, trysystem_exec, synopsis2, descrip2);
res |= ast_register_application(app, system_exec, synopsis, descrip);
return res;
return ASTERISK_GPL_KEY;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Generic System() application");

View File

@@ -1,227 +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 Playback a file with audio detect
*
* \author Mark Spencer <markster@digium.com>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "asterisk/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/dsp.h"
static char *app = "BackgroundDetect";
static char *synopsis = "Background a file with talk detect";
static char *descrip =
" BackgroundDetect(filename[|sil[|min|[max]]]): Plays back a given\n"
"filename, waiting for interruption from a given digit (the digit must\n"
"start the beginning of a valid extension, or it will be ignored).\n"
"During the playback of the file, audio is monitored in the receive\n"
"direction, and if a period of non-silence which is greater than 'min' ms\n"
"yet less than 'max' ms is followed by silence for at least 'sil' ms then\n"
"the audio playback is aborted and processing jumps to the 'talk' extension\n"
"if available. If unspecified, sil, min, and max default to 1000, 100, and\n"
"infinity respectively.\n";
static int background_detect_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *tmp;
char *options;
char *stringp;
struct ast_frame *fr;
int notsilent=0;
struct timeval start = { 0, 0};
int sil = 1000;
int min = 100;
int max = -1;
int x;
int origrformat=0;
struct ast_dsp *dsp;
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "BackgroundDetect requires an argument (filename)\n");
return -1;
}
u = ast_module_user_add(chan);
tmp = ast_strdupa(data);
stringp=tmp;
strsep(&stringp, "|");
options = strsep(&stringp, "|");
if (options) {
if ((sscanf(options, "%d", &x) == 1) && (x > 0))
sil = x;
options = strsep(&stringp, "|");
if (options) {
if ((sscanf(options, "%d", &x) == 1) && (x > 0))
min = x;
options = strsep(&stringp, "|");
if (options) {
if ((sscanf(options, "%d", &x) == 1) && (x > 0))
max = x;
}
}
}
ast_log(LOG_DEBUG, "Preparing detect of '%s', sil=%d,min=%d,max=%d\n",
tmp, sil, min, max);
if (chan->_state != AST_STATE_UP) {
/* Otherwise answer unless we're supposed to send this while on-hook */
res = ast_answer(chan);
}
if (!res) {
origrformat = chan->readformat;
if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR)))
ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
}
if (!(dsp = ast_dsp_new())) {
ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
res = -1;
}
if (!res) {
ast_stopstream(chan);
res = ast_streamfile(chan, tmp, chan->language);
if (!res) {
while(chan->stream) {
res = ast_sched_wait(chan->sched);
if ((res < 0) && !chan->timingfunc) {
res = 0;
break;
}
if (res < 0)
res = 1000;
res = ast_waitfor(chan, res);
if (res < 0) {
ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
break;
} else if (res > 0) {
fr = ast_read(chan);
if (!fr) {
res = -1;
break;
} else if (fr->frametype == AST_FRAME_DTMF) {
char t[2];
t[0] = fr->subclass;
t[1] = '\0';
if (ast_canmatch_extension(chan, chan->context, t, 1, chan->cid.cid_num)) {
/* They entered a valid extension, or might be anyhow */
res = fr->subclass;
ast_frfree(fr);
break;
}
} else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR)) {
int totalsilence;
int ms;
res = ast_dsp_silence(dsp, fr, &totalsilence);
if (res && (totalsilence > sil)) {
/* We've been quiet a little while */
if (notsilent) {
/* We had heard some talking */
ms = ast_tvdiff_ms(ast_tvnow(), start);
ms -= sil;
if (ms < 0)
ms = 0;
if ((ms > min) && ((max < 0) || (ms < max))) {
char ms_str[10];
ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
/* Save detected talk time (in milliseconds) */
sprintf(ms_str, "%d", ms );
pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
ast_goto_if_exists(chan, chan->context, "talk", 1);
res = 0;
ast_frfree(fr);
break;
} else
ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
notsilent = 0;
}
} else {
if (!notsilent) {
/* Heard some audio, mark the begining of the token */
start = ast_tvnow();
ast_log(LOG_DEBUG, "Start of voice token!\n");
notsilent = 1;
}
}
}
ast_frfree(fr);
}
ast_sched_runq(chan->sched);
}
ast_stopstream(chan);
} else {
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
res = 0;
}
}
if (res > -1) {
if (origrformat && ast_set_read_format(chan, origrformat)) {
ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n",
chan->name, ast_getformatname(origrformat));
}
}
if (dsp)
ast_dsp_free(dsp);
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, background_detect_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Playback with Talk Detection");

View File

@@ -1,512 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* Mark Spencer <markster@digium.com>
* Russell Bryant <russelb@clemson.edu>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Applications to test connection and produce report in text file
*
* \author Mark Spencer <markster@digium.com>
* \author Russell Bryant <russelb@clemson.edu>
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "asterisk/channel.h"
#include "asterisk/options.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
static char *tests_descrip =
"TestServer(): Perform test server function and write call report.\n"
"Results stored in /var/log/asterisk/testreports/<testid>-server.txt";
static char *tests_app = "TestServer";
static char *tests_synopsis = "Execute Interface Test Server";
static char *testc_descrip =
"TestClient(testid): Executes test client with given testid.\n"
"Results stored in /var/log/asterisk/testreports/<testid>-client.txt";
static char *testc_app = "TestClient";
static char *testc_synopsis = "Execute Interface Test Client";
static int measurenoise(struct ast_channel *chan, int ms, char *who)
{
int res=0;
int mssofar;
int noise=0;
int samples=0;
int x;
short *foo;
struct timeval start;
struct ast_frame *f;
int rformat;
rformat = chan->readformat;
if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_NOTICE, "Unable to set to linear mode!\n");
return -1;
}
start = ast_tvnow();
for(;;) {
mssofar = ast_tvdiff_ms(ast_tvnow(), start);
if (mssofar > ms)
break;
res = ast_waitfor(chan, ms - mssofar);
if (res < 1)
break;
f = ast_read(chan);
if (!f) {
res = -1;
break;
}
if ((f->frametype == AST_FRAME_VOICE) && (f->subclass == AST_FORMAT_SLINEAR)) {
foo = (short *)f->data;
for (x=0;x<f->samples;x++) {
noise += abs(foo[x]);
samples++;
}
}
ast_frfree(f);
}
if (rformat) {
if (ast_set_read_format(chan, rformat)) {
ast_log(LOG_NOTICE, "Unable to restore original format!\n");
return -1;
}
}
if (res < 0)
return res;
if (!samples) {
ast_log(LOG_NOTICE, "No samples were received from the other side!\n");
return -1;
}
ast_log(LOG_DEBUG, "%s: Noise: %d, samples: %d, avg: %d\n", who, noise, samples, noise / samples);
return (noise / samples);
}
static int sendnoise(struct ast_channel *chan, int ms)
{
int res;
res = ast_tonepair_start(chan, 1537, 2195, ms, 8192);
if (!res) {
res = ast_waitfordigit(chan, ms);
ast_tonepair_stop(chan);
}
return res;
}
static int testclient_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
int res = 0;
char *testid=data;
char fn[80];
char serverver[80];
FILE *f;
/* Check for test id */
if (ast_strlen_zero(testid)) {
ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n");
return -1;
}
u = ast_module_user_add(chan);
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
/* Wait a few just to be sure things get started */
res = ast_safe_sleep(chan, 3000);
/* Transmit client version */
if (!res)
res = ast_dtmf_stream(chan, NULL, "8378*1#", 0);
if (option_debug)
ast_log(LOG_DEBUG, "Transmit client version\n");
/* Read server version */
if (option_debug)
ast_log(LOG_DEBUG, "Read server version\n");
if (!res)
res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0);
if (res > 0)
res = 0;
if (option_debug)
ast_log(LOG_DEBUG, "server version: %s\n", serverver);
if (res > 0)
res = 0;
if (!res)
res = ast_safe_sleep(chan, 1000);
/* Send test id */
if (!res)
res = ast_dtmf_stream(chan, NULL, testid, 0);
if (!res)
res = ast_dtmf_stream(chan, NULL, "#", 0);
if (option_debug)
ast_log(LOG_DEBUG, "send test identifier: %s\n", testid);
if ((res >=0) && (!ast_strlen_zero(testid))) {
/* Make the directory to hold the test results in case it's not there */
snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
mkdir(fn, 0777);
snprintf(fn, sizeof(fn), "%s/testresults/%s-client.txt", ast_config_AST_LOG_DIR, testid);
if ((f = fopen(fn, "w+"))) {
setlinebuf(f);
fprintf(f, "CLIENTCHAN: %s\n", chan->name);
fprintf(f, "CLIENTTEST ID: %s\n", testid);
fprintf(f, "ANSWER: PASS\n");
res = 0;
if (!res) {
/* Step 1: Wait for "1" */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 2. Wait DTMF 1\n");
res = ast_waitfordigit(chan, 3000);
fprintf(f, "WAIT DTMF 1: %s\n", (res != '1') ? "FAIL" : "PASS");
if (res == '1')
res = 0;
else
res = -1;
}
if (!res)
res = ast_safe_sleep(chan, 1000);
if (!res) {
/* Step 2: Send "2" */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 2. Send DTMF 2\n");
res = ast_dtmf_stream(chan, NULL, "2", 0);
fprintf(f, "SEND DTMF 2: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 3: Wait one second */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 3. Wait one second\n");
res = ast_safe_sleep(chan, 1000);
fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 4: Measure noise */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 4. Measure noise\n");
res = measurenoise(chan, 5000, "TestClient");
fprintf(f, "MEASURENOISE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
if (res > 0)
res = 0;
}
if (!res) {
/* Step 5: Wait for "4" */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 5. Wait DTMF 4\n");
res = ast_waitfordigit(chan, 3000);
fprintf(f, "WAIT DTMF 4: %s\n", (res != '4') ? "FAIL" : "PASS");
if (res == '4')
res = 0;
else
res = -1;
}
if (!res) {
/* Step 6: Transmit tone noise */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 6. Transmit tone\n");
res = sendnoise(chan, 6000);
fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS");
}
if (!res || (res == '5')) {
/* Step 7: Wait for "5" */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 7. Wait DTMF 5\n");
if (!res)
res = ast_waitfordigit(chan, 3000);
fprintf(f, "WAIT DTMF 5: %s\n", (res != '5') ? "FAIL" : "PASS");
if (res == '5')
res = 0;
else
res = -1;
}
if (!res) {
/* Step 8: Wait one second */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 8. Wait one second\n");
res = ast_safe_sleep(chan, 1000);
fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 9: Measure noise */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 6. Measure tone\n");
res = measurenoise(chan, 4000, "TestClient");
fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
if (res > 0)
res = 0;
}
if (!res) {
/* Step 10: Send "7" */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 7. Send DTMF 7\n");
res = ast_dtmf_stream(chan, NULL, "7", 0);
fprintf(f, "SEND DTMF 7: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res =0;
}
if (!res) {
/* Step 11: Wait for "8" */
if (option_debug)
ast_log(LOG_DEBUG, "TestClient: 11. Wait DTMF 8\n");
res = ast_waitfordigit(chan, 3000);
fprintf(f, "WAIT DTMF 8: %s\n", (res != '8') ? "FAIL" : "PASS");
if (res == '8')
res = 0;
else
res = -1;
}
if (option_debug && !res ) {
/* Step 12: Hangup! */
ast_log(LOG_DEBUG, "TestClient: 12. Hangup\n");
}
if (option_debug)
ast_log(LOG_DEBUG, "-- TEST COMPLETE--\n");
fprintf(f, "-- END TEST--\n");
fclose(f);
res = -1;
} else
res = -1;
} else {
ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", chan->name);
res = -1;
}
ast_module_user_remove(u);
return res;
}
static int testserver_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
int res = 0;
char testid[80]="";
char fn[80];
FILE *f;
u = ast_module_user_add(chan);
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
/* Read version */
if (option_debug)
ast_log(LOG_DEBUG, "Read client version\n");
if (!res)
res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
if (res > 0)
res = 0;
if (option_debug) {
ast_log(LOG_DEBUG, "client version: %s\n", testid);
ast_log(LOG_DEBUG, "Transmit server version\n");
}
res = ast_safe_sleep(chan, 1000);
if (!res)
res = ast_dtmf_stream(chan, NULL, "8378*1#", 0);
if (res > 0)
res = 0;
if (!res)
res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
if (option_debug)
ast_log(LOG_DEBUG, "read test identifier: %s\n", testid);
/* Check for sneakyness */
if (strchr(testid, '/'))
res = -1;
if ((res >=0) && (!ast_strlen_zero(testid))) {
/* Got a Test ID! Whoo hoo! */
/* Make the directory to hold the test results in case it's not there */
snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
mkdir(fn, 0777);
snprintf(fn, sizeof(fn), "%s/testresults/%s-server.txt", ast_config_AST_LOG_DIR, testid);
if ((f = fopen(fn, "w+"))) {
setlinebuf(f);
fprintf(f, "SERVERCHAN: %s\n", chan->name);
fprintf(f, "SERVERTEST ID: %s\n", testid);
fprintf(f, "ANSWER: PASS\n");
ast_log(LOG_DEBUG, "Processing Test ID '%s'\n", testid);
res = ast_safe_sleep(chan, 1000);
if (!res) {
/* Step 1: Send "1" */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 1. Send DTMF 1\n");
res = ast_dtmf_stream(chan, NULL, "1", 0);
fprintf(f, "SEND DTMF 1: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 2: Wait for "2" */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 2. Wait DTMF 2\n");
res = ast_waitfordigit(chan, 3000);
fprintf(f, "WAIT DTMF 2: %s\n", (res != '2') ? "FAIL" : "PASS");
if (res == '2')
res = 0;
else
res = -1;
}
if (!res) {
/* Step 3: Measure noise */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 3. Measure noise\n");
res = measurenoise(chan, 6000, "TestServer");
fprintf(f, "MEASURENOISE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
if (res > 0)
res = 0;
}
if (!res) {
/* Step 4: Send "4" */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 4. Send DTMF 4\n");
res = ast_dtmf_stream(chan, NULL, "4", 0);
fprintf(f, "SEND DTMF 4: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 5: Wait one second */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 5. Wait one second\n");
res = ast_safe_sleep(chan, 1000);
fprintf(f, "WAIT 1 SEC: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 6: Measure noise */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 6. Measure tone\n");
res = measurenoise(chan, 4000, "TestServer");
fprintf(f, "MEASURETONE: %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
if (res > 0)
res = 0;
}
if (!res) {
/* Step 7: Send "5" */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 7. Send DTMF 5\n");
res = ast_dtmf_stream(chan, NULL, "5", 0);
fprintf(f, "SEND DTMF 5: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 8: Transmit tone noise */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 8. Transmit tone\n");
res = sendnoise(chan, 6000);
fprintf(f, "SENDTONE: %s\n", (res < 0) ? "FAIL" : "PASS");
}
if (!res || (res == '7')) {
/* Step 9: Wait for "7" */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 9. Wait DTMF 7\n");
if (!res)
res = ast_waitfordigit(chan, 3000);
fprintf(f, "WAIT DTMF 7: %s\n", (res != '7') ? "FAIL" : "PASS");
if (res == '7')
res = 0;
else
res = -1;
}
if (!res)
res = ast_safe_sleep(chan, 1000);
if (!res) {
/* Step 10: Send "8" */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 10. Send DTMF 8\n");
res = ast_dtmf_stream(chan, NULL, "8", 0);
fprintf(f, "SEND DTMF 8: %s\n", (res < 0) ? "FAIL" : "PASS");
if (res > 0)
res = 0;
}
if (!res) {
/* Step 11: Wait for hangup to arrive! */
if (option_debug)
ast_log(LOG_DEBUG, "TestServer: 11. Waiting for hangup\n");
res = ast_safe_sleep(chan, 10000);
fprintf(f, "WAIT HANGUP: %s\n", (res < 0) ? "PASS" : "FAIL");
}
ast_log(LOG_NOTICE, "-- TEST COMPLETE--\n");
fprintf(f, "-- END TEST--\n");
fclose(f);
res = -1;
} else
res = -1;
} else {
ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", chan->name);
res = -1;
}
ast_module_user_remove(u);
return res;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(testc_app);
res |= ast_unregister_application(tests_app);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application(testc_app, testclient_exec, testc_synopsis, testc_descrip);
res |= ast_register_application(tests_app, testserver_exec, tests_synopsis, tests_descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Interface Test Application");

View File

@@ -1,156 +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 Transfer a caller
*
* \author Mark Spencer <markster@digium.com>
*
* Requires transfer support from channel driver
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.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/app.h"
static const char *app = "Transfer";
static const char *synopsis = "Transfer caller to remote extension";
static const char *descrip =
" Transfer([Tech/]dest[|options]): Requests the remote caller be transferred\n"
"to a given destination. If TECH (SIP, IAX2, LOCAL etc) is used, only\n"
"an incoming call with the same channel technology will be transfered.\n"
"Note that for SIP, if you transfer before call is setup, a 302 redirect\n"
"SIP message will be returned to the caller.\n"
"\nThe result of the application will be reported in the TRANSFERSTATUS\n"
"channel variable:\n"
" SUCCESS Transfer succeeded\n"
" FAILURE Transfer failed\n"
" UNSUPPORTED Transfer unsupported by channel driver\n"
"The option string many contain the following character:\n"
"'j' -- jump to n+101 priority if the channel transfer attempt\n"
" fails\n";
static int transfer_exec(struct ast_channel *chan, void *data)
{
int res;
int len;
struct ast_module_user *u;
char *slash;
char *tech = NULL;
char *dest = NULL;
char *status;
char *parse;
int priority_jump = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(dest);
AST_APP_ARG(options);
);
u = ast_module_user_add(chan);
if (ast_strlen_zero((char *)data)) {
ast_log(LOG_WARNING, "Transfer requires an argument ([Tech/]destination[|options])\n");
ast_module_user_remove(u);
pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", "FAILURE");
return 0;
} else
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
if (args.options) {
if (strchr(args.options, 'j'))
priority_jump = 1;
}
dest = args.dest;
if ((slash = strchr(dest, '/')) && (len = (slash - dest))) {
tech = dest;
dest = slash + 1;
/* Allow execution only if the Tech/destination agrees with the type of the channel */
if (strncasecmp(chan->tech->type, tech, len)) {
pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", "FAILURE");
ast_module_user_remove(u);
return 0;
}
}
/* Check if the channel supports transfer before we try it */
if (!chan->tech->transfer) {
pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", "UNSUPPORTED");
ast_module_user_remove(u);
return 0;
}
res = ast_transfer(chan, dest);
if (res < 0) {
status = "FAILURE";
if (priority_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
res = 0;
} else {
status = "SUCCESS";
res = 0;
}
pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", status);
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, transfer_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Transfer");

View File

@@ -1,173 +1,137 @@
/*
* Asterisk -- An open source telephony toolkit.
* Asterisk -- A telephony toolkit for Linux.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* App to transmit a URL
*
* 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 URL
*
* \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/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 <pthread.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 = "Send URL Applications";
static char *app = "SendURL";
static char *synopsis = "Send a URL";
static char *descrip =
" SendURL(URL[|option]): Requests client go to URL (IAX2) or sends the \n"
"URL to the client (other channels).\n"
"Result is returned in the SENDURLSTATUS channel variable:\n"
" SUCCESS URL successfully sent to client\n"
" FAILURE Failed to send URL\n"
" NOLOAD Client failed to load URL (wait enabled)\n"
" UNSUPPORTED Channel does not support URL transport\n"
"\n"
"If the option 'wait' is specified, execution will wait for an\n"
"acknowledgement that the URL has been loaded before continuing\n"
"\n"
"If jumping is specified as an option (the 'j' flag), the client does not\n"
"support Asterisk \"html\" transport, and there exists a step with priority\n"
"n + 101, then execution will continue at that step.\n"
"\n"
"SendURL continues normally if the URL was sent correctly or if the channel\n"
"does not support HTML transport. Otherwise, the channel is hung up.\n";
" SendURL(URL[|option]): Requests client go to URL. If the client\n"
"does not support html 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"
"SendURL only returns 0 if the URL was sent correctly or if\n"
"the channel does not support HTML transport, and -1 otherwise.\n"
"If the option 'wait' is specified, execution will wait for an\n"
"acknowledgement that the URL has been loaded before continuing\n"
"and will return -1 if the peer is unable to load the URL\n";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
static int sendurl_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct ast_module_user *u;
char *tmp;
struct localuser *u;
char tmp[256];
char *options;
int local_option_wait=0;
int local_option_jump = 0;
int option_wait=0;
struct ast_frame *f;
char *stringp=NULL;
char *status = "FAILURE";
if (ast_strlen_zero(data)) {
if (!data || !strlen((char *)data)) {
ast_log(LOG_WARNING, "SendURL requires an argument (URL)\n");
pbx_builtin_setvar_helper(chan, "SENDURLSTATUS", status);
return -1;
}
u = ast_module_user_add(chan);
tmp = ast_strdupa(data);
stringp=tmp;
strsep(&stringp, "|");
options = strsep(&stringp, "|");
strncpy(tmp, (char *)data, sizeof(tmp)-1);
strtok(tmp, "|");
options = strtok(NULL, "|");
if (options && !strcasecmp(options, "wait"))
local_option_wait = 1;
if (options && !strcasecmp(options, "j"))
local_option_jump = 1;
option_wait = 1;
LOCAL_USER_ADD(u);
if (!ast_channel_supports_html(chan)) {
/* Does not support transport */
if (local_option_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
pbx_builtin_setvar_helper(chan, "SENDURLSTATUS", "UNSUPPORTED");
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;
}
res = ast_channel_sendurl(chan, tmp);
if (res == -1) {
pbx_builtin_setvar_helper(chan, "SENDURLSTATUS", "FAILURE");
ast_module_user_remove(u);
return res;
}
status = "SUCCESS";
if (local_option_wait) {
for(;;) {
/* Wait for an event */
res = ast_waitfor(chan, -1);
if (res < 0)
break;
f = ast_read(chan);
if (!f) {
res = -1;
status = "FAILURE";
break;
}
if (f->frametype == AST_FRAME_HTML) {
switch(f->subclass) {
case AST_HTML_LDCOMPLETE:
res = 0;
ast_frfree(f);
status = "NOLOAD";
goto out;
if (res > -1) {
if (option_wait) {
for(;;) {
/* Wait for an event */
res = ast_waitfor(chan, -1);
if (res < 0)
break;
case AST_HTML_NOSUPPORT:
/* Does not support transport */
status ="UNSUPPORTED";
if (local_option_jump || ast_opt_priority_jumping)
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
res = 0;
ast_frfree(f);
goto out;
f = ast_read(chan);
if (!f) {
res = -1;
break;
default:
ast_log(LOG_WARNING, "Don't know what to do with HTML subclass %d\n", f->subclass);
};
}
if (f->frametype == AST_FRAME_HTML) {
switch(f->subclass) {
case AST_HTML_LDCOMPLETE:
res = 0;
ast_frfree(f);
goto out;
break;
case AST_HTML_NOSUPPORT:
/* Does not support transport */
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority += 100;
res = 0;
goto out;
break;
default:
ast_log(LOG_WARNING, "Don't know what to do with HTML subclass %d\n", f->subclass);
};
}
ast_frfree(f);
}
ast_frfree(f);
}
}
}
out:
pbx_builtin_setvar_helper(chan, "SENDURLSTATUS", status);
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, sendurl_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send URL Applications");
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@@ -1,109 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2005, Digium, Inc.
*
* 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 UserEvent application -- send manager event
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.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/manager.h"
#include "asterisk/app.h"
static char *app = "UserEvent";
static char *synopsis = "Send an arbitrary event to the manager interface";
static char *descrip =
" UserEvent(eventname[|body]): Sends an arbitrary event to the manager\n"
"interface, with an optional body representing additional arguments. The\n"
"body may be specified as a | delimeted list of headers. Each additional\n"
"argument will be placed on a new line in the event. The format of the\n"
"event will be:\n"
" Event: UserEvent\n"
" UserEvent: <specified event name>\n"
" [body]\n"
"If no body is specified, only Event and UserEvent headers will be present.\n";
static int userevent_exec(struct ast_channel *chan, void *data)
{
struct ast_module_user *u;
char *parse, buf[2048] = "";
int x, buflen = 0;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(eventname);
AST_APP_ARG(extra)[100];
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "UserEvent requires an argument (eventname|optional event body)\n");
return -1;
}
u = ast_module_user_add(chan);
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
for (x = 0; x < args.argc - 1; x++) {
ast_copy_string(buf + buflen, args.extra[x], sizeof(buf) - buflen - 2);
buflen += strlen(args.extra[x]);
ast_copy_string(buf + buflen, "\r\n", 3);
buflen += 2;
}
manager_event(EVENT_FLAG_USER, "UserEvent", "UserEvent: %s\r\n%s", args.eventname, buf);
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, userevent_exec, synopsis, descrip);
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Custom User Event Application");

View File

@@ -1,168 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (c) 2004 - 2005 Tilghman Lesher. All rights reserved.
*
* Tilghman Lesher <app_verbose_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 Verbose logging application
*
* \author Tilghman Lesher <app_verbose_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/options.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
static char *app_verbose = "Verbose";
static char *verbose_synopsis = "Send arbitrary text to verbose output";
static char *verbose_descrip =
"Verbose([<level>|]<message>)\n"
" level must be an integer value. If not specified, defaults to 0.\n";
static char *app_log = "Log";
static char *log_synopsis = "Send arbitrary text to a selected log level";
static char *log_descrip =
"Log(<level>|<message>)\n"
" level must be one of ERROR, WARNING, NOTICE, DEBUG, VERBOSE, DTMF\n";
static int verbose_exec(struct ast_channel *chan, void *data)
{
char *vtext;
int vsize;
struct ast_module_user *u;
u = ast_module_user_add(chan);
if (data) {
char *tmp;
vtext = ast_strdupa(data);
tmp = strsep(&vtext, "|");
if (vtext) {
if (sscanf(tmp, "%d", &vsize) != 1) {
vsize = 0;
ast_log(LOG_WARNING, "'%s' is not a verboser number\n", vtext);
}
} else {
vtext = tmp;
vsize = 0;
}
if (option_verbose >= vsize) {
switch (vsize) {
case 0:
ast_verbose("%s\n", vtext);
break;
case 1:
ast_verbose(VERBOSE_PREFIX_1 "%s\n", vtext);
break;
case 2:
ast_verbose(VERBOSE_PREFIX_2 "%s\n", vtext);
break;
case 3:
ast_verbose(VERBOSE_PREFIX_3 "%s\n", vtext);
break;
default:
ast_verbose(VERBOSE_PREFIX_4 "%s\n", vtext);
}
}
}
ast_module_user_remove(u);
return 0;
}
static int log_exec(struct ast_channel *chan, void *data)
{
char *level, *ltext;
struct ast_module_user *u;
int lnum = -1;
char extension[AST_MAX_EXTENSION + 5], context[AST_MAX_EXTENSION + 2];
u = ast_module_user_add(chan);
if (ast_strlen_zero(data)) {
ast_module_user_remove(u);
return 0;
}
ltext = ast_strdupa(data);
level = strsep(&ltext, "|");
if (!strcasecmp(level, "ERROR")) {
lnum = __LOG_ERROR;
} else if (!strcasecmp(level, "WARNING")) {
lnum = __LOG_WARNING;
} else if (!strcasecmp(level, "NOTICE")) {
lnum = __LOG_NOTICE;
} else if (!strcasecmp(level, "DEBUG")) {
lnum = __LOG_DEBUG;
} else if (!strcasecmp(level, "VERBOSE")) {
lnum = __LOG_VERBOSE;
} else if (!strcasecmp(level, "DTMF")) {
lnum = __LOG_DTMF;
} else if (!strcasecmp(level, "EVENT")) {
lnum = __LOG_EVENT;
} else {
ast_log(LOG_ERROR, "Unknown log level: '%s'\n", level);
}
if (lnum > -1) {
snprintf(context, sizeof(context), "@ %s", chan->context);
snprintf(extension, sizeof(extension), "Ext. %s", chan->exten);
ast_log(lnum, extension, chan->priority, context, "%s\n", ltext);
}
ast_module_user_remove(u);
return 0;
}
static int unload_module(void)
{
int res;
res = ast_unregister_application(app_verbose);
res |= ast_unregister_application(app_log);
ast_module_user_hangup_all();
return res;
}
static int load_module(void)
{
int res;
res = ast_register_application(app_log, log_exec, log_synopsis, log_descrip);
res |= ast_register_application(app_verbose, verbose_exec, verbose_synopsis, verbose_descrip);
return res;
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Send verbose output");

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