mirror of
https://github.com/asterisk/asterisk.git
synced 2026-01-20 08:44:06 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f72b2febe | ||
|
|
a1bf01718e | ||
|
|
0a5d88d0f8 |
@@ -1 +0,0 @@
|
||||
9
|
||||
@@ -1 +0,0 @@
|
||||
9
|
||||
58
BUGS
58
BUGS
@@ -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
|
||||
|
||||
272
CHANGES
272
CHANGES
@@ -1,127 +1,145 @@
|
||||
Changes since Asterisk 1.2.0-beta2:
|
||||
|
||||
* Cygwin build system portability
|
||||
* Optional generation of outbound silence during channel recording
|
||||
|
||||
Changes since Asterisk 1.2.0-beta1:
|
||||
|
||||
* Many, many bug fixes
|
||||
* Documentation and sample configuration updates
|
||||
* Vastly improved presence/subscription support in the SIP channel driver
|
||||
* A new (experimental) mISDN channel driver
|
||||
* A new monitoring application (MixMonitor)
|
||||
* More portability fixes for non-Linux platforms
|
||||
* New dialplan functions replacing old applications
|
||||
* Significant deadlock and performance upgrades for the Manager interface
|
||||
* An upgrade to the 'new' dialplan expression parser for all users
|
||||
* New Zaptel echo cancellers with improved performance
|
||||
* Support for the latest OSP toolkit from TransNexus
|
||||
* Support user-controlled volume adjustment in MeetMe application
|
||||
* More dialplan applications now return status variables instead of priority jumping
|
||||
* Much more powerful ENUM support in the dialplan
|
||||
* SIP domain support for authentication and virtual hosting
|
||||
* Many PRI protocol updates and fixes, including more complete Q.SIG support
|
||||
* New applications: Pickup() and Page()
|
||||
|
||||
Changes since Asterisk 1.0:
|
||||
|
||||
This list currently only containts changes made from the end of November until
|
||||
March 26, 2005.
|
||||
|
||||
* Add new applications:
|
||||
-- AgentMonitorOutgoing
|
||||
-- Curl
|
||||
-- ExecIf
|
||||
-- ExecIfTime
|
||||
-- IAX2Provision
|
||||
-- MacroExit
|
||||
-- MacroIf
|
||||
-- PauseQueueMember
|
||||
-- ReadFile
|
||||
-- SetRDNIS
|
||||
-- SIPAddHeader
|
||||
-- SIPGetHeader
|
||||
-- StartMusicOnHold
|
||||
-- StopMusicOnHold
|
||||
-- UnpauseQueueMember
|
||||
-- WaitForSilence
|
||||
-- While / EndWhile
|
||||
* app Answer
|
||||
-- added delay option
|
||||
* app ChanIsAvail
|
||||
-- added 's' option
|
||||
* app Dial
|
||||
-- add option to specify the class for musiconhold with m option
|
||||
* app EnumLookup
|
||||
-- added "reload enum" for configuration
|
||||
* app Goto
|
||||
-- added relative priorities
|
||||
* app GotoIf
|
||||
-- added relative priorities
|
||||
* app MeetMe
|
||||
-- added 'i' option
|
||||
-- added 'r' option
|
||||
-- added 'T' option
|
||||
-- added 'P' option
|
||||
-- added 'c' option
|
||||
-- added adminpin to meetme.conf
|
||||
-- added reload command
|
||||
* app PrivacyManager
|
||||
-- add config file privacy.conf
|
||||
* app queue
|
||||
-- queues.conf
|
||||
-- added persistentmembers option to queues.conf
|
||||
-- changed music option to musiconhold
|
||||
-- added weight option
|
||||
-- added note about why agent groups probably shouldn't be used
|
||||
-- added timeoutrestart option
|
||||
* app Read
|
||||
-- added attempts parameter
|
||||
-- added timeout parameter
|
||||
* app Record
|
||||
-- added 'q' option
|
||||
* app SendDTMF
|
||||
-- add timeout option
|
||||
* app SMS
|
||||
-- document alternative syntax for queueing messages
|
||||
* app Voicemail
|
||||
-- add info about VM_CATEGORY
|
||||
-- voicemail.conf
|
||||
-- added usedirectory option
|
||||
-- added VM_CIDNUM and VM_CIDNAME in message config
|
||||
* chan IAX2
|
||||
-- new jitterbuffer
|
||||
-- added setvar option
|
||||
-- added regex to iax2 show peers/users
|
||||
-- allow multiple bindaddr lines in iax.conf
|
||||
-- added reload command
|
||||
-- added forcejitterbuffer option
|
||||
-- added note about specifying bindport before bindaddr
|
||||
-- added trunktimestamps option
|
||||
* chan Agent
|
||||
-- added agent logoff CLI command
|
||||
* chan OSS
|
||||
-- added Flash CLI command
|
||||
* chan SIP
|
||||
-- added setvar option
|
||||
-- added compactheaders option
|
||||
-- added usereqphone option
|
||||
-- added registertimeout option
|
||||
-- added externhost option
|
||||
-- added sip notify CLI command
|
||||
-- added sip_notify.conf
|
||||
-- added allowguest option
|
||||
* chan Zap
|
||||
-- added hanguponplarityswitch option
|
||||
-- added sendcalleridafter option
|
||||
-- added priresetinterval option
|
||||
-- added TON/NPI config options (the ones right above the resetinterval option)
|
||||
-- added answeronpolarityswitch option
|
||||
-- added "never" for resetinterval
|
||||
* extensions
|
||||
-- allow '*' when including files (#include "sip-*.conf")
|
||||
-- added eswitch
|
||||
* General
|
||||
-- added #exec syntax for including output from a command
|
||||
-- added show features CLI command
|
||||
-- added configuration templates for category inheritance
|
||||
Asterisk 0.1.11
|
||||
-- Add ISDN RAS capability
|
||||
-- Add stutter dialtone to Chan Zap
|
||||
-- Add "#include" capability to config files.
|
||||
-- Add call-forward variable to Chan Zap (*72, *73)
|
||||
-- Optimize IAX flow when transfer isn't possible
|
||||
-- Allow transmission of ANI over IAX
|
||||
Asterisk 0.1.10
|
||||
-- Make ast_readstring parameter be the max # of digits, not the max size with \0
|
||||
-- Make up any missing messages on the fly
|
||||
-- Add support for specific DTMF interruption to saying numbers
|
||||
-- Add new "u" and "b" options to condense busy/unavail handling
|
||||
-- Add support for RSA authentication on IAX calls
|
||||
-- Add support for ADSI compatible CPE
|
||||
-- Outgoing call queue
|
||||
-- Remote dialplan fixes for Quicknet
|
||||
-- Added AGI commands supporting TDD functions (RECEIVE CHAR & TDD MODE)
|
||||
-- Added TDD support (send/receive text in chan_zap)
|
||||
-- Fix all strncpy references
|
||||
-- Implement CSV CDR backend
|
||||
-- Implement Call Detail Records
|
||||
Asterisk 0.1.9
|
||||
-- Implement IAX quelching
|
||||
-- Allow Caller*ID to be overridden and suggested
|
||||
-- Configure defaults to use IAXTEL
|
||||
-- Allow remote dialplan polling via IAX
|
||||
-- Eliminate ast_longest_extension
|
||||
-- Implement dialplan request/reply
|
||||
-- Let peers have allow/disallow for codecs
|
||||
-- Change allow/deny to permit/deny in IAX
|
||||
-- Allow dialplan entries to match Caller*ID as well
|
||||
-- Added AGI (Asterisk Gateway Interface) scripting interface (app_agi)
|
||||
-- Added chan_zap for zapata telephony kernel interface, removed chan_tor
|
||||
-- Add convenience functions
|
||||
-- Fix race condition in channel hangup
|
||||
-- Fix memory leaks in both asterisk and iax frame allocations
|
||||
-- Add "iax show stats" command and -DTRACE_FRAMES (for frame tracing)
|
||||
-- Add DISA application (Thanks to Jim Dixon)
|
||||
-- Add IAX transfer support
|
||||
-- Add URL and HTML transmission
|
||||
-- Add application for sending images
|
||||
-- Add RedHat RPM spec file and build capability
|
||||
-- Fix GSM WAV file format bug
|
||||
-- Move ignorepat to main dialplan
|
||||
-- Add ability to specificy TOS bits in IAX
|
||||
-- Allow username:password in IAX strings
|
||||
-- Updates to PhoneJack interface
|
||||
-- Allow "servermail" in voicemail.conf to override e-mail in "from" line
|
||||
-- Add 'skip' option to app_playback
|
||||
-- Reject IAX calls on unknown extensions
|
||||
-- Fix version stuff
|
||||
Asterisk 0.1.8
|
||||
-- Keep track of version information
|
||||
-- Add -f to cause Asterisk not to fork
|
||||
-- Keep important information in voicemail .txt file
|
||||
-- Adtran Voice over Frame Relay updates
|
||||
-- Implement option setting/querying of channel drivers
|
||||
-- IAX performance improvements and protocol fixes
|
||||
-- Substantial enhancement of console channel driver
|
||||
-- Add IAX registration. Now IAX can dynamically register
|
||||
-- Add flash-hook transfer on tormenta channels
|
||||
-- Added Three Way Calling on tormenta channels
|
||||
-- Start on concept of zombie channel
|
||||
-- Add Call Waiting CallerID
|
||||
-- Keep track of who registeres contexts, includes, and extensions
|
||||
-- Added Call Waiting(tm), *67, *70, and *82 codes
|
||||
-- Move parked calls into "parkedcalls" context by default
|
||||
-- Allow dialplan to be displayed
|
||||
-- Allow "=>" instead of just "=" to make instantiation clearer
|
||||
-- Asterisk forks if called with no arguments
|
||||
-- Add remote control by running asterisk -vvvc
|
||||
-- Adjust verboseness with "set verbose" now
|
||||
-- No longer requires libaudiofile
|
||||
-- Install beep
|
||||
-- Make PBX Config module reload extensions on SIGHUP
|
||||
-- Allow modules to be reloaded when SIGHUP is received
|
||||
-- Variables now contain line numbers
|
||||
-- Make dialer send in band signalling
|
||||
-- Add record application
|
||||
-- Added PRI signalling to Tormenta driver
|
||||
-- Allow use of BYEXTENSION in "Goto"
|
||||
-- Allow adjustment of gains on tormenta channels
|
||||
-- Added raw PCM file format support
|
||||
-- Add U-law translator
|
||||
-- Fix DTMF handling in bridge code
|
||||
-- Fix access control with IAX
|
||||
* Asterisk 0.1.7
|
||||
-- Update configuration files and add some missing sounds
|
||||
-- Added ability to include one context in another
|
||||
-- Rewrite of PBX switching
|
||||
-- Major mods to dialler application
|
||||
-- Added Caller*ID spill reception
|
||||
-- Added Dialogic VOX file format support
|
||||
-- Added ADPCM Codec
|
||||
-- Add Tormenta driver (RBS signalling)
|
||||
-- Add Caller*ID spill creation
|
||||
-- Rewrite of translation layer entirely
|
||||
-- Add ability to run PBX without additional thread
|
||||
* Asterisk 0.1.6
|
||||
-- Make app_dial handle a lack of translators smoothly
|
||||
-- Add ISDN4Linux support -- dtmf is weird...
|
||||
-- Minor bug fixes
|
||||
* Asterisk 0.1.5
|
||||
-- Fix a small mistake in IAX
|
||||
-- Fix the QuickNet driver to work with newer cards
|
||||
* Asterisk 0.1.4
|
||||
-- Update VoFR some more
|
||||
-- Fix the QuickNet driver to work with LineJack
|
||||
-- Add ability to pass images for IAX.
|
||||
* Asterisk 0.1.3
|
||||
-- Update VoFR for latest sangoma code
|
||||
-- Update QuickNet Driver
|
||||
-- Add text message handling
|
||||
-- Fix transfers to use "default" if not in current context
|
||||
-- Add call parking
|
||||
-- Improve format/content negotiation
|
||||
-- Added support for multiple languages
|
||||
-- Bug fixes, as always...
|
||||
* Asterisk 0.1.2
|
||||
-- Updated README file with a "Getting Started" section
|
||||
-- Added sample sounds and configuration files.
|
||||
-- Added LPC10 very low bandwidth (low quality) compression
|
||||
-- Enhanced translation selection mechanism.
|
||||
-- Enhanced IAX jitter buffer, improved reliability
|
||||
-- Support echo cancelation on PhoneJack
|
||||
-- Updated PhoneJack driver to std. Telephony interface
|
||||
-- Added app_echo for evaluating VoIP latency
|
||||
-- Added app_system to execute arbitrary programs
|
||||
-- Updated sample configuration files
|
||||
-- Added OSS channel driver (full duplex only)
|
||||
-- Added IAX implementation
|
||||
-- Fixed some deadlocks.
|
||||
-- A whole bunch of bug fixes
|
||||
* Asterisk 0.1.1
|
||||
-- Revised translator, fixed some general race conditions throughout *
|
||||
-- Made dialer somewhat more aware of incompatible voice channels
|
||||
-- Added Voice Modem driver and A/Open Modem Driver stub
|
||||
-- Added MP3 decoder channel
|
||||
-- Added Microsoft WAV49 support
|
||||
-- Revised License -- Pure GPL, nothing else
|
||||
-- Modified Copyright statement since code is still currently owned by author
|
||||
-- Added RAW GSM headerless data format
|
||||
-- Innumerable bug fixes
|
||||
* Asterisk 0.1.0
|
||||
-- Initial Release
|
||||
|
||||
341
COPYING
341
COPYING
@@ -1,341 +0,0 @@
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
101
CREDITS
101
CREDITS
@@ -1,105 +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)
|
||||
|
||||
=== MISCELLANEOUS PATCHES ===
|
||||
Jim Dixon - Zapata Telephony and app_rpt
|
||||
http://www.zapatatelephony.org/app_rpt.html
|
||||
Russell Bryant - Asterisk 1.0 maintainer and misc. enhancements
|
||||
russelb@clemson.edu
|
||||
Anthony Minessale II - Countless big and small fixes, and relentless forward push
|
||||
ChanSpy, ForkCDR, ControlPlayback, While/EndWhile, DumpChan, Dictate,
|
||||
MacroIf, ExecIf, ExecIfTime, RetryDial, MixMonitor applications; res_odbc;
|
||||
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, 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
|
||||
Claude Patry - bug fixes, feature enhancements, and bug marshalling
|
||||
cpatry@gmail.com
|
||||
|
||||
=== OTHER CONTRIBUTIONS ===
|
||||
John Todd - Monkey sounds and associated teletorture prompt
|
||||
Michael Jerris - bug marshaling
|
||||
Leif Madsen, Jared Smith and Jim van Meggelen - the Asterisk book
|
||||
available under a Creative Commons License at http://www.asteriskdocs.org
|
||||
=== DEVELOPMENT SUPPORT ===
|
||||
I'd like to thank the following companies for helping fund development of
|
||||
Asterisk:
|
||||
|
||||
Pilosoft, Inc. - for supporting ADSI development in Asterisk
|
||||
|
||||
=== HOLD MUSIC ===
|
||||
Music provided by www.opsound.org
|
||||
|
||||
=== OTHER SOURCE CODE IN ASTERISK ===
|
||||
|
||||
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,
|
||||
@@ -124,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,
|
||||
|
||||
70
HARDWARE
70
HARDWARE
@@ -1,70 +0,0 @@
|
||||
A PBX is only really useful if you can get calls into it. Of course, you
|
||||
can use Asterisk with VoIP calls (SIP, H.323, IAX), but you can also talk
|
||||
to the real PSTN through various cards.
|
||||
|
||||
Supported Hardware is divided into two general groups: Zaptel devices and
|
||||
non-zaptel devices. The Zaptel compatible hardware supports pseudo-TDM
|
||||
conferencing and all call features through chan_zap, whereas non-zaptel
|
||||
compatible hardware may have different features.
|
||||
|
||||
Zaptel compatible hardware
|
||||
==========================
|
||||
|
||||
-- Digium (Primary author of Asterisk)
|
||||
http://www.digium.com, http://store.yahoo.com/asteriskpbx
|
||||
|
||||
* Wildcard X100P - Single FXO interface connects to Loopstart phone
|
||||
line
|
||||
|
||||
* Wildcard T400P (obsolete) - Quad T1 interface connects to four T1/PRI
|
||||
interfaces. Supports RBS and PRI voice and PPP, FR, and HDLC data.
|
||||
|
||||
* Wildcard E400P (obsolete)- Quad E1 interface connects to four E1/PRI
|
||||
(or PRA) interfaces. Supports PRA/PRI, EuroISDN voice and data.
|
||||
|
||||
* Wildcard T100P - Single T1 interface connects to a single T1/PRI
|
||||
interface. Supports RBS and PRI voice and PPP, FR, and HDLC data.
|
||||
|
||||
* Wildcard E100P - Single E1 interface connects to a single E1/PRI (or PRA)
|
||||
interface. Supports PRA/PRI, EuroISDN voice and PPP, FR, HDLC data.
|
||||
|
||||
* Wildcard S100U - Single FXS interface connects to a standard analog
|
||||
telephone.
|
||||
|
||||
* Wildcard TDM400P - Quad Modular FXS interface connects to standard
|
||||
analog telephones.
|
||||
|
||||
* Wildcard TE410P - Quad T1/E1 switchable interface. Supports PRI and
|
||||
RBS signalling, as well as PPP, FR, and HDLC data modes.
|
||||
|
||||
Non-zaptel compatible hardware
|
||||
==============================
|
||||
|
||||
-- QuickNet, Inc.
|
||||
http://www.quicknet.net
|
||||
|
||||
* Internet PhoneJack - Single FXS interface. Supports Linux telephony
|
||||
interface. DSP compression built-in.
|
||||
|
||||
* Internet LineJack - Single FXS or FXO interface. Supports Linux
|
||||
telephony interface.
|
||||
|
||||
|
||||
Miscellaneous other interfaces
|
||||
==============================
|
||||
|
||||
-- ISDN4Linux
|
||||
http://www.isdn4linux.de/
|
||||
|
||||
* Any ISDN terminal adapter supported by isdn4linux should provide
|
||||
connectivity.
|
||||
|
||||
-- ALSA
|
||||
http://www.alsa-project.org
|
||||
|
||||
* Any ALSA compatible full-duplex sound card
|
||||
|
||||
-- OSS
|
||||
http://www.opensound.com
|
||||
|
||||
* Any OSS compatible full-duplex sound card
|
||||
389
LICENSE
389
LICENSE
@@ -1,68 +1,341 @@
|
||||
Asterisk is distributed under the GNU General Public License version 2
|
||||
and is also available under alternative licenses negotiated directly
|
||||
with Digium, Inc. If you obtained Asterisk under the GPL, then the GPL
|
||||
applies to all loadable Asterisk modules used on your system as well,
|
||||
except as defined below. The GPL (version 2) is included in this
|
||||
source tree in the file COPYING.
|
||||
|
||||
This package also includes various components that are not part of
|
||||
Asterisk itself; these components are in the 'contrib' directory
|
||||
and its subdirectories. Most of these components are also
|
||||
distributed under the GPL version 2 as well, except for the following:
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
contrib/firmware/iax/iaxy.bin:
|
||||
This file is Copyright (C) Digium, Inc. and is licensed for
|
||||
use with Digium IAXy hardware devices only. It can be
|
||||
distributed freely as long as the distribution is in the
|
||||
original form present in this package (not reformatted or
|
||||
modified).
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Digium, Inc. (formerly Linux Support Services) holds copyright
|
||||
and/or sufficient licenses to all components of the Asterisk
|
||||
package, and therefore can grant, at its sole discretion, the ability
|
||||
for companies, individuals, or organizations to create proprietary or
|
||||
Open Source (even if not GPL) modules which may be dynamically linked at
|
||||
runtime with the portions of Asterisk which fall under our
|
||||
copyright/license umbrella, or are distributed under more flexible
|
||||
licenses than GPL.
|
||||
Preamble
|
||||
|
||||
If you wish to use our code in other GPL programs, don't worry --
|
||||
there is no requirement that you provide the same exception in your
|
||||
GPL'd products (although if you've written a module for Asterisk we
|
||||
would strongly encourage you to make the same exception that we do).
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
Specific permission is also granted to link Asterisk with OpenSSL and
|
||||
OpenH323 and distribute the resulting binary files.
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
In addition, Asterisk implements two management/control protocols: the
|
||||
Asterisk Manager Interface (AMI) and the Asterisk Gateway Interface
|
||||
(AGI). It is our belief that applications using these protocols to
|
||||
manage or control an Asterisk instance do not have to be licensed
|
||||
under the GPL or a compatible license, as we believe these protocols
|
||||
do not create a 'derivative work' as referred to in the GPL. However,
|
||||
should any court or other judiciary body find that these protocols do
|
||||
fall under the terms of the GPL, then we hereby grant you a license to
|
||||
use these protocols in combination with Asterisk in external
|
||||
applications licensed under any license you wish.
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
The 'Asterisk' name and logos are trademarks owned by Digium, Inc.,
|
||||
and use of them is subject to our trademark licensing policies. If you
|
||||
wish to use these trademarks for purposes other than simple
|
||||
redistribution of Asterisk source code obtained from Digium, you
|
||||
should contact our licensing department to determine the necessary
|
||||
steps you must take.
|
||||
For 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/pbx.digium.com (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.
|
||||
|
||||
216
README
216
README
@@ -1,136 +1,98 @@
|
||||
The Asterisk Open Source PBX
|
||||
by Mark Spencer <markster@digium.com>
|
||||
and the Asterisk.org developer community
|
||||
|
||||
Copyright (C) 2001-2005 Digium, Inc.
|
||||
and other copyright holders.
|
||||
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 file 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
|
||||
* 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, chan_misdn and
|
||||
zaphfc.
|
||||
|
||||
* UPGRADING FROM VERSION 1.0
|
||||
|
||||
If you are updating from a previous version of Asterisk, make sure you
|
||||
read the UPGRADE.txt file in the source directory. There are some files
|
||||
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:
|
||||
Assuming you have one of these (most likely the third) you're ready to
|
||||
proceed:
|
||||
|
||||
1) Run "make"
|
||||
|
||||
Assuming the build completes successfully:
|
||||
|
||||
2) Run "make install"
|
||||
|
||||
Each time you update or checkout from CVS, you are strongly encouraged
|
||||
to ensure all previous object files are removed to avoid internal
|
||||
inconsistency in Asterisk. Normally, this is automatically done with
|
||||
the presence of the file .cleancount, which increments each time a 'make clean'
|
||||
is required, and the file .lastclean, which contains the last .cleancount used.
|
||||
|
||||
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:
|
||||
|
||||
3) "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,
|
||||
@@ -139,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:
|
||||
@@ -155,86 +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
|
||||
Mark
|
||||
|
||||
14
README.cdr
Normal file
14
README.cdr
Normal 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.
|
||||
326
README.iax
Normal file
326
README.iax
Normal file
@@ -0,0 +1,326 @@
|
||||
Inter-Asterisk eXchange Protocol
|
||||
================================
|
||||
|
||||
INTRODUCTION
|
||||
------------
|
||||
|
||||
This document is intended as an introduction to the Inter-Asterisk
|
||||
eXchange (or simply IAX) protocol. It provides both a theoretical
|
||||
background and practical information on its use.
|
||||
|
||||
WHY IAX
|
||||
-------
|
||||
The first question most people are thinking at this point is "Why do you
|
||||
need another VoIP protocol? Why didn't you just use SIP or H.323?"
|
||||
|
||||
Well, the answer is a fairly complicated one, but in a nutshell it's like
|
||||
this... Asterisk is intended as a very flexible and powerful
|
||||
communications tool. As such, the primary feature we need from a VoIP
|
||||
protocol is the ability to meet our own goals with Asterisk, and one with
|
||||
enough flexibility that we could use it as a kind of laboratory for
|
||||
inventing and implementing new concepts in the field. Neither H.323 or
|
||||
SIP fit the roles we needed, so we developed our own protocol, which,
|
||||
while not standards based, provides a number of advantages over both SIP
|
||||
and H.323, some of which are:
|
||||
|
||||
* Interoperability with NAT/PAT/Masquerade firewalls
|
||||
IAX seamlessly interoperates through all sorts of NAT and PAT
|
||||
and other firewalls, including the ability to place and
|
||||
receive calls, and transfer calls to other stations.
|
||||
|
||||
* High performance, low overhead protocol
|
||||
When running on low-bandwidth connections, or when running
|
||||
large numbers of calls, optimized bandwidth utilization is
|
||||
imperitive. IAX uses only 4 bytes of overhead
|
||||
|
||||
* Internationalization support
|
||||
IAX transmits language information, so that remote PBX
|
||||
content can be delivered in the native language of the
|
||||
calling party.
|
||||
|
||||
* Remote dialplan polling
|
||||
IAX allows a PBX or IP phone to poll the availability of a
|
||||
number from a remote server. This allows PBX dialplans to
|
||||
be centralized.
|
||||
|
||||
* Flexible authentication
|
||||
IAX supports cleartext, md5, and RSA authentication,
|
||||
providing flexible security models for outgoing calls and
|
||||
registration services.
|
||||
|
||||
* Multimedia protocol
|
||||
IAX supports the transmission of voice, video, images, text,
|
||||
HTML, DTMF, and URL's. Voice menus can be presented in both
|
||||
audibly and visually.
|
||||
|
||||
* Call statistic gathering
|
||||
IAX gathers statistics about network performance (including
|
||||
latency and jitter, as well as providing end-to-end latency
|
||||
measurement.
|
||||
|
||||
* Call parameter communication
|
||||
Caller*ID, requested extension, requested context, etc are
|
||||
all communicated through the call.
|
||||
|
||||
* Single socket design
|
||||
IAX's single socket design allows up to 32768 calls to be
|
||||
multiplexed.
|
||||
|
||||
While we value the importance of standards based (i.e. SIP) call handling,
|
||||
hopefully this will provide a reasonable explanation of why we developed
|
||||
IAX rather than starting with SIP.
|
||||
|
||||
CONFIG FILE CONVENTIONS
|
||||
-----------------------
|
||||
Lines beginning with '>' represent lines which might appear in an actual
|
||||
configuration file. The '>' is used to help separate them from the
|
||||
descriptive text and should not actually be included in the file itself.
|
||||
|
||||
Lines within []'s by themselves represent section labels within the
|
||||
configuration file. like this:
|
||||
|
||||
> [mysection]
|
||||
|
||||
Options are set using the "=" sign, for example
|
||||
|
||||
> myoption = value
|
||||
|
||||
Sometimes an option will have a number of discrete values which it can
|
||||
take. In that case, in the documentation, the options will be listed
|
||||
within square brackets (the "[" and "]" ones) separated by the pipe symbol
|
||||
("|"). For example:
|
||||
|
||||
> myoption = [value1|value2|value3]
|
||||
|
||||
means the option "myoption" can be assigned a value of "value1", "value2",
|
||||
or "value3".
|
||||
|
||||
Objects, or pseudo-objects are instantiated using the "=>" construct. For
|
||||
example:
|
||||
|
||||
> myobject => parameter
|
||||
|
||||
creates an object called "myobject" with some parameter whose definition
|
||||
would be specific to that object. Note that the config file parser
|
||||
considers "=>" and "=" to be equivalent and their use is purely to make
|
||||
configuration files more readable and easier to "humanly parse".
|
||||
|
||||
The comment character in Asterisk configuration files is the semicolon
|
||||
";". The reason it is not "#" is because the "#" symbol can be used as
|
||||
parts of extensions and it didn't seem like a good idea to have to escape
|
||||
it.
|
||||
|
||||
IAX CONFIGURATION IN ASTERISK
|
||||
-----------------------------
|
||||
|
||||
Like everything else in Asterisk, IAX's configuration lies in
|
||||
/etc/asterisk -- specifically /etc/asterisk/iax.conf
|
||||
|
||||
The IAX configuration file is a collection of sections, each of which
|
||||
(with the exception of the "general" section) represents an entity within
|
||||
the IAX scope.
|
||||
|
||||
------------
|
||||
|
||||
The first section is typically the "general" section. In this area,
|
||||
a number of parameters which affect the entire system are configured.
|
||||
Specifically, the default codecs, port and address, jitter behavior, TOS
|
||||
bits, and registrations.
|
||||
|
||||
The first line of the "general" section is always:
|
||||
|
||||
> [general]
|
||||
|
||||
Following the first line are a number of other possibilities:
|
||||
|
||||
> port = <portnum>
|
||||
|
||||
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>
|
||||
|
||||
This allows you to bind IAX to a specific local IP address instead of
|
||||
binding to all addresses. This could be used to enhance security if, for
|
||||
example, you only wanted IAX to be available to users on your LAN.
|
||||
|
||||
> bandwidth = [low|medium|high]
|
||||
|
||||
The bandwidth selection initializes the codec selection to appropriate
|
||||
values for given bandwidths. The "high" selection enables all codecs and
|
||||
is recommended only for 10Mbps or higher connections. The "medium"
|
||||
bandwidth eliminates signed linear, Mu-law and A-law codecs, leaving only
|
||||
the codecs which are 32kbps and smaller (with MP3 as a special case). It
|
||||
can be used with broadband connections if desired. "low" eliminates ADPCM
|
||||
and MP3 formats, leaving only the G.723.1, GSM, and LPC10.
|
||||
|
||||
> allow = [gsm|lpc10|g723.1|adpcm|ulaw|alaw|mp3|slinear|all]
|
||||
> disallow = [gsm|lpc10|g723.1|adpcm|ulaw|alaw|mp3|slinear|all]
|
||||
|
||||
The "allow" and "disallow" allow you to fine tune the codec selection
|
||||
beyond the initial bandwidth selection on a codec-by-codec basis.
|
||||
|
||||
The recommended configuration is to select "low" bandwidth and then
|
||||
disallow the LPC10 codec just because it doesn't sound very good.
|
||||
|
||||
> jitterbuffer = [yes|no]
|
||||
> dropcount = <dropamount>
|
||||
> maxjitterbuffer = <max>
|
||||
> maxexcessbuffer = <max>
|
||||
|
||||
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. 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]
|
||||
|
||||
These parameters affect call detail record generation. The first sets the
|
||||
account code for records received with IAX. The account code can be
|
||||
overridden on a per-user basis for incoming calls (see below). The
|
||||
amaflags controls how the record is labeled ("omit" causes no record to be
|
||||
written. "billing" and "documentation" label the records as billing or
|
||||
documentation records respectively, and "default" selects the system
|
||||
default.
|
||||
|
||||
> tos = [lowdelay|throughput|reliability|mincost|none]
|
||||
|
||||
IAX can optionally set the TOS (Type of Service) bits to specified values
|
||||
to help improve performance in routing. The recommended value is
|
||||
"lowdelay", which many routers (including any Linux routers with 2.4
|
||||
kernels that have not been altered with ip tables) will give priority to
|
||||
these packets, improving voice quality.
|
||||
|
||||
> register => <name>[:<secret>]@<host>[:port]
|
||||
|
||||
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
|
||||
dynamic peer entry with the same name (and secret if provided).
|
||||
|
||||
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 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 5036 if not specified.
|
||||
|
||||
-------------
|
||||
|
||||
The following sections, after "general" define either users, peers or
|
||||
friends. A "user" is someone who connects to us. A "peer" is someone
|
||||
that we connect to. A "friend" is simply shorthand for creating a "user"
|
||||
and "peer" with identical parameters (i.e. someone who can contact us and
|
||||
who we contact).
|
||||
|
||||
> [identifier]
|
||||
|
||||
The section begins with the identifier in square brackets. The identifier
|
||||
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 people we connect to, and a friend is
|
||||
shorthand for creating a user and a peer with identical information
|
||||
|
||||
----------------
|
||||
User fields:
|
||||
|
||||
> context = <context>
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
> 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. For example:
|
||||
|
||||
> permit = 0.0.0.0/0.0.0.0
|
||||
> deny = 192.168.0.0/255.255.255.0
|
||||
|
||||
would deny anyone in 192.168.0.0 with a netmask of 24 bits (class C),
|
||||
whereas:
|
||||
|
||||
> 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, thsu
|
||||
overriding the denial.
|
||||
|
||||
If no permit/deny rules are listed, it is assumed that someone may connect
|
||||
from anywhere.
|
||||
|
||||
> callerid = <callerid>
|
||||
|
||||
You may override the Caller*ID information passed by a user to you (if
|
||||
they choose to send it) in order that it always be accurate from the
|
||||
perspective of your server.
|
||||
|
||||
> auth = [md5|plaintext|rsa]
|
||||
|
||||
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 specifed with "inkeys"
|
||||
|
||||
If no secret is specified and no authentication method is specified, then
|
||||
no authentication will be required.
|
||||
|
||||
> secret = <secret>
|
||||
|
||||
The "secret" line specifies the shared secret for md5 and plaintext
|
||||
authentication methods. It is never suggested to use plaintext except in
|
||||
some cases for debugging.
|
||||
|
||||
> inkeys = key1[:key2...]
|
||||
|
||||
The "inkeys" line specifies which keys we can use to authenticate the
|
||||
remote peer. If the peer's challenge passes with any of the given keys,
|
||||
then we accept its authentication. The key files live in
|
||||
/var/lib/asterisk/keys/<name>.pub and are *public keys*. Public keys are
|
||||
not typically DES3 encrypted and thus do not usually need initialization.
|
||||
|
||||
---------------
|
||||
Peer configuration
|
||||
|
||||
> allow = [gsm|lpc10|g723.1|adpcm|ulaw|alaw|mp3|slinear|all]
|
||||
> disallow = [gsm|lpc10|g723.1|adpcm|ulaw|alaw|mp3|slinear|all]
|
||||
|
||||
The "allow" and "disallow" may be used to enable or disable specific codec
|
||||
support on a per-peer basis.
|
||||
|
||||
> host = [<ipaddr>|dynamic]
|
||||
|
||||
The host line specifies the hostname or IP address of the remote host, or
|
||||
may be the word "dynamic" signifying that the host will register with us
|
||||
(see register => in the general section above).
|
||||
|
||||
> defaultip = <ipaddr>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
About Hold Music
|
||||
================
|
||||
These files were obtained from http://opsound.org, where the authors placed them
|
||||
under the Creative Commons Attribution-Share Alike 2.5 license, a copy of which
|
||||
may be found at http://creativecommons.org.
|
||||
|
||||
Credits
|
||||
================
|
||||
macroform-cold_day - Paul Shuler (Macroform)
|
||||
paulshuler@gmail.com - http://macroform.bandcamp.com/
|
||||
|
||||
macroform-robot_dity - Paul Shuler (Macroform)
|
||||
paulshuler@gmail.com - http://macroform.bandcamp.com/
|
||||
|
||||
macroform-the_simplicity - Paul Shuler (Macroform)
|
||||
paulshuler@gmail.com - http://macroform.bandcamp.com/
|
||||
|
||||
manolo_camp-morning_coffee - Manolo Camp
|
||||
beatbastard@gmx.net - http://ccmixter.org/people/ManoloCamp
|
||||
|
||||
reno_project-system - Reno Project
|
||||
renoproject@hotmail.com - http://www.jamendo.com/en/album/23661
|
||||
40
SECURITY
40
SECURITY
@@ -4,32 +4,6 @@ PLEASE READ THE FOLLOWING IMPORTANT SECURITY RELATED INFORMATION.
|
||||
IMPROPER CONFIGURATION OF ASTERISK COULD ALLOW UNAUTHORIZED USE OF YOUR
|
||||
FACILITIES, POTENTIALLY INCURRING SUBSTANTIAL CHARGES.
|
||||
|
||||
Asterisk security involves both network security (encryption, authentication)
|
||||
as well as dialplan security (authorization - who can access services in
|
||||
your pbx). If you are setting up Asterisk in production use, please make
|
||||
sure you understand the issues involved.
|
||||
|
||||
* NETWORK SECURITY
|
||||
|
||||
If you install Asterisk and use the "make samples" command to install
|
||||
a demonstration configuration, Asterisk will open a few ports for accepting
|
||||
VoIP calls. Check the channel configuration files for the ports and IP addresses.
|
||||
|
||||
If you enable the manager interface in manager.conf, please make sure that
|
||||
you access manager in a safe environment or protect it with SSH or other
|
||||
VPN solutions.
|
||||
|
||||
For all TCP/IP connections in Asterisk, you can set ACL lists that
|
||||
will permit or deny network access to Asterisk services. Please check
|
||||
the "permit" and "deny" configuration options in manager.conf and
|
||||
the VoIP channel configurations - i.e. sip.conf and iax.conf.
|
||||
|
||||
The IAX2 protocol supports strong RSA key authentication as well as
|
||||
AES encryption of voice and signalling. The SIP channel does not
|
||||
support encryption in this version of Asterisk.
|
||||
|
||||
* DIALPLAN SECURITY
|
||||
|
||||
First and foremost remember this:
|
||||
|
||||
USE THE EXTENSION CONTEXTS TO ISOLATE OUTGOING OR TOLL SERVICES FROM ANY
|
||||
@@ -51,23 +25,17 @@ the "default" context within other private contexts by using:
|
||||
in the appropriate section. A well designed PBX might look like this:
|
||||
|
||||
[longdistance]
|
||||
exten => _91NXXNXXXXXX,1,Dial(Zap/g2/${EXTEN:1})
|
||||
exten => _91NXXNXXXXXX,1,Dial,Tor/g2/BYEXTENSION
|
||||
include => local
|
||||
|
||||
[local]
|
||||
exten => _9NXXNXXX,1,Dial(Zap/g2/${EXTEN:1})
|
||||
exten => _9NXXNXXX,1,Dial,Tor/g2/BYEXTENSION
|
||||
include => default
|
||||
|
||||
[default]
|
||||
exten => 6123,Dial(Zap/1)
|
||||
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.
|
||||
|
||||
* LOG SECURITY
|
||||
|
||||
Please note that the Asterisk log files, as well as information printed to the
|
||||
Asterisk CLI, may contain sensitive information such as passwords and call
|
||||
history. Keep this in mind when providing access to these resources.
|
||||
play with your asterisk setup remotely.
|
||||
|
||||
225
UPGRADE.txt
225
UPGRADE.txt
@@ -1,225 +0,0 @@
|
||||
Information for Upgrading From Previous Asterisk Releases
|
||||
=========================================================
|
||||
|
||||
IAX2:
|
||||
|
||||
* There have been some changes to the IAX2 protocol to address the security
|
||||
concerns documented in the security advisory AST-2009-006. Please see the
|
||||
IAX2 security document, doc/IAX2-security.pdf, for information regarding
|
||||
backwards compatibility with versions of Asterisk that do not contain these
|
||||
changes to IAX2.
|
||||
|
||||
Compiling:
|
||||
|
||||
* The Asterisk 1.2 source code now uses C language features
|
||||
supported only by 'modern' C compilers. Generally, this means GCC
|
||||
version 3.0 or higher, although some GCC 2.96 releases will also
|
||||
work. Some non-GCC compilers that support C99 and the common GCC
|
||||
extensions (including anonymous structures and unions) will also
|
||||
work. All releases of GCC 2.95 do _not_ have the requisite feature
|
||||
support; systems using that compiler will need to be upgraded to
|
||||
a more recent compiler release.
|
||||
|
||||
Dialplan Expressions:
|
||||
|
||||
* The dialplan expression parser (which handles $[ ... ] constructs)
|
||||
has gone through a major upgrade, but has one incompatible change:
|
||||
spaces are no longer required around expression operators, including
|
||||
string comparisons. However, you can now use quoting to keep strings
|
||||
together for comparison. For more details, please read the
|
||||
doc/README.variables file, and check over your dialplan for possible
|
||||
problems.
|
||||
|
||||
Agents:
|
||||
|
||||
* The default for ackcall has been changed to "no" instead of "yes"
|
||||
because of a bug which caused the "yes" behavior to generally act like
|
||||
"no". You may need to adjust the value if your agents behave
|
||||
differently than you expect with respect to acknowledgement.
|
||||
|
||||
* The AgentCallBackLogin application now requires a second '|' before
|
||||
specifying an extension@context. This is to distinguish the options
|
||||
string from the extension, so that they do not conflict. See
|
||||
'show application AgentCallbackLogin' for more details.
|
||||
|
||||
Parking:
|
||||
|
||||
* Parking behavior has changed slightly; when a parked call times out,
|
||||
Asterisk will attempt to deliver the call back to the extension that
|
||||
parked it, rather than the 's' extension. If that extension is busy
|
||||
or unavailable, the parked call will be lost.
|
||||
|
||||
Dialing:
|
||||
|
||||
* The Caller*ID of the outbound leg is now the extension that was
|
||||
called, rather than the Caller*ID of the inbound leg of the call. The
|
||||
"o" flag for Dial can be used to restore the original behavior if
|
||||
desired. Note that if you are looking for the originating callerid
|
||||
from the manager event, there is a new manager event "Dial" which
|
||||
provides the source and destination channels and callerid.
|
||||
|
||||
IAX:
|
||||
|
||||
* The naming convention for IAX channels has changed in two ways:
|
||||
1. The call number follows a "-" rather than a "/" character.
|
||||
2. The name of the channel has been simplified to IAX2/peer-callno,
|
||||
rather than IAX2/peer@peer-callno or even IAX2/peer@peer/callno.
|
||||
|
||||
SIP:
|
||||
|
||||
* The global option "port" in 1.0.X that is used to set which port to
|
||||
bind to has been changed to "bindport" to be more consistent with
|
||||
the other channel drivers and to avoid confusion with the "port"
|
||||
option for users/peers.
|
||||
|
||||
* The "Registry" event now uses "Username" rather than "User" for
|
||||
consistency with IAX.
|
||||
|
||||
Applications:
|
||||
|
||||
* With the addition of dialplan functions (which operate similarly
|
||||
to variables), the SetVar application has been renamed to Set.
|
||||
|
||||
* The CallerPres application has been removed. Use SetCallerPres
|
||||
instead. It accepts both numeric and symbolic names.
|
||||
|
||||
* The applications GetGroupCount, GetGroupMatchCount, SetGroup, and
|
||||
CheckGroup have been deprecated in favor of functions. Here is a
|
||||
table of their replacements:
|
||||
|
||||
GetGroupCount([groupname][@category] GROUP_COUNT([groupname][@category]) Set(GROUPCOUNT=${GROUP_COUNT()})
|
||||
GroupMatchCount(groupmatch[@category]) GROUP_MATCH_COUNT(groupmatch[@category]) Set(GROUPCOUNT=${GROUP_MATCH_COUNT(SIP/.*)})
|
||||
SetGroup(groupname[@category]) GROUP([category])=groupname Set(GROUP()=test)
|
||||
CheckGroup(max[@category]) N/A GotoIf($[ ${GROUP_COUNT()} > 5 ]?103)
|
||||
|
||||
Note that CheckGroup does not have a direct replacement. There is
|
||||
also a new function called GROUP_LIST() which will return a space
|
||||
separated list of all of the groups set on a channel. The GROUP()
|
||||
function can also return the name of the group set on a channel when
|
||||
used in a read environment.
|
||||
|
||||
* The applications DBGet and DBPut have been deprecated in favor of
|
||||
functions. Here is a table of their replacements:
|
||||
|
||||
DBGet(foo=family/key) Set(foo=${DB(family/key)})
|
||||
DBPut(family/key=${foo}) Set(DB(family/key)=${foo})
|
||||
|
||||
* The application SetLanguage has been deprecated in favor of the
|
||||
function LANGUAGE().
|
||||
|
||||
SetLanguage(fr) Set(LANGUAGE()=fr)
|
||||
|
||||
The LANGUAGE function can also return the currently set language:
|
||||
|
||||
Set(MYLANG=${LANGUAGE()})
|
||||
|
||||
* The applications AbsoluteTimeout, DigitTimeout, and ResponseTimeout
|
||||
have been deprecated in favor of the function TIMEOUT(timeouttype):
|
||||
|
||||
AbsoluteTimeout(300) Set(TIMEOUT(absolute)=300)
|
||||
DigitTimeout(15) Set(TIMEOUT(digit)=15)
|
||||
ResponseTimeout(15) Set(TIMEOUT(response)=15)
|
||||
|
||||
The TIMEOUT() function can also return the currently set timeouts:
|
||||
|
||||
Set(DTIMEOUT=${TIMEOUT(digit)})
|
||||
|
||||
* The applications SetCIDName, SetCIDNum, and SetRDNIS have been
|
||||
deprecated in favor of the CALLERID(datatype) function:
|
||||
|
||||
SetCIDName(Joe Cool) Set(CALLERID(name)=Joe Cool)
|
||||
SetCIDNum(2025551212) Set(CALLERID(number)=2025551212)
|
||||
SetRDNIS(2024561414) Set(CALLERID(RDNIS)=2024561414)
|
||||
|
||||
* The application Record now uses the period to separate the filename
|
||||
from the format, rather than the colon.
|
||||
|
||||
* The application VoiceMail now supports a 'temporary' greeting for each
|
||||
mailbox. This greeting can be recorded by using option 4 in the
|
||||
'mailbox options' menu, and 'change your password' option has been
|
||||
moved to option 5.
|
||||
|
||||
* The application VoiceMailMain now only matches the 'default' context if
|
||||
none is specified in the arguments. (This was the previously
|
||||
documented behavior, however, we didn't follow that behavior.) The old
|
||||
behavior can be restored by setting searchcontexts=yes in voicemail.conf.
|
||||
|
||||
Queues:
|
||||
|
||||
* A queue is now considered empty not only if there are no members but if
|
||||
none of the members are available (e.g. agents not logged on). To
|
||||
restore the original behavior, use "leavewhenempty=strict" or
|
||||
"joinwhenempty=strict" instead of "=yes" for those options.
|
||||
|
||||
* It is now possible to use multi-digit extensions in the exit context
|
||||
for a queue (although you should not have overlapping extensions,
|
||||
as there is no digit timeout). This means that the EXITWITHKEY event
|
||||
in queue_log can now contain a key field with more than a single
|
||||
character in it.
|
||||
|
||||
Extensions:
|
||||
|
||||
* By default, there is a new option called "autofallthrough" in
|
||||
extensions.conf that is set to yes. Asterisk 1.0 (and earlier)
|
||||
behavior was to wait for an extension to be dialed after there were no
|
||||
more extensions to execute. "autofallthrough" changes this behavior
|
||||
so that the call will immediately be terminated with BUSY,
|
||||
CONGESTION, or HANGUP based on Asterisk's best guess. If you are
|
||||
writing an extension for IVR, you must use the WaitExten application
|
||||
if "autofallthrough" is set to yes.
|
||||
|
||||
AGI:
|
||||
|
||||
* AGI scripts did not always get SIGHUP at the end, previously. That
|
||||
behavior has been fixed. If you do not want your script to terminate
|
||||
at the end of AGI being called (e.g. on a hangup) then set SIGHUP to
|
||||
be ignored within your application.
|
||||
|
||||
* CallerID is reported with agi_callerid and agi_calleridname instead
|
||||
of a single parameter holding both.
|
||||
|
||||
Music On Hold:
|
||||
|
||||
* The preferred format for musiconhold.conf has changed; please see the
|
||||
sample configuration file for the new format. The existing format
|
||||
is still supported but will generate warnings when the module is loaded.
|
||||
|
||||
chan_modem:
|
||||
|
||||
* All the chan_modem channel drivers (aopen, bestdata and i4l) are deprecated
|
||||
in this release, and will be removed in the next major Asterisk release.
|
||||
Please migrate to chan_misdn for ISDN interfaces; there is no upgrade
|
||||
path for aopen and bestdata modem users.
|
||||
|
||||
MeetMe:
|
||||
|
||||
* The conference application now allows users to increase/decrease their
|
||||
speaking volume and listening volume (independently of each other and
|
||||
other users); the 'admin' and 'user' menus have changed, and new sound
|
||||
files are included with this release. However, if a user calling in
|
||||
over a Zaptel channel that does NOT have hardware DTMF detection
|
||||
increases their speaking volume, it is likely they will no longer be
|
||||
able to enter/exit the menu or make any further adjustments, as the
|
||||
software DTMF detector will not be able to recognize the DTMF coming
|
||||
from their device.
|
||||
|
||||
GetVar Manager Action:
|
||||
|
||||
* Previously, the behavior of the GetVar manager action reported the value
|
||||
of a variable in the following manner:
|
||||
> name: value
|
||||
This has been changed to a manner similar to the SetVar action and is now
|
||||
> Variable: name
|
||||
> Value: value
|
||||
|
||||
iLBC Codec:
|
||||
|
||||
* Previously, the Asterisk source code distribution included the iLBC
|
||||
encoder/decoder source code, from Global IP Solutions
|
||||
(http://www.gipscorp.com). This code is not licensed for
|
||||
distribution, and thus has been removed from the Asterisk source
|
||||
code distribution. If you wish to use codec_ilbc to support iLBC
|
||||
channels in Asterisk, you can run the contrib/scripts/get_ilbc_source.sh
|
||||
script to download the source and put it in the proper place in
|
||||
the Asterisk build tree. Once that is done you can follow your normal
|
||||
steps of building Asterisk.
|
||||
347
acl.c
347
acl.c
@@ -1,347 +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 Various sorts of access control
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#include <fcntl.h>
|
||||
#include <net/route.h>
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS)
|
||||
#include <sys/sockio.h>
|
||||
#endif
|
||||
|
||||
/* netinet/ip.h may not define the following (See RFCs 791 and 1349) */
|
||||
#if !defined(IPTOS_LOWCOST)
|
||||
#define IPTOS_LOWCOST 0x02
|
||||
#endif
|
||||
|
||||
#if !defined(IPTOS_MINCOST)
|
||||
#define IPTOS_MINCOST IPTOS_LOWCOST
|
||||
#endif
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/acl.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/srv.h"
|
||||
#include "asterisk/compat.h"
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
AST_MUTEX_DEFINE_STATIC(routeseq_lock);
|
||||
#endif
|
||||
|
||||
/* Default IP - if not otherwise set, don't breathe garbage */
|
||||
static struct in_addr __ourip = { 0x00000000 };
|
||||
|
||||
struct my_ifreq {
|
||||
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "eth0", "ppp0", etc. */
|
||||
struct sockaddr_in ifru_addr;
|
||||
};
|
||||
|
||||
/* Free HA structure */
|
||||
void ast_free_ha(struct ast_ha *ha)
|
||||
{
|
||||
struct ast_ha *hal;
|
||||
while(ha) {
|
||||
hal = ha;
|
||||
ha = ha->next;
|
||||
free(hal);
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy HA structure */
|
||||
void ast_copy_ha(const struct ast_ha *from, struct ast_ha *to)
|
||||
{
|
||||
memcpy(&to->netaddr, &from->netaddr, sizeof(from->netaddr));
|
||||
memcpy(&to->netmask, &from->netmask, sizeof(from->netmask));
|
||||
to->sense = from->sense;
|
||||
}
|
||||
|
||||
/* Create duplicate of ha structure */
|
||||
static struct ast_ha *ast_duplicate_ha(struct ast_ha *original)
|
||||
{
|
||||
struct ast_ha *new_ha = malloc(sizeof(struct ast_ha));
|
||||
/* Copy from original to new object */
|
||||
ast_copy_ha(original, new_ha);
|
||||
|
||||
return new_ha;
|
||||
}
|
||||
|
||||
/* Create duplicate HA link list */
|
||||
/* Used in chan_sip2 templates */
|
||||
struct ast_ha *ast_duplicate_ha_list(struct ast_ha *original)
|
||||
{
|
||||
struct ast_ha *start=original;
|
||||
struct ast_ha *ret = NULL;
|
||||
struct ast_ha *link,*prev=NULL;
|
||||
|
||||
while (start) {
|
||||
link = ast_duplicate_ha(start); /* Create copy of this object */
|
||||
if (prev)
|
||||
prev->next = link; /* Link previous to this object */
|
||||
|
||||
if (!ret)
|
||||
ret = link; /* Save starting point */
|
||||
|
||||
start = start->next; /* Go to next object */
|
||||
prev = link; /* Save pointer to this object */
|
||||
}
|
||||
return ret; /* Return start of list */
|
||||
}
|
||||
|
||||
struct ast_ha *ast_append_ha(char *sense, const char *stuff, struct ast_ha *path)
|
||||
{
|
||||
struct ast_ha *ha = malloc(sizeof(struct ast_ha));
|
||||
char *nm = "255.255.255.255";
|
||||
char tmp[256];
|
||||
struct ast_ha *prev = NULL;
|
||||
struct ast_ha *ret;
|
||||
int x, z;
|
||||
unsigned int y;
|
||||
ret = path;
|
||||
while (path) {
|
||||
prev = path;
|
||||
path = path->next;
|
||||
}
|
||||
if (ha) {
|
||||
ast_copy_string(tmp, stuff, sizeof(tmp));
|
||||
nm = strchr(tmp, '/');
|
||||
if (!nm) {
|
||||
nm = "255.255.255.255";
|
||||
} else {
|
||||
*nm = '\0';
|
||||
nm++;
|
||||
}
|
||||
if (!strchr(nm, '.')) {
|
||||
if ((sscanf(nm, "%30d", &x) == 1) && (x >= 0) && (x <= 32)) {
|
||||
y = 0;
|
||||
for (z=0;z<x;z++) {
|
||||
y >>= 1;
|
||||
y |= 0x80000000;
|
||||
}
|
||||
ha->netmask.s_addr = htonl(y);
|
||||
}
|
||||
} else if (!inet_aton(nm, &ha->netmask)) {
|
||||
ast_log(LOG_WARNING, "%s is not a valid netmask\n", nm);
|
||||
free(ha);
|
||||
return ret;
|
||||
}
|
||||
if (!inet_aton(tmp, &ha->netaddr)) {
|
||||
ast_log(LOG_WARNING, "%s is not a valid IP\n", tmp);
|
||||
free(ha);
|
||||
return ret;
|
||||
}
|
||||
ha->netaddr.s_addr &= ha->netmask.s_addr;
|
||||
if (!strncasecmp(sense, "p", 1)) {
|
||||
ha->sense = AST_SENSE_ALLOW;
|
||||
} else {
|
||||
ha->sense = AST_SENSE_DENY;
|
||||
}
|
||||
ha->next = NULL;
|
||||
if (prev) {
|
||||
prev->next = ha;
|
||||
} else {
|
||||
ret = ha;
|
||||
}
|
||||
}
|
||||
ast_log(LOG_DEBUG, "%s/%s appended to acl for peer\n", stuff, nm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ast_apply_ha(struct ast_ha *ha, struct sockaddr_in *sin)
|
||||
{
|
||||
/* Start optimistic */
|
||||
int res = AST_SENSE_ALLOW;
|
||||
while (ha) {
|
||||
char iabuf[INET_ADDRSTRLEN];
|
||||
char iabuf2[INET_ADDRSTRLEN];
|
||||
/* DEBUG */
|
||||
ast_log(LOG_DEBUG,
|
||||
"##### Testing %s with %s\n",
|
||||
ast_inet_ntoa(iabuf, sizeof(iabuf), sin->sin_addr),
|
||||
ast_inet_ntoa(iabuf2, sizeof(iabuf2), ha->netaddr));
|
||||
/* For each rule, if this address and the netmask = the net address
|
||||
apply the current rule */
|
||||
if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == ha->netaddr.s_addr)
|
||||
res = ha->sense;
|
||||
ha = ha->next;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_get_ip_or_srv(struct sockaddr_in *sin, const char *value, const char *service)
|
||||
{
|
||||
struct hostent *hp;
|
||||
struct ast_hostent ahp;
|
||||
char srv[256];
|
||||
char host[256];
|
||||
int tportno = ntohs(sin->sin_port);
|
||||
if (inet_aton(value, &sin->sin_addr))
|
||||
return 0;
|
||||
if (service) {
|
||||
snprintf(srv, sizeof(srv), "%s.%s", service, value);
|
||||
if (ast_get_srv(NULL, host, sizeof(host), &tportno, srv) > 0) {
|
||||
sin->sin_port = htons(tportno);
|
||||
value = host;
|
||||
}
|
||||
}
|
||||
hp = ast_gethostbyname(value, &ahp);
|
||||
if (hp) {
|
||||
memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_str2tos(const char *value, int *tos)
|
||||
{
|
||||
int fval;
|
||||
if (sscanf(value, "%30i", &fval) == 1)
|
||||
*tos = fval & 0xff;
|
||||
else if (!strcasecmp(value, "lowdelay"))
|
||||
*tos = IPTOS_LOWDELAY;
|
||||
else if (!strcasecmp(value, "throughput"))
|
||||
*tos = IPTOS_THROUGHPUT;
|
||||
else if (!strcasecmp(value, "reliability"))
|
||||
*tos = IPTOS_RELIABILITY;
|
||||
else if (!strcasecmp(value, "mincost"))
|
||||
*tos = IPTOS_MINCOST;
|
||||
else if (!strcasecmp(value, "none"))
|
||||
*tos = 0;
|
||||
else
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_get_ip(struct sockaddr_in *sin, const char *value)
|
||||
{
|
||||
return ast_get_ip_or_srv(sin, value, NULL);
|
||||
}
|
||||
|
||||
/* iface is the interface (e.g. eth0); address is the return value */
|
||||
int ast_lookup_iface(char *iface, struct in_addr *address)
|
||||
{
|
||||
int mysock, res = 0;
|
||||
struct my_ifreq ifreq;
|
||||
|
||||
memset(&ifreq, 0, sizeof(ifreq));
|
||||
ast_copy_string(ifreq.ifrn_name, iface, sizeof(ifreq.ifrn_name));
|
||||
|
||||
mysock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
res = ioctl(mysock, SIOCGIFADDR, &ifreq);
|
||||
|
||||
close(mysock);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to get IP of %s: %s\n", iface, strerror(errno));
|
||||
memcpy((char *)address, (char *)&__ourip, sizeof(__ourip));
|
||||
return -1;
|
||||
} else {
|
||||
memcpy((char *)address, (char *)&ifreq.ifru_addr.sin_addr, sizeof(ifreq.ifru_addr.sin_addr));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ast_ouraddrfor(struct in_addr *them, struct in_addr *us)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t slen;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
ast_log(LOG_WARNING, "Cannot create socket\n");
|
||||
return -1;
|
||||
}
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = 5060;
|
||||
sin.sin_addr = *them;
|
||||
if (connect(s, (struct sockaddr *)&sin, sizeof(sin))) {
|
||||
ast_log(LOG_WARNING, "Cannot connect\n");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
slen = sizeof(sin);
|
||||
if (getsockname(s, (struct sockaddr *)&sin, &slen)) {
|
||||
ast_log(LOG_WARNING, "Cannot get socket name\n");
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
close(s);
|
||||
*us = sin.sin_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_find_ourip(struct in_addr *ourip, struct sockaddr_in bindaddr)
|
||||
{
|
||||
char ourhost[MAXHOSTNAMELEN] = "";
|
||||
struct ast_hostent ahp;
|
||||
struct hostent *hp;
|
||||
struct in_addr saddr;
|
||||
|
||||
/* just use the bind address if it is nonzero */
|
||||
if (ntohl(bindaddr.sin_addr.s_addr)) {
|
||||
memcpy(ourip, &bindaddr.sin_addr, sizeof(*ourip));
|
||||
return 0;
|
||||
}
|
||||
/* try to use our hostname */
|
||||
if (gethostname(ourhost, sizeof(ourhost) - 1)) {
|
||||
ast_log(LOG_WARNING, "Unable to get hostname\n");
|
||||
} else {
|
||||
hp = ast_gethostbyname(ourhost, &ahp);
|
||||
if (hp) {
|
||||
memcpy(ourip, hp->h_addr, sizeof(*ourip));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* A.ROOT-SERVERS.NET. */
|
||||
if (inet_aton("198.41.0.4", &saddr) && !ast_ouraddrfor(&saddr, ourip))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
20
addmailbox
Normal file
20
addmailbox
Normal 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
|
||||
|
||||
313
aescrypt.c
313
aescrypt.c
@@ -1,313 +0,0 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2003, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
|
||||
All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
*/
|
||||
/*! \file
|
||||
\brief This file contains the code for implementing encryption and decryption
|
||||
for AES (Rijndael) for block and key sizes of 16, 24 and 32 bytes. It
|
||||
can optionally be replaced by code written in assembler using NASM. For
|
||||
further details see the file aesopt.h
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
|
||||
#define so(y,x,c) word_out(y, c, s(x,c))
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define locals(y,x) x[4],y[4]
|
||||
#else
|
||||
#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3
|
||||
#endif
|
||||
|
||||
#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \
|
||||
s(y,2) = s(x,2); s(y,3) = s(x,3);
|
||||
#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3)
|
||||
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
|
||||
#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3)
|
||||
|
||||
#if defined(ENCRYPTION) && !defined(AES_ASM)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma optimize( "s", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define fwd_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
|
||||
|
||||
#if defined(FT4_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
|
||||
#elif defined(FT1_SET)
|
||||
#undef dec_fmvars
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c))
|
||||
#elif defined(FL1_SET)
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c))
|
||||
#else
|
||||
#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c))
|
||||
#endif
|
||||
|
||||
aes_rval aes_encrypt(const void *in_blk, void *out_blk, const aes_encrypt_ctx cx[1])
|
||||
{ aes_32t locals(b0, b1);
|
||||
const aes_32t *kp = cx->ks;
|
||||
#ifdef dec_fmvars
|
||||
dec_fmvars; /* declare variables for fwd_mcol() if needed */
|
||||
#endif
|
||||
|
||||
aes_32t nr = (kp[45] ^ kp[52] ^ kp[53] ? kp[52] : 14);
|
||||
|
||||
#ifdef AES_ERR_CHK
|
||||
if( (nr != 10 || !(kp[0] | kp[3] | kp[4]))
|
||||
&& (nr != 12 || !(kp[0] | kp[5] | kp[6]))
|
||||
&& (nr != 14 || !(kp[0] | kp[7] | kp[8])) )
|
||||
return aes_error;
|
||||
#endif
|
||||
|
||||
state_in(b0, in_blk, kp);
|
||||
|
||||
#if (ENC_UNROLL == FULL)
|
||||
|
||||
switch(nr)
|
||||
{
|
||||
case 14:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 12:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
kp += 2 * N_COLS;
|
||||
case 10:
|
||||
round(fwd_rnd, b1, b0, kp + 1 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 2 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 3 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 4 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 5 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 6 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 7 * N_COLS);
|
||||
round(fwd_rnd, b0, b1, kp + 8 * N_COLS);
|
||||
round(fwd_rnd, b1, b0, kp + 9 * N_COLS);
|
||||
round(fwd_lrnd, b0, b1, kp +10 * N_COLS);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (ENC_UNROLL == PARTIAL)
|
||||
{ aes_32t rnd;
|
||||
for(rnd = 0; rnd < (nr >> 1) - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b0, b1, kp);
|
||||
}
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ aes_32t rnd;
|
||||
for(rnd = 0; rnd < nr - 1; ++rnd)
|
||||
{
|
||||
kp += N_COLS;
|
||||
round(fwd_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp += N_COLS;
|
||||
round(fwd_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out_blk, b0);
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DECRYPTION) && !defined(AES_ASM)
|
||||
|
||||
/* Visual C++ .Net v7.1 provides the fastest encryption code when using
|
||||
Pentium optimiation with small code but this is poor for decryption
|
||||
so we need to control this with the following VC++ pragmas
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma optimize( "t", on )
|
||||
#endif
|
||||
|
||||
/* Given the column (c) of the output state variable, the following
|
||||
macros give the input state variables which are needed in its
|
||||
computation for each row (r) of the state. All the alternative
|
||||
macros give the same end values but expand into different ways
|
||||
of calculating these values. In particular the complex macro
|
||||
used for dynamically variable block sizes is designed to expand
|
||||
to a compile time constant whenever possible but will expand to
|
||||
conditional clauses on some branches (I am grateful to Frank
|
||||
Yellin for this construction)
|
||||
*/
|
||||
|
||||
#define inv_var(x,r,c)\
|
||||
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||
: r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\
|
||||
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||
: ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0)))
|
||||
|
||||
#if defined(IT4_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c))
|
||||
#elif defined(IT1_SET)
|
||||
#undef dec_imvars
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)))
|
||||
#endif
|
||||
|
||||
#if defined(IL4_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c))
|
||||
#elif defined(IL1_SET)
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c))
|
||||
#else
|
||||
#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))
|
||||
#endif
|
||||
|
||||
aes_rval aes_decrypt(const void *in_blk, void *out_blk, const aes_decrypt_ctx cx[1])
|
||||
{ aes_32t locals(b0, b1);
|
||||
#ifdef dec_imvars
|
||||
dec_imvars; /* declare variables for inv_mcol() if needed */
|
||||
#endif
|
||||
|
||||
aes_32t nr = (cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] ? cx->ks[52] : 14);
|
||||
const aes_32t *kp = cx->ks + nr * N_COLS;
|
||||
|
||||
#ifdef AES_ERR_CHK
|
||||
if( (nr != 10 || !(cx->ks[0] | cx->ks[3] | cx->ks[4]))
|
||||
&& (nr != 12 || !(cx->ks[0] | cx->ks[5] | cx->ks[6]))
|
||||
&& (nr != 14 || !(cx->ks[0] | cx->ks[7] | cx->ks[8])) )
|
||||
return aes_error;
|
||||
#endif
|
||||
|
||||
state_in(b0, in_blk, kp);
|
||||
|
||||
#if (DEC_UNROLL == FULL)
|
||||
|
||||
switch(nr)
|
||||
{
|
||||
case 14:
|
||||
round(inv_rnd, b1, b0, kp - 1 * N_COLS);
|
||||
round(inv_rnd, b0, b1, kp - 2 * N_COLS);
|
||||
kp -= 2 * N_COLS;
|
||||
case 12:
|
||||
round(inv_rnd, b1, b0, kp - 1 * N_COLS);
|
||||
round(inv_rnd, b0, b1, kp - 2 * N_COLS);
|
||||
kp -= 2 * N_COLS;
|
||||
case 10:
|
||||
round(inv_rnd, b1, b0, kp - 1 * N_COLS);
|
||||
round(inv_rnd, b0, b1, kp - 2 * N_COLS);
|
||||
round(inv_rnd, b1, b0, kp - 3 * N_COLS);
|
||||
round(inv_rnd, b0, b1, kp - 4 * N_COLS);
|
||||
round(inv_rnd, b1, b0, kp - 5 * N_COLS);
|
||||
round(inv_rnd, b0, b1, kp - 6 * N_COLS);
|
||||
round(inv_rnd, b1, b0, kp - 7 * N_COLS);
|
||||
round(inv_rnd, b0, b1, kp - 8 * N_COLS);
|
||||
round(inv_rnd, b1, b0, kp - 9 * N_COLS);
|
||||
round(inv_lrnd, b0, b1, kp - 10 * N_COLS);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if (DEC_UNROLL == PARTIAL)
|
||||
{ aes_32t rnd;
|
||||
for(rnd = 0; rnd < (nr >> 1) - 1; ++rnd)
|
||||
{
|
||||
kp -= N_COLS;
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
kp -= N_COLS;
|
||||
round(inv_rnd, b0, b1, kp);
|
||||
}
|
||||
kp -= N_COLS;
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
#else
|
||||
{ aes_32t rnd;
|
||||
for(rnd = 0; rnd < nr - 1; ++rnd)
|
||||
{
|
||||
kp -= N_COLS;
|
||||
round(inv_rnd, b1, b0, kp);
|
||||
l_copy(b0, b1);
|
||||
}
|
||||
#endif
|
||||
kp -= N_COLS;
|
||||
round(inv_lrnd, b0, b1, kp);
|
||||
}
|
||||
#endif
|
||||
|
||||
state_out(out_blk, b0);
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
465
aeskey.c
465
aeskey.c
@@ -1,465 +0,0 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2003, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
|
||||
All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
*/
|
||||
/*! \file
|
||||
\brief This file contains the code for implementing the key schedule for AES
|
||||
(Rijndael) for block and key sizes of 16, 24, and 32 bytes. See aesopt.h
|
||||
for further details including optimisation.
|
||||
*/
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* Initialise the key schedule from the user supplied key. The key
|
||||
length can be specified in bytes, with legal values of 16, 24
|
||||
and 32, or in bits, with legal values of 128, 192 and 256. These
|
||||
values correspond with Nk values of 4, 6 and 8 respectively.
|
||||
|
||||
The following macros implement a single cycle in the key
|
||||
schedule generation process. The number of cycles needed
|
||||
for each cx->n_col and nk value is:
|
||||
|
||||
nk = 4 5 6 7 8
|
||||
------------------------------
|
||||
cx->n_col = 4 10 9 8 7 7
|
||||
cx->n_col = 5 14 11 10 9 9
|
||||
cx->n_col = 6 19 15 12 11 11
|
||||
cx->n_col = 7 21 19 16 13 14
|
||||
cx->n_col = 8 29 23 19 17 14
|
||||
*/
|
||||
|
||||
#define ke4(k,i) \
|
||||
{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \
|
||||
k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
#define kel4(k,i) \
|
||||
{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+5] = ss[1] ^= ss[0]; \
|
||||
k[4*(i)+6] = ss[2] ^= ss[1]; k[4*(i)+7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke6(k,i) \
|
||||
{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \
|
||||
k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \
|
||||
k[6*(i)+10] = ss[4] ^= ss[3]; k[6*(i)+11] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
#define kel6(k,i) \
|
||||
{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 7] = ss[1] ^= ss[0]; \
|
||||
k[6*(i)+ 8] = ss[2] ^= ss[1]; k[6*(i)+ 9] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke8(k,i) \
|
||||
{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \
|
||||
k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \
|
||||
k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); k[8*(i)+13] = ss[5] ^= ss[4]; \
|
||||
k[8*(i)+14] = ss[6] ^= ss[5]; k[8*(i)+15] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
#define kel8(k,i) \
|
||||
{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 9] = ss[1] ^= ss[0]; \
|
||||
k[8*(i)+10] = ss[2] ^= ss[1]; k[8*(i)+11] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#if defined(ENCRYPTION_KEY_SCHEDULE)
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
|
||||
aes_rval aes_encrypt_key128(const void *in_key, aes_encrypt_ctx cx[1])
|
||||
{ aes_32t ss[4];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(in_key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(in_key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(in_key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(in_key, 3);
|
||||
|
||||
#if ENC_UNROLL == NONE
|
||||
{ aes_32t i;
|
||||
|
||||
for(i = 0; i < ((11 * N_COLS - 1) / 4); ++i)
|
||||
ke4(cx->ks, i);
|
||||
}
|
||||
#else
|
||||
ke4(cx->ks, 0); ke4(cx->ks, 1);
|
||||
ke4(cx->ks, 2); ke4(cx->ks, 3);
|
||||
ke4(cx->ks, 4); ke4(cx->ks, 5);
|
||||
ke4(cx->ks, 6); ke4(cx->ks, 7);
|
||||
ke4(cx->ks, 8); kel4(cx->ks, 9);
|
||||
#endif
|
||||
|
||||
/* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */
|
||||
/* key and must be non-zero for 128 and 192 bits keys */
|
||||
cx->ks[53] = cx->ks[45] = 0;
|
||||
cx->ks[52] = 10;
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
|
||||
aes_rval aes_encrypt_key192(const void *in_key, aes_encrypt_ctx cx[1])
|
||||
{ aes_32t ss[6];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(in_key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(in_key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(in_key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(in_key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(in_key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(in_key, 5);
|
||||
|
||||
#if ENC_UNROLL == NONE
|
||||
{ aes_32t i;
|
||||
|
||||
for(i = 0; i < (13 * N_COLS - 1) / 6; ++i)
|
||||
ke6(cx->ks, i);
|
||||
}
|
||||
#else
|
||||
ke6(cx->ks, 0); ke6(cx->ks, 1);
|
||||
ke6(cx->ks, 2); ke6(cx->ks, 3);
|
||||
ke6(cx->ks, 4); ke6(cx->ks, 5);
|
||||
ke6(cx->ks, 6); kel6(cx->ks, 7);
|
||||
#endif
|
||||
|
||||
/* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */
|
||||
/* key and must be non-zero for 128 and 192 bits keys */
|
||||
cx->ks[53] = cx->ks[45];
|
||||
cx->ks[52] = 12;
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
|
||||
aes_rval aes_encrypt_key256(const void *in_key, aes_encrypt_ctx cx[1])
|
||||
{ aes_32t ss[8];
|
||||
|
||||
cx->ks[0] = ss[0] = word_in(in_key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(in_key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(in_key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(in_key, 3);
|
||||
cx->ks[4] = ss[4] = word_in(in_key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(in_key, 5);
|
||||
cx->ks[6] = ss[6] = word_in(in_key, 6);
|
||||
cx->ks[7] = ss[7] = word_in(in_key, 7);
|
||||
|
||||
#if ENC_UNROLL == NONE
|
||||
{ aes_32t i;
|
||||
|
||||
for(i = 0; i < (15 * N_COLS - 1) / 8; ++i)
|
||||
ke8(cx->ks, i);
|
||||
}
|
||||
#else
|
||||
ke8(cx->ks, 0); ke8(cx->ks, 1);
|
||||
ke8(cx->ks, 2); ke8(cx->ks, 3);
|
||||
ke8(cx->ks, 4); ke8(cx->ks, 5);
|
||||
kel8(cx->ks, 6);
|
||||
#endif
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
|
||||
aes_rval aes_encrypt_key(const void *in_key, int key_len, aes_encrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
#ifdef AES_ERR_CHK
|
||||
case 16: case 128: return aes_encrypt_key128(in_key, cx);
|
||||
case 24: case 192: return aes_encrypt_key192(in_key, cx);
|
||||
case 32: case 256: return aes_encrypt_key256(in_key, cx);
|
||||
default: return aes_error;
|
||||
#else
|
||||
case 16: case 128: aes_encrypt_key128(in_key, cx); return;
|
||||
case 24: case 192: aes_encrypt_key192(in_key, cx); return;
|
||||
case 32: case 256: aes_encrypt_key256(in_key, cx); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DECRYPTION_KEY_SCHEDULE)
|
||||
|
||||
#if DEC_ROUND == NO_TABLES
|
||||
#define ff(x) (x)
|
||||
#else
|
||||
#define ff(x) inv_mcol(x)
|
||||
#ifdef dec_imvars
|
||||
#define d_vars dec_imvars
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; ss[1] = ss[1] ^ ss[3]; ss[2] = ss[2] ^ ss[3]; ss[3] = ss[3]; \
|
||||
ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
|
||||
ss[4] ^= k[4*(i)]; k[4*(i)+4] = ff(ss[4]); ss[4] ^= k[4*(i)+1]; k[4*(i)+5] = ff(ss[4]); \
|
||||
ss[4] ^= k[4*(i)+2]; k[4*(i)+6] = ff(ss[4]); ss[4] ^= k[4*(i)+3]; k[4*(i)+7] = ff(ss[4]); \
|
||||
}
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
|
||||
k[4*(i)+4] = ss[4] ^= k[4*(i)]; k[4*(i)+5] = ss[4] ^= k[4*(i)+1]; \
|
||||
k[4*(i)+6] = ss[4] ^= k[4*(i)+2]; k[4*(i)+7] = ss[4] ^= k[4*(i)+3]; \
|
||||
}
|
||||
#define kdl4(k,i) \
|
||||
{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \
|
||||
k[4*(i)+4] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; k[4*(i)+5] = ss[1] ^ ss[3]; \
|
||||
k[4*(i)+6] = ss[0]; k[4*(i)+7] = ss[1]; \
|
||||
}
|
||||
#else
|
||||
#define kdf4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+ 4] = ff(ss[0]); ss[1] ^= ss[0]; k[4*(i)+ 5] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[4*(i)+ 6] = ff(ss[2]); ss[3] ^= ss[2]; k[4*(i)+ 7] = ff(ss[3]); \
|
||||
}
|
||||
#define kd4(k,i) \
|
||||
{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[4*(i)+ 4] = ss[4] ^= k[4*(i)]; \
|
||||
ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[4] ^= k[4*(i)+ 1]; \
|
||||
ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[4] ^= k[4*(i)+ 2]; \
|
||||
ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[4] ^= k[4*(i)+ 3]; \
|
||||
}
|
||||
#define kdl4(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[4*(i)+ 4] = ss[0]; ss[1] ^= ss[0]; k[4*(i)+ 5] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[4*(i)+ 6] = ss[2]; ss[3] ^= ss[2]; k[4*(i)+ 7] = ss[3]; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define kdf6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 6] = ff(ss[0]); ss[1] ^= ss[0]; k[6*(i)+ 7] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[6*(i)+ 8] = ff(ss[2]); ss[3] ^= ss[2]; k[6*(i)+ 9] = ff(ss[3]); \
|
||||
ss[4] ^= ss[3]; k[6*(i)+10] = ff(ss[4]); ss[5] ^= ss[4]; k[6*(i)+11] = ff(ss[5]); \
|
||||
}
|
||||
#define kd6(k,i) \
|
||||
{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[6*(i)+ 6] = ss[6] ^= k[6*(i)]; \
|
||||
ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[6] ^= k[6*(i)+ 1]; \
|
||||
ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[6] ^= k[6*(i)+ 2]; \
|
||||
ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[6] ^= k[6*(i)+ 3]; \
|
||||
ss[4] ^= ss[3]; k[6*(i)+10] = ss[6] ^= k[6*(i)+ 4]; \
|
||||
ss[5] ^= ss[4]; k[6*(i)+11] = ss[6] ^= k[6*(i)+ 5]; \
|
||||
}
|
||||
#define kdl6(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[6*(i)+ 6] = ss[0]; ss[1] ^= ss[0]; k[6*(i)+ 7] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[6*(i)+ 8] = ss[2]; ss[3] ^= ss[2]; k[6*(i)+ 9] = ss[3]; \
|
||||
}
|
||||
|
||||
#define kdf8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 8] = ff(ss[0]); ss[1] ^= ss[0]; k[8*(i)+ 9] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[8*(i)+10] = ff(ss[2]); ss[3] ^= ss[2]; k[8*(i)+11] = ff(ss[3]); \
|
||||
ss[4] ^= ls_box(ss[3],0); k[8*(i)+12] = ff(ss[4]); ss[5] ^= ss[4]; k[8*(i)+13] = ff(ss[5]); \
|
||||
ss[6] ^= ss[5]; k[8*(i)+14] = ff(ss[6]); ss[7] ^= ss[6]; k[8*(i)+15] = ff(ss[7]); \
|
||||
}
|
||||
#define kd8(k,i) \
|
||||
{ aes_32t g = ls_box(ss[7],3) ^ t_use(r,c)[i]; \
|
||||
ss[0] ^= g; g = ff(g); k[8*(i)+ 8] = g ^= k[8*(i)]; \
|
||||
ss[1] ^= ss[0]; k[8*(i)+ 9] = g ^= k[8*(i)+ 1]; \
|
||||
ss[2] ^= ss[1]; k[8*(i)+10] = g ^= k[8*(i)+ 2]; \
|
||||
ss[3] ^= ss[2]; k[8*(i)+11] = g ^= k[8*(i)+ 3]; \
|
||||
g = ls_box(ss[3],0); \
|
||||
ss[4] ^= g; g = ff(g); k[8*(i)+12] = g ^= k[8*(i)+ 4]; \
|
||||
ss[5] ^= ss[4]; k[8*(i)+13] = g ^= k[8*(i)+ 5]; \
|
||||
ss[6] ^= ss[5]; k[8*(i)+14] = g ^= k[8*(i)+ 6]; \
|
||||
ss[7] ^= ss[6]; k[8*(i)+15] = g ^= k[8*(i)+ 7]; \
|
||||
}
|
||||
#define kdl8(k,i) \
|
||||
{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[8*(i)+ 8] = ss[0]; ss[1] ^= ss[0]; k[8*(i)+ 9] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[8*(i)+10] = ss[2]; ss[3] ^= ss[2]; k[8*(i)+11] = ss[3]; \
|
||||
}
|
||||
|
||||
#if defined(AES_128) || defined(AES_VAR)
|
||||
|
||||
aes_rval aes_decrypt_key128(const void *in_key, aes_decrypt_ctx cx[1])
|
||||
{ aes_32t ss[5];
|
||||
#ifdef d_vars
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[0] = ss[0] = word_in(in_key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(in_key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(in_key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(in_key, 3);
|
||||
|
||||
#if DEC_UNROLL == NONE
|
||||
{ aes_32t i;
|
||||
|
||||
for(i = 0; i < (11 * N_COLS - 1) / 4; ++i)
|
||||
ke4(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 10 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
kdf4(cx->ks, 0); kd4(cx->ks, 1);
|
||||
kd4(cx->ks, 2); kd4(cx->ks, 3);
|
||||
kd4(cx->ks, 4); kd4(cx->ks, 5);
|
||||
kd4(cx->ks, 6); kd4(cx->ks, 7);
|
||||
kd4(cx->ks, 8); kdl4(cx->ks, 9);
|
||||
#endif
|
||||
|
||||
/* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */
|
||||
/* key and must be non-zero for 128 and 192 bits keys */
|
||||
cx->ks[53] = cx->ks[45] = 0;
|
||||
cx->ks[52] = 10;
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_192) || defined(AES_VAR)
|
||||
|
||||
aes_rval aes_decrypt_key192(const void *in_key, aes_decrypt_ctx cx[1])
|
||||
{ aes_32t ss[7];
|
||||
#ifdef d_vars
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[0] = ss[0] = word_in(in_key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(in_key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(in_key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(in_key, 3);
|
||||
|
||||
#if DEC_UNROLL == NONE
|
||||
cx->ks[4] = ss[4] = word_in(in_key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(in_key, 5);
|
||||
{ aes_32t i;
|
||||
|
||||
for(i = 0; i < (13 * N_COLS - 1) / 6; ++i)
|
||||
ke6(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 12 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
cx->ks[4] = ff(ss[4] = word_in(in_key, 4));
|
||||
cx->ks[5] = ff(ss[5] = word_in(in_key, 5));
|
||||
kdf6(cx->ks, 0); kd6(cx->ks, 1);
|
||||
kd6(cx->ks, 2); kd6(cx->ks, 3);
|
||||
kd6(cx->ks, 4); kd6(cx->ks, 5);
|
||||
kd6(cx->ks, 6); kdl6(cx->ks, 7);
|
||||
#endif
|
||||
|
||||
/* cx->ks[45] ^ cx->ks[52] ^ cx->ks[53] is zero for a 256 bit */
|
||||
/* key and must be non-zero for 128 and 192 bits keys */
|
||||
cx->ks[53] = cx->ks[45];
|
||||
cx->ks[52] = 12;
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_256) || defined(AES_VAR)
|
||||
|
||||
aes_rval aes_decrypt_key256(const void *in_key, aes_decrypt_ctx cx[1])
|
||||
{ aes_32t ss[8];
|
||||
#ifdef d_vars
|
||||
d_vars;
|
||||
#endif
|
||||
cx->ks[0] = ss[0] = word_in(in_key, 0);
|
||||
cx->ks[1] = ss[1] = word_in(in_key, 1);
|
||||
cx->ks[2] = ss[2] = word_in(in_key, 2);
|
||||
cx->ks[3] = ss[3] = word_in(in_key, 3);
|
||||
|
||||
#if DEC_UNROLL == NONE
|
||||
cx->ks[4] = ss[4] = word_in(in_key, 4);
|
||||
cx->ks[5] = ss[5] = word_in(in_key, 5);
|
||||
cx->ks[6] = ss[6] = word_in(in_key, 6);
|
||||
cx->ks[7] = ss[7] = word_in(in_key, 7);
|
||||
{ aes_32t i;
|
||||
|
||||
for(i = 0; i < (15 * N_COLS - 1) / 8; ++i)
|
||||
ke8(cx->ks, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for(i = N_COLS; i < 14 * N_COLS; ++i)
|
||||
cx->ks[i] = inv_mcol(cx->ks[i]);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
cx->ks[4] = ff(ss[4] = word_in(in_key, 4));
|
||||
cx->ks[5] = ff(ss[5] = word_in(in_key, 5));
|
||||
cx->ks[6] = ff(ss[6] = word_in(in_key, 6));
|
||||
cx->ks[7] = ff(ss[7] = word_in(in_key, 7));
|
||||
kdf8(cx->ks, 0); kd8(cx->ks, 1);
|
||||
kd8(cx->ks, 2); kd8(cx->ks, 3);
|
||||
kd8(cx->ks, 4); kd8(cx->ks, 5);
|
||||
kdl8(cx->ks, 6);
|
||||
#endif
|
||||
#ifdef AES_ERR_CHK
|
||||
return aes_good;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(AES_VAR)
|
||||
|
||||
aes_rval aes_decrypt_key(const void *in_key, int key_len, aes_decrypt_ctx cx[1])
|
||||
{
|
||||
switch(key_len)
|
||||
{
|
||||
#ifdef AES_ERR_CHK
|
||||
case 16: case 128: return aes_decrypt_key128(in_key, cx);
|
||||
case 24: case 192: return aes_decrypt_key192(in_key, cx);
|
||||
case 32: case 256: return aes_decrypt_key256(in_key, cx);
|
||||
default: return aes_error;
|
||||
#else
|
||||
case 16: case 128: aes_decrypt_key128(in_key, cx); return;
|
||||
case 24: case 192: aes_decrypt_key192(in_key, cx); return;
|
||||
case 32: case 256: aes_decrypt_key256(in_key, cx); return;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
232
aestab.c
232
aestab.c
@@ -1,232 +0,0 @@
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Copyright (c) 2003, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
|
||||
All rights reserved.
|
||||
|
||||
LICENSE TERMS
|
||||
|
||||
The free distribution and use of this software in both source and binary
|
||||
form is allowed (with or without changes) provided that:
|
||||
|
||||
1. distributions of this source code include the above copyright
|
||||
notice, this list of conditions and the following disclaimer;
|
||||
|
||||
2. distributions in binary form include the above copyright
|
||||
notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other associated materials;
|
||||
|
||||
3. the copyright holder's name is not used to endorse products
|
||||
built using this software without specific written permission.
|
||||
|
||||
ALTERNATIVELY, provided that this notice is retained in full, this product
|
||||
may be distributed under the terms of the GNU General Public License (GPL),
|
||||
in which case the provisions of the GPL apply INSTEAD OF those given above.
|
||||
|
||||
DISCLAIMER
|
||||
|
||||
This software is provided 'as is' with no explicit or implied warranties
|
||||
in respect of its properties, including, but not limited to, correctness
|
||||
and/or fitness for purpose.
|
||||
---------------------------------------------------------------------------
|
||||
Issue Date: 26/08/2003
|
||||
|
||||
*/
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define DO_TABLES
|
||||
|
||||
#include "aesopt.h"
|
||||
|
||||
#if defined(FIXED_TABLES)
|
||||
|
||||
/* implemented in case of wrong call for fixed tables */
|
||||
|
||||
void gen_tabs(void)
|
||||
{
|
||||
}
|
||||
|
||||
#else /* dynamic table generation */
|
||||
|
||||
#if !defined(FF_TABLES)
|
||||
|
||||
/* Generate the tables for the dynamic table option
|
||||
|
||||
It will generally be sensible to use tables to compute finite
|
||||
field multiplies and inverses but where memory is scarse this
|
||||
code might sometimes be better. But it only has effect during
|
||||
initialisation so its pretty unimportant in overall terms.
|
||||
*/
|
||||
|
||||
/* return 2 ^ (n - 1) where n is the bit number of the highest bit
|
||||
set in x with x in the range 1 < x < 0x00000200. This form is
|
||||
used so that locals within fi can be bytes rather than words
|
||||
*/
|
||||
|
||||
static aes_08t hibit(const aes_32t x)
|
||||
{ aes_08t r = (aes_08t)((x >> 1) | (x >> 2));
|
||||
|
||||
r |= (r >> 2);
|
||||
r |= (r >> 4);
|
||||
return (r + 1) >> 1;
|
||||
}
|
||||
|
||||
/* return the inverse of the finite field element x */
|
||||
|
||||
static aes_08t fi(const aes_08t x)
|
||||
{ aes_08t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
|
||||
|
||||
if(x < 2) return x;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(!n1) return v1;
|
||||
|
||||
while(n2 >= n1)
|
||||
{
|
||||
n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2);
|
||||
}
|
||||
|
||||
if(!n2) return v2;
|
||||
|
||||
while(n1 >= n2)
|
||||
{
|
||||
n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* The forward and inverse affine transformations used in the S-box */
|
||||
|
||||
#define fwd_affine(x) \
|
||||
(w = (aes_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(aes_08t)(w^(w>>8)))
|
||||
|
||||
#define inv_affine(x) \
|
||||
(w = (aes_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(aes_08t)(w^(w>>8)))
|
||||
|
||||
static int init = 0;
|
||||
|
||||
void gen_tabs(void)
|
||||
{ aes_32t i, w;
|
||||
|
||||
#if defined(FF_TABLES)
|
||||
|
||||
aes_08t pow[512], log[256];
|
||||
|
||||
if(init) return;
|
||||
/* log and power tables for GF(2^8) finite field with
|
||||
WPOLY as modular polynomial - the simplest primitive
|
||||
root is 0x03, used here to generate the tables
|
||||
*/
|
||||
|
||||
i = 0; w = 1;
|
||||
do
|
||||
{
|
||||
pow[i] = (aes_08t)w;
|
||||
pow[i + 255] = (aes_08t)w;
|
||||
log[w] = (aes_08t)i++;
|
||||
w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0);
|
||||
}
|
||||
while (w != 1);
|
||||
|
||||
#else
|
||||
if(init) return;
|
||||
#endif
|
||||
|
||||
for(i = 0, w = 1; i < RC_LENGTH; ++i)
|
||||
{
|
||||
t_set(r,c)[i] = bytes2word(w, 0, 0, 0);
|
||||
w = f2(w);
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i)
|
||||
{ aes_08t b;
|
||||
|
||||
b = fwd_affine(fi((aes_08t)i));
|
||||
w = bytes2word(f2(b), b, b, f3(b));
|
||||
|
||||
#ifdef SBX_SET
|
||||
t_set(s,box)[i] = b;
|
||||
#endif
|
||||
|
||||
#ifdef FT1_SET /* tables for a normal encryption round */
|
||||
t_set(f,n)[i] = w;
|
||||
#endif
|
||||
#ifdef FT4_SET
|
||||
t_set(f,n)[0][i] = w;
|
||||
t_set(f,n)[1][i] = upr(w,1);
|
||||
t_set(f,n)[2][i] = upr(w,2);
|
||||
t_set(f,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
|
||||
#ifdef FL1_SET /* tables for last encryption round (may also */
|
||||
t_set(f,l)[i] = w; /* be used in the key schedule) */
|
||||
#endif
|
||||
#ifdef FL4_SET
|
||||
t_set(f,l)[0][i] = w;
|
||||
t_set(f,l)[1][i] = upr(w,1);
|
||||
t_set(f,l)[2][i] = upr(w,2);
|
||||
t_set(f,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#ifdef LS1_SET /* table for key schedule if t_set(f,l) above is */
|
||||
t_set(l,s)[i] = w; /* not of the required form */
|
||||
#endif
|
||||
#ifdef LS4_SET
|
||||
t_set(l,s)[0][i] = w;
|
||||
t_set(l,s)[1][i] = upr(w,1);
|
||||
t_set(l,s)[2][i] = upr(w,2);
|
||||
t_set(l,s)[3][i] = upr(w,3);
|
||||
#endif
|
||||
|
||||
b = fi(inv_affine((aes_08t)i));
|
||||
w = bytes2word(fe(b), f9(b), fd(b), fb(b));
|
||||
|
||||
#ifdef IM1_SET /* tables for the inverse mix column operation */
|
||||
t_set(i,m)[b] = w;
|
||||
#endif
|
||||
#ifdef IM4_SET
|
||||
t_set(i,m)[0][b] = w;
|
||||
t_set(i,m)[1][b] = upr(w,1);
|
||||
t_set(i,m)[2][b] = upr(w,2);
|
||||
t_set(i,m)[3][b] = upr(w,3);
|
||||
#endif
|
||||
|
||||
#ifdef ISB_SET
|
||||
t_set(i,box)[i] = b;
|
||||
#endif
|
||||
#ifdef IT1_SET /* tables for a normal decryption round */
|
||||
t_set(i,n)[i] = w;
|
||||
#endif
|
||||
#ifdef IT4_SET
|
||||
t_set(i,n)[0][i] = w;
|
||||
t_set(i,n)[1][i] = upr(w,1);
|
||||
t_set(i,n)[2][i] = upr(w,2);
|
||||
t_set(i,n)[3][i] = upr(w,3);
|
||||
#endif
|
||||
w = bytes2word(b, 0, 0, 0);
|
||||
#ifdef IL1_SET /* tables for last decryption round */
|
||||
t_set(i,l)[i] = w;
|
||||
#endif
|
||||
#ifdef IL4_SET
|
||||
t_set(i,l)[0][i] = w;
|
||||
t_set(i,l)[1][i] = upr(w,1);
|
||||
t_set(i,l)[2][i] = upr(w,2);
|
||||
t_set(i,l)[3][i] = upr(w,3);
|
||||
#endif
|
||||
}
|
||||
init = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
41
agi/Makefile
41
agi/Makefile
@@ -1,52 +1,27 @@
|
||||
#
|
||||
# Asterisk -- A telephony toolkit for Linux.
|
||||
#
|
||||
# Makefile for AGI-related stuff
|
||||
# Makefile for PBX frontends (dynamically loaded)
|
||||
#
|
||||
# Copyright (C) 1999-2005, 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
|
||||
#
|
||||
|
||||
AGIS=agi-test.agi eagi-test eagi-sphinx-test
|
||||
AGIS=agi-test.agi
|
||||
|
||||
CFLAGS+=-DNO_AST_MM
|
||||
CFLAGS+=
|
||||
|
||||
LIBS=
|
||||
ifeq ($(OSARCH),SunOS)
|
||||
LIBS=-lsocket -lnsl ../strcompat.o
|
||||
endif
|
||||
|
||||
ifeq ($(findstring BSD,${OSARCH}),BSD)
|
||||
CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
|
||||
endif
|
||||
|
||||
all: depend $(AGIS)
|
||||
all: $(AGIS)
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)$(AGI_DIR)
|
||||
for x in $(AGIS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(AGI_DIR) ; done
|
||||
|
||||
eagi-test: eagi-test.o
|
||||
$(CC) $(CFLAGS) -o eagi-test eagi-test.o $(LIBS)
|
||||
|
||||
eagi-sphinx-test: eagi-sphinx-test.o
|
||||
$(CC) $(CFLAGS) -o eagi-sphinx-test eagi-sphinx-test.o $(LIBS)
|
||||
for x in $(AGIS); do $(INSTALL) -m 755 $$x $(AGI_DIR) ; done
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o look .depend eagi-test eagi-sphinx-test
|
||||
rm -f *.so *.o look
|
||||
|
||||
%.so : %.o
|
||||
$(CC) -shared -Xlinker -x -o $@ $<
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
depend: .depend
|
||||
|
||||
.depend:
|
||||
../build_tools/mkdep $(CFLAGS) `ls *.c`
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -1,219 +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/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);
|
||||
}
|
||||
162
agi/eagi-test.c
162
agi/eagi-test.c
@@ -1,162 +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/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);
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
29
alaw.c
29
alaw.c
@@ -1,32 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/alaw.h"
|
||||
#include <asterisk/alaw.h>
|
||||
|
||||
#define AMI_MASK 0x55
|
||||
|
||||
|
||||
122
apps/Makefile
122
apps/Makefile
@@ -1,130 +1,42 @@
|
||||
#
|
||||
# Asterisk -- A telephony toolkit for Linux.
|
||||
#
|
||||
# Makefile for PBX applications
|
||||
# Makefile for PBX frontends (dynamically loaded)
|
||||
#
|
||||
# Copyright (C) 1999-2005, 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
|
||||
#
|
||||
|
||||
APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\
|
||||
#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_adsiprog.so app_getcpeid.so app_milliwatt.so \
|
||||
app_zapateller.so app_setcallerid.so app_festival.so \
|
||||
app_queue.so app_senddtmf.so app_parkandannounce.so \
|
||||
app_setcidname.so app_lookupcidname.so app_macro.so \
|
||||
app_authenticate.so app_softhangup.so app_lookupblacklist.so \
|
||||
app_waitforring.so app_privacy.so app_db.so app_chanisavail.so \
|
||||
app_enumlookup.so app_transfer.so app_setcidnum.so app_cdr.so \
|
||||
app_hasnewvoicemail.so app_sayunixtime.so app_cut.so app_read.so \
|
||||
app_setcdruserfield.so app_random.so app_ices.so app_eval.so \
|
||||
app_nbscat.so app_sendtext.so app_exec.so \
|
||||
app_groupcount.so app_txtcidname.so app_controlplayback.so \
|
||||
app_talkdetect.so app_alarmreceiver.so app_userevent.so app_verbose.so \
|
||||
app_test.so app_forkcdr.so app_math.so app_realtime.so \
|
||||
app_dumpchan.so app_waitforsilence.so app_while.so app_setrdnis.so \
|
||||
app_md5.so app_readfile.so app_chanspy.so app_settransfercapability.so \
|
||||
app_dictate.so app_externalivr.so app_directed_pickup.so \
|
||||
app_mixmonitor.so app_stack.so
|
||||
app_agi.so app_qcall.so
|
||||
|
||||
#
|
||||
# Obsolete things...
|
||||
#
|
||||
#APPS+=app_sql_postgres.so
|
||||
#APPS+=app_sql_odbc.so
|
||||
APPS+=$(shell if [ -f /usr/include/zap.h ]; then echo "app_zapras.so" ; fi)
|
||||
|
||||
#
|
||||
# Experimental things
|
||||
#
|
||||
#APPS+=app_ivrdemo.so
|
||||
#APPS+=app_skel.so
|
||||
#APPS+=app_rpt.so
|
||||
|
||||
ifndef WITHOUT_ZAPTEL
|
||||
ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/include/linux/zaptel.h)$(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/zaptel.h),)
|
||||
APPS+=app_zapras.so app_meetme.so app_flash.so app_zapbarge.so app_zapscan.so app_page.so
|
||||
endif
|
||||
endif # WITHOUT_ZAPTEL
|
||||
|
||||
ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/osp/osp.h $(CROSS_COMPILE_TARGET)/usr/include/osp/osp.h),)
|
||||
APPS+=app_osplookup.so
|
||||
endif
|
||||
|
||||
ifeq ($(findstring BSD,${OSARCH}),BSD)
|
||||
CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
|
||||
endif
|
||||
|
||||
CURLLIBS=$(shell $(CROSS_COMPILE_BIN)curl-config --libs)
|
||||
ifneq ($(shell if [[ 0x`$(CROSS_COMPILE_BIN)curl-config --vernum` -ge 0x70907 ]]; then echo "OK" ; fi),)
|
||||
ifneq (${CURLLIBS},)
|
||||
APPS+=app_curl.so
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (${OSARCH},CYGWIN)
|
||||
CYGSOLINK=-Wl,--out-implib=lib$@.a -Wl,--export-all-symbols
|
||||
CYGSOLIB=-L.. -L. -L../res -lasterisk.dll -lres_features.so -lres_adsi.so -lres_monitor.so
|
||||
else
|
||||
CFLAGS+=-fPIC
|
||||
APPS+=app_sms.so
|
||||
endif
|
||||
|
||||
#
|
||||
# If you have UnixODBC you can use ODBC voicemail
|
||||
# storage
|
||||
#
|
||||
# Uncomment to use ODBC storage
|
||||
#CFLAGS+=-DUSE_ODBC_STORAGE
|
||||
# Uncomment for extended ODBC voicemail storage
|
||||
#CFLAGS+=-DEXTENDED_ODBC_STORAGE
|
||||
# See doc/README.odbcstorage for more information
|
||||
CFLAGS+=
|
||||
|
||||
all: $(APPS)
|
||||
|
||||
clean:
|
||||
rm -f *.so *.o .depend
|
||||
rm -f *.so *.o look
|
||||
|
||||
%.so : %.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB}
|
||||
|
||||
app_rpt.so : app_rpt.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -ltonezone
|
||||
$(CC) -shared -Xlinker -x -o $@ $<
|
||||
|
||||
install: all
|
||||
for x in $(APPS); do $(INSTALL) -m 755 $$x $(DESTDIR)$(MODULES_DIR) ; done
|
||||
rm -f $(DESTDIR)$(MODULES_DIR)/app_datetime.so
|
||||
rm -f $(DESTDIR)$(MODULES_DIR)/app_qcall.so
|
||||
for x in $(APPS); do $(INSTALL) -m 755 $$x $(MODULES_DIR) ; done
|
||||
|
||||
app_curl.so: app_curl.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CURLLIBS)
|
||||
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_sql_postgres.o: app_sql_postgres.c
|
||||
$(CC) -pipe -I$(CROSS_COMPILE_TARGET)/usr/local/pgsql/include -I$(CROSS_COMPILE_TARGET)/usr/include/postgresql $(CFLAGS) -c -o app_sql_postgres.o app_sql_postgres.c
|
||||
|
||||
app_sql_postgres.so: app_sql_postgres.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -L/usr/local/pgsql/lib -lpq
|
||||
|
||||
app_sql_odbc.so: app_sql_odbc.o
|
||||
$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} -lodbc
|
||||
|
||||
ifeq (SunOS,$(shell uname))
|
||||
app_chanspy.so: app_chanspy.o
|
||||
$(CC) $(SOLINK) -o $@ $< -lrt
|
||||
endif
|
||||
app_todd.so: app_todd.o
|
||||
$(CC) -shared -Xlinker -x -o $@ $< -L/usr/local/ssl/lib -lssl -lcrypto
|
||||
|
||||
|
||||
ifneq ($(wildcard .depend),)
|
||||
include .depend
|
||||
endif
|
||||
|
||||
depend: .depend
|
||||
|
||||
.depend:
|
||||
../build_tools/mkdep $(CFLAGS) `ls *.c`
|
||||
|
||||
env:
|
||||
env
|
||||
look: look.c
|
||||
gcc -pipe -O6 -g look.c -o look -lncurses
|
||||
|
||||
1606
apps/app_adsiprog.c
1606
apps/app_adsiprog.c
File diff suppressed because it is too large
Load Diff
873
apps/app_agi.c
Normal file
873
apps/app_agi.c
Normal 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,¬ime) < 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);
|
||||
}
|
||||
@@ -1,868 +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 details. *
|
||||
*
|
||||
* *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING *** WARNING ***
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/ulaw.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
|
||||
#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 *tdesc = "Alarm Receiver for Asterisk";
|
||||
|
||||
static char *app = "AlarmReceiver";
|
||||
|
||||
static char *synopsis = "Provide support for receving alarm reports from a burglar or fire alarm panel";
|
||||
static char *descrip =
|
||||
" AlarmReceiver(): Only 1 signalling format is supported at this time: Ademco\n"
|
||||
"Contact ID. This application should be called whenever there is an alarm\n"
|
||||
"panel calling in to dump its events. The application will handshake with the\n"
|
||||
"alarm panel, and receive events, validate them, handshake them, and store them\n"
|
||||
"until the panel hangs up. Once the panel hangs up, the application will run the\n"
|
||||
"system command specified by the eventcmd setting in alarmreceiver.conf and pipe\n"
|
||||
"the events to the standard input of the application. The configuration file also\n"
|
||||
"contains settings for DTMF timing, and for the loudness of the acknowledgement\n"
|
||||
"tones.\n";
|
||||
|
||||
/* 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";
|
||||
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/*
|
||||
* Attempt to access a database variable and increment it,
|
||||
* provided that the user defined db-family in alarmreceiver.conf
|
||||
* 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, "%30u", &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 = malloc(sizeof(event_node_t))) == NULL){
|
||||
if(option_verbose >= 1)
|
||||
ast_verbose(VERBOSE_PREFIX_1 "AlarmReceiver: Failed to allocate memory\n");
|
||||
ast_log(LOG_WARNING, "AlarmReceiver Failed to allocate memory\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(enew, 0, sizeof(event_node_t));
|
||||
|
||||
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 localuser *u;
|
||||
event_node_t *elp, *efree;
|
||||
char signalling_type[64] = "";
|
||||
|
||||
event_node_t *event_head = NULL;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_set_read_format(chan,AST_FORMAT_ULAW)){
|
||||
ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",chan->name);
|
||||
LOCAL_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) {
|
||||
LOCAL_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);
|
||||
}
|
||||
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the configuration from the configuration file
|
||||
*/
|
||||
|
||||
static int load_config(void)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
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");
|
||||
}
|
||||
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 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions are required to implement an Asterisk App.
|
||||
*/
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
load_config();
|
||||
return ast_register_application(app, alarmreceiver_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -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 Execute arbitrary authenticate commands
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Authentication Application";
|
||||
|
||||
static char *app = "Authenticate";
|
||||
|
||||
static char *synopsis = "Authenticate a user";
|
||||
|
||||
static char *descrip =
|
||||
" Authenticate(password[|options]): This application asks the caller to enter a\n"
|
||||
"given password in order to continue dialplan execution. If the password begins\n"
|
||||
"with the '/' character, it is interpreted as a file which contains a list of\n"
|
||||
"valid passwords, listed 1 password per line in the file.\n"
|
||||
" When using a database key, the value associated with the key can be anything.\n"
|
||||
"Users have three attempts to authenticate before the channel is hung up. If the\n"
|
||||
"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"
|
||||
;
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int auth_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int jump = 0;
|
||||
int retries;
|
||||
struct localuser *u;
|
||||
char password[256]="";
|
||||
char passwd[256];
|
||||
char *opts;
|
||||
char *prompt;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Authenticate requires an argument(password)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(password, data, sizeof(password) - 1);
|
||||
opts=strchr(password, '|');
|
||||
if (opts) {
|
||||
*opts = 0;
|
||||
opts++;
|
||||
} else
|
||||
opts = "";
|
||||
if (strchr(opts, 'j'))
|
||||
jump = 1;
|
||||
/* Start asking for password */
|
||||
prompt = "agent-pass";
|
||||
for (retries = 0; retries < 3; retries++) {
|
||||
res = ast_app_getdata(chan, prompt, passwd, sizeof(passwd) - 2, 0);
|
||||
if (res < 0)
|
||||
break;
|
||||
res = 0;
|
||||
if (password[0] == '/') {
|
||||
if (strchr(opts, 'd')) {
|
||||
char tmp[256];
|
||||
/* Compare against a database key */
|
||||
if (!ast_db_get(password + 1, passwd, tmp, sizeof(tmp))) {
|
||||
/* It's a good password */
|
||||
if (strchr(opts, 'r')) {
|
||||
ast_db_del(password + 1, passwd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Compare against a file */
|
||||
FILE *f;
|
||||
f = fopen(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 (strchr(opts, 'm')) {
|
||||
md5secret = strchr(buf, ':');
|
||||
if (md5secret == NULL)
|
||||
continue;
|
||||
*md5secret = '\0';
|
||||
md5secret++;
|
||||
ast_md5_hash(md5passwd, passwd);
|
||||
if (!strcmp(md5passwd, md5secret)) {
|
||||
if (strchr(opts, 'a'))
|
||||
ast_cdr_setaccount(chan, buf);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (!strcmp(passwd, buf)) {
|
||||
if (strchr(opts, 'a'))
|
||||
ast_cdr_setaccount(chan, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
if (!ast_strlen_zero(buf)) {
|
||||
if (strchr(opts, 'm')) {
|
||||
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", password, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
/* Compare against a fixed password */
|
||||
if (!strcmp(passwd, password))
|
||||
break;
|
||||
}
|
||||
prompt="auth-incorrect";
|
||||
}
|
||||
if ((retries < 3) && !res) {
|
||||
if (strchr(opts, 'a') && !strchr(opts, 'm'))
|
||||
ast_cdr_setaccount(chan, passwd);
|
||||
res = ast_streamfile(chan, "auth-thankyou", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
} else {
|
||||
if (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;
|
||||
}
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, auth_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,97 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/pbx.h"
|
||||
|
||||
|
||||
static char *tdesc = "Tell Asterisk to not maintain a CDR for the current call";
|
||||
|
||||
static char *nocdr_descrip =
|
||||
" NoCDR(): This application will tell Asterisk not to maintain a CDR for the\n"
|
||||
"current call.\n";
|
||||
|
||||
static char *nocdr_app = "NoCDR";
|
||||
static char *nocdr_synopsis = "Tell Asterisk to not maintain a CDR for the current call";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int nocdr_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (chan->cdr) {
|
||||
ast_cdr_free(chan->cdr);
|
||||
chan->cdr = NULL;
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(nocdr_app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(nocdr_app, nocdr_exec, nocdr_synopsis, nocdr_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,185 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/devicestate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Check channel availability";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int chanavail_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=-1, inuse=-1, option_state=0, priority_jump=0;
|
||||
int status;
|
||||
struct localuser *u;
|
||||
char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur, *options, *stringp;
|
||||
struct ast_channel *tempchan;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
info = ast_strdupa(data);
|
||||
stringp = info;
|
||||
strsep(&stringp, "|");
|
||||
options = strsep(&stringp, "|");
|
||||
if (options) {
|
||||
if (strchr(options, 's'))
|
||||
option_state = 1;
|
||||
if (strchr(options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
peers = info;
|
||||
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");
|
||||
LOCAL_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 || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, chanavail_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,585 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005 Anthony Minessale II (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 ChanSpy: Listen in on any channel.
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/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"
|
||||
|
||||
AST_MUTEX_DEFINE_STATIC(modlock);
|
||||
|
||||
#define AST_NAME_STRLEN 256
|
||||
#define ALL_DONE(u, ret) LOCAL_USER_REMOVE(u); return ret;
|
||||
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
|
||||
|
||||
static const char *synopsis = "Listen to the audio of an active channel";
|
||||
static const char *app = "ChanSpy";
|
||||
static const char *desc =
|
||||
" ChanSpy([chanprefix][|options]): This application is used to listen to the\n"
|
||||
"audio from an active 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"
|
||||
" 'grp'.\n"
|
||||
" q - Don't play a beep when beginning to spy on a channel.\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"
|
||||
;
|
||||
|
||||
static const char *chanspy_spy_type = "ChanSpy";
|
||||
|
||||
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), /* Record */
|
||||
} chanspy_opt_flags;
|
||||
|
||||
enum {
|
||||
OPT_ARG_VOLUME = 0,
|
||||
OPT_ARG_GROUP,
|
||||
OPT_ARG_RECORD,
|
||||
OPT_ARG_ARRAY_SIZE,
|
||||
} chanspy_opt_args;
|
||||
|
||||
AST_APP_OPTIONS(chanspy_opts, {
|
||||
AST_APP_OPTION('q', OPTION_QUIET),
|
||||
AST_APP_OPTION('b', OPTION_BRIDGED),
|
||||
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),
|
||||
});
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct chanspy_translation_helper {
|
||||
/* spy data */
|
||||
struct ast_channel_spy spy;
|
||||
int fd;
|
||||
int volfactor;
|
||||
};
|
||||
|
||||
static struct ast_channel *local_channel_walk(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_channel *ret;
|
||||
ast_mutex_lock(&modlock);
|
||||
if ((ret = ast_channel_walk_locked(chan))) {
|
||||
ast_mutex_unlock(&ret->lock);
|
||||
}
|
||||
ast_mutex_unlock(&modlock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ast_channel *local_get_channel_begin_name(char *name)
|
||||
{
|
||||
struct ast_channel *chan, *ret = NULL;
|
||||
ast_mutex_lock(&modlock);
|
||||
chan = local_channel_walk(NULL);
|
||||
while (chan) {
|
||||
if (!strncmp(chan->name, name, strlen(name)) && strncmp(chan->name, "Zap/pseudo", 10)) {
|
||||
ret = chan;
|
||||
break;
|
||||
}
|
||||
chan = local_channel_walk(chan);
|
||||
}
|
||||
ast_mutex_unlock(&modlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_mutex_lock(&chan->lock);
|
||||
res = ast_channel_spy_add(chan, spy);
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
|
||||
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) {
|
||||
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int channel_spy(struct ast_channel *chan, struct ast_channel *spyee, int *volfactor, int fd)
|
||||
{
|
||||
struct chanspy_translation_helper csth;
|
||||
int running = 0, res = 0, x = 0;
|
||||
char inp[24] = "", *name = NULL;
|
||||
struct ast_frame *f = NULL;
|
||||
|
||||
if ((chan && ast_check_hangup(chan)) || (spyee && ast_check_hangup(spyee)))
|
||||
return 0;
|
||||
|
||||
name = ast_strdupa(spyee->name);
|
||||
if (option_verbose > 1)
|
||||
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_spy_type;
|
||||
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_channel_spy_free(&csth.spy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_activate_generator(chan, &spygen, &csth);
|
||||
|
||||
while (csth.spy.status == CHANSPY_RUNNING &&
|
||||
(res = ast_waitfor(chan, -1) > -1)) {
|
||||
|
||||
/* Read in frame from channel, break out if no frame */
|
||||
if (!(f = ast_read(chan)))
|
||||
break;
|
||||
|
||||
/* Now if this is DTMF then we have to handle it as such, otherwise just skip it */
|
||||
res = 0;
|
||||
if (f->frametype == AST_FRAME_DTMF)
|
||||
res = f->subclass;
|
||||
ast_frfree(f);
|
||||
if (!res)
|
||||
continue;
|
||||
|
||||
if (x == sizeof(inp))
|
||||
x = 0;
|
||||
|
||||
if (res < 0) {
|
||||
running = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process DTMF digits */
|
||||
if (res == '#') {
|
||||
if (!ast_strlen_zero(inp)) {
|
||||
running = x ? atoi(inp) : -1;
|
||||
break;
|
||||
} else {
|
||||
(*volfactor)++;
|
||||
if (*volfactor > 4)
|
||||
*volfactor = -1;
|
||||
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 == '*') {
|
||||
break;
|
||||
} else if (res >= 48 && res <= 57) {
|
||||
inp[x++] = res;
|
||||
}
|
||||
}
|
||||
|
||||
ast_deactivate_generator(chan);
|
||||
|
||||
csth.spy.status = CHANSPY_DONE;
|
||||
|
||||
ast_mutex_lock(&csth.spy.lock);
|
||||
if (csth.spy.chan) {
|
||||
ast_mutex_lock(&csth.spy.chan->lock);
|
||||
ast_channel_spy_remove(csth.spy.chan, &csth.spy);
|
||||
ast_mutex_unlock(&csth.spy.chan->lock);
|
||||
}
|
||||
ast_mutex_unlock(&csth.spy.lock);
|
||||
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Done Spying on channel %s\n", name);
|
||||
|
||||
ast_channel_spy_free(&csth.spy);
|
||||
|
||||
return running;
|
||||
}
|
||||
|
||||
static int chanspy_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
struct ast_channel *peer=NULL, *prev=NULL;
|
||||
char name[AST_NAME_STRLEN],
|
||||
peer_name[AST_NAME_STRLEN + 5],
|
||||
*args,
|
||||
*ptr = NULL,
|
||||
*options = NULL,
|
||||
*spec = NULL,
|
||||
*argv[5],
|
||||
*mygroup = NULL,
|
||||
*recbase = NULL;
|
||||
int res = -1,
|
||||
volfactor = 0,
|
||||
silent = 0,
|
||||
argc = 0,
|
||||
bronly = 0,
|
||||
chosen = 0,
|
||||
count=0,
|
||||
waitms = 100,
|
||||
num = 0,
|
||||
oldrf = 0,
|
||||
oldwf = 0,
|
||||
fd = 0;
|
||||
struct ast_flags flags;
|
||||
signed char zero_volume = 0;
|
||||
|
||||
if (!(args = ast_strdupa((char *)data))) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
oldrf = chan->readformat;
|
||||
oldwf = chan->writeformat;
|
||||
if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
|
||||
ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
|
||||
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_answer(chan);
|
||||
|
||||
ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */
|
||||
|
||||
if ((argc = ast_app_separate_args(args, '|', 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(chanspy_opts, &flags, opts, options);
|
||||
if (ast_test_flag(&flags, OPTION_GROUP)) {
|
||||
mygroup = opts[OPT_ARG_GROUP];
|
||||
}
|
||||
if (ast_test_flag(&flags, OPTION_RECORD)) {
|
||||
if (!(recbase = opts[OPT_ARG_RECORD])) {
|
||||
recbase = "chanspy";
|
||||
}
|
||||
}
|
||||
silent = ast_test_flag(&flags, OPTION_QUIET);
|
||||
bronly = ast_test_flag(&flags, OPTION_BRIDGED);
|
||||
if (ast_test_flag(&flags, OPTION_VOLUME) && opts[OPT_ARG_VOLUME]) {
|
||||
int vol;
|
||||
|
||||
if ((sscanf(opts[OPT_ARG_VOLUME], "%30d", &vol) != 1) || (vol > 4) || (vol < -4))
|
||||
ast_log(LOG_NOTICE, "Volume factor must be a number between -4 and 4\n");
|
||||
else
|
||||
volfactor = vol;
|
||||
}
|
||||
}
|
||||
else
|
||||
ast_clear_flag(&flags, AST_FLAGS_ALL);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if (!silent) {
|
||||
res = ast_streamfile(chan, "beep", chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, "");
|
||||
if (res < 0) {
|
||||
ast_clear_flag(chan, AST_FLAG_SPYING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
count = 0;
|
||||
res = ast_waitfordigit(chan, waitms);
|
||||
if (res < 0) {
|
||||
ast_clear_flag(chan, AST_FLAG_SPYING);
|
||||
break;
|
||||
}
|
||||
|
||||
peer = local_channel_walk(NULL);
|
||||
prev=NULL;
|
||||
while(peer) {
|
||||
if (peer != chan) {
|
||||
char *group = NULL;
|
||||
int igrp = 1;
|
||||
|
||||
if (peer == prev && !chosen) {
|
||||
break;
|
||||
}
|
||||
chosen = 0;
|
||||
group = pbx_builtin_getvar_helper(peer, "SPYGROUP");
|
||||
if (mygroup) {
|
||||
if (!group || strcmp(mygroup, group)) {
|
||||
igrp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (igrp && (!spec || ((strlen(spec) <= strlen(peer->name) &&
|
||||
!strncasecmp(peer->name, spec, strlen(spec)))))) {
|
||||
if (peer && (!bronly || ast_bridged_channel(peer)) &&
|
||||
!ast_check_hangup(peer) && !ast_test_flag(peer, AST_FLAG_SPYING)) {
|
||||
int x = 0;
|
||||
strncpy(peer_name, "spy-", 5);
|
||||
strncpy(peer_name + strlen(peer_name), peer->name, AST_NAME_STRLEN);
|
||||
ptr = strchr(peer_name, '/');
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
for (x = 0 ; x < strlen(peer_name) ; x++) {
|
||||
if (peer_name[x] == '/') {
|
||||
break;
|
||||
}
|
||||
peer_name[x] = tolower(peer_name[x]);
|
||||
}
|
||||
|
||||
if (!silent) {
|
||||
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);
|
||||
}
|
||||
count++;
|
||||
prev = peer;
|
||||
res = channel_spy(chan, peer, &volfactor, fd);
|
||||
if (res == -1) {
|
||||
break;
|
||||
} else if (res > 1 && spec) {
|
||||
snprintf(name, AST_NAME_STRLEN, "%s/%d", spec, res);
|
||||
if ((peer = local_get_channel_begin_name(name))) {
|
||||
chosen = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((peer = local_channel_walk(peer)) == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
waitms = count ? 100 : 5000;
|
||||
}
|
||||
|
||||
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (oldrf && ast_set_read_format(chan, oldrf) < 0) {
|
||||
ast_log(LOG_ERROR, "Could Not Set Read Format.\n");
|
||||
}
|
||||
|
||||
if (oldwf && ast_set_write_format(chan, oldwf) < 0) {
|
||||
ast_log(LOG_ERROR, "Could Not Set Write Format.\n");
|
||||
}
|
||||
|
||||
ast_clear_flag(chan, AST_FLAG_SPYING);
|
||||
|
||||
ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);
|
||||
|
||||
ALL_DONE(u, res);
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, chanspy_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) synopsis;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,190 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static const char *tdesc = "Control Playback Application";
|
||||
|
||||
static const char *app = "ControlPlayback";
|
||||
|
||||
static const char *synopsis = "Play a file with fast forward and rewind";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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 localuser *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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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");
|
||||
LOCAL_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 || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
|
||||
ast_log(LOG_WARNING, "ControlPlayback tried to jump to priority n+101 as requested, but priority didn't exist\n");
|
||||
}
|
||||
}
|
||||
res = 0;
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "ERROR");
|
||||
} else
|
||||
pbx_builtin_setvar_helper(chan, "CPLAYBACKSTATUS", "SUCCESS");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, controlplayback_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
257
apps/app_curl.c
257
apps/app_curl.c
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2004 - 2005, Tilghman Lesher
|
||||
*
|
||||
* Tilghman Lesher <curl-20050919@the-tilghman.com>
|
||||
* and Brian Wilkins <bwilkins@cfl.rr.com> (Added POST option)
|
||||
*
|
||||
* app_curl.c is distributed with no restrictions on usage or
|
||||
* redistribution.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
* \brief Curl - App to load a URL
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Load external URL";
|
||||
|
||||
static char *app = "Curl";
|
||||
|
||||
static char *synopsis = "Load an external URL";
|
||||
|
||||
static char *descrip =
|
||||
" Curl(URL[|postdata]): This application will request the specified URL.\n"
|
||||
"It is mainly used for signalling external applications of an event.\n"
|
||||
"Parameters:\n"
|
||||
" URL - This is the external URL to request.\n"
|
||||
" postdata - This information will be treated as POST data.\n"
|
||||
"This application will set the following variable:\n"
|
||||
" CURL - This variable will contain the resulting page.\n"
|
||||
"This application has been deprecated in favor of the CURL function.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct MemoryStruct {
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static void *myrealloc(void *ptr, size_t size)
|
||||
{
|
||||
/* There might be a realloc() out there that doesn't like reallocing
|
||||
NULL pointers, so we take care of it here */
|
||||
if (ptr)
|
||||
return realloc(ptr, size);
|
||||
else
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
{
|
||||
register int realsize = size * nmemb;
|
||||
struct MemoryStruct *mem = (struct MemoryStruct *)data;
|
||||
|
||||
mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1);
|
||||
if (mem->memory) {
|
||||
memcpy(&(mem->memory[mem->size]), ptr, realsize);
|
||||
mem->size += realsize;
|
||||
mem->memory[mem->size] = 0;
|
||||
}
|
||||
return realsize;
|
||||
}
|
||||
|
||||
static int curl_internal(struct MemoryStruct *chunk, char *url, char *post)
|
||||
{
|
||||
CURL *curl;
|
||||
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (!curl) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "asterisk-libcurl-agent/1.0");
|
||||
|
||||
if (post) {
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);
|
||||
}
|
||||
|
||||
curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int curl_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *info, *post_data=NULL, *url;
|
||||
struct MemoryStruct chunk = { NULL, 0 };
|
||||
static int dep_warning = 0;
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application Curl is deprecated. Please use the CURL() function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Curl requires an argument (URL)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if ((info = ast_strdupa(data))) {
|
||||
url = strsep(&info, "|");
|
||||
post_data = info;
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! curl_internal(&chunk, url, post_data)) {
|
||||
if (chunk.memory) {
|
||||
chunk.memory[chunk.size] = '\0';
|
||||
if (chunk.memory[chunk.size - 1] == 10)
|
||||
chunk.memory[chunk.size - 1] = '\0';
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "CURL", chunk.memory);
|
||||
|
||||
free(chunk.memory);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
|
||||
res = -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *acf_curl_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
struct localuser *u;
|
||||
char *info, *post_data=NULL, *url;
|
||||
struct MemoryStruct chunk = { NULL, 0 };
|
||||
|
||||
*buf = '\0';
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "CURL requires an argument (URL)\n");
|
||||
return buf;
|
||||
}
|
||||
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
info = ast_strdupa(data);
|
||||
if (!info) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
url = strsep(&info, "|");
|
||||
post_data = info;
|
||||
|
||||
if (! curl_internal(&chunk, url, post_data)) {
|
||||
if (chunk.memory) {
|
||||
chunk.memory[chunk.size] = '\0';
|
||||
if (chunk.memory[chunk.size - 1] == 10)
|
||||
chunk.memory[chunk.size - 1] = '\0';
|
||||
|
||||
ast_copy_string(buf, chunk.memory, len);
|
||||
free(chunk.memory);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Cannot allocate curl structure\n");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ast_custom_function acf_curl = {
|
||||
.name = "CURL",
|
||||
.synopsis = "Retrieves the contents of a URL",
|
||||
.syntax = "CURL(url[|post-data])",
|
||||
.desc =
|
||||
" url - URL to retrieve\n"
|
||||
" post-data - Optional data to send as a POST (GET is default action)\n",
|
||||
.read = acf_curl_exec,
|
||||
};
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_unregister(&acf_curl);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
curl_global_cleanup();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
res = ast_custom_function_register(&acf_curl);
|
||||
res |= ast_register_application(app, curl_exec, synopsis, descrip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
473
apps/app_cut.c
473
apps/app_cut.c
@@ -1,473 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_cut__v003@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 Cut application
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
static char *tdesc = "Cut out information from a string";
|
||||
|
||||
static char *app_cut = "Cut";
|
||||
|
||||
static char *cut_synopsis = "Splits a variable's contents using the specified delimiter";
|
||||
|
||||
static char *cut_descrip =
|
||||
" Cut(newvar=varname,delimiter,fieldspec): This application will split the\n"
|
||||
"contents of a variable based on the given delimeter and store the result in\n"
|
||||
"a new variable.\n"
|
||||
"Parameters:\n"
|
||||
" newvar - new variable created from result string\n"
|
||||
" varname - variable you want cut\n"
|
||||
" delimiter - defaults to '-'\n"
|
||||
" fieldspec - number of the field you want (1-based offset)\n"
|
||||
" may also be specified as a range (with -)\n"
|
||||
" or group of ranges and fields (with &)\n"
|
||||
"This application has been deprecated in favor of the CUT function.\n";
|
||||
|
||||
static char *app_sort = "Sort";
|
||||
static char *app_sort_synopsis = "Sorts a list of keywords and values";
|
||||
static char *app_sort_descrip =
|
||||
" Sort(newvar=key1:val1[,key2:val2[[...],keyN:valN]]): This application will\n"
|
||||
"sort the list provided in ascending order. The result will be stored in the\n"
|
||||
"specified variable name.\n"
|
||||
" This application has been deprecated in favor of the SORT function.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct sortable_keys {
|
||||
char *key;
|
||||
float value;
|
||||
};
|
||||
|
||||
static int sort_subroutine(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct sortable_keys *one=arg1, *two=arg2;
|
||||
if (one->value < two->value) {
|
||||
return -1;
|
||||
} else if (one->value == two->value) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define ERROR_NOARG (-1)
|
||||
#define ERROR_NOMEM (-2)
|
||||
#define ERROR_USAGE (-3)
|
||||
|
||||
static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
|
||||
{
|
||||
char *strings, *ptrkey, *ptrvalue;
|
||||
int count=1, count2, element_count=0;
|
||||
struct sortable_keys *sortable_keys;
|
||||
|
||||
memset(buffer, 0, buflen);
|
||||
|
||||
if (!data) {
|
||||
return ERROR_NOARG;
|
||||
}
|
||||
|
||||
strings = ast_strdupa((char *)data);
|
||||
if (!strings) {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
|
||||
for (ptrkey = strings; *ptrkey; ptrkey++) {
|
||||
if (*ptrkey == '|') {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
sortable_keys = alloca(count * sizeof(struct sortable_keys));
|
||||
if (!sortable_keys) {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
|
||||
memset(sortable_keys, 0, count * sizeof(struct sortable_keys));
|
||||
|
||||
/* Parse each into a struct */
|
||||
count2 = 0;
|
||||
while ((ptrkey = strsep(&strings, "|"))) {
|
||||
ptrvalue = index(ptrkey, ':');
|
||||
if (!ptrvalue) {
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
*ptrvalue = '\0';
|
||||
ptrvalue++;
|
||||
sortable_keys[count2].key = ptrkey;
|
||||
sscanf(ptrvalue, "%30f", &sortable_keys[count2].value);
|
||||
count2++;
|
||||
}
|
||||
|
||||
/* Sort the structs */
|
||||
qsort(sortable_keys, count, sizeof(struct sortable_keys), sort_subroutine);
|
||||
|
||||
for (count2 = 0; count2 < count; count2++) {
|
||||
int blen = strlen(buffer);
|
||||
if (element_count++) {
|
||||
strncat(buffer + blen, ",", buflen - blen - 1);
|
||||
blen++;
|
||||
}
|
||||
strncat(buffer + blen, sortable_keys[count2].key, buflen - blen - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
|
||||
{
|
||||
char *s, *args[3], *varname=NULL, *delimiter=NULL, *field=NULL;
|
||||
int args_okay = 0;
|
||||
|
||||
memset(buffer, 0, buflen);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
ast_app_separate_args(s, '|', args, 3);
|
||||
varname = args[0];
|
||||
delimiter = args[1];
|
||||
field = args[2];
|
||||
|
||||
if (field) {
|
||||
args_okay = 1;
|
||||
}
|
||||
} else {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (args_okay) {
|
||||
char d, ds[2];
|
||||
char *tmp = alloca(strlen(varname) + 4);
|
||||
char varvalue[MAXRESULT], *tmp2=varvalue;
|
||||
|
||||
if (tmp) {
|
||||
snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
|
||||
memset(varvalue, 0, sizeof(varvalue));
|
||||
} else {
|
||||
return ERROR_NOMEM;
|
||||
}
|
||||
|
||||
if (delimiter[0])
|
||||
d = delimiter[0];
|
||||
else
|
||||
d = '-';
|
||||
|
||||
/* String form of the delimiter, for use with strsep(3) */
|
||||
snprintf(ds, sizeof(ds), "%c", d);
|
||||
|
||||
pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
|
||||
|
||||
if (tmp2) {
|
||||
int curfieldnum = 1;
|
||||
while ((tmp2 != NULL) && (field != NULL)) {
|
||||
char *nextgroup = strsep(&field, "&");
|
||||
int num1 = 0, num2 = MAXRESULT;
|
||||
char trashchar;
|
||||
|
||||
if (sscanf(nextgroup, "%30d-%30d", &num1, &num2) == 2) {
|
||||
/* range with both start and end */
|
||||
} else if (sscanf(nextgroup, "-%30d", &num2) == 1) {
|
||||
/* range with end */
|
||||
num1 = 0;
|
||||
} else if ((sscanf(nextgroup, "%30d%1c", &num1, &trashchar) == 2) && (trashchar == '-')) {
|
||||
/* range with start */
|
||||
num2 = MAXRESULT;
|
||||
} else if (sscanf(nextgroup, "%30d", &num1) == 1) {
|
||||
/* single number */
|
||||
num2 = num1;
|
||||
} else {
|
||||
return ERROR_USAGE;
|
||||
}
|
||||
|
||||
/* Get to start, if any */
|
||||
if (num1 > 0) {
|
||||
while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
|
||||
tmp2 = index(tmp2, d) + 1;
|
||||
curfieldnum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Most frequent problem is the expectation of reordering fields */
|
||||
if ((num1 > 0) && (curfieldnum > num1)) {
|
||||
ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
|
||||
}
|
||||
|
||||
/* Re-null tmp2 if we added 1 to NULL */
|
||||
if (tmp2 == (char *)NULL + 1)
|
||||
tmp2 = NULL;
|
||||
|
||||
/* Output fields until we either run out of fields or num2 is reached */
|
||||
while ((tmp2 != NULL) && (curfieldnum <= num2)) {
|
||||
char *tmp3 = strsep(&tmp2, ds);
|
||||
int curlen = strlen(buffer);
|
||||
|
||||
if (curlen) {
|
||||
snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3);
|
||||
} else {
|
||||
snprintf(buffer, buflen, "%s", tmp3);
|
||||
}
|
||||
|
||||
curfieldnum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return ERROR_NOARG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sort_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *varname, *strings, result[512] = "";
|
||||
static int dep_warning=0;
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application Sort is deprecated. Please use the SORT() function instead.\n");
|
||||
dep_warning=1;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
ast_log(LOG_ERROR, "Sort() requires an argument\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
strings = ast_strdupa((char *)data);
|
||||
if (!strings) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
varname = strsep(&strings, "=");
|
||||
switch (sort_internal(chan, strings, result, sizeof(result))) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "Sort() requires an argument\n");
|
||||
res = 0;
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
break;
|
||||
case 0:
|
||||
pbx_builtin_setvar_helper(chan, varname, result);
|
||||
res = 0;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
res = -1;
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int cut_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s, *newvar=NULL, result[512];
|
||||
static int dep_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application Cut is deprecated. Please use the CUT() function instead.\n");
|
||||
dep_warning=1;
|
||||
}
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
newvar = strsep(&s, "=");
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cut_internal(chan, s, result, sizeof(result))) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "Cut() requires an argument\n");
|
||||
res = 0;
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
break;
|
||||
case ERROR_USAGE:
|
||||
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
|
||||
res = 0;
|
||||
break;
|
||||
case 0:
|
||||
pbx_builtin_setvar_helper(chan, newvar, result);
|
||||
res = 0;
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
res = -1;
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
switch (sort_internal(chan, data, buf, len)) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "SORT() requires an argument\n");
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *acf_cut_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
switch (cut_internal(chan, data, buf, len)) {
|
||||
case ERROR_NOARG:
|
||||
ast_log(LOG_ERROR, "CUT() requires an argument\n");
|
||||
break;
|
||||
case ERROR_NOMEM:
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
break;
|
||||
case ERROR_USAGE:
|
||||
ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_ERROR, "Unknown internal error\n");
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct ast_custom_function acf_sort = {
|
||||
.name = "SORT",
|
||||
.synopsis = "Sorts a list of key/vals into a list of keys, based upon the vals",
|
||||
.syntax = "SORT(key1:val1[...][,keyN:valN])",
|
||||
.desc =
|
||||
"Takes a comma-separated list of keys and values, each separated by a colon, and returns a\n"
|
||||
"comma-separated list of the keys, sorted by their values. Values will be evaluated as\n"
|
||||
"floating-point numbers.\n",
|
||||
.read = acf_sort_exec,
|
||||
};
|
||||
|
||||
struct ast_custom_function acf_cut = {
|
||||
.name = "CUT",
|
||||
.synopsis = "Slices and dices strings, based upon a named delimiter.",
|
||||
.syntax = "CUT(<varname>,<char-delim>,<range-spec>)",
|
||||
.desc =
|
||||
" varname - variable you want cut\n"
|
||||
" char-delim - defaults to '-'\n"
|
||||
" range-spec - number of the field you want (1-based offset)\n"
|
||||
" may also be specified as a range (with -)\n"
|
||||
" or group of ranges and fields (with &)\n",
|
||||
.read = acf_cut_exec,
|
||||
};
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_unregister(&acf_cut);
|
||||
res |= ast_custom_function_unregister(&acf_sort);
|
||||
res |= ast_unregister_application(app_sort);
|
||||
res |= ast_unregister_application(app_cut);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_custom_function_register(&acf_cut);
|
||||
res |= ast_custom_function_register(&acf_sort);
|
||||
res |= ast_register_application(app_sort, sort_exec, app_sort_synopsis, app_sort_descrip);
|
||||
res |= ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,101 +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 Time of day - Report the time of day
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/say.h"
|
||||
|
||||
static char *tdesc = "Date and Time";
|
||||
|
||||
static char *app = "DateTime";
|
||||
|
||||
static char *synopsis = "Say the date and time";
|
||||
|
||||
static char *descrip =
|
||||
" DateTime(): This application will say the current date and time.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int datetime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
time_t t;
|
||||
struct localuser *u;
|
||||
LOCAL_USER_ADD(u);
|
||||
time(&t);
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
res = ast_answer(chan);
|
||||
if (!res)
|
||||
res = ast_say_datetime(chan, t, "", chan->language);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, datetime_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
323
apps/app_db.c
323
apps/app_db.c
@@ -1,323 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Database Access Functions";
|
||||
|
||||
static char *g_descrip =
|
||||
" DBget(varname=family/key[|options]): This application will retrieve a value\n"
|
||||
"from the Asterisk database and store it in the given variable.\n"
|
||||
" Options:\n"
|
||||
" j - Jump to priority n+101 if the requested family/key isn't found.\n"
|
||||
" This application sets the following channel variable upon completion:\n"
|
||||
" DBGETSTATUS - This variable will contain the status of the attempt\n"
|
||||
" FOUND | NOTFOUND \n"
|
||||
" This application has been deprecated in favor of the DB function.\n";
|
||||
|
||||
static char *p_descrip =
|
||||
" DBput(family/key=value): This application will store the given value in the\n"
|
||||
"specified location in the Asterisk database.\n"
|
||||
" This application has been deprecated in favor of the DB function.\n";
|
||||
|
||||
static char *d_descrip =
|
||||
" DBdel(family/key): This application will delete a key from the Asterisk\n"
|
||||
"database.\n";
|
||||
|
||||
static char *dt_descrip =
|
||||
" DBdeltree(family[/keytree]): This application will delete a family or keytree\n"
|
||||
"from the Asterisk database\n";
|
||||
|
||||
static char *g_app = "DBget";
|
||||
static char *p_app = "DBput";
|
||||
static char *d_app = "DBdel";
|
||||
static char *dt_app = "DBdeltree";
|
||||
|
||||
static char *g_synopsis = "Retrieve a value from the database";
|
||||
static char *p_synopsis = "Store a value in the database";
|
||||
static char *d_synopsis = "Delete a key from the database";
|
||||
static char *dt_synopsis = "Delete a family or keytree from the database";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int deltree_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *family, *keytree;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log(LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(argv, '/')) {
|
||||
family = strsep(&argv, "/");
|
||||
keytree = strsep(&argv, "\0");
|
||||
if (!family || !keytree) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
LOCAL_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");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int del_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *family, *key;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log (LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(argv, '/')) {
|
||||
family = strsep(&argv, "/");
|
||||
key = strsep(&argv, "\0");
|
||||
if (!family || !key) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
LOCAL_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");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int put_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *value, *family, *key;
|
||||
static int dep_warning = 0;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the ${DB(family/key)} function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log(LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(argv, '/') && strchr(argv, '=')) {
|
||||
family = strsep(&argv, "/");
|
||||
key = strsep(&argv, "=");
|
||||
value = strsep(&argv, "\0");
|
||||
if (!value || !family || !key) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBput: family=%s, key=%s, value=%s\n", family, key, value);
|
||||
if (ast_db_put(family, key, value)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBput: Error writing value to database.\n");
|
||||
}
|
||||
|
||||
} else {
|
||||
ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *argv, *varname, *family, *key, *options = NULL;
|
||||
char dbresult[256];
|
||||
static int dep_warning = 0;
|
||||
int priority_jump = 0;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the ${DB(family/key)} function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
argv = ast_strdupa(data);
|
||||
if (!argv) {
|
||||
ast_log(LOG_ERROR, "Memory allocation failed\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strchr(argv, '=') && strchr(argv, '/')) {
|
||||
varname = strsep(&argv, "=");
|
||||
family = strsep(&argv, "/");
|
||||
if (strchr((void *)&argv, '|')) {
|
||||
key = strsep(&argv, "|");
|
||||
options = strsep(&argv, "\0");
|
||||
} else
|
||||
key = strsep(&argv, "\0");
|
||||
|
||||
if (!varname || !family || !key) {
|
||||
ast_log(LOG_DEBUG, "Ignoring; Syntax error in argument\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
if (strchr(options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBget: varname=%s, family=%s, key=%s\n", varname, family, key);
|
||||
if (!ast_db_get(family, key, dbresult, sizeof (dbresult) - 1)) {
|
||||
pbx_builtin_setvar_helper(chan, varname, dbresult);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBget: set variable %s to %s\n", varname, dbresult);
|
||||
pbx_builtin_setvar_helper(chan, "DBGETSTATUS", "FOUND");
|
||||
} else {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "DBget: Value not found in database.\n");
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
/* Send the call to n+101 priority, where n is the current priority */
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "DBGETSTATUS", "NOTFOUND");
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "Ignoring, no parameters\n");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = ast_unregister_application(dt_app);
|
||||
retval |= ast_unregister_application(d_app);
|
||||
retval |= ast_unregister_application(p_app);
|
||||
retval |= ast_unregister_application(g_app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = ast_register_application(g_app, get_exec, g_synopsis, g_descrip);
|
||||
retval |= ast_register_application(p_app, put_exec, p_synopsis, p_descrip);
|
||||
retval |= ast_register_application(d_app, del_exec, d_synopsis, d_descrip);
|
||||
retval |= ast_register_application(dt_app, deltree_exec, dt_synopsis, dt_descrip);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
1741
apps/app_dial.c
1741
apps/app_dial.c
File diff suppressed because it is too large
Load Diff
@@ -1,359 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h> /* for mkdir */
|
||||
|
||||
#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/say.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Virtual Dictation Machine";
|
||||
static char *app = "Dictate";
|
||||
static char *synopsis = "Virtual Dictation Machine";
|
||||
static char *desc = " Dictate([<base_dir>])\n"
|
||||
"Start dictation machine using optional base dir for files.\n";
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
typedef enum {
|
||||
DFLAG_RECORD = (1 << 0),
|
||||
DFLAG_PLAY = (1 << 1),
|
||||
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 *mydata, *argv[2], *path = NULL, filein[256];
|
||||
char dftbase[256];
|
||||
char *base;
|
||||
struct ast_flags flags = {0};
|
||||
struct ast_filestream *fs;
|
||||
struct ast_frame *f = NULL;
|
||||
struct localuser *u;
|
||||
int ffactor = 320 * 80,
|
||||
res = 0,
|
||||
argc = 0,
|
||||
done = 0,
|
||||
oldr = 0,
|
||||
lastop = 0,
|
||||
samples = 0,
|
||||
speed = 1,
|
||||
digit = 0,
|
||||
len = 0,
|
||||
maxlen = 0,
|
||||
mode = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
snprintf(dftbase, sizeof(dftbase), "%s/dictate", ast_config_AST_SPOOL_DIR);
|
||||
if (!ast_strlen_zero(data) && (mydata = ast_strdupa(data))) {
|
||||
argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
}
|
||||
|
||||
if (argc) {
|
||||
base = argv[0];
|
||||
} else {
|
||||
base = dftbase;
|
||||
}
|
||||
|
||||
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");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_answer(chan);
|
||||
ast_safe_sleep(chan, 200);
|
||||
for(res = 0; !res;) {
|
||||
if (ast_app_getdata(chan, "dictate/enter_filename", filein, sizeof(filein), 0) ||
|
||||
ast_strlen_zero(filein)) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
mkdir(base, 0755);
|
||||
len = strlen(base) + strlen(filein) + 2;
|
||||
if (!path || len > maxlen) {
|
||||
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);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, dictate_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,169 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static const char *tdesc = "Directed Call Pickup Application";
|
||||
static const char *app = "Pickup";
|
||||
static const char *synopsis = "Directed Call Pickup";
|
||||
static const char *descrip =
|
||||
" Pickup(extension[@context]): 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.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int pickup_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u = NULL;
|
||||
struct ast_channel *origin = NULL, *target = NULL;
|
||||
char *tmp = NULL, *exten = NULL, *context = NULL;
|
||||
char workspace[256] = "";
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Get the extension and context if present */
|
||||
exten = data;
|
||||
context = strchr(data, '@');
|
||||
if (context) {
|
||||
*context = '\0';
|
||||
context++;
|
||||
}
|
||||
|
||||
/* Find a channel to pickup */
|
||||
origin = ast_get_channel_by_exten_locked(exten, context);
|
||||
if (origin && origin->cdr) {
|
||||
ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace,
|
||||
sizeof(workspace), 0);
|
||||
if (tmp) {
|
||||
/* We have a possible channel... now we need to find it! */
|
||||
target = ast_get_channel_by_name_locked(tmp);
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No target channel found.\n");
|
||||
res = -1;
|
||||
}
|
||||
ast_mutex_unlock(&origin->lock);
|
||||
} else {
|
||||
if (origin)
|
||||
ast_mutex_unlock(&origin->lock);
|
||||
ast_log(LOG_DEBUG, "No originating channel found.\n");
|
||||
}
|
||||
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING))) {
|
||||
ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name,
|
||||
chan->name);
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
res = ast_queue_control(chan, AST_CONTROL_ANSWER);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n",
|
||||
chan->name);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
res = ast_channel_masquerade(target, chan);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
|
||||
res = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No call pickup possible...\n");
|
||||
res = -1;
|
||||
}
|
||||
/* Done */
|
||||
out:
|
||||
if (target)
|
||||
ast_mutex_unlock(&target->lock);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, pickup_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,84 +1,46 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/say.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
#ifdef USE_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
|
||||
#include "../asterisk.h"
|
||||
|
||||
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"
|
||||
" 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
|
||||
@@ -87,101 +49,6 @@ STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#ifdef USE_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];
|
||||
|
||||
odbc_obj *obj;
|
||||
obj = fetch_odbc_obj(odbc_database, 0);
|
||||
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 = 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);
|
||||
} 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(char *lastname)
|
||||
{
|
||||
char *tmp;
|
||||
@@ -243,6 +110,7 @@ static char *convert(char *lastname)
|
||||
case 'Z':
|
||||
tmp[lcount++] = '9';
|
||||
break;
|
||||
default:
|
||||
}
|
||||
lastname++;
|
||||
}
|
||||
@@ -251,206 +119,19 @@ static char *convert(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 fromappvm) {
|
||||
int res = 0;
|
||||
int loop = 3;
|
||||
char fn[256];
|
||||
char fn2[256];
|
||||
|
||||
/* Check for the VoiceMail2 greeting first */
|
||||
snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/greet",
|
||||
(char *)ast_config_AST_SPOOL_DIR, context, ext);
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
retrieve_file(fn);
|
||||
#endif
|
||||
|
||||
/* Otherwise, check for an old-style Voicemail greeting */
|
||||
snprintf(fn2, sizeof(fn2), "%s/vm/%s/greet",
|
||||
(char *)ast_config_AST_SPOOL_DIR, ext);
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
retrieve_file(fn2);
|
||||
#endif
|
||||
|
||||
if (ast_fileexists(fn, NULL, chan->language) > 0) {
|
||||
res = ast_streamfile(chan, fn, chan->language);
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
} else if (ast_fileexists(fn2, NULL, chan->language) > 0) {
|
||||
res = ast_streamfile(chan, fn2, chan->language);
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
} else {
|
||||
res = ast_say_character_str(chan, !ast_strlen_zero(name) ? name : ext,
|
||||
AST_DIGIT_ANY, chan->language);
|
||||
}
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
ast_filedelete(fn, NULL);
|
||||
ast_filedelete(fn2, NULL);
|
||||
#endif
|
||||
|
||||
while (loop) {
|
||||
if (!res) {
|
||||
res = ast_streamfile(chan, "dir-instr", chan->language);
|
||||
}
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
}
|
||||
if (!res) {
|
||||
res = ast_waitfordigit(chan, 3000);
|
||||
}
|
||||
ast_stopstream(chan);
|
||||
|
||||
if (res > -1) {
|
||||
switch (res) {
|
||||
case '1':
|
||||
/* Name selected */
|
||||
loop = 0;
|
||||
if (fromappvm) {
|
||||
/* We still want to set the exten */
|
||||
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;
|
||||
|
||||
case '*':
|
||||
/* Skip to next match in list */
|
||||
loop = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Not '1', or '*', so decrement number of tries */
|
||||
res = 0;
|
||||
loop--;
|
||||
break;
|
||||
} /* end switch */
|
||||
} /* end if */
|
||||
else {
|
||||
/* User hungup, so jump out now */
|
||||
loop = 0;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
static struct ast_config *realtime_directory(char *context)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
struct ast_config *rtdata;
|
||||
struct ast_category *cat;
|
||||
struct ast_variable *var;
|
||||
char *mailbox;
|
||||
char *fullname;
|
||||
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 = ast_category_browse(rtdata, NULL);
|
||||
while (mailbox) {
|
||||
fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
|
||||
hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
|
||||
snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
|
||||
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);
|
||||
mailbox = ast_category_browse(rtdata, mailbox);
|
||||
}
|
||||
ast_config_destroy(rtdata);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *context, char *dialcontext, char digit, int last, 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];
|
||||
char name[80] = "";
|
||||
struct ast_variable *v;
|
||||
int res;
|
||||
int found=0;
|
||||
int lastuserchoice = 0;
|
||||
char *start, *pos, *conv,*stringp=NULL;
|
||||
|
||||
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);
|
||||
@@ -459,18 +140,16 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *
|
||||
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);
|
||||
@@ -484,46 +163,51 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *
|
||||
}
|
||||
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, 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;
|
||||
} else if (res == '*') {
|
||||
res = 0;
|
||||
v = v->next;
|
||||
} else {
|
||||
res = 0;
|
||||
goto ahem;
|
||||
}
|
||||
}
|
||||
v = v->next;
|
||||
} 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') {
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -533,110 +217,47 @@ static int directory_exec(struct ast_channel *chan, void *data)
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
struct ast_config *cfg;
|
||||
int last = 1;
|
||||
int fromappvm = 0;
|
||||
char *context, *dialcontext, *dirintro, *options;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Directory requires an argument (context[,dialcontext])\n");
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "directory requires an argument (context)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
context = ast_strdupa(data);
|
||||
dialcontext = strchr(context, '|');
|
||||
if (dialcontext) {
|
||||
*dialcontext = '\0';
|
||||
dialcontext++;
|
||||
options = strchr(dialcontext, '|');
|
||||
if (options) {
|
||||
*options = '\0';
|
||||
options++;
|
||||
if (strchr(options, 'f'))
|
||||
last = 0;
|
||||
if (strchr(options, 'v'))
|
||||
fromappvm = 1;
|
||||
}
|
||||
} else
|
||||
dialcontext = context;
|
||||
|
||||
cfg = realtime_directory(context);
|
||||
cfg = ast_load(DIRECTORY_CONFIG);
|
||||
if (!cfg) {
|
||||
LOCAL_USER_REMOVE(u);
|
||||
ast_log(LOG_WARNING, "Unable to open directory configuration %s\n", DIRECTORY_CONFIG);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dirintro = ast_variable_retrieve(cfg, context, "directoryintro");
|
||||
if (ast_strlen_zero(dirintro))
|
||||
dirintro = ast_variable_retrieve(cfg, "general", "directoryintro");
|
||||
if (ast_strlen_zero(dirintro)) {
|
||||
if (last)
|
||||
dirintro = "dir-intro";
|
||||
else
|
||||
dirintro = "dir-intro-fn";
|
||||
}
|
||||
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
res = ast_answer(chan);
|
||||
|
||||
for (;;) {
|
||||
if (!res)
|
||||
res = ast_streamfile(chan, dirintro, chan->language);
|
||||
if (!res)
|
||||
res = ast_waitstream(chan, 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, context, dialcontext, res, last, 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;
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
ast_destroy(cfg);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
520
apps/app_disa.c
520
apps/app_disa.c
@@ -1,52 +1,31 @@
|
||||
/*
|
||||
* 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/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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#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"
|
||||
#define TONE_BLOCK_SIZE 200
|
||||
|
||||
static char *tdesc = "DISA (Direct Inward System Access) Application";
|
||||
|
||||
@@ -55,160 +34,164 @@ 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 allow 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.\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.";
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static void play_dialtone(struct ast_channel *chan, char *mailbox)
|
||||
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;
|
||||
int firstdigittimeout = 20000;
|
||||
int digittimeout = 10000;
|
||||
int i,j,k,x;
|
||||
struct localuser *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;
|
||||
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);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (ast_set_write_format(chan,AST_FORMAT_ULAW))
|
||||
{
|
||||
ast_log(LOG_WARNING, "Unable to set write format to Mu-law on %s\n",chan->name);
|
||||
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->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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (ast_set_read_format(chan,AST_FORMAT_ULAW)) {
|
||||
ast_log(LOG_WARNING, "Unable to set read format to Mu-law on %s\n",chan->name);
|
||||
LOCAL_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);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
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)
|
||||
{
|
||||
@@ -221,10 +204,6 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
ast_frfree(f);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
ast_frfree(f);
|
||||
continue;
|
||||
}
|
||||
/* if not DTMF, just do it again */
|
||||
if (f->frametype != AST_FRAME_DTMF)
|
||||
@@ -232,161 +211,176 @@ static int disa_exec(struct ast_channel *chan, void *data)
|
||||
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 (!k) /* if in password state */
|
||||
{
|
||||
if (j == '#') /* end of password */
|
||||
{
|
||||
/* see if this is an integer */
|
||||
if (sscanf(args.passcode,"%30d",&j) < 1)
|
||||
if (sscanf(tmp,"%d",&j) < 1)
|
||||
{ /* nope, it must be a filename */
|
||||
fp = fopen(args.passcode,"r");
|
||||
fp = fopen(tmp,"r");
|
||||
if (!fp)
|
||||
{
|
||||
ast_log(LOG_WARNING,"DISA password file %s not found on chan %s\n",args.passcode,chan->name);
|
||||
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))
|
||||
tmp[0] = 0;
|
||||
while(fgets(tmp,sizeof(tmp) - 1,fp))
|
||||
{
|
||||
if (!pwline[0]) continue;
|
||||
if (pwline[strlen(pwline) - 1] == '\n')
|
||||
pwline[strlen(pwline) - 1] = 0;
|
||||
if (!pwline[0]) continue;
|
||||
if (!tmp[0]) continue;
|
||||
if (tmp[strlen(tmp) - 1] == '\n')
|
||||
tmp[strlen(tmp) - 1] = 0;
|
||||
if (!tmp[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);
|
||||
|
||||
if (tmp[0] == '#') continue;
|
||||
if (tmp[0] == ';') continue;
|
||||
strtok(tmp, "|");
|
||||
ourcontext = strtok(NULL, "|");
|
||||
/* password must be in valid format (numeric) */
|
||||
if (sscanf(args.passcode,"%30d",&j) < 1) continue;
|
||||
if (sscanf(tmp,"%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;
|
||||
}
|
||||
if (!strcmp(exten,tmp)) break;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
/* compare the two */
|
||||
if (strcmp(exten,args.passcode))
|
||||
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);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
exten[i++] = j; /* save digit */
|
||||
exten[i] = 0;
|
||||
if (!(k&1)) continue; /* if getting password, continue doing it */
|
||||
if (!k) 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 == 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))
|
||||
if (ast_exists_extension(chan,ourcontext,exten,1, chan->callerid))
|
||||
{
|
||||
ast_callerid_split(args.cid, ourcidname, sizeof(ourcidname), ourcidnum, sizeof(ourcidnum));
|
||||
ast_set_callerid(chan, ourcidnum, ourcidname, ourcidnum);
|
||||
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;
|
||||
}
|
||||
reorder:
|
||||
/* 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,¬ime) < 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,¬ime) < 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);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(acctcode))
|
||||
ast_copy_string(chan->accountcode, acctcode, sizeof(chan->accountcode));
|
||||
|
||||
ast_cdr_reset(chan->cdr, &flags);
|
||||
ast_explicit_goto(chan, args.context, exten, 1);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Received invalid, but no "i" extension exists in the given context */
|
||||
|
||||
reorder:
|
||||
|
||||
ast_indicate(chan,AST_CONTROL_CONGESTION);
|
||||
/* something is invalid, give em reorder for several seconds */
|
||||
time(&rstart);
|
||||
while(time(NULL) < rstart + 10)
|
||||
{
|
||||
if (ast_waitfor(chan, -1) < 0)
|
||||
break;
|
||||
f = ast_read(chan);
|
||||
if (!f)
|
||||
break;
|
||||
ast_frfree(f);
|
||||
}
|
||||
ast_playtones_stop(chan);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
@@ -406,7 +400,7 @@ int usecount(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key(void)
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,193 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/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 *tdesc = "Dump Info About The Calling Channel";
|
||||
static char *app = "DumpChan";
|
||||
static char *synopsis = "Dump Info About The Calling Channel";
|
||||
static char *desc =
|
||||
" DumpChan([<min_verbose_level>])\n"
|
||||
"Displays information on channel and listing of all channel\n"
|
||||
"variables. If min_verbose_level is specified, output is only\n"
|
||||
"displayed when the verbose level is currently set to that number\n"
|
||||
"or greater. \n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int ast_serialize_showchan(struct ast_channel *c, char *buf, size_t size)
|
||||
{
|
||||
struct timeval now;
|
||||
long elapsed_seconds=0;
|
||||
int hour=0, min=0, sec=0;
|
||||
char cgrp[256];
|
||||
char pgrp[256];
|
||||
|
||||
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"
|
||||
"State= %s (%d)\n"
|
||||
"Rings= %d\n"
|
||||
"NativeFormat= %d\n"
|
||||
"WriteFormat= %d\n"
|
||||
"ReadFormat= %d\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->type,
|
||||
c->uniqueid,
|
||||
(c->cid.cid_num ? c->cid.cid_num : "(N/A)"),
|
||||
(c->cid.cid_name ? c->cid.cid_name : "(N/A)"),
|
||||
(c->cid.cid_dnid ? c->cid.cid_dnid : "(N/A)" ),
|
||||
ast_state2str(c->_state),
|
||||
c->_state,
|
||||
c->rings,
|
||||
c->nativeformats,
|
||||
c->writeformat,
|
||||
c->readformat,
|
||||
c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ? " (DEBUGGED)" : "",
|
||||
c->fout & 0x7fffffff, (c->fout & 0x80000000) ? " (DEBUGGED)" : "", (long)c->whentohangup,
|
||||
hour,
|
||||
min,
|
||||
sec,
|
||||
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 ? (!ast_strlen_zero(c->data) ? 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)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char vars[1024];
|
||||
char info[1024];
|
||||
int level = 0;
|
||||
static char *line = "================================================================================";
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!ast_strlen_zero(data)) {
|
||||
level = atoi(data);
|
||||
}
|
||||
|
||||
pbx_builtin_serialize_variables(chan, vars, sizeof(vars));
|
||||
ast_serialize_showchan(chan, info, sizeof(info));
|
||||
if (option_verbose >= level)
|
||||
ast_verbose("\nDumping Info For Channel: %s:\n%s\nInfo:\n%s\nVariables:\n%s%s\n",chan->name, line, info, vars, line);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, dumpchan_exec, synopsis, desc);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Echo application -- play back what you hear to evaluate latency
|
||||
*
|
||||
* \ingroup applications
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
#include <pthread.h>
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Simple Echo Application";
|
||||
|
||||
@@ -46,9 +31,8 @@ static char *app = "Echo";
|
||||
static char *synopsis = "Echo audio read back to the user";
|
||||
|
||||
static char *descrip =
|
||||
" Echo(): Echo audio read from channel back to the channel. \n"
|
||||
"User can exit the application by either pressing the '#' key, \n"
|
||||
"or hanging up.\n";
|
||||
" 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;
|
||||
|
||||
@@ -63,18 +47,10 @@ static int echo_exec(struct ast_channel *chan, void *data)
|
||||
ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
|
||||
ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
|
||||
/* Do our thing here */
|
||||
while(ast_waitfor(chan, -1) > -1) {
|
||||
f = ast_read(chan);
|
||||
if (!f)
|
||||
break;
|
||||
f->delivery.tv_sec = 0;
|
||||
f->delivery.tv_usec = 0;
|
||||
while((f = ast_read(chan))) {
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
} else if (f->frametype == AST_FRAME_VIDEO) {
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
} else if (f->frametype == AST_FRAME_DTMF) {
|
||||
if (f->subclass == '#') {
|
||||
res = 0;
|
||||
@@ -91,13 +67,8 @@ static int echo_exec(struct ast_channel *chan, void *data)
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
|
||||
@@ -1,270 +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 Enumlookup - lookup entry in ENUM
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/enum.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "ENUM Lookup";
|
||||
|
||||
static char *app = "EnumLookup";
|
||||
|
||||
static char *synopsis = "Lookup number in ENUM";
|
||||
|
||||
static char *descrip =
|
||||
" EnumLookup(exten[|option]): Looks up an extension via ENUM and sets\n"
|
||||
"the variable 'ENUM'. For VoIP URIs this variable will \n"
|
||||
"look like 'TECHNOLOGY/URI' with the appropriate technology.\n"
|
||||
"Currently, the enumservices SIP, H323, IAX, IAX2 and TEL are recognized. \n"
|
||||
"\nReturns status in the ENUMSTATUS channel variable:\n"
|
||||
" ERROR Failed to do a lookup\n"
|
||||
" <tech> Technology of the successful lookup: SIP, H323, IAX, IAX2 or TEL\n"
|
||||
" BADURI Got URI Asterisk does not understand.\n"
|
||||
" The option string may contain zero or the following character:\n"
|
||||
" 'j' -- jump to +101 priority if the lookup isn't successful.\n"
|
||||
" and jump to +51 priority on a TEL entry.\n";
|
||||
|
||||
#define ENUM_CONFIG "enum.conf"
|
||||
|
||||
static char h323driver[80] = "";
|
||||
#define H323DRIVERDEFAULT "H323"
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/*--- enumlookup_exec: Look up number in ENUM and return result */
|
||||
static int enumlookup_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0,priority_jump=0;
|
||||
char tech[80];
|
||||
char dest[80];
|
||||
char tmp[256];
|
||||
char *c,*t = NULL;
|
||||
static int dep_warning=0;
|
||||
struct localuser *u;
|
||||
char *parse;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(d);
|
||||
AST_APP_ARG(o);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "EnumLookup requires an argument (extension)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "The application EnumLookup is deprecated. Please use the ENUMLOOKUP() function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
parse = ast_strdupa(data);
|
||||
if (!parse) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
tech[0] = '\0';
|
||||
dest[0] = '\0';
|
||||
|
||||
if (args.o) {
|
||||
if (strchr(args.o, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
res = ast_get_enum(chan, args.d, dest, sizeof(dest), tech, sizeof(tech), NULL, NULL);
|
||||
|
||||
if (!res) { /* Failed to do a lookup */
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
/* Look for a "busy" place */
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "ENUMSTATUS", "ERROR");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, "ENUMSTATUS", tech);
|
||||
/* Parse it out */
|
||||
if (res > 0) {
|
||||
if (!strcasecmp(tech, "SIP")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "sip:", 4))
|
||||
c += 4;
|
||||
snprintf(tmp, sizeof(tmp), "SIP/%s", c);
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "h323")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "h323:", 5))
|
||||
c += 5;
|
||||
snprintf(tmp, sizeof(tmp), "%s/%s", h323driver, c);
|
||||
/* do a s!;.*!! on the H323 URI */
|
||||
t = strchr(c,';');
|
||||
if (t)
|
||||
*t = 0;
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "iax")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "iax:", 4))
|
||||
c += 4;
|
||||
snprintf(tmp, sizeof(tmp), "IAX/%s", c);
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "iax2")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "iax2:", 5))
|
||||
c += 5;
|
||||
snprintf(tmp, sizeof(tmp), "IAX2/%s", c);
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
} else if (!strcasecmp(tech, "tel")) {
|
||||
c = dest;
|
||||
if (!strncmp(c, "tel:", 4))
|
||||
c += 4;
|
||||
|
||||
if (c[0] != '+') {
|
||||
ast_log(LOG_NOTICE, "tel: uri must start with a \"+\" (got '%s')\n", c);
|
||||
res = 0;
|
||||
} else {
|
||||
/* now copy over the number, skipping all non-digits and stop at ; or NULL */
|
||||
t = tmp;
|
||||
while( *c && (*c != ';') && (t - tmp < (sizeof(tmp) - 1))) {
|
||||
if (isdigit(*c))
|
||||
*t++ = *c;
|
||||
c++;
|
||||
}
|
||||
*t = 0;
|
||||
pbx_builtin_setvar_helper(chan, "ENUM", tmp);
|
||||
ast_log(LOG_NOTICE, "tel: ENUM set to \"%s\"\n", tmp);
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 51))
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
} else if (!ast_strlen_zero(tech)) {
|
||||
ast_log(LOG_NOTICE, "Don't know how to handle technology '%s'\n", tech);
|
||||
pbx_builtin_setvar_helper(chan, "ENUMSTATUS", "BADURI");
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*--- load_config: Load enum.conf and find out how to handle H.323 */
|
||||
static int load_config(void)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
char *s;
|
||||
|
||||
cfg = ast_config_load(ENUM_CONFIG);
|
||||
if (cfg) {
|
||||
if (!(s=ast_variable_retrieve(cfg, "general", "h323driver"))) {
|
||||
strncpy(h323driver, H323DRIVERDEFAULT, sizeof(h323driver) - 1);
|
||||
} else {
|
||||
strncpy(h323driver, s, sizeof(h323driver) - 1);
|
||||
}
|
||||
ast_config_destroy(cfg);
|
||||
return 0;
|
||||
}
|
||||
ast_log(LOG_NOTICE, "No ENUM Config file, using defaults\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*--- unload_module: Unload this application from PBX */
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--- load_module: Load this application into PBX */
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app, enumlookup_exec, synopsis, descrip);
|
||||
|
||||
if (!res)
|
||||
res = load_config();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--- reload: Reload configuration file */
|
||||
int reload(void)
|
||||
{
|
||||
return load_config();
|
||||
}
|
||||
|
||||
|
||||
/*--- description: Describe module */
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
127
apps/app_eval.c
127
apps/app_eval.c
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_eval__v001@the-tilghman.com>
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
* \brief Eval application
|
||||
*
|
||||
* \author Tilghman Lesher <app_eval__v001@the-tilghman.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
static char *tdesc = "Reevaluates strings";
|
||||
|
||||
static char *app_eval = "Eval";
|
||||
|
||||
static char *eval_synopsis = "Evaluates a string";
|
||||
|
||||
static char *eval_descrip =
|
||||
"Usage: Eval(newvar=somestring)\n"
|
||||
" Normally Asterisk evaluates variables inline. But what if you want to\n"
|
||||
"store variable offsets in a database, to be evaluated later? Eval is\n"
|
||||
"the answer, by allowing a string to be evaluated twice in the dialplan,\n"
|
||||
"the first time as part of the normal dialplan, and the second using Eval.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int eval_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s, *newvar=NULL, tmp[MAXRESULT];
|
||||
static int dep_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated in favor of the dialplan function, EVAL\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
newvar = strsep(&s, "=");
|
||||
if (newvar && (newvar[0] != '\0')) {
|
||||
memset(tmp, 0, MAXRESULT);
|
||||
pbx_substitute_variables_helper(chan, s, tmp, MAXRESULT - 1);
|
||||
pbx_builtin_setvar_helper(chan, newvar, tmp);
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_eval);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_eval, eval_exec, eval_synopsis, eval_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
135
apps/app_exec.c
135
apps/app_exec.c
@@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2004 - 2005, Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_exec__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 Exec application
|
||||
*
|
||||
* \author Tilghman Lesher <app_exec__v001@the-tilghman.com>
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
/* Maximum length of any variable */
|
||||
#define MAXRESULT 1024
|
||||
|
||||
static char *tdesc = "Executes applications";
|
||||
|
||||
static char *app_exec = "Exec";
|
||||
|
||||
static char *exec_synopsis = "Executes internal application";
|
||||
|
||||
static char *exec_descrip =
|
||||
"Usage: Exec(appname(arguments))\n"
|
||||
" Allows an arbitrary application to be invoked even when not\n"
|
||||
"hardcoded into the dialplan. To invoke external applications\n"
|
||||
"see the application System. Returns whatever value the\n"
|
||||
"app returns or a non-zero value if the app cannot be found.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int exec_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s, *appname, *endargs, args[MAXRESULT];
|
||||
struct ast_app *app;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
memset(args, 0, MAXRESULT);
|
||||
|
||||
/* Check and parse arguments */
|
||||
if (data) {
|
||||
s = ast_strdupa((char *)data);
|
||||
if (s) {
|
||||
appname = strsep(&s, "(");
|
||||
if (s) {
|
||||
endargs = strrchr(s, ')');
|
||||
if (endargs)
|
||||
*endargs = '\0';
|
||||
pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
|
||||
}
|
||||
if (appname) {
|
||||
app = pbx_findapp(appname);
|
||||
if (app) {
|
||||
res = pbx_exec(chan, app, args, 1);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_exec);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_exec, exec_exec, exec_synopsis, exec_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,597 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/linkedlists.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static const char *tdesc = "External IVR Interface Application";
|
||||
|
||||
static const char *app = "ExternalIVR";
|
||||
|
||||
static const char *synopsis = "Interfaces with an external IVR application";
|
||||
|
||||
static const char *descrip =
|
||||
" ExternalIVR(command[|arg[|arg...]]): Forks 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/README.externalivr for a protocol specification.\n";
|
||||
|
||||
/* XXX the parser in gcc 2.95 gets confused if you don't put a space between 'name' and the comma */
|
||||
#define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
|
||||
|
||||
struct playlist_entry {
|
||||
AST_LIST_ENTRY(playlist_entry) list;
|
||||
char filename[1];
|
||||
};
|
||||
|
||||
struct localuser {
|
||||
struct ast_channel *chan;
|
||||
struct localuser *next;
|
||||
AST_LIST_HEAD(playlist, playlist_entry) playlist;
|
||||
AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
|
||||
int abort_current_sound;
|
||||
int playing_silence;
|
||||
int option_autoclear;
|
||||
};
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
struct gen_state {
|
||||
struct 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 localuser *u = params;
|
||||
struct gen_state *state;
|
||||
|
||||
state = calloc(1, sizeof(*state));
|
||||
|
||||
if (!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 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 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;
|
||||
|
||||
entry = calloc(1, sizeof(*entry) + strlen(filename) + 10);
|
||||
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
strcpy(entry->filename, filename);
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static int app_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u = NULL;
|
||||
struct playlist_entry *entry;
|
||||
const char *args = data;
|
||||
int child_stdin[2] = { 0,0 };
|
||||
int child_stdout[2] = { 0,0 };
|
||||
int child_stderr[2] = { 0,0 };
|
||||
int res = -1;
|
||||
int 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;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
sigfillset(&fullset);
|
||||
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
|
||||
|
||||
AST_LIST_HEAD_INIT(&u->playlist);
|
||||
AST_LIST_HEAD_INIT(&u->finishlist);
|
||||
u->abort_current_sound = 0;
|
||||
|
||||
if (ast_strlen_zero(args)) {
|
||||
ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
buf = ast_strdupa(data);
|
||||
if (!buf) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));
|
||||
|
||||
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 (option_highpriority)
|
||||
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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, app_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,548 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#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.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/md5.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define FESTIVAL_CONFIG "festival.conf"
|
||||
|
||||
static char *tdesc = "Simple Festival Interface";
|
||||
|
||||
static char *app = "Festival";
|
||||
|
||||
static char *synopsis = "Say text to the user";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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;
|
||||
buff = (char *)malloc(bufflen);
|
||||
*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;
|
||||
buff = (char *)realloc(buff,bufflen);
|
||||
}
|
||||
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 (option_highpriority)
|
||||
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;
|
||||
|
||||
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.mallocd = 0;
|
||||
myf.f.offset = AST_FRIENDLY_OFFSET;
|
||||
myf.f.src = __PRETTY_FUNCTION__;
|
||||
myf.f.data = myf.frdata;
|
||||
if (ast_write(chan, &myf.f) < 0) {
|
||||
res = -1;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
if (res < needed) { /* last frame */
|
||||
ast_log(LOG_DEBUG, "Last frame\n");
|
||||
res=0;
|
||||
ast_frfree(f);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
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 localuser *u;
|
||||
struct sockaddr_in serv_addr;
|
||||
struct hostent *serverhost;
|
||||
struct ast_hostent ahp;
|
||||
int fd;
|
||||
FILE *fs;
|
||||
char *host;
|
||||
char *cachedir;
|
||||
char *temp;
|
||||
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;
|
||||
|
||||
if (ast_strlen_zero(vdata)) {
|
||||
ast_log(LOG_WARNING, "festival requires an argument (text)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
cfg = ast_config_load(FESTIVAL_CONFIG);
|
||||
if (!cfg) {
|
||||
ast_log(LOG_WARNING, "No such configuration file %s\n", FESTIVAL_CONFIG);
|
||||
LOCAL_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";
|
||||
}
|
||||
|
||||
data = ast_strdupa(vdata);
|
||||
if (!data) {
|
||||
ast_log(LOG_ERROR, "Out of memery\n");
|
||||
ast_config_destroy(cfg);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intstr = strchr(data, '|');
|
||||
if (intstr) {
|
||||
*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);
|
||||
LOCAL_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);
|
||||
LOCAL_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);
|
||||
LOCAL_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);
|
||||
LOCAL_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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
|
||||
return ast_register_application(app, festival_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
141
apps/app_flash.c
141
apps/app_flash.c
@@ -1,141 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/zaptel.h>
|
||||
#else
|
||||
#include <zaptel.h>
|
||||
#endif /* __linux__ */
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Flash zap trunk application";
|
||||
|
||||
static char *app = "Flash";
|
||||
|
||||
static char *synopsis = "Flashes a Zap Trunk";
|
||||
|
||||
static char *descrip =
|
||||
" 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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static inline int zt_wait_event(int fd)
|
||||
{
|
||||
/* Avoid the silly zt_waitevent which ignores a bunch of events */
|
||||
int i,j=0;
|
||||
i = 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 localuser *u;
|
||||
struct zt_params ztp;
|
||||
LOCAL_USER_ADD(u);
|
||||
if (!strcasecmp(chan->type, "Zap")) {
|
||||
memset(&ztp, 0, sizeof(ztp));
|
||||
res = ioctl(chan->fds[0], 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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, flash_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,131 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/cdr.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Fork The CDR into 2 separate entities.";
|
||||
static char *app = "ForkCDR";
|
||||
static char *synopsis =
|
||||
"Forks the Call Data Record";
|
||||
static char *descrip =
|
||||
" ForkCDR([options]): Causes the Call Data Record to fork an additional\n"
|
||||
"cdr record starting from the time of the fork call\n"
|
||||
"If the option 'v' is passed all cdr variables will be passed along also.\n"
|
||||
"";
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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 localuser *u;
|
||||
|
||||
if (!chan->cdr) {
|
||||
ast_log(LOG_WARNING, "Channel does not have a CDR\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!ast_strlen_zero(data))
|
||||
ast_set2_flag(chan->cdr, strchr(data, 'v'), AST_CDR_FLAG_KEEP_VARS);
|
||||
|
||||
ast_cdr_fork(chan);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, forkcdr_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,167 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/adsi.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Get ADSI CPE ID";
|
||||
|
||||
static char *app = "GetCPEID";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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 adsi_print(chan, tmp, justify, voice);
|
||||
}
|
||||
|
||||
static int cpeid_exec(struct ast_channel *chan, void *idata)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
unsigned char cpeid[4];
|
||||
int gotgeometry = 0;
|
||||
int gotcpeid = 0;
|
||||
int width, height, buttons;
|
||||
char data[4][80];
|
||||
char *stuff[4];
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
stuff[0] = data[0];
|
||||
stuff[1] = data[1];
|
||||
stuff[2] = data[2];
|
||||
stuff[3] = data[3];
|
||||
memset(data, 0, sizeof(data));
|
||||
strncpy(stuff[0], "** CPE Info **", sizeof(data[0]) - 1);
|
||||
strncpy(stuff[1], "Identifying CPE...", sizeof(data[1]) - 1);
|
||||
strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
|
||||
res = adsi_load_session(chan, NULL, 0, 1);
|
||||
if (res > 0) {
|
||||
cpeid_setstatus(chan, stuff, 0);
|
||||
res = adsi_get_cpeid(chan, cpeid, 0);
|
||||
if (res > 0) {
|
||||
gotcpeid = 1;
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Got CPEID of '%02x:%02x:%02x:%02x' on '%s'\n", cpeid[0], cpeid[1], cpeid[2], cpeid[3], chan->name);
|
||||
}
|
||||
if (res > -1) {
|
||||
strncpy(stuff[1], "Measuring CPE...", sizeof(data[1]) - 1);
|
||||
strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
|
||||
cpeid_setstatus(chan, stuff, 0);
|
||||
res = adsi_get_cpeinfo(chan, &width, &height, &buttons, 0);
|
||||
if (res > -1) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "CPE has %d lines, %d columns, and %d buttons on '%s'\n", height, width, buttons, chan->name);
|
||||
gotgeometry = 1;
|
||||
}
|
||||
}
|
||||
if (res > -1) {
|
||||
if (gotcpeid)
|
||||
snprintf(stuff[1], sizeof(data[1]), "CPEID: %02x:%02x:%02x:%02x", cpeid[0], cpeid[1], cpeid[2], cpeid[3]);
|
||||
else
|
||||
strncpy(stuff[1], "CPEID Unknown", sizeof(data[1]) - 1);
|
||||
if (gotgeometry)
|
||||
snprintf(stuff[2], sizeof(data[2]), "Geom: %dx%d, %d buttons", width, height, buttons);
|
||||
else
|
||||
strncpy(stuff[2], "Geometry unknown", sizeof(data[2]) - 1);
|
||||
strncpy(stuff[3], "Press # to exit", sizeof(data[3]) - 1);
|
||||
cpeid_setstatus(chan, stuff, 1);
|
||||
for(;;) {
|
||||
res = ast_waitfordigit(chan, 1000);
|
||||
if (res < 0)
|
||||
break;
|
||||
if (res == '#') {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
adsi_unload_session(chan);
|
||||
}
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, cpeid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,338 +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 Group Manipulation Applications
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int group_count_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int count;
|
||||
struct localuser *u;
|
||||
char group[80] = "";
|
||||
char category[80] = "";
|
||||
char ret[80] = "";
|
||||
char *grp;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The GetGroupCount application has been deprecated, please use the GROUP_COUNT function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
|
||||
|
||||
if (ast_strlen_zero(group)) {
|
||||
grp = pbx_builtin_getvar_helper(chan, category);
|
||||
if (!ast_strlen_zero(grp))
|
||||
ast_copy_string(group, grp, sizeof(group));
|
||||
}
|
||||
|
||||
count = ast_app_group_get_count(group, category);
|
||||
snprintf(ret, sizeof(ret), "%d", count);
|
||||
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_match_count_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int count;
|
||||
struct localuser *u;
|
||||
char group[80] = "";
|
||||
char category[80] = "";
|
||||
char ret[80] = "";
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The GetGroupMatchCount application has been deprecated, please use the GROUP_MATCH_COUNT function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
|
||||
|
||||
if (!ast_strlen_zero(group)) {
|
||||
count = ast_app_group_match_get_count(group, category);
|
||||
snprintf(ret, sizeof(ret), "%d", count);
|
||||
pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_set_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The SetGroup application has been deprecated, please use the GROUP() function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_app_group_set_channel(chan, data))
|
||||
ast_log(LOG_WARNING, "SetGroup requires an argument (group name)\n");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_check_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
int max, count;
|
||||
struct localuser *u;
|
||||
char limit[80]="";
|
||||
char category[80]="";
|
||||
static int deprecation_warning = 0;
|
||||
char *parse;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(max);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "The CheckGroup application has been deprecated, please use a combination of the GotoIf application and the GROUP_COUNT() function.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "CheckGroup requires an argument(max[@category][|options])\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(parse = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.max)) {
|
||||
ast_log(LOG_WARNING, "CheckGroup requires an argument(max[@category][|options])\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
ast_app_group_split_group(args.max, limit, sizeof(limit), category, sizeof(category));
|
||||
|
||||
if ((sscanf(limit, "%30d", &max) == 1) && (max > -1)) {
|
||||
count = ast_app_group_get_count(pbx_builtin_getvar_helper(chan, category), category);
|
||||
if (count > max) {
|
||||
pbx_builtin_setvar_helper(chan, "CHECKGROUPSTATUS", "OVERMAX");
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
res = -1;
|
||||
}
|
||||
} else
|
||||
pbx_builtin_setvar_helper(chan, "CHECKGROUPSTATUS", "OK");
|
||||
} else
|
||||
ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int group_show_channels(int fd, int argc, char *argv[])
|
||||
{
|
||||
#define FORMAT_STRING "%-25s %-20s %-20s\n"
|
||||
|
||||
int numchans = 0;
|
||||
struct ast_group_info *gi = NULL;
|
||||
regex_t regexbuf;
|
||||
int havepattern = 0;
|
||||
|
||||
if (argc < 3 || argc > 4)
|
||||
return RESULT_SHOWUSAGE;
|
||||
|
||||
if (argc == 4) {
|
||||
if (regcomp(®exbuf, argv[3], REG_EXTENDED | REG_NOSUB))
|
||||
return RESULT_SHOWUSAGE;
|
||||
havepattern = 1;
|
||||
}
|
||||
|
||||
ast_cli(fd, FORMAT_STRING, "Channel", "Group", "Category");
|
||||
|
||||
ast_app_group_list_lock();
|
||||
|
||||
gi = ast_app_group_list_head();
|
||||
while (gi) {
|
||||
if (!havepattern || !regexec(®exbuf, gi->group, 0, NULL, 0)) {
|
||||
ast_cli(fd, FORMAT_STRING, gi->chan->name, gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
|
||||
numchans++;
|
||||
}
|
||||
gi = AST_LIST_NEXT(gi, list);
|
||||
}
|
||||
|
||||
ast_app_group_list_unlock();
|
||||
|
||||
if (havepattern)
|
||||
regfree(®exbuf);
|
||||
|
||||
ast_cli(fd, "%d active channel%s\n", numchans, (numchans != 1) ? "s" : "");
|
||||
return RESULT_SUCCESS;
|
||||
#undef FORMAT_STRING
|
||||
}
|
||||
|
||||
static char *tdesc = "Group Management Routines";
|
||||
|
||||
static char *app_group_count = "GetGroupCount";
|
||||
static char *app_group_set = "SetGroup";
|
||||
static char *app_group_check = "CheckGroup";
|
||||
static char *app_group_match_count = "GetGroupMatchCount";
|
||||
|
||||
static char *group_count_synopsis = "Get the channel count of a group";
|
||||
static char *group_set_synopsis = "Set the channel's group";
|
||||
static char *group_check_synopsis = "Check the channel count of a group against a limit";
|
||||
static char *group_match_count_synopsis = "Get the channel count of all groups that match a pattern";
|
||||
|
||||
static char *group_count_descrip =
|
||||
"Usage: GetGroupCount([groupname][@category])\n"
|
||||
" Calculates the group count for the specified group, or uses\n"
|
||||
"the current channel's group if not specifed (and non-empty).\n"
|
||||
"Stores result in GROUPCOUNT. \n"
|
||||
"Note: This application has been deprecated, please use the function\n"
|
||||
"GROUP_COUNT.\n";
|
||||
|
||||
static char *group_set_descrip =
|
||||
"Usage: SetGroup(groupname[@category])\n"
|
||||
" Sets the channel group to the specified value. Equivalent to\n"
|
||||
"Set(GROUP=group). Always returns 0.\n";
|
||||
|
||||
static char *group_check_descrip =
|
||||
"Usage: CheckGroup(max[@category][|options])\n"
|
||||
" Checks that the current number of total channels in the\n"
|
||||
"current channel's group does not exceed 'max'. If the number\n"
|
||||
"does not exceed 'max', we continue to the next step. \n"
|
||||
" The option string may contain zero of the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the number does in fact exceed max,\n"
|
||||
" and priority n+101 exists. Execuation then continues at that\n"
|
||||
" step, otherwise -1 is returned.\n"
|
||||
" This application sets the following channel variable upon successful completion:\n"
|
||||
" CHECKGROUPSTATUS The status of the check that the current channel's\n"
|
||||
" group does not exceed 'max'. It's value is one of\n"
|
||||
" OK | OVERMAX \n";
|
||||
|
||||
static char *group_match_count_descrip =
|
||||
"Usage: GetGroupMatchCount(groupmatch[@category])\n"
|
||||
" Calculates the group count for all groups that match the specified\n"
|
||||
"pattern. Uses standard regular expression matching (see regex(7)).\n"
|
||||
"Stores result in GROUPCOUNT. Always returns 0.\n"
|
||||
"Note: This application has been deprecated, please use the function\n"
|
||||
"GROUP_MATCH_COUNT.\n";
|
||||
|
||||
static char show_channels_usage[] =
|
||||
"Usage: group show channels [pattern]\n"
|
||||
" Lists all currently active channels with channel group(s) specified.\n Optional regular expression pattern is matched to group names for each channel.\n";
|
||||
|
||||
static struct ast_cli_entry cli_show_channels =
|
||||
{ { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", show_channels_usage};
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_cli_unregister(&cli_show_channels);
|
||||
res |= ast_unregister_application(app_group_count);
|
||||
res |= ast_unregister_application(app_group_set);
|
||||
res |= ast_unregister_application(app_group_check);
|
||||
res |= ast_unregister_application(app_group_match_count);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
|
||||
res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
|
||||
res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
|
||||
res |= ast_register_application(app_group_match_count, group_match_count_exec, group_match_count_synopsis, group_match_count_descrip);
|
||||
res |= ast_cli_register(&cli_show_channels);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Changes Copyright (c) 2004 - 2005 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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
#include "asterisk/res_odbc.h"
|
||||
|
||||
static char odbc_database[80];
|
||||
static char odbc_table[80];
|
||||
#endif
|
||||
|
||||
static char *tdesc = "Indicator for whether a voice mailbox has messages in a given folder.";
|
||||
static char *app_hasvoicemail = "HasVoicemail";
|
||||
static char *hasvoicemail_synopsis = "Conditionally branches to priority + 101 with the right options set";
|
||||
static char *hasvoicemail_descrip =
|
||||
"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";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
static int hasvoicemail_internal(const char *context, const char *mailbox, const char *folder)
|
||||
{
|
||||
int nummsgs = 0;
|
||||
int res;
|
||||
SQLHSTMT stmt;
|
||||
char sql[256];
|
||||
char rowdata[20];
|
||||
|
||||
if (!folder)
|
||||
folder = "INBOX";
|
||||
/* If no mailbox, return immediately */
|
||||
if (ast_strlen_zero(mailbox))
|
||||
return 0;
|
||||
if (ast_strlen_zero(context))
|
||||
context = "default";
|
||||
|
||||
odbc_obj *obj;
|
||||
obj = fetch_odbc_obj(odbc_database, 0);
|
||||
if (obj) {
|
||||
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");
|
||||
goto yuck;
|
||||
}
|
||||
snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir = '%s/voicemail/%s/%s/%s'", odbc_table, ast_config_AST_SPOOL_DIR, context, mailbox, folder);
|
||||
res = SQLPrepare(stmt, 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);
|
||||
goto yuck;
|
||||
}
|
||||
res = 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);
|
||||
goto yuck;
|
||||
}
|
||||
res = SQLFetch(stmt);
|
||||
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);
|
||||
goto yuck;
|
||||
}
|
||||
res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
|
||||
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);
|
||||
goto yuck;
|
||||
}
|
||||
nummsgs = atoi(rowdata);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
|
||||
|
||||
yuck:
|
||||
return nummsgs;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int hasvoicemail_internal(const char *context, const char *mailbox, const char *folder)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
char fn[256];
|
||||
int count = 0;
|
||||
|
||||
if (ast_strlen_zero(folder))
|
||||
folder = "INBOX";
|
||||
if (ast_strlen_zero(context))
|
||||
context = "default";
|
||||
/* If no mailbox, return immediately */
|
||||
if (ast_strlen_zero(mailbox))
|
||||
return 0;
|
||||
snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/%s", ast_config_AST_SPOOL_DIR, context, mailbox, folder);
|
||||
dir = opendir(fn);
|
||||
if (!dir)
|
||||
return 0;
|
||||
while ((de = readdir(dir))) {
|
||||
if (!strncasecmp(de->d_name, "msg", 3) && !strcasecmp(de->d_name + 8, "txt"))
|
||||
count++;
|
||||
}
|
||||
closedir(dir);
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int hasvoicemail_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
input = ast_strdupa((char *)data);
|
||||
if (! input) {
|
||||
ast_log(LOG_ERROR, "Out of memory error\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, input);
|
||||
|
||||
if ((vmbox = strsep(&args.vmbox, "@")))
|
||||
if (!ast_strlen_zero(args.vmbox))
|
||||
context = args.vmbox;
|
||||
if (!vmbox)
|
||||
vmbox = 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 = hasvoicemail_internal(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 || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
ast_log(LOG_WARNING, "VM box %s@%s has new voicemail, but extension %s, priority %d doesn't exist\n", vmbox, context, chan->exten, chan->priority + 101);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%d", vmcount);
|
||||
pbx_builtin_setvar_helper(chan, "HASVMSTATUS", tmp);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *acf_vmcount_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
|
||||
{
|
||||
struct localuser *u;
|
||||
char *args, *context, *box, *folder;
|
||||
|
||||
LOCAL_USER_ACF_ADD(u);
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
args = ast_strdupa(data);
|
||||
if (!args) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return buf;
|
||||
}
|
||||
|
||||
box = strsep(&args, "|");
|
||||
if (strchr(box, '@')) {
|
||||
context = box;
|
||||
box = strsep(&context, "@");
|
||||
} else {
|
||||
context = "default";
|
||||
}
|
||||
|
||||
if (args) {
|
||||
folder = args;
|
||||
} else {
|
||||
folder = "INBOX";
|
||||
}
|
||||
|
||||
snprintf(buf, len, "%d", hasvoicemail_internal(context, box, folder));
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
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 load_config(void)
|
||||
{
|
||||
#ifdef USE_ODBC_STORAGE
|
||||
struct ast_config *cfg;
|
||||
char *tmp;
|
||||
cfg = ast_config_load("voicemail.conf");
|
||||
if (cfg) {
|
||||
if (! (tmp = ast_variable_retrieve(cfg, "general", "odbcstorage")))
|
||||
tmp = "asterisk";
|
||||
ast_copy_string(odbc_database, tmp, sizeof(odbc_database));
|
||||
|
||||
if (! (tmp = ast_variable_retrieve(cfg, "general", "odbctable")))
|
||||
tmp = "voicemessages";
|
||||
ast_copy_string(odbc_table, tmp, sizeof(odbc_table));
|
||||
ast_config_destroy(cfg);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reload(void)
|
||||
{
|
||||
return load_config();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
load_config();
|
||||
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;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
241
apps/app_ices.c
241
apps/app_ices.c
@@ -1,241 +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)
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define ICES "/usr/bin/ices"
|
||||
#define LOCAL_ICES "/usr/local/bin/ices"
|
||||
|
||||
static char *tdesc = "Encode and Stream via icecast and ices";
|
||||
|
||||
static char *app = "ICES";
|
||||
|
||||
static char *synopsis = "Encode and stream using 'ices'";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int icesencode(char *filename, int fd)
|
||||
{
|
||||
int res;
|
||||
int x;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
sigfillset(&fullset);
|
||||
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
|
||||
|
||||
res = fork();
|
||||
if (res < 0)
|
||||
ast_log(LOG_WARNING, "Fork failed\n");
|
||||
if (res) {
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Stop ignoring PIPE */
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
|
||||
|
||||
if (option_highpriority)
|
||||
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 localuser *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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
last = ast_tv(0, 0);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
LOCAL_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");
|
||||
LOCAL_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");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (((char *)data)[0] == '/')
|
||||
strncpy(filename, (char *)data, sizeof(filename) - 1);
|
||||
else
|
||||
snprintf(filename, sizeof(filename), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, (char *)data);
|
||||
/* Placeholder for options */
|
||||
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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, ices_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
116
apps/app_image.c
116
apps/app_image.c
@@ -1,46 +1,26 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static char *tdesc = "Image Transmission Application";
|
||||
|
||||
@@ -49,15 +29,12 @@ 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;
|
||||
|
||||
@@ -67,61 +44,26 @@ static int sendimage_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *parse;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(filename);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (!data || !strlen((char *)data)) {
|
||||
ast_log(LOG_WARNING, "SendImage requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(parse = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (ast_strlen_zero(args.filename)) {
|
||||
ast_log(LOG_WARNING, "SendImage requires an argument (filename[|options])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (!ast_supports_images(chan)) {
|
||||
/* Does not support transport */
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
pbx_builtin_setvar_helper(chan, "SENDIMAGESTATUS", "NOSUPPORT");
|
||||
LOCAL_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");
|
||||
|
||||
res = ast_send_image(chan, data);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
|
||||
@@ -1,63 +1,34 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
* Use /dev/dsp as an intercom.
|
||||
*
|
||||
* 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 Use /dev/dsp as an intercom.
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/frame.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/soundcard.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <linux/soundcard.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/soundcard.h>
|
||||
#else
|
||||
#include <soundcard.h>
|
||||
#endif
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
#define DEV_DSP "/dev/audio"
|
||||
#else
|
||||
#define DEV_DSP "/dev/dsp"
|
||||
#endif
|
||||
|
||||
/* Number of 32 byte buffers -- each buffer is 2 ms */
|
||||
#define BUFFER_SIZE 32
|
||||
@@ -69,36 +40,37 @@ static char *app = "Intercom";
|
||||
static char *synopsis = "(Obsolete) Send to Intercom";
|
||||
static char *descrip =
|
||||
" Intercom(): Sends the user to the intercom (i.e. /dev/dsp). This program\n"
|
||||
"is generally considered obselete by the chan_oss module. User can terminate\n"with a DTMF tone, or by hangup.\n";
|
||||
"is generally considered obselete by the chan_oss module. Returns 0 if the\n"
|
||||
"user exits with a DTMF tone, or -1 if they hangup.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
AST_MUTEX_DEFINE_STATIC(sound_lock);
|
||||
static 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_mutex_lock(&sound_lock);
|
||||
ast_pthread_mutex_lock(&sound_lock);
|
||||
if (sound < 0) {
|
||||
ast_log(LOG_WARNING, "Sound device closed?\n");
|
||||
ast_mutex_unlock(&sound_lock);
|
||||
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_mutex_unlock(&sound_lock);
|
||||
ast_pthread_mutex_unlock(&sound_lock);
|
||||
return -1;
|
||||
}
|
||||
res = write(sound, data, len);
|
||||
ast_mutex_unlock(&sound_lock);
|
||||
ast_pthread_mutex_unlock(&sound_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int create_audio(void)
|
||||
static int create_audio()
|
||||
{
|
||||
int fmt, desired, res, fd;
|
||||
fd = open(DEV_DSP, O_WRONLY);
|
||||
@@ -158,7 +130,6 @@ static int intercom_exec(struct ast_channel *chan, void *data)
|
||||
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
/* Read packets from the channel */
|
||||
@@ -186,27 +157,18 @@ static int intercom_exec(struct ast_channel *chan, void *data)
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (!res)
|
||||
ast_set_read_format(chan, oreadformat);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
if (sound > -1)
|
||||
close(sound);
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
|
||||
@@ -1,144 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/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 },
|
||||
});
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* 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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, skel_exec, tdesc, synopsis);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,141 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "Look up Caller*ID name/number from blacklist database";
|
||||
|
||||
static char *app = "LookupBlacklist";
|
||||
|
||||
static char *synopsis = "Look up Caller*ID name/number from blacklist database";
|
||||
|
||||
static char *descrip =
|
||||
" LookupBlacklist(options): Looks up the Caller*ID number on the active\n"
|
||||
"channel in the Asterisk database (family 'blacklist'). \n"
|
||||
"The option string may contain the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the number/name is found in the blacklist\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" LOOKUPBLSTATUS The status of the Blacklist lookup as a text string, one of\n"
|
||||
" FOUND | NOTFOUND\n"
|
||||
"Example: exten => 1234,1,LookupBlacklist()\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int
|
||||
lookupblacklist_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
char blacklist[1];
|
||||
struct localuser *u;
|
||||
int bl = 0;
|
||||
int priority_jump = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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 || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "FOUND");
|
||||
} else
|
||||
pbx_builtin_setvar_helper(chan, "LOOKUPBLSTATUS", "NOTFOUND");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module (void)
|
||||
{
|
||||
return ast_register_application (app, lookupblacklist_exec, synopsis,descrip);
|
||||
}
|
||||
|
||||
char *description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,120 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/astdb.h"
|
||||
|
||||
static char *tdesc = "Look up CallerID Name from local database";
|
||||
|
||||
static char *app = "LookupCIDName";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int
|
||||
lookupcidname_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
char dbname[64];
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD (u);
|
||||
if (chan->cid.cid_num) {
|
||||
if (!ast_db_get ("cidname", chan->cid.cid_num, dbname, sizeof (dbname))) {
|
||||
ast_set_callerid (chan, NULL, dbname, NULL);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "Changed Caller*ID name to %s\n",
|
||||
dbname);
|
||||
}
|
||||
}
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application (app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
load_module (void)
|
||||
{
|
||||
return ast_register_application (app, lookupcidname_exec, synopsis,
|
||||
descrip);
|
||||
}
|
||||
|
||||
char *
|
||||
description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int
|
||||
usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
540
apps/app_macro.c
540
apps/app_macro.c
@@ -1,540 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#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 *tdesc = "Extension Macros";
|
||||
|
||||
static char *descrip =
|
||||
" Macro(macroname|arg1|arg2...): Executes a macro using the context\n"
|
||||
"'macro-<macroname>', jumping to the 's' extension of that context and\n"
|
||||
"executing each step, then returning when the steps end. \n"
|
||||
"The calling extension, context, and priority are stored in ${MACRO_EXTEN}, \n"
|
||||
"${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\n"
|
||||
" macros 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 *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 *exit_app = "MacroExit";
|
||||
|
||||
static char *synopsis = "Macro Implementation";
|
||||
static char *if_synopsis = "Conditional Macro Implementation";
|
||||
static char *exit_synopsis = "Exit From Macro";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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)
|
||||
{
|
||||
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] = "";
|
||||
char *offsets, *s, *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 localuser *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Macro() requires arguments. See \"show application macro\" for help.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* does the user want a deeper rabbit hole? */
|
||||
s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION");
|
||||
if (s)
|
||||
sscanf(s, "%3d", &maxdepth);
|
||||
|
||||
/* Count how many levels deep the rabbit hole goes */
|
||||
tmp = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
|
||||
if (tmp) {
|
||||
sscanf(tmp, "%3d", &depth);
|
||||
} else {
|
||||
depth = 0;
|
||||
}
|
||||
|
||||
/* 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, "%3d", &inhangup);
|
||||
|
||||
if (depth >= maxdepth) {
|
||||
ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
|
||||
LOCAL_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");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
|
||||
if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->cid.cid_num)) {
|
||||
if (!ast_context_find(fullmacro))
|
||||
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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 = pbx_builtin_getvar_helper(chan, "MACRO_EXTEN");
|
||||
if (save_macro_exten)
|
||||
save_macro_exten = strdup(save_macro_exten);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
|
||||
|
||||
save_macro_context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT");
|
||||
if (save_macro_context)
|
||||
save_macro_context = strdup(save_macro_context);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
|
||||
|
||||
save_macro_priority = pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY");
|
||||
if (save_macro_priority)
|
||||
save_macro_priority = strdup(save_macro_priority);
|
||||
snprintf(pc, sizeof(pc), "%d", oldpriority);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
|
||||
|
||||
save_macro_offset = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET");
|
||||
if (save_macro_offset)
|
||||
save_macro_offset = strdup(save_macro_offset);
|
||||
pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
|
||||
|
||||
/* 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)) {
|
||||
/* Save copy of old arguments if we're overwriting some, otherwise
|
||||
let them pass through to the other macro */
|
||||
snprintf(varname, sizeof(varname), "ARG%d", argc);
|
||||
oldargs[argc] = pbx_builtin_getvar_helper(chan, varname);
|
||||
if (oldargs[argc])
|
||||
oldargs[argc] = strdup(oldargs[argc]);
|
||||
pbx_builtin_setvar_helper(chan, varname, cur);
|
||||
argc++;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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 */
|
||||
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, "%30d", &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);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int macroif_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *expr = NULL, *label_a = NULL, *label_b = NULL;
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
expr = ast_strdupa(data);
|
||||
if (!expr) {
|
||||
ast_log(LOG_ERROR, "Out of Memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((label_a = strchr(expr, '?'))) {
|
||||
*label_a = '\0';
|
||||
label_a++;
|
||||
if ((label_b = strchr(label_a, ':'))) {
|
||||
*label_b = '\0';
|
||||
label_b++;
|
||||
}
|
||||
if (pbx_checkcondition(expr))
|
||||
res = macro_exec(chan, label_a);
|
||||
else if (label_b)
|
||||
res = macro_exec(chan, label_b);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Invalid Syntax.\n");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int macro_exit_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
return MACRO_EXIT_RESULT;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(if_app);
|
||||
res |= ast_unregister_application(exit_app);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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(app, macro_exec, synopsis, descrip);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
298
apps/app_math.c
298
apps/app_math.c
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2004 - 2005, Andy Powell
|
||||
*
|
||||
* Updated by Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief A simple math application
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/say.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/manager.h"
|
||||
#include "asterisk/localtime.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
|
||||
static char *tdesc = "Basic Math Functions";
|
||||
|
||||
static char *app_math = "Math";
|
||||
|
||||
static char *math_synopsis = "Performs Mathematical Functions";
|
||||
|
||||
static char *math_descrip =
|
||||
"Math(returnvar,<number1><op><number 2>\n\n"
|
||||
"Perform floating point calculation on number 1 to number 2 and \n"
|
||||
"store the result in returnvar. Valid ops are: \n"
|
||||
" +,-,/,*,%,<,>,>=,<=,==\n"
|
||||
"and behave as their C equivalents.\n"
|
||||
" This application has been deprecated in favor of the MATH function.\n";
|
||||
|
||||
#define ADDFUNCTION 0
|
||||
#define DIVIDEFUNCTION 1
|
||||
#define MULTIPLYFUNCTION 2
|
||||
#define SUBTRACTFUNCTION 3
|
||||
#define MODULUSFUNCTION 4
|
||||
|
||||
#define GTFUNCTION 5
|
||||
#define LTFUNCTION 6
|
||||
#define GTEFUNCTION 7
|
||||
#define LTEFUNCTION 8
|
||||
#define EQFUNCTION 9
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int math_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
float fnum1;
|
||||
float fnum2;
|
||||
float ftmp = 0;
|
||||
char *op;
|
||||
int iaction=-1;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
/* dunno, big calulations :D */
|
||||
char user_result[30];
|
||||
|
||||
char *s;
|
||||
char *mvar, *mvalue1, *mvalue2=NULL;
|
||||
|
||||
struct localuser *u;
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "Math() is deprecated, please use Set(var=${MATH(...)} instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "No parameters passed. !\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
if (!s) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mvar = strsep(&s, "|");
|
||||
mvalue1 = strsep(&s, "|");
|
||||
|
||||
if ((op = strchr(mvalue1, '+'))) {
|
||||
iaction = ADDFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '-'))) {
|
||||
iaction = SUBTRACTFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '*'))) {
|
||||
iaction = MULTIPLYFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '/'))) {
|
||||
iaction = DIVIDEFUNCTION;
|
||||
*op = '\0';
|
||||
} else if ((op = strchr(mvalue1, '>'))) {
|
||||
iaction = GTFUNCTION;
|
||||
*op = '\0';
|
||||
if (*(op+1) == '=') {
|
||||
op++;
|
||||
*op = '\0';
|
||||
iaction = GTEFUNCTION;
|
||||
}
|
||||
} else if ((op = strchr(mvalue1, '<'))) {
|
||||
iaction = LTFUNCTION;
|
||||
*op = '\0';
|
||||
if (*(op+1) == '=') {
|
||||
op++;
|
||||
*op = '\0';
|
||||
iaction = LTEFUNCTION;
|
||||
}
|
||||
} else if ((op = strchr(mvalue1, '='))) {
|
||||
iaction = GTFUNCTION;
|
||||
*op = '\0';
|
||||
if (*(op+1) == '=') {
|
||||
op++;
|
||||
*op = '\0';
|
||||
iaction = EQFUNCTION;
|
||||
} else
|
||||
op = NULL;
|
||||
}
|
||||
|
||||
if (op)
|
||||
mvalue2 = op + 1;
|
||||
|
||||
if (!mvar || !mvalue1 || !mvalue2) {
|
||||
ast_log(LOG_WARNING, "Supply all the parameters - just this once, please\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp(mvar,"")) {
|
||||
ast_log(LOG_WARNING, "No return variable set.\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(mvalue1, "%30f", &fnum1) != 1) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue1);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sscanf(mvalue2, "%30f", &fnum2) != 1) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue2);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (iaction) {
|
||||
case ADDFUNCTION :
|
||||
ftmp = fnum1 + fnum2;
|
||||
break;
|
||||
case DIVIDEFUNCTION :
|
||||
if (fnum2 <=0)
|
||||
ftmp = 0; /* can't do a divide by 0 */
|
||||
else
|
||||
ftmp = (fnum1 / fnum2);
|
||||
break;
|
||||
case MULTIPLYFUNCTION :
|
||||
ftmp = (fnum1 * fnum2);
|
||||
break;
|
||||
case SUBTRACTFUNCTION :
|
||||
ftmp = (fnum1 - fnum2);
|
||||
break;
|
||||
case MODULUSFUNCTION : {
|
||||
int inum1 = fnum1;
|
||||
int inum2 = fnum2;
|
||||
|
||||
ftmp = (inum1 % inum2);
|
||||
|
||||
break;
|
||||
}
|
||||
case GTFUNCTION :
|
||||
if (fnum1 > fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case LTFUNCTION :
|
||||
if (fnum1 < fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case GTEFUNCTION :
|
||||
if (fnum1 >= fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case LTEFUNCTION :
|
||||
if (fnum1 <= fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
case EQFUNCTION :
|
||||
if (fnum1 == fnum2)
|
||||
strcpy(user_result, "TRUE");
|
||||
else
|
||||
strcpy(user_result, "FALSE");
|
||||
break;
|
||||
default :
|
||||
ast_log(LOG_WARNING, "Something happened that neither of us should be proud of %d\n", iaction);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (iaction < GTFUNCTION || iaction > EQFUNCTION)
|
||||
snprintf(user_result,sizeof(user_result),"%f",ftmp);
|
||||
|
||||
pbx_builtin_setvar_helper(chan, mvar, user_result);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_math);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_math, math_exec, math_synopsis, math_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
/* Fading everything to black and blue... */
|
||||
205
apps/app_md5.c
205
apps/app_md5.c
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Olle E. Johansson, Edvina.net
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief MD5 checksum application
|
||||
*
|
||||
* \todo Remove this deprecated application in 1.3dev
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc_md5 = "MD5 checksum applications";
|
||||
static char *app_md5 = "MD5";
|
||||
static char *desc_md5 = "Calculate MD5 checksum";
|
||||
static char *synopsis_md5 =
|
||||
" MD5(<var>=<string>): Calculates a MD5 checksum on <string>.\n"
|
||||
"Returns hash value in a channel variable. \n";
|
||||
|
||||
static char *app_md5check = "MD5Check";
|
||||
static char *desc_md5check = "Check MD5 checksum";
|
||||
static char *synopsis_md5check =
|
||||
" MD5Check(<md5hash>|<string>[|options]): Calculates a MD5 checksum on <string>\n"
|
||||
"and compares it with the hash. Returns 0 if <md5hash> is correct for <string>.\n"
|
||||
"The option string may contain zero or more of the following characters:\n"
|
||||
" 'j' -- jump to priority n+101 if the hash and string do not match \n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" CHECKMD5STATUS The status of the MD5 check, one of the following\n"
|
||||
" MATCH | NOMATCH\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
/*--- md5_exec: Calculate MD5 checksum (hash) on given string and
|
||||
return it in channel variable ---*/
|
||||
static int md5_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *varname= NULL; /* Variable to set */
|
||||
char *string = NULL; /* String to calculate on */
|
||||
char retvar[50]; /* Return value */
|
||||
static int dep_warning = 0;
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the MD5 function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Syntax: md5(<varname>=<string>) - missing argument!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
memset(retvar,0, sizeof(retvar));
|
||||
string = ast_strdupa(data);
|
||||
varname = strsep(&string,"=");
|
||||
if (ast_strlen_zero(varname)) {
|
||||
ast_log(LOG_WARNING, "Syntax: md5(<varname>=<string>) - missing argument!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
ast_md5_hash(retvar, string);
|
||||
pbx_builtin_setvar_helper(chan, varname, retvar);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*--- md5check_exec: Calculate MD5 checksum and compare it with
|
||||
existing checksum. ---*/
|
||||
static int md5check_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *string = NULL; /* String to calculate on */
|
||||
char newhash[50]; /* Return value */
|
||||
static int dep_warning = 0;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(md5hash);
|
||||
AST_APP_ARG(string);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (!dep_warning) {
|
||||
ast_log(LOG_WARNING, "This application has been deprecated, please use the CHECK_MD5 function instead.\n");
|
||||
dep_warning = 1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(string = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, string);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args.md5hash) || ast_strlen_zero(args.string)) {
|
||||
ast_log(LOG_WARNING, "Syntax: MD5Check(<md5hash>|<string>[|options]) - missing argument!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(newhash,0, sizeof(newhash));
|
||||
|
||||
ast_md5_hash(newhash, args.string);
|
||||
if (!strcmp(newhash, args.md5hash)) { /* Verification ok */
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "MD5 verified ok: %s -- %s\n", args.md5hash, args.string);
|
||||
pbx_builtin_setvar_helper(chan, "CHECKMD5STATUS", "MATCH");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "ERROR: MD5 not verified: %s -- %s\n", args.md5hash, args.string);
|
||||
pbx_builtin_setvar_helper(chan, "CHECKMD5STATUS", "NOMATCH");
|
||||
if (priority_jump || option_priority_jumping) {
|
||||
if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "Can't jump to exten+101 (e%s,p%d), sorry\n", chan->exten,chan->priority+101);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_md5);
|
||||
res |= ast_unregister_application(app_md5check);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app_md5check, md5check_exec, desc_md5check, synopsis_md5check);
|
||||
res |= ast_register_application(app_md5, md5_exec, desc_md5, synopsis_md5);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc_md5;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
2252
apps/app_meetme.c
2252
apps/app_meetme.c
File diff suppressed because it is too large
Load Diff
@@ -1,170 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Digital Milliwatt (mu-law) Test Application";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static char digital_milliwatt[] = {0x1e,0x0b,0x0b,0x1e,0x9e,0x8b,0x8b,0x9e} ;
|
||||
|
||||
static void *milliwatt_alloc(struct ast_channel *chan, void *params)
|
||||
{
|
||||
int *indexp;
|
||||
indexp = malloc(sizeof(int));
|
||||
if (indexp == NULL) return(NULL);
|
||||
*indexp = 0;
|
||||
return(indexp);
|
||||
}
|
||||
|
||||
static void milliwatt_release(struct ast_channel *chan, void *data)
|
||||
{
|
||||
free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
static int milliwatt_generate(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct ast_frame wf;
|
||||
unsigned char buf[AST_FRIENDLY_OFFSET + 640];
|
||||
int i,*indexp = (int *) data;
|
||||
|
||||
if (len + AST_FRIENDLY_OFFSET > sizeof(buf))
|
||||
{
|
||||
ast_log(LOG_WARNING,"Only doing %d bytes (%d bytes requested)\n",(int)(sizeof(buf) - AST_FRIENDLY_OFFSET),len);
|
||||
len = sizeof(buf) - AST_FRIENDLY_OFFSET;
|
||||
}
|
||||
wf.frametype = AST_FRAME_VOICE;
|
||||
wf.subclass = AST_FORMAT_ULAW;
|
||||
wf.offset = AST_FRIENDLY_OFFSET;
|
||||
wf.mallocd = 0;
|
||||
wf.data = buf + AST_FRIENDLY_OFFSET;
|
||||
wf.datalen = len;
|
||||
wf.samples = wf.datalen;
|
||||
wf.src = "app_milliwatt";
|
||||
wf.delivery.tv_sec = 0;
|
||||
wf.delivery.tv_usec = 0;
|
||||
wf.prev = wf.next = NULL;
|
||||
/* create a buffer containing the digital milliwatt pattern */
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
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 localuser *u;
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_set_write_format(chan, AST_FORMAT_ULAW);
|
||||
ast_set_read_format(chan, AST_FORMAT_ULAW);
|
||||
if (chan->_state != AST_STATE_UP)
|
||||
{
|
||||
ast_answer(chan);
|
||||
}
|
||||
if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0)
|
||||
{
|
||||
ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
while(!ast_safe_sleep(chan, 10000));
|
||||
ast_deactivate_generator(chan);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, milliwatt_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,454 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2005, Anthony Minessale II
|
||||
* Copyright (C) 2005, 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
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/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"
|
||||
|
||||
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
|
||||
|
||||
static const char *tdesc = "Mixed Audio Monitoring Application";
|
||||
static const char *app = "MixMonitor";
|
||||
static const char *synopsis = "Record a call and mix the audio during the recording";
|
||||
static const char *desc = ""
|
||||
" MixMonitor(<file>.<ext>[|<options>[|<command>]])\n\n"
|
||||
"Records the audio on the current channel to the specified file.\n"
|
||||
"If the filename is an absolute path, uses that path, otherwise\n"
|
||||
"creates the file in the configured monitoring directory from\n"
|
||||
"asterisk.conf.\n\n"
|
||||
"Valid options:\n"
|
||||
" a - Append to the file instead of overwriting it.\n"
|
||||
" b - Only save audio to the file while the channel is bridged.\n"
|
||||
" Note: Does not include conferences or sounds played to each bridged\n"
|
||||
" party.\n"
|
||||
" v(<x>) - Adjust the heard volume by a factor of <x> (range -4 to 4)\n"
|
||||
" V(<x>) - Adjust the spoken volume by a factor of <x> (range -4 to 4)\n"
|
||||
" W(<x>) - Adjust the both heard and spoken volumes by a factor of <x>\n"
|
||||
" (range -4 to 4)\n\n"
|
||||
"<command> will be executed when the recording is over\n"
|
||||
"Any strings matching ^{X} will be unescaped to ${X}.\n"
|
||||
"All variables will be evaluated at the time MixMonitor is called.\n"
|
||||
"The variable MIXMONITOR_FILENAME will contain the filename used to record.\n"
|
||||
"";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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_mutex_lock(&chan->lock);
|
||||
res = ast_channel_spy_add(chan, spy);
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
|
||||
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
|
||||
ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
STANDARD_INCREMENT_USECOUNT;
|
||||
|
||||
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 = f->next;
|
||||
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_frfree(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
STANDARD_DECREMENT_USECOUNT;
|
||||
|
||||
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))) {
|
||||
ast_log(LOG_ERROR, "Memory Error!\n");
|
||||
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(&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 localuser *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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(parse = ast_strdupa(data))) {
|
||||
ast_log(LOG_WARNING, "Memory Error!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (ast_strlen_zero(args.filename)) {
|
||||
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args.options) {
|
||||
char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
|
||||
|
||||
ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
|
||||
ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
|
||||
} else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
|
||||
ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
|
||||
} else {
|
||||
readvol = get_volfactor(x);
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
|
||||
ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
|
||||
} else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
|
||||
ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
|
||||
} else {
|
||||
writevol = get_volfactor(x);
|
||||
}
|
||||
}
|
||||
|
||||
if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
|
||||
if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
|
||||
ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
|
||||
} else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
|
||||
ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
|
||||
} else {
|
||||
readvol = writevol = get_volfactor(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if not provided an absolute path, use the system-configured monitoring directory */
|
||||
if (args.filename[0] != '/') {
|
||||
char *build;
|
||||
|
||||
build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
|
||||
sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
|
||||
args.filename = build;
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
|
||||
launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
|
||||
|
||||
LOCAL_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_mutex_unlock(&chan->lock);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static struct ast_cli_entry cli_mixmonitor = {
|
||||
{ "mixmonitor", NULL, NULL },
|
||||
mixmonitor_cli,
|
||||
"Execute a MixMonitor command",
|
||||
"mixmonitor <start|stop> <chan_name> [<args>]\n"
|
||||
};
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_cli_unregister(&cli_mixmonitor);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_cli_register(&cli_mixmonitor);
|
||||
res |= ast_register_application(app, mixmonitor_exec, synopsis, desc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
225
apps/app_mp3.c
225
apps/app_mp3.c
@@ -1,51 +1,32 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define LOCAL_MPG_123 "/usr/local/bin/mpg123"
|
||||
#define MPG_123 "/usr/bin/mpg123"
|
||||
|
||||
static char *tdesc = "Silly MP3 Application";
|
||||
@@ -55,9 +36,9 @@ 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;
|
||||
|
||||
@@ -67,62 +48,23 @@ 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 (option_highpriority)
|
||||
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)
|
||||
@@ -130,66 +72,101 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
||||
int res=0;
|
||||
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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create pipe\n");
|
||||
LOCAL_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");
|
||||
LOCAL_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;
|
||||
@@ -198,56 +175,28 @@ 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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
|
||||
@@ -1,255 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#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.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/frame.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
#define LOCAL_NBSCAT "/usr/local/bin/nbscat8k"
|
||||
#define NBSCAT "/usr/bin/nbscat8k"
|
||||
|
||||
#ifndef AF_LOCAL
|
||||
#define AF_LOCAL AF_UNIX
|
||||
#endif
|
||||
|
||||
static char *tdesc = "Silly NBS Stream Application";
|
||||
|
||||
static char *app = "NBScat";
|
||||
|
||||
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.";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int NBScatplay(int fd)
|
||||
{
|
||||
int res;
|
||||
int x;
|
||||
sigset_t fullset, oldset;
|
||||
|
||||
sigfillset(&fullset);
|
||||
pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
|
||||
|
||||
res = fork();
|
||||
if (res < 0)
|
||||
ast_log(LOG_WARNING, "Fork failed\n");
|
||||
if (res) {
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
return res;
|
||||
}
|
||||
signal(SIGPIPE, SIG_DFL);
|
||||
pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
|
||||
|
||||
if (option_highpriority)
|
||||
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 localuser *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;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) {
|
||||
ast_log(LOG_WARNING, "Unable to create socketpair\n");
|
||||
LOCAL_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");
|
||||
LOCAL_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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, NBScat_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,377 +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 Open Settlement Protocol Lookup
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/causes.h"
|
||||
#include "asterisk/astosp.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/options.h"
|
||||
|
||||
static char *tdesc = "OSP Lookup";
|
||||
|
||||
static char *app = "OSPLookup";
|
||||
static char *app2 = "OSPNext";
|
||||
static char *app3 = "OSPFinish";
|
||||
|
||||
static char *synopsis = "Lookup number in OSP";
|
||||
static char *synopsis2 = "Lookup next OSP entry";
|
||||
static char *synopsis3 = "Record OSP entry";
|
||||
|
||||
static char *descrip =
|
||||
" OSPLookup(exten[|provider[|options]]): Looks up an extension via OSP and sets\n"
|
||||
"the variables, where 'n' is the number of the result beginning with 1:\n"
|
||||
" ${OSPTECH}: The technology to use for the call\n"
|
||||
" ${OSPDEST}: The destination to use for the call\n"
|
||||
" ${OSPTOKEN}: The actual OSP token as a string\n"
|
||||
" ${OSPHANDLE}: The OSP Handle for anything remaining\n"
|
||||
" ${OSPRESULTS}: The number of OSP results total remaining\n"
|
||||
"\n"
|
||||
"The option string may contain the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the lookup was NOT successful\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" OSPLOOKUPSTATUS The status of the OSP Lookup attempt as a text string, one of\n"
|
||||
" SUCCESS | FAILED \n";
|
||||
|
||||
|
||||
static char *descrip2 =
|
||||
" OSPNext(cause[|options]): Looks up the next OSP Destination for ${OSPHANDLE}\n"
|
||||
"See OSPLookup for more information\n"
|
||||
"\n"
|
||||
"The option string may contain the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the lookup was NOT successful\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" OSPNEXTSTATUS The status of the OSP Next attempt as a text string, one of\n"
|
||||
" SUCCESS | FAILED \n";
|
||||
|
||||
static char *descrip3 =
|
||||
" OSPFinish(status[|options]): Records call state for ${OSPHANDLE}, according to\n"
|
||||
"status, which should be one of BUSY, CONGESTION, ANSWER, NOANSWER, or CHANUNAVAIL\n"
|
||||
"or coincidentally, just what the Dial application stores in its ${DIALSTATUS}.\n"
|
||||
"\n"
|
||||
"The option string may contain the following character:\n"
|
||||
" 'j' -- jump to n+101 priority if the finish attempt was NOT successful\n"
|
||||
"This application sets the following channel variable upon completion:\n"
|
||||
" OSPFINISHSTATUS The status of the OSP Finish attempt as a text string, one of\n"
|
||||
" SUCCESS | FAILED \n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int str2cause(char *cause)
|
||||
{
|
||||
if (!strcasecmp(cause, "BUSY"))
|
||||
return AST_CAUSE_BUSY;
|
||||
if (!strcasecmp(cause, "CONGESTION"))
|
||||
return AST_CAUSE_CONGESTION;
|
||||
if (!strcasecmp(cause, "ANSWER"))
|
||||
return AST_CAUSE_NORMAL;
|
||||
if (!strcasecmp(cause, "CANCEL"))
|
||||
return AST_CAUSE_NORMAL;
|
||||
if (!strcasecmp(cause, "NOANSWER"))
|
||||
return AST_CAUSE_NOANSWER;
|
||||
if (!strcasecmp(cause, "NOCHANAVAIL"))
|
||||
return AST_CAUSE_CONGESTION;
|
||||
ast_log(LOG_WARNING, "Unknown cause '%s', using NORMAL\n", cause);
|
||||
return AST_CAUSE_NORMAL;
|
||||
}
|
||||
|
||||
static int osplookup_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *temp;
|
||||
struct ast_osp_result result;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(extension);
|
||||
AST_APP_ARG(provider);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "OSPLookup requires an argument OSPLookup(exten[|provider[|options]])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
temp = ast_strdupa(data);
|
||||
if (!temp) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, temp);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
ast_log(LOG_DEBUG, "Whoo hoo, looking up OSP on '%s' via '%s'\n", args.extension, args.provider ? args.provider : "<default>");
|
||||
if ((res = ast_osp_lookup(chan, args.provider, args.extension, chan->cid.cid_num, &result)) > 0) {
|
||||
char tmp[80];
|
||||
snprintf(tmp, sizeof(tmp), "%d", result.handle);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPHANDLE", tmp);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPTECH", result.tech);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPDEST", result.dest);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPTOKEN", result.token);
|
||||
snprintf(tmp, sizeof(tmp), "%d", result.numresults);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPRESULTS", tmp);
|
||||
pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", "SUCCESS");
|
||||
|
||||
} else {
|
||||
if (!res) {
|
||||
ast_log(LOG_NOTICE, "OSP Lookup failed for '%s' (provider '%s')\n", args.extension, args.provider ? args.provider : "<default>");
|
||||
pbx_builtin_setvar_helper(chan, "OSPLOOKUPSTATUS", "FAILED");
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Lookup for '%s' (provider '%s')!\n", chan->name, args.extension, args.provider ? args.provider : "<default>" );
|
||||
}
|
||||
if (!res) {
|
||||
/* Look for a "busy" place */
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
} else if (res > 0)
|
||||
res = 0;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ospnext_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *temp;
|
||||
int cause;
|
||||
struct ast_osp_result result;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(cause);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "OSPNext should have an argument (cause[|options])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
temp = ast_strdupa(data);
|
||||
if (!temp) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, temp);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
cause = str2cause(args.cause);
|
||||
temp = pbx_builtin_getvar_helper(chan, "OSPHANDLE");
|
||||
result.handle = -1;
|
||||
if (ast_strlen_zero(temp) || (sscanf(temp, "%30d", &result.handle) != 1)) {
|
||||
result.handle = -1;
|
||||
}
|
||||
temp = pbx_builtin_getvar_helper(chan, "OSPRESULTS");
|
||||
if (ast_strlen_zero(temp) || (sscanf(temp, "%30d", &result.numresults) != 1)) {
|
||||
result.numresults = 0;
|
||||
}
|
||||
if ((res = ast_osp_next(&result, cause)) > 0) {
|
||||
char tmp[80];
|
||||
snprintf(tmp, sizeof(tmp), "%d", result.handle);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPHANDLE", tmp);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPTECH", result.tech);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPDEST", result.dest);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPTOKEN", result.token);
|
||||
snprintf(tmp, sizeof(tmp), "%d", result.numresults);
|
||||
pbx_builtin_setvar_helper(chan, "_OSPRESULTS", tmp);
|
||||
pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", "SUCCESS");
|
||||
} else {
|
||||
if (!res) {
|
||||
if (result.handle < 0)
|
||||
ast_log(LOG_NOTICE, "OSP Lookup Next failed for handle '%d'\n", result.handle);
|
||||
else
|
||||
ast_log(LOG_DEBUG, "No OSP handle specified\n");
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Next!\n", chan->name);
|
||||
|
||||
pbx_builtin_setvar_helper(chan, "OSPNEXTSTATUS", "FAILED");
|
||||
}
|
||||
if (!res) {
|
||||
/* Look for a "busy" place */
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
} else if (res > 0)
|
||||
res = 0;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ospfinished_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *temp;
|
||||
int cause;
|
||||
time_t start=0, duration=0;
|
||||
struct ast_osp_result result;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(status);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "OSPFinish should have an argument (status[|options])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
temp = ast_strdupa(data);
|
||||
if (!temp) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, temp);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (chan->cdr) {
|
||||
start = chan->cdr->answer.tv_sec;
|
||||
if (start)
|
||||
duration = time(NULL) - start;
|
||||
else
|
||||
duration = 0;
|
||||
} else
|
||||
ast_log(LOG_WARNING, "OSPFinish called on channel '%s' with no CDR!\n", chan->name);
|
||||
|
||||
cause = str2cause(args.status);
|
||||
temp = pbx_builtin_getvar_helper(chan, "OSPHANDLE");
|
||||
result.handle = -1;
|
||||
if (!ast_strlen_zero(temp) && (sscanf(temp, "%30d", &result.handle) == 1) && (result.handle > -1)) {
|
||||
if (!ast_osp_terminate(result.handle, cause, start, duration)) {
|
||||
pbx_builtin_setvar_helper(chan, "_OSPHANDLE", "");
|
||||
pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", "SUCCESS");
|
||||
res = 1;
|
||||
}
|
||||
} else {
|
||||
if (!res) {
|
||||
if (result.handle > -1)
|
||||
ast_log(LOG_NOTICE, "OSP Finish failed for handle '%d'\n", result.handle);
|
||||
else
|
||||
ast_log(LOG_DEBUG, "No OSP handle specified\n");
|
||||
pbx_builtin_setvar_helper(chan, "OSPFINISHSTATUS", "FAILED");
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Got hangup on '%s' while doing OSP Terminate!\n", chan->name);
|
||||
}
|
||||
if (!res) {
|
||||
/* Look for a "busy" place */
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
} else if (res > 0)
|
||||
res = 0;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app3);
|
||||
res |= ast_unregister_application(app2);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_register_application(app, osplookup_exec, synopsis, descrip);
|
||||
res |= ast_register_application(app2, ospnext_exec, synopsis2, descrip2);
|
||||
res |= ast_register_application(app3, ospfinished_exec, synopsis3, descrip3);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int reload(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
246
apps/app_page.c
246
apps/app_page.c
@@ -1,246 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/chanvars.h"
|
||||
|
||||
|
||||
static const char *tdesc = "Page Multiple Phones";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
enum {
|
||||
PAGE_DUPLEX = (1 << 0),
|
||||
PAGE_QUIET = (1 << 1),
|
||||
} page_opt_flags;
|
||||
|
||||
AST_APP_OPTIONS(page_opts, {
|
||||
AST_APP_OPTION('d', PAGE_DUPLEX),
|
||||
AST_APP_OPTION('q', PAGE_QUIET),
|
||||
});
|
||||
|
||||
struct calloutdata {
|
||||
char cidnum[64];
|
||||
char cidname[64];
|
||||
char tech[64];
|
||||
char resource[256];
|
||||
char meetmeopts[64];
|
||||
struct ast_variable *variables;
|
||||
};
|
||||
|
||||
static void *page_thread(void *data)
|
||||
{
|
||||
struct calloutdata *cd = data;
|
||||
ast_pbx_outgoing_app(cd->tech, AST_FORMAT_SLINEAR, cd->resource, 30000,
|
||||
"MeetMe", cd->meetmeopts, NULL, 0, cd->cidnum, cd->cidname, cd->variables, NULL, NULL);
|
||||
free(cd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void launch_page(struct ast_channel *chan, const char *meetmeopts, const char *tech, const char *resource)
|
||||
{
|
||||
struct calloutdata *cd;
|
||||
const char *varname;
|
||||
struct ast_variable *lastvar = NULL;
|
||||
struct ast_var_t *varptr;
|
||||
pthread_t t;
|
||||
pthread_attr_t attr;
|
||||
cd = malloc(sizeof(struct calloutdata));
|
||||
if (cd) {
|
||||
memset(cd, 0, sizeof(struct calloutdata));
|
||||
ast_copy_string(cd->cidnum, chan->cid.cid_num ? chan->cid.cid_num : "", sizeof(cd->cidnum));
|
||||
ast_copy_string(cd->cidname, chan->cid.cid_name ? chan->cid.cid_name : "", sizeof(cd->cidname));
|
||||
ast_copy_string(cd->tech, tech, sizeof(cd->tech));
|
||||
ast_copy_string(cd->resource, resource, sizeof(cd->resource));
|
||||
ast_copy_string(cd->meetmeopts, meetmeopts, sizeof(cd->meetmeopts));
|
||||
|
||||
AST_LIST_TRAVERSE(&chan->varshead, varptr, entries) {
|
||||
if (!(varname = ast_var_full_name(varptr)))
|
||||
continue;
|
||||
if (varname[0] == '_') {
|
||||
struct ast_variable *newvar = NULL;
|
||||
|
||||
if (varname[1] == '_') {
|
||||
newvar = ast_variable_new(varname, ast_var_value(varptr));
|
||||
} else {
|
||||
newvar = ast_variable_new(&varname[1], ast_var_value(varptr));
|
||||
}
|
||||
|
||||
if (newvar) {
|
||||
if (lastvar)
|
||||
lastvar->next = newvar;
|
||||
else
|
||||
cd->variables = newvar;
|
||||
lastvar = newvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (ast_pthread_create(&t, &attr, page_thread, cd)) {
|
||||
ast_log(LOG_WARNING, "Unable to create paging thread: %s\n", strerror(errno));
|
||||
free(cd);
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
}
|
||||
|
||||
static int page_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
char *options;
|
||||
char *tech, *resource;
|
||||
char meetmeopts[80];
|
||||
struct ast_flags flags = { 0 };
|
||||
unsigned int confid = rand();
|
||||
struct ast_app *app;
|
||||
char *tmp;
|
||||
int res=0;
|
||||
char originator[AST_CHANNEL_NAME];
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "This application requires at least one argument (destination(s) to page)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!(app = pbx_findapp("MeetMe"))) {
|
||||
ast_log(LOG_WARNING, "There is no MeetMe application available!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
};
|
||||
|
||||
options = ast_strdupa(data);
|
||||
if (!options) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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), "%ud|%sqxdw(5)", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "m");
|
||||
|
||||
while ((tech = strsep(&tmp, "&"))) {
|
||||
/* don't call the originating device */
|
||||
if (!strcasecmp(tech, originator))
|
||||
continue;
|
||||
|
||||
if ((resource = strchr(tech, '/'))) {
|
||||
*resource++ = '\0';
|
||||
launch_page(chan, meetmeopts, tech, resource);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Incomplete destination '%s' supplied.\n", tech);
|
||||
}
|
||||
}
|
||||
|
||||
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%sqxd", confid, ast_test_flag(&flags, PAGE_DUPLEX) ? "" : "t");
|
||||
pbx_exec(chan, app, meetmeopts, 1);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_page);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_page, page_exec, page_synopsis, page_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, 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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#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"
|
||||
|
||||
static char *tdesc = "Call Parking and Announce Application";
|
||||
|
||||
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 over the console.\n"
|
||||
"announce template: colon separated list of files to announce, the word PARKED\n"
|
||||
" will be replaced by a say_digits of the ext the call is parked in\n"
|
||||
"timeout: time in seconds before the call returns into the return context.\n"
|
||||
"dial: The app_dial style resource to call to make the announcement. Console/dsp calls the console.\n"
|
||||
"return_context: the goto style label to jump the call back into after timeout. default=prio+1\n";
|
||||
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int parkandannounce_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
char *return_context;
|
||||
int l, lot, timeout = 0, dres;
|
||||
char *working, *context, *exten, *priority, *dial, *dialtech, *dialstr;
|
||||
char *template, *tpl_working, *tpl_current;
|
||||
char *tmp[100];
|
||||
int looptemp=0,i=0;
|
||||
char *s,*orig_s;
|
||||
|
||||
struct ast_channel *dchan;
|
||||
struct outgoing_helper oh;
|
||||
int outstate;
|
||||
|
||||
struct localuser *u;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "ParkAndAnnounce requires arguments: (announce:template|timeout|dial|[return_context])\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
l=strlen(data)+2;
|
||||
orig_s=malloc(l);
|
||||
if(!orig_s) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
s=orig_s;
|
||||
strncpy(s,data,l);
|
||||
|
||||
template=strsep(&s,"|");
|
||||
if(! template) {
|
||||
ast_log(LOG_WARNING, "PARK: An announce template must be defined\n");
|
||||
free(orig_s);
|
||||
LOCAL_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");
|
||||
free(orig_s);
|
||||
LOCAL_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);
|
||||
free(orig_s);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
/* At this point we have a priority and maybe an extension and a context */
|
||||
chan->priority = atoi(priority);
|
||||
if(exten && strcasecmp(exten, "BYEXTENSION"))
|
||||
strncpy(chan->exten, exten, sizeof(chan->exten)-1);
|
||||
if(context)
|
||||
strncpy(chan->context, context, sizeof(chan->context)-1);
|
||||
} else { /* increment the priority by default*/
|
||||
chan->priority++;
|
||||
}
|
||||
|
||||
if(option_verbose > 2) {
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
|
||||
if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
|
||||
ast_verbose( VERBOSE_PREFIX_3 "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 */
|
||||
|
||||
memset(&oh, 0, sizeof(oh));
|
||||
oh.parent_channel = chan;
|
||||
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);
|
||||
free(orig_s);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "PARK: Unable to allocate announce channel.\n");
|
||||
free(orig_s);
|
||||
LOCAL_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);
|
||||
free(orig_s);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
/* return ast_register_application(app, park_exec); */
|
||||
return ast_register_application(app, parkandannounce_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,68 +1,42 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Sound File Playback Application";
|
||||
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;
|
||||
|
||||
@@ -70,47 +44,27 @@ LOCAL_USER_DECL;
|
||||
|
||||
static int playback_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0, mres = 0;
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *tmp = NULL;
|
||||
char tmp[256];
|
||||
char *options;
|
||||
int option_skip=0;
|
||||
int option_noanswer = 0;
|
||||
char *front = NULL, *back = NULL;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(filenames);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
if (!data || !strlen((char *)data)) {
|
||||
ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, tmp);
|
||||
|
||||
if (args.options) {
|
||||
if (strcasestr(args.options, "skip"))
|
||||
option_skip = 1;
|
||||
if (strcasestr(args.options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
if (chan->state != AST_STATE_UP) {
|
||||
if (option_skip) {
|
||||
/* At the user's option, skip if the line is not up */
|
||||
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "SUCCESS");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
} else if (!option_noanswer)
|
||||
@@ -119,43 +73,21 @@ static int playback_exec(struct ast_channel *chan, void *data)
|
||||
}
|
||||
if (!res) {
|
||||
ast_stopstream(chan);
|
||||
front = tmp;
|
||||
while (!res && front) {
|
||||
if ((back = strchr(front, '&'))) {
|
||||
*back = '\0';
|
||||
back++;
|
||||
}
|
||||
res = ast_streamfile(chan, front, chan->language);
|
||||
if (!res) {
|
||||
res = ast_waitstream(chan, "");
|
||||
ast_stopstream(chan);
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
res = 0;
|
||||
mres = 1;
|
||||
}
|
||||
front = back;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (mres)
|
||||
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "FAILED");
|
||||
else
|
||||
pbx_builtin_setvar_helper(chan, "PLAYBACKSTATUS", "SUCCESS");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
|
||||
@@ -1,262 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/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 *tdesc = "Require phone number to be entered, if no CallerID sent";
|
||||
|
||||
static char *app = "PrivacyManager";
|
||||
|
||||
static char *synopsis = "Require phone number to be entered, if no CallerID sent";
|
||||
|
||||
static char *descrip =
|
||||
" PrivacyManager([maxretries[|minlength[|options]]]): If no Caller*ID \n"
|
||||
"is sent, PrivacyManager answers the channel and asks the caller to\n"
|
||||
"enter their phone number. The caller is given 3 attempts to do so.\n"
|
||||
"The application does nothing if Caller*ID was received on the channel.\n"
|
||||
" Configuration file privacy.conf contains two variables:\n"
|
||||
" maxretries default 3 -maximum number of attempts the caller is allowed \n"
|
||||
" to input a callerid.\n"
|
||||
" minlength default 10 -minimum allowable digits in the input callerid number.\n"
|
||||
"If you don't want to use the config file and have an i/o operation with\n"
|
||||
"every call, you can also specify maxretries and minlength as application\n"
|
||||
"parameters. Doing so supercedes any values set in privacy.conf.\n"
|
||||
"The option string may contain the following character: \n"
|
||||
" 'j' -- jump to n+101 priority after <maxretries> failed attempts to collect\n"
|
||||
" the minlength number of digits.\n"
|
||||
"The application sets the following channel variable upon completion: \n"
|
||||
"PRIVACYMGRSTATUS The status of the privacy manager's attempt to collect \n"
|
||||
" a phone number from the user. A text string that is either:\n"
|
||||
" SUCCESS | FAILED \n"
|
||||
;
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
|
||||
|
||||
static int privacy_exec (struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
int retries;
|
||||
int maxretries = 3;
|
||||
int minlength = 10;
|
||||
int x = 0;
|
||||
char *s;
|
||||
char phone[30];
|
||||
struct localuser *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);
|
||||
);
|
||||
|
||||
LOCAL_USER_ADD (u);
|
||||
if (!ast_strlen_zero(chan->cid.cid_num)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose (VERBOSE_PREFIX_3 "CallerID Present: Skipping\n");
|
||||
} else {
|
||||
/*Answer the channel if it is not already*/
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
res = ast_answer(chan);
|
||||
if (res) {
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero((char *)data))
|
||||
{
|
||||
parse = ast_strdupa(data);
|
||||
if (!parse) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.maxretries) {
|
||||
if (sscanf(args.maxretries, "%30d", &x) == 1)
|
||||
maxretries = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid max retries argument\n");
|
||||
}
|
||||
if (args.minlength) {
|
||||
if (sscanf(args.minlength, "%30d", &x) == 1)
|
||||
minlength = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid min length argument\n");
|
||||
}
|
||||
if (args.options)
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
|
||||
}
|
||||
|
||||
if (!x)
|
||||
{
|
||||
/*Read in the config file*/
|
||||
cfg = ast_config_load(PRIV_CONFIG);
|
||||
|
||||
if (cfg && (s = ast_variable_retrieve(cfg, "general", "maxretries"))) {
|
||||
if (sscanf(s, "%30d", &x) == 1)
|
||||
maxretries = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid max retries argument\n");
|
||||
}
|
||||
|
||||
if (cfg && (s = ast_variable_retrieve(cfg, "general", "minlength"))) {
|
||||
if (sscanf(s, "%30d", &x) == 1)
|
||||
minlength = x;
|
||||
else
|
||||
ast_log(LOG_WARNING, "Invalid min length argument\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*Play unidentified call*/
|
||||
res = ast_safe_sleep(chan, 1000);
|
||||
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 || option_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);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE (u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
unload_module (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application (app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
load_module (void)
|
||||
{
|
||||
return ast_register_application (app, privacy_exec, synopsis,
|
||||
descrip);
|
||||
}
|
||||
|
||||
char *
|
||||
description (void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int
|
||||
usecount (void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT (res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
key ()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
370
apps/app_qcall.c
Normal file
370
apps/app_qcall.c
Normal 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;
|
||||
}
|
||||
4063
apps/app_queue.c
4063
apps/app_queue.c
File diff suppressed because it is too large
Load Diff
@@ -1,126 +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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Random goto";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static char random_state[256];
|
||||
|
||||
static int random_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
|
||||
char *s;
|
||||
char *prob;
|
||||
int probint;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Random requires an argument ([probability]:[[context|]extension|]priority)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
if (!s) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
prob = strsep(&s,":");
|
||||
if ((!prob) || (sscanf(prob, "%3d", &probint) != 1))
|
||||
probint = 0;
|
||||
|
||||
if ((random() % 100) + probint >= 100) {
|
||||
res = ast_parseable_goto(chan, s);
|
||||
if (option_verbose > 2)
|
||||
ast_verbose( VERBOSE_PREFIX_3 "Random branches to (%s,%s,%d)\n",
|
||||
chan->context,chan->exten, chan->priority+1);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_random);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
initstate((getppid() * 65535 + getpid()) % RAND_MAX, random_state, 256);
|
||||
return ast_register_application(app_random, random_exec, random_synopsis, random_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
/* Don't allow unload, since rand(3) depends upon this module being here. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
235
apps/app_read.c
235
apps/app_read.c
@@ -1,235 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Read Variable Application";
|
||||
|
||||
static char *app = "Read";
|
||||
|
||||
static char *synopsis = "Read a variable";
|
||||
|
||||
static char *descrip =
|
||||
" Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n"
|
||||
"Reads a #-terminated string of digits a certain number of times from the\n"
|
||||
"user in to the given variable.\n"
|
||||
" filename -- file to play before reading digits.\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 -- may be 'skip' to return immediately if the line is not up,\n"
|
||||
" or 'noanswer' to read digits even if the line is not up.\n"
|
||||
" attempts -- if greater than 1, that many attempts will be made in the \n"
|
||||
" event no data is entered.\n"
|
||||
" timeout -- if greater than 0, that value will override the default timeout.\n\n"
|
||||
"Read should disconnect if the function fails or errors out.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
#define ast_next_data(instr,ptr,delim) if((ptr=strchr(instr,delim))) { *(ptr) = '\0' ; ptr++;}
|
||||
|
||||
static int read_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char tmp[256];
|
||||
char *timeout = NULL;
|
||||
char *varname = NULL;
|
||||
char *filename = NULL;
|
||||
char *loops;
|
||||
char *maxdigitstr=NULL;
|
||||
char *options=NULL;
|
||||
int option_skip = 0;
|
||||
int option_noanswer = 0;
|
||||
int maxdigits=255;
|
||||
int tries = 1;
|
||||
int to = 0;
|
||||
int x = 0;
|
||||
char *argcopy = NULL;
|
||||
char *args[8];
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "Read requires an argument (variable)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
argcopy = ast_strdupa(data);
|
||||
if (!argcopy) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ast_app_separate_args(argcopy, '|', args, sizeof(args) / sizeof(args[0])) < 1) {
|
||||
ast_log(LOG_WARNING, "Cannot Parse Arguments.\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
varname = args[x++];
|
||||
filename = args[x++];
|
||||
maxdigitstr = args[x++];
|
||||
options = args[x++];
|
||||
loops = args[x++];
|
||||
timeout = args[x++];
|
||||
|
||||
if (options) {
|
||||
if (!strcasecmp(options, "skip"))
|
||||
option_skip = 1;
|
||||
else if (!strcasecmp(options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
else {
|
||||
if (strchr(options, 's'))
|
||||
option_skip = 1;
|
||||
if (strchr(options, 'n'))
|
||||
option_noanswer = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(loops) {
|
||||
tries = atoi(loops);
|
||||
if(tries <= 0)
|
||||
tries = 1;
|
||||
}
|
||||
|
||||
if(timeout) {
|
||||
to = atoi(timeout);
|
||||
if (to <= 0)
|
||||
to = 0;
|
||||
else
|
||||
to *= 1000;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(filename))
|
||||
filename = NULL;
|
||||
if (maxdigitstr) {
|
||||
maxdigits = atoi(maxdigitstr);
|
||||
if ((maxdigits<1) || (maxdigits>255)) {
|
||||
maxdigits = 255;
|
||||
} else if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Accepting a maximum of %d digits.\n", maxdigits);
|
||||
}
|
||||
if (ast_strlen_zero(varname)) {
|
||||
ast_log(LOG_WARNING, "Invalid! Usage: Read(variable[|filename][|maxdigits][|option][|attempts][|timeout])\n\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chan->_state != AST_STATE_UP) {
|
||||
if (option_skip) {
|
||||
/* At the user's option, skip if the line is not up */
|
||||
pbx_builtin_setvar_helper(chan, varname, "\0");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
} else if (!option_noanswer) {
|
||||
/* Otherwise answer unless we're supposed to read while on-hook */
|
||||
res = ast_answer(chan);
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
while(tries && !res) {
|
||||
ast_stopstream(chan);
|
||||
res = ast_app_getdata(chan, filename, tmp, maxdigits, to);
|
||||
if (res > -1) {
|
||||
pbx_builtin_setvar_helper(chan, varname, tmp);
|
||||
if (!ast_strlen_zero(tmp)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User entered '%s'\n", tmp);
|
||||
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 {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "User disconnected\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, read_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,144 +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.
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/app.h"
|
||||
#include "asterisk/module.h"
|
||||
|
||||
static char *tdesc = "Stores output of file into a variable";
|
||||
|
||||
static char *app_readfile = "ReadFile";
|
||||
|
||||
static char *readfile_synopsis = "ReadFile(varname=file,length)";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
|
||||
static int readfile_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
s = ast_strdupa(data);
|
||||
if (!s) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
varname = strsep(&s, "=");
|
||||
file = strsep(&s, "|");
|
||||
length = s;
|
||||
|
||||
if (!varname || !file) {
|
||||
ast_log(LOG_ERROR, "No file or variable specified!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length) {
|
||||
if ((sscanf(length, "%30d", &len) != 1) || (len < 0)) {
|
||||
ast_log(LOG_WARNING, "%s is not a positive number, defaulting length to max\n", length);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((returnvar = ast_read_textfile(file))) {
|
||||
if (len > 0) {
|
||||
if (len < strlen(returnvar))
|
||||
returnvar[len]='\0';
|
||||
else
|
||||
ast_log(LOG_WARNING, "%s is longer than %d, and %d \n", file, len, (int)strlen(returnvar));
|
||||
}
|
||||
pbx_builtin_setvar_helper(chan, varname, returnvar);
|
||||
free(returnvar);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_readfile);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app_readfile, readfile_exec, readfile_synopsis, readfile_descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,262 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/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 *tdesc = "Realtime Data Lookup/Rewrite";
|
||||
static char *app = "RealTime";
|
||||
static char *uapp = "RealTimeUpdate";
|
||||
static char *synopsis = "Realtime Data Lookup";
|
||||
static char *usynopsis = "Realtime Data Rewrite";
|
||||
static char *USAGE = "RealTime(<family>|<colmatch>|<value>[|<prefix>])";
|
||||
static char *UUSAGE = "RealTimeUpdate(<family>|<colmatch>|<value>|<newcol>|<newval>)";
|
||||
static char *desc = "Use the RealTime config handler system to read data into channel variables.\n"
|
||||
"RealTime(<family>|<colmatch>|<value>[|<prefix>])\n\n"
|
||||
"All unique column names will be set as channel variables with optional prefix to the name.\n"
|
||||
"e.g. prefix of 'var_' would make the column 'name' become the variable ${var_name}\n\n";
|
||||
static char *udesc = "Use the RealTime config handler system to update a value\n"
|
||||
"RealTimeUpdate(<family>|<colmatch>|<value>|<newcol>|<newval>)\n\n"
|
||||
"The column <newcol> in 'family' matching column <colmatch>=<value> will be updated to <newval>\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int cli_load_realtime(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_update_realtime(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_load_realtime_usage[] =
|
||||
"Usage: realtime load <family> <colmatch> <value>\n"
|
||||
" Prints out a list of variables using the RealTime driver.\n";
|
||||
|
||||
static struct ast_cli_entry cli_load_realtime_cmd = {
|
||||
{ "realtime", "load", NULL, NULL }, cli_load_realtime,
|
||||
"Used to print out RealTime variables.", cli_load_realtime_usage, NULL };
|
||||
|
||||
static char cli_update_realtime_usage[] =
|
||||
"Usage: realtime update <family> <colmatch> <value>\n"
|
||||
" Update a single variable using the RealTime driver.\n";
|
||||
|
||||
static struct ast_cli_entry cli_update_realtime_cmd = {
|
||||
{ "realtime", "update", NULL, NULL }, cli_update_realtime,
|
||||
"Used to update RealTime variables.", cli_update_realtime_usage, NULL };
|
||||
|
||||
static int realtime_update_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *family=NULL, *colmatch=NULL, *value=NULL, *newcol=NULL, *newval=NULL;
|
||||
struct localuser *u;
|
||||
int res = 0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if ((family = ast_strdupa(data))) {
|
||||
if ((colmatch = strchr(family,'|'))) {
|
||||
crop_data(colmatch);
|
||||
if ((value = strchr(colmatch,'|'))) {
|
||||
crop_data(value);
|
||||
if ((newcol = strchr(value,'|'))) {
|
||||
crop_data(newcol);
|
||||
if ((newval = strchr(newcol,'|')))
|
||||
crop_data(newval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! (family && value && colmatch && newcol && newval) ) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",UUSAGE);
|
||||
res = -1;
|
||||
} else {
|
||||
ast_update_realtime(family,colmatch,value,newcol,newval,NULL);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static int realtime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
struct ast_variable *var, *itt;
|
||||
char *family=NULL, *colmatch=NULL, *value=NULL, *prefix=NULL, *vname=NULL;
|
||||
size_t len;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR,"Invalid input: usage %s\n",USAGE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if ((family = ast_strdupa(data))) {
|
||||
if ((colmatch = strchr(family,'|'))) {
|
||||
crop_data(colmatch);
|
||||
if ((value = strchr(colmatch,'|'))) {
|
||||
crop_data(value);
|
||||
if ((prefix = strchr(value,'|')))
|
||||
crop_data(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! (family && value && colmatch) ) {
|
||||
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);
|
||||
}
|
||||
ast_variables_destroy(var);
|
||||
} else if (option_verbose > 3)
|
||||
ast_verbose(VERBOSE_PREFIX_4"No Realtime Matches Found.\n");
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_cli_unregister(&cli_load_realtime_cmd);
|
||||
res |= ast_cli_unregister(&cli_update_realtime_cmd);
|
||||
res |= ast_unregister_application(uapp);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_cli_register(&cli_load_realtime_cmd);
|
||||
res |= ast_cli_register(&cli_update_realtime_cmd);
|
||||
res |= ast_register_application(uapp, realtime_update_exec, usynopsis, udesc);
|
||||
res |= ast_register_application(app, realtime_exec, synopsis, desc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
@@ -1,47 +1,25 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* \ingroup applications
|
||||
* the GNU General Public License
|
||||
*/
|
||||
|
||||
#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 "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/dsp.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static char *tdesc = "Trivial Record Application";
|
||||
|
||||
@@ -50,27 +28,10 @@ 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 instead of default '#'\n"
|
||||
"\n"
|
||||
"If filename contains '%d', these characters will be replaced with a number\n"
|
||||
"incremented by one each time the file is recorded. A channel variable\n"
|
||||
"named RECORDED_FILE will also be set, which contains the final filemname.\n\n"
|
||||
"Use '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;
|
||||
|
||||
@@ -81,306 +42,113 @@ 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 localuser *u;
|
||||
struct ast_frame *f = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
/* Yay for strsep being easy */
|
||||
vdata = ast_strdupa(data);
|
||||
if (!vdata) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = vdata;
|
||||
filename = strsep(&p, "|");
|
||||
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");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
if (silstr) {
|
||||
if ((sscanf(silstr, "%30d", &i) == 1) && (i > -1)) {
|
||||
silence = i * 1000;
|
||||
} else if (!ast_strlen_zero(silstr)) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid silence duration\n", silstr);
|
||||
|
||||
if (i == strlen(vdata) ) {
|
||||
ast_log(LOG_WARNING, "No extension found\n");
|
||||
return -1;
|
||||
}
|
||||
fil[i] = vdata[i];
|
||||
}
|
||||
|
||||
if (maxstr) {
|
||||
if ((sscanf(maxstr, "%30d", &i) == 1) && (i > -1))
|
||||
/* Convert duration to milliseconds */
|
||||
maxduration = i * 1000;
|
||||
else if (!ast_strlen_zero(maxstr))
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid maximum duration\n", maxstr);
|
||||
}
|
||||
if (options) {
|
||||
/* Retain backwards compatibility with old style options */
|
||||
if (!strcasecmp(options, "skip"))
|
||||
option_skip = 1;
|
||||
else if (!strcasecmp(options, "noanswer"))
|
||||
option_noanswer = 1;
|
||||
else {
|
||||
if (strchr(options, 's'))
|
||||
option_skip = 1;
|
||||
if (strchr(options, 'n'))
|
||||
option_noanswer = 1;
|
||||
if (strchr(options, 'a'))
|
||||
option_append = 1;
|
||||
if (strchr(options, 't'))
|
||||
terminator = '*';
|
||||
if (strchr(options, '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, '%'); */
|
||||
fname.argc = ast_app_separate_args(tmp2, '%', fname.argv, (sizeof(fname) - sizeof(fname.argc)) / sizeof(fname.argv[0]));
|
||||
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) != -1 );
|
||||
pbx_builtin_setvar_helper(chan, "RECORDED_FILE", tmp);
|
||||
} else
|
||||
strncpy(tmp, filename, sizeof(tmp)-1);
|
||||
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 */
|
||||
LOCAL_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");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
sildet = ast_dsp_new();
|
||||
if (!sildet) {
|
||||
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
|
||||
LOCAL_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 (option_transmit_silence_during_record)
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
|
||||
6564
apps/app_rpt.c
6564
apps/app_rpt.c
File diff suppressed because it is too large
Load Diff
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (c) 2003 Tilghman Lesher. All rights reserved.
|
||||
*
|
||||
* Tilghman Lesher <app_sayunixtime__200309@the-tilghman.com>
|
||||
*
|
||||
* This code is released by the author with no restrictions on usage.
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief SayUnixTime application
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/say.h"
|
||||
|
||||
|
||||
static char *tdesc = "Say time";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int sayunixtime_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *s,*zone=NULL,*timec,*format;
|
||||
time_t unixtime;
|
||||
struct timeval tv;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tv = ast_tvnow();
|
||||
unixtime = (time_t)tv.tv_sec;
|
||||
|
||||
if( !strcasecmp(chan->language, "da" ) ) {
|
||||
format = "A dBY HMS";
|
||||
} else if ( !strcasecmp(chan->language, "de" ) ) {
|
||||
format = "A dBY HMS";
|
||||
} else {
|
||||
format = "ABdY 'digits/at' IMp";
|
||||
}
|
||||
|
||||
if (data) {
|
||||
s = data;
|
||||
s = ast_strdupa(s);
|
||||
if (s) {
|
||||
timec = strsep(&s,"|");
|
||||
if ((timec) && (*timec != '\0')) {
|
||||
long timein;
|
||||
if (sscanf(timec,"%30ld",&timein) == 1) {
|
||||
unixtime = (time_t)timein;
|
||||
}
|
||||
}
|
||||
if (s) {
|
||||
zone = strsep(&s,"|");
|
||||
if (zone && (*zone == '\0'))
|
||||
zone = NULL;
|
||||
if (s) {
|
||||
format = s;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_ERROR, "Out of memory error\n");
|
||||
}
|
||||
}
|
||||
|
||||
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, format, zone);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app_sayunixtime);
|
||||
res |= ast_unregister_application(app_datetime);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,129 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/utils.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Send DTMF digits Application";
|
||||
|
||||
static char *app = "SendDTMF";
|
||||
|
||||
static char *synopsis = "Sends arbitrary DTMF digits";
|
||||
|
||||
static char *descrip =
|
||||
" SendDTMF(digits[|timeout_ms]): Sends DTMF digits on a channel. \n"
|
||||
" Accepted digits: 0-9, *#abcd, w (.5s pause)\n"
|
||||
" The application will either pass the assigned digits or terminate if it\n"
|
||||
" encounters an error.\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int senddtmf_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *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;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
digits = ast_strdupa(data);
|
||||
if (!digits) {
|
||||
ast_log(LOG_ERROR, "Out of Memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((to = strchr(digits,'|'))) {
|
||||
*to = '\0';
|
||||
to++;
|
||||
timeout = atoi(to);
|
||||
}
|
||||
|
||||
if(timeout <= 0)
|
||||
timeout = 250;
|
||||
|
||||
res = ast_dtmf_stream(chan,NULL,digits,timeout);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, senddtmf_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,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 App to transmit a text message
|
||||
*
|
||||
* Requires support of sending text messages from channel driver
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/options.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static const char *tdesc = "Send Text Applications";
|
||||
|
||||
static const char *app = "SendText";
|
||||
|
||||
static const char *synopsis = "Send a Text Message";
|
||||
|
||||
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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int sendtext_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *status = "UNSUPPORTED";
|
||||
char *parse = NULL;
|
||||
int priority_jump = 0;
|
||||
AST_DECLARE_APP_ARGS(args,
|
||||
AST_APP_ARG(text);
|
||||
AST_APP_ARG(options);
|
||||
);
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "SendText requires an argument (text[|options])\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
} else {
|
||||
parse = ast_strdupa(data);
|
||||
if (!parse) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
AST_STANDARD_APP_ARGS(args, parse);
|
||||
|
||||
if (args.options) {
|
||||
if (strchr(args.options, 'j'))
|
||||
priority_jump = 1;
|
||||
}
|
||||
|
||||
ast_mutex_lock(&chan->lock);
|
||||
if (!chan->tech->send_text) {
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
/* Does not support transport */
|
||||
if (priority_jump || option_priority_jumping)
|
||||
ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
status = "FAILURE";
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
res = ast_sendtext(chan, args.text);
|
||||
if (!res)
|
||||
status = "SUCCESS";
|
||||
pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, sendtext_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return (char *) tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
STANDARD_USECOUNT(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,178 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
|
||||
static char *app2 = "SetCallerPres";
|
||||
|
||||
static char *synopsis2 = "Set CallerID Presentation";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static char *descrip2 =
|
||||
" SetCallerPres(presentation): Set Caller*ID presentation on a call.\n"
|
||||
" 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 localuser *u;
|
||||
int pres = -1;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
pres = ast_parse_caller_presentation(data);
|
||||
|
||||
if (pres < 0) {
|
||||
ast_log(LOG_WARNING, "'%s' is not a valid presentation (see 'show application SetCallerPres')\n",
|
||||
(char *) data);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
chan->cid.cid_pres = pres;
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static char *tdesc = "Set CallerID Application";
|
||||
|
||||
static char *app = "SetCallerID";
|
||||
|
||||
static char *synopsis = "Set CallerID";
|
||||
|
||||
static char *descrip =
|
||||
" SetCallerID(clid[|a]): Set Caller*ID on a call to a new\n"
|
||||
"value. Sets ANI as well if a flag is used. \n";
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
char *tmp = NULL;
|
||||
char name[256];
|
||||
char num[256];
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
int anitoo = 0;
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "SetCallerID requires an argument!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app2);
|
||||
res |= ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/cdr.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/config.h"
|
||||
#include "asterisk/manager.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
|
||||
static char *tdesc = "CDR user field apps";
|
||||
|
||||
static char *setcdruserfield_descrip =
|
||||
"[Synopsis]\n"
|
||||
"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";
|
||||
|
||||
|
||||
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";
|
||||
|
||||
static char *appendcdruserfield_app = "AppendCDRUserField";
|
||||
static char *appendcdruserfield_synopsis = "Append to the CDR user field";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int action_setcdruserfield(struct mansession *s, struct message *m)
|
||||
{
|
||||
struct ast_channel *c = NULL;
|
||||
char *userfield = astman_get_header(m, "UserField");
|
||||
char *channel = astman_get_header(m, "Channel");
|
||||
char *append = astman_get_header(m, "Append");
|
||||
|
||||
if (ast_strlen_zero(channel)) {
|
||||
astman_send_error(s, m, "No Channel specified");
|
||||
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 localuser *u;
|
||||
int res = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (chan->cdr && data) {
|
||||
ast_cdr_setuserfield(chan, (char*)data);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int appendcdruserfield_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
int res = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (chan->cdr && data) {
|
||||
ast_cdr_appenduserfield(chan, (char*)data);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(setcdruserfield_app);
|
||||
res |= ast_unregister_application(appendcdruserfield_app);
|
||||
res |= ast_manager_unregister("SetCDRUserField");
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set callerid
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Set CallerID Name";
|
||||
|
||||
static char *app = "SetCIDName";
|
||||
|
||||
static char *synopsis = "Set CallerID Name";
|
||||
|
||||
static char *descrip =
|
||||
" SetCIDName(cname[|a]): Set Caller*ID Name on a call to a new\n"
|
||||
"value, while preserving the original Caller*ID number. This is\n"
|
||||
"useful for providing additional information to the called\n"
|
||||
"party. \n"
|
||||
"SetCIDName has been deprecated in favor of the function\n"
|
||||
"CALLERID(name)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *tmp = NULL;
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "SetCIDName is deprecated, please use Set(CALLERID(name)=value) instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_ERROR, "SetCIDName requires an argument!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
tmp = ast_strdupa(data);
|
||||
if (!tmp) {
|
||||
ast_log(LOG_ERROR, "Out of memory\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
}
|
||||
|
||||
ast_set_callerid(chan, NULL, tmp, NULL);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Oliver Daudey <traveler@xs4all.nl>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set callerid number
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Set CallerID Number";
|
||||
|
||||
static char *app = "SetCIDNum";
|
||||
|
||||
static char *synopsis = "Set CallerID Number";
|
||||
|
||||
static char *descrip =
|
||||
" SetCIDNum(cnum[|a]): Set Caller*ID Number on a call to a new\n"
|
||||
"value, while preserving the original Caller*ID name. This is\n"
|
||||
"useful for providing additional information to the called\n"
|
||||
"party. Sets ANI as well if a flag is used.\n"
|
||||
"SetCIDNum has been deprecated in favor of the function\n"
|
||||
"CALLERID(number)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setcallerid_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct localuser *u;
|
||||
char *opt;
|
||||
int anitoo = 0;
|
||||
char *tmp = NULL;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "SetCIDNum is deprecated, please use Set(CALLERID(number)=value) instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (data)
|
||||
tmp = ast_strdupa(data);
|
||||
else
|
||||
tmp = "";
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt) {
|
||||
*opt = '\0';
|
||||
opt++;
|
||||
if (*opt == 'a')
|
||||
anitoo = 1;
|
||||
}
|
||||
|
||||
ast_set_callerid(chan, tmp, NULL, anitoo ? tmp : NULL);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, setcallerid_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 1999 - 2005, Digium, Inc.
|
||||
*
|
||||
* Mark Spencer <markster@digium.com>
|
||||
* Oliver Daudey <traveler@xs4all.nl>
|
||||
*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2. See the LICENSE file
|
||||
* at the top of the source tree.
|
||||
*/
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief App to set rdnis
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/lock.h"
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/logger.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/translate.h"
|
||||
#include "asterisk/image.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/utils.h"
|
||||
|
||||
static char *tdesc = "Set RDNIS Number";
|
||||
|
||||
static char *app = "SetRDNIS";
|
||||
|
||||
static char *synopsis = "Set RDNIS Number";
|
||||
|
||||
static char *descrip =
|
||||
" SetRDNIS(cnum): Set RDNIS Number on a call to a new\n"
|
||||
"value.\n"
|
||||
"SetRDNIS has been deprecated in favor of the function\n"
|
||||
"CALLERID(rdnis)\n";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int setrdnis_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct localuser *u;
|
||||
char *opt, *n, *l;
|
||||
char *tmp = NULL;
|
||||
static int deprecation_warning = 0;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
if (!deprecation_warning) {
|
||||
ast_log(LOG_WARNING, "SetRDNIS is deprecated, please use Set(CALLERID(rdnis)=value) instead.\n");
|
||||
deprecation_warning = 1;
|
||||
}
|
||||
|
||||
if (data)
|
||||
tmp = ast_strdupa(data);
|
||||
else
|
||||
tmp = "";
|
||||
|
||||
opt = strchr(tmp, '|');
|
||||
if (opt)
|
||||
*opt = '\0';
|
||||
|
||||
n = l = NULL;
|
||||
ast_callerid_parse(tmp, &n, &l);
|
||||
if (l) {
|
||||
ast_shrink_phone_number(l);
|
||||
ast_mutex_lock(&chan->lock);
|
||||
if (chan->cid.cid_rdnis)
|
||||
free(chan->cid.cid_rdnis);
|
||||
chan->cid.cid_rdnis = (l[0]) ? strdup(l) : NULL;
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
}
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, setrdnis_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
@@ -1,145 +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
|
||||
*
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#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";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
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"
|
||||
;
|
||||
|
||||
static int settransfercapability_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
char *tmp = NULL;
|
||||
struct localuser *u;
|
||||
int x;
|
||||
char *opts;
|
||||
int transfercapability = -1;
|
||||
|
||||
LOCAL_USER_ADD(u);
|
||||
|
||||
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);
|
||||
LOCAL_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);
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, settransfercapability_exec, synopsis, descrip);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return synopsis;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
114
apps/app_skel.c
114
apps/app_skel.c
@@ -1,134 +1,60 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
* This is a skeleton for development of an Asterisk application
|
||||
* \ingroup applications
|
||||
*/
|
||||
|
||||
#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.h"
|
||||
#include <pthread.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/lock.h"
|
||||
#include "asterisk/app.h"
|
||||
|
||||
static char *tdesc = "Trivial skeleton Application";
|
||||
static char *app = "Skel";
|
||||
static char *synopsis =
|
||||
"Skeleton application.";
|
||||
static char *descrip = "This application is a template to build other applications from.\n"
|
||||
" It shows you the basic structure to create your own Asterisk applications.\n";
|
||||
|
||||
#define OPTION_A (1 << 0) /* Option A */
|
||||
#define OPTION_B (1 << 1) /* Option B(n) */
|
||||
#define OPTION_C (1 << 2) /* Option C(str) */
|
||||
#define OPTION_NULL (1 << 3) /* Dummy Termination */
|
||||
|
||||
AST_APP_OPTIONS(app_opts,{
|
||||
['a'] = { OPTION_A },
|
||||
['b'] = { OPTION_B, 1 },
|
||||
['c'] = { OPTION_C, 2 }
|
||||
});
|
||||
static char *app = "skel";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int app_exec(struct ast_channel *chan, void *data)
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res = 0;
|
||||
struct ast_flags flags;
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
char *options=NULL;
|
||||
char *dummy = NULL;
|
||||
char *args;
|
||||
int argc = 0;
|
||||
char *opts[2];
|
||||
char *argv[2];
|
||||
|
||||
if (ast_strlen_zero(data)) {
|
||||
ast_log(LOG_WARNING, "%s requires an argument (dummy|[options])\n",app);
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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! */
|
||||
args = ast_strdupa(data);
|
||||
if (!args) {
|
||||
ast_log(LOG_ERROR, "Out of memory!\n");
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
|
||||
dummy = argv[0];
|
||||
options = argv[1];
|
||||
ast_app_parse_options(app_opts, &flags, opts, options);
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(dummy))
|
||||
ast_log(LOG_NOTICE, "Dummy value is : %s\n", dummy);
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_A))
|
||||
ast_log(LOG_NOTICE, "Option A is set\n");
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_B))
|
||||
ast_log(LOG_NOTICE,"Option B is set with : %s\n", opts[0] ? opts[0] : "<unspecified>");
|
||||
|
||||
if (ast_test_flag(&flags, OPTION_C))
|
||||
ast_log(LOG_NOTICE,"Option C is set with : %s\n", opts[1] ? opts[1] : "<unspecified>");
|
||||
|
||||
LOCAL_USER_REMOVE(u);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = ast_unregister_application(app);
|
||||
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
|
||||
return res;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, app_exec, synopsis, descrip);
|
||||
return ast_register_application(app, skel_exec);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
|
||||
1554
apps/app_sms.c
1554
apps/app_sms.c
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user