<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][15082] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=15082">15082</a></dd>
<dt>Author</dt> <dd>gled</dd>
<dt>Date</dt> <dd>2009-10-05 07:40:50 -0500 (Mon, 05 Oct 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>needed for tests</pre>

<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchtrunkcontribgledphpcheckphp">freeswitch/trunk/contrib/gled/php/check.php</a></li>
<li>freeswitch/trunk/contrib/gled/php/phpagi-2.14/</li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214COPYING">freeswitch/trunk/contrib/gled/php/phpagi-2.14/COPYING</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214README">freeswitch/trunk/contrib/gled/php/phpagi-2.14/README</a></li>
<li>freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/</li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsCHANGELOG">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CHANGELOG</a></li>
<li>freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/</li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsCVSEntries">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Entries</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsCVSRepository">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Repository</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsCVSRoot">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Root</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsREADMEphpagi">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsREADMEphpagiasmanager">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-asmanager</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsREADMEphpagifastagi">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-fastagi</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsfastagixinetd">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/fastagi.xinetd</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214docsphpagiexampleconf">freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/phpagi.example.conf</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214mkdocsphp">freeswitch/trunk/contrib/gled/php/phpagi-2.14/mkdocs.php</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214phpagiasmanagerphp">freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-asmanager.php</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214phpagifastagiphp">freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-fastagi.php</a></li>
<li><a href="#freeswitchtrunkcontribgledphpphpagi214phpagiphp">freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunkcontribgledphpcheckphp"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/check.php (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/check.php                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/check.php        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+#!/usr/bin/php -q
+&lt;?php
+require_once('phpagi-2.14/phpagi.php');
+
+$agi = new AGI();
+logthis(&quot;New call incoming&quot;);
+
+$agi-&gt;answer();
+
+logthis(&quot;Answered&quot;);
+
+$res = $agi-&gt;stream_file('/telephony/freeswitch/sounds/en/us/callie/ivr/8000/ivr-you_have_dialed_an_invalid_extension.wav',&quot;*&quot;);
+
+logthis(&quot;Stream_file res:&quot;.print_r($res,true));
+
+$agi-&gt;hangup();
+
+?&gt;
</ins><span class="cx">Property changes on: freeswitch/trunk/contrib/gled/php/check.php
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx">   + *
</span></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214COPYING"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/COPYING (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/COPYING                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/COPYING        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,458 @@
</span><ins>+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 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.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the &quot;Lesser&quot; General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+&quot;work based on the library&quot; and a &quot;work that uses the library&quot;.  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called &quot;this License&quot;).
+Each licensee is addressed as &quot;you&quot;.
+
+  A &quot;library&quot; means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The &quot;Library&quot;, below, refers to any such software library or work
+which has been distributed under these terms.  A &quot;work based on the
+Library&quot; means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term &quot;modification&quot;.)
+
+  &quot;Source code&quot; for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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 Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a &quot;work that uses the Library&quot;.  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a &quot;work that uses the Library&quot; with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a &quot;work that uses the
+library&quot;.  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a &quot;work that uses the Library&quot; uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a &quot;work that uses the Library&quot; with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable &quot;work that
+    uses the Library&quot;, as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the &quot;work that uses the
+Library&quot; must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be 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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+specifies a version number of this License which applies to it and
+&quot;any later version&quot;, 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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY &quot;AS IS&quot; 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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214README"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/README (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/README                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/README        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+PHPAGI README
+ $Id: README,v 1.4 2005/05/19 13:19:37 pinhole Exp $
+---------------------------------------
+
+Welcome to PHPAGI. 
+
+phpagi is a set of PHP classes for use in developing applications with
+the Asterisk Gateway Interface, and is licensed under the GNU Lesser
+General Public License (see COPYING for terms).
+
+This release (version 2) of the phpagi classes is a significant overhaul
+from the old version 1 library.  API functions have been renamed and 
+restructured.
+
+Version 1 of phpagi is no longer supported, but will continue to be
+available for historical purposes.  We strongly encourage you to migrate
+to this new version.
+
+If you have developed software based around phpagi, we'd like to hear from 
+you!  Drop us a note, and indicate whether you'd like us to list your 
+application on our website.
+
+FILES
+-----
+ phpagi.php           - The main phpagi class.
+ phpagi-asmanager.php - The Asterisk Manager class.
+ phpagi-fastagi.php   - FastAGI class.
+ phpagi_1.php         - Compatability class for 1.12 release
+
+ docs/                - README files for the classes.
+ api-docs/            - API Documentation (html)
+
+DOCS
+----
+ README.phpagi           - The main phpagi README
+ README.phpagi-asmanager - The phpagi asterisk manager README
+ README.phpagi-fastagi   - phpagi fastagi README

+ CHANGELOG               - Change Log.
+
+ phpagi.conf             - An example configuration file for phpagi.
+ fastagi.xinetd          - xinetd.conf sample configuration for fastagi
+
+
+SUPPORT
+-------
+
+Support for phpagi is available from the project website. 
+
+ * http://phpagi.sourceforge.net
+ * http://sourceforge.net/projects/phpagi/
+
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsCHANGELOG"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CHANGELOG (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CHANGELOG                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CHANGELOG        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,159 @@
</span><ins>+----------
+CHANGES
+----------
+
+May 25, 2005 - David Eder
+        * Added fastpass support.
+
+May 18, 2005 - David Eder
+        * Added phpagi_1.php as a wrapper class for 1.12 compatibility.
+
+March 25, 2005 - David Eder
+        * Changed the way text2wave and swift are executed for better compatibility.
+        * Added caching to text2wav and swift.
+
+March 12, 2005 - David Eder
+        * fixed autohangup in phpagi-asmanager.php, renamed to set_autohangup.
+        * Added more documentation to phpagi-asmanager.php.
+        * Added weather example.
+
+March 4, 2005 - David Eder
+        * FastAGI via xinetd
+
+February 17, 2005 - David Eder
+        * Fixed bugs with error handler.
+
+February 16, 2005 - David Eder
+        * Added Cepstral swift TTS patch from C. Arbusti of Soluzioni Vocali ( http://soluzionivocali.it ).
+        * Extended swift TTS functionality.
+        * Moved tempdir from [festival] to [phpagi] so that it can be shared with other extensions.
+
+February 2, 2005 - David Eder
+        * More documentation.
+        * Reworked and reintegrated AGI_AsteriskManager class.
+
+January 21, 2005 - David Eder
+        * Added exec_dial($type, $identifier, $timeout=NULL, $options=NULL, $url=NULL).
+        * Added exec_goto($a, $b=NULL, $c=NULL).
+        * Fixed bugs in evaluate, better support of multiline and  closed input and output.
+        * Fixed bugs in config initialization.
+
+January 19, 2005 - David Eder
+        * SUMMARY:
+        *   Massive restructuring!
+        *   Updated to use more PHP internal functions.
+        *   Updated function arguments to represent their AGI function's arguments.
+        *   Functions now return a consistent result array.
+        *   Added phpdoc documentation.
+        *   Removed functions that can be done with internal PHP or AGI functions.
+        *   Enhanced error handler.
+        *
+        * Goals of changes:
+        *
+        * It is important for a language API to not wander too far from the general
+        * API. Functions that are named differently have been updated.  Function
+        * arguments that do not match the AGI API have been updated. Underscores
+        * have been substituted for spaces to make them compatible with PHP function
+        * names.  Optional arguments in AGI should remain optional if possible. Return
+        * values should be consistent.  Functions need to be better documented.
+        *
+        * Result:
+        *
+        * The return from most functions is now
+        *   array('code'=&gt;$code, 'result'=&gt;$result, 'data'=&gt;$data)
+        * ['data'] still needs some work.
+        *
+        * removed class variables:
+        *   $response -  It was no longer used with the new return structure.
+        *
+        * removed functions:
+        *   agi_is_error($retarr) - It was no longer used with the new return
+        *     structure.  Each function has it's own result that must be evalutated
+        *     by the programmer, as the return values are often specific to the function.
+        *   agi_readresult($str=FALSE) - It was no longer used with the new return structure.
+        *   agi_response_code() - It was no longer used with the new return structure.
+        *   agi_response_result() - It was no longer used with the new return structure.
+        *   agi_response_data() - It was no longer used with the new return structure.
+        *   agi_response_var($var) - It was no longer used with the new return structure.
+        *   agi_response_is_error() - see agi_is_error
+        *   agi_read() - It was deprecated
+        *   con_print_r($arr,$label='',$lvl=0) - Use print_r($arr, true) in conjunction with conlog
+        *   agi_getdtmf($len,$timeout,$terminator=FALSE,$prompt=FALSE) - use get_data
+        *   agi_dtmf2text($len,$timeout,$terminator=FALSE,$prompt=FALSE) - use text_input
+        *   arr2str($arr) - use PHP function join
+        *   config_load($file) - use PHP function parse_ini_file
+        *   enum_lookup($telnumber,$rDNS=&quot;e164.org&quot;) - use exec_enumlookup
+        *   enum_txtlookup($telnumber,$rDNS=&quot;e164.org&quot;) - use exec_enumlookup
+        *
+        * added functions:
+        *   answer()
+        *   autohangup($time=0)
+        *   exec($application, $options)
+        *   get_data($filename, $timeout=NULL, $max_digits=NULL)
+        *   receive_char($timeout=-1)
+        *   say_phonetic($text, $escape_digits='')
+        *   set_context($context)
+        *   set_extension($extension)
+        *   set_priority($priority)
+        *   tdd_mode($setting)
+        *   wait_for_digit($timeout=-1)
+        *   database_deltree($family, $keytree='')
+        *   noop()
+        *   set_music($enabled=true, $class='')
+        *   exec_absolutetimeout($seconds=0)
+        *   exec_agi($command, $args)
+        *   exec_enumlookup($exten)
+        *   text_input($mode='NUMERIC')
+        *   say_punctuation($text, $escape_digits='', $frequency=8000)
+        *   which($cmd, $checkpath=NULL)
+        *   make_folder($folder, $perms=0755)
+        * updated functions:
+        *   agi_exec($str) -&gt; evaluate($command) - exec is an AGI function
+        *   agi_verbose($str,$vbl=1) -&gt; verbose($message, $level=1) - consistency with AGI
+        *   db_get($family,$key) -&gt; database_get($family, $key) - consistency with AGI
+        *   db_put($family,$key,$val) -&gt; database_put($family, $key, $value) - consistency with AGI
+        *   db_del($family,$key) -&gt; database_del($family, $key) - consistency with AGI
+        *   get_var($var) -&gt; get_variable($variable) - consistency with AGI
+        *   set_var($var,$val) -&gt; set_variable($variable, $value) - consistency with AGI
+        *   agi_hangup() -&gt; hangup($channel='') - consistency with AGI
+        *   agi_channel_status($channel) -&gt; channel_status($channel='') - consistency with AGI
+        *   agi_recordfile($file,$format,$timeout=5000,$prompt=FALSE) -&gt; record_file($file, $format, $escape_digits='', $timeout=-1, $beep=false, $silence=NULL) - consistency with AGI
+        *   agi_play($file) -&gt; stream_file($filename, $escape_digits='', $offset=0) - consistency with AGI
+        *   agi_goto($con,$ext='s',$pri=1) -&gt; goto($context, $extension='s', $priority=1) - consistency with AGI
+        *   agi_saydigits($digits) -&gt; say_digits($digits, $escape_digits='') - consistency with AGI
+        *   agi_saynumber($number) -&gt; say_number($number, $escape_digits='') - consistency with AGI
+        *   agi_saytime($time=&quot;&quot;) -&gt; say_time($time=NULL, $escape_digits='') - consistency with AGI
+        *   agi_setlanguage($language=&quot;en&quot;) -&gt; exec_setlanguage($language='en') - consistency with AGI
+        *   text2wav($text) -&gt; text2wav($text, $escape_digits='', $frequency=8000) - consistency with AGI
+        *   phpagi_error_handler($errno, $errstr, $errfile, $errline) -&gt; phpagi_error_handler($level, $message, $file, $line, $context) - I needed better error handling
+
+August 29, 2004 -
+        * Fixed db_get now returns a value
+        * Fixed db_put now stores a value
+        * Added enum_lookup, requires external &quot;dig&quot; utility.
+        * Tweak con_print_r now dumps arrays, displays variable type.
+        * Added enum_txtlookup, requires external &quot;dig&quot; utility&quot;.
+        * Added parse_callerid, thanks to http://www.sbuehl.com/projects/asterisk/asterisk-howto-3.html
+
+August 26, 2004 - 
+        * Added agi_verbose
+        * Added debug config-option to shut conlog up
+        * Added agi_saydigits, agi_saynumber, agi_saytime, agi_setlanguage
+
+April 8, 2004 - v1.5 internal
+    * Added agi_goto - David Croft
+    * Added this changelog (maintain it eh?) - Matthew Asham
+    * Added quote fixing to conlog - David Croft
+    * Added new parameter to AGI constructor, $configopt array - Matthew Asham
+    - Added phpagi_error_handler - David Croft
+    

+    
+March 20, 2004 - v1.5 
+        * Fixed buffering bugs - David Croft
+        * added demo app. - Matthew Asham
+        * misc stuff. - Matthew Asham
+
+November 2003 
+        * Initial version
+        
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsCVSEntries"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Entries (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Entries                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Entries        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/CHANGELOG/1.4/Wed May 25 18:43:57 2005//
+/README.phpagi/1.1/Mon Mar 14 19:38:20 2005//
+/README.phpagi-asmanager/1.1/Mon Mar 14 19:38:20 2005//
+/README.phpagi-fastagi/1.1/Mon Mar 14 19:38:20 2005//
+/fastagi.xinetd/1.1/Mon Mar 14 19:38:20 2005//
+/phpagi.example.conf/1.1/Mon Mar 14 19:38:20 2005//
+D
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsCVSRepository"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Repository (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Repository                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Repository        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+phpagi/docs
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsCVSRoot"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Root (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Root                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/CVS/Root        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+:ext:masham@cvs.sourceforge.net:/cvsroot/phpagi
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsREADMEphpagi"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,94 @@
</span><ins>+phpagi:  an AGI class written in PHP
+
+  Matthew Asham &lt;matthewa@bcwireless.net&gt;
+  http://phpagi.sourceforge.net
+
+Contributions by:
+  Florian Overkamp &lt;florian@speakup.nl&gt;
+  David Eder &lt;david@eder.us&gt;
+
+OVERVIEW
+--------
+
+Include it:
+
+require 'phpagi.php';
+
+Construct it:
+
+$agi = new AGI();
+
+This creates a new AGI object with all the agi vars read in, you're now ready
+to rock and roll.
+
+Answer the line.
+
+$agi-&gt;answer();
+
+Play a file.
+
+$agi-&gt;stream_file('somefile.gsm');
+
+Record a file.
+
+$agi-&gt;record_file($file, $format, $escape_digits='', $timeout=-1, $beep=false, $silence=NULL)
+
+There's more, read the class or refer to the PHPAGI website for more information.  
+
+                     This README is seriousley lacking.
+
+CONFIGURATION
+-------------
+
+phpagi supports an ini style configuration file, and run time configuration.
+
+By default the class reads in the contents of /etc/asterisk/phpagi.conf into
+$this-&gt;config.  The format of the ini file is as follows:
+
+[examplesection]
+foo=bar
+bar=dew
+dew=pale ale
+
+This is read into $this-&gt;config as:
+
+$this-&gt;config['examplesection']['foo']='bar';
+$this-&gt;config['examplesection']['bar]='dew';
+$this-&gt;config['examplesection']['dew']='pale ale';
+
+
+Run time configuration is also supported.  Pass an array of variables and values as the
+second parameter to the AGI constructor, these fields are stored in $this-&gt;config['phpagi'].
+
+ie:
+
+$myconfig=array(
+        &quot;error_handler&quot;=&quot;true&quot;
+);
+
+        $agi=new AGI(&quot;/etc/asterisk/phpagi.conf&quot;,$myconfig);
+
+
+The following run-time configuration options are used by the phpagi class to change behaviour.  They 
+are all contained in the $this-&gt;config['phpagi'] array.
+
+ * error_handler - set to &quot;true&quot; (string) to enable php debugging

+        
+EXAMPLE APPLICATION
+-------------------
+
+ping.php is an example phpagi application.  it asks for an IP address to be
+entered, and reads back the results of a &quot;ping&quot; summary.
+
+to use it, you'll need festival installed.  see  http://www.voip-info.org/tiki-index.php?page=Asterisk+festival+installation 
+for all the groovy bits to get festival working with asterisk, then configure
+phpagi to use it too:
+
+in /etc/asterisk/phpagi.conf:
+
+[festival]
+text2wave=/usr/src/festival/bin/text2wave
+tempdir=/var/lib/asterisk/sounds/tmp/
+
+
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsREADMEphpagiasmanager"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-asmanager (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-asmanager                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-asmanager        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,218 @@
</span><ins>+phpagi-asmanager:  an Asterisk Manager class written in PHP
+
+  Matthew Asham &lt;matthewa@bcwireless.net&gt;
+  http://phpagi.sourceforge.net
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+SECURITY
+------------------------------------------------------------------------------
+
+Validation:
+
+******If asterisk is running as root, the manager interface may allow the
+execution of arbitrary shell commands as root. If the user can update any
+configuration file that can execute arbitrary command (like the dialplan),
+the system may be compromised.
+
+Also, look out for command injection.  Consider the following example:
+
+        $as-&gt;Events($_POST['events_status']);
+
+We expect either 'on' or 'off', but the attacker uses:
+
+        &quot;\r\n\r\nAction: Command\r\nCommand: database put forward 54321 19005551212&quot;;
+
+
+Validation is a *must* for all user data.
+
+
+Username and Secret:
+
+Storing the username and secret in the config file will isolate them from your
+code.
+
+Isolation of username and secret in the config file does not mean that the
+script cannot simple read the config file.  The config file must be readable
+by the script.
+
+
+CREATING A NEW INSTANCE OF THE CLASS
+------------------------------------------------------------------------------
+
+The class can be created standalone of phpagi.php, or through phpagi.
+
+STANDALONE:
+
+require &quot;phpagi-asmanager.php&quot;;
+
+$as = new AGI_AsteriskManager();
+
+FROM PHPAGI:
+
+require &quot;phpagi.php&quot;;
+
+$agi = new AGI();
+$as = $agi-&gt;new_AsteriskManager();
+
+Notes:
+
+* If the class is created using $agi-&gt;new_AsteriskManager(),
+  AGI_AsteriskManager will use the parent phpagi for logging to the Asterisk 
+  console.  
+
+* phpagi.php will include phpagi-asmanager.php by itself.  
+  * If phpagi-asmanager.php is included _before_ phpagi.php, phpagi.php will 
+    not attempt to re-include it.
+  * If phpagi.php tries to include phpagi-asmanager.php but is unable to do 
+    so, an error will be echoed to the asterisk console and the script will 
+    continue running normally.  in this case the return value of 
+    new_AsteriskManager() will be FALSE.
+
+------------------------------------------------------------------------------
+CONFIGURATION
+------------------------------------------------------------------------------
+
+phpagi-asmanager uses the same configuration file as phpagi.conf (usually
+/etc/asterisk/phpagi.conf). All configuration information specific to
+phpagi-asmanager is contained in the [asmanager] section of the .conf file.
+
+supported directives:
+
+[asmanager]
+# server to connect to
+server=localhost
+
+# default manager port
+port=5038
+
+#username for login
+username=me_and_only_me
+
+#password for login
+secret=i_am_not_telling
+
+
+
+------------------------------------------------------------------------------
+CONNECTING
+------------------------------------------------------------------------------
+
+        $res = $as-&gt;connect(&quot;localhost&quot;, &quot;username&quot;, &quot;password&quot;);
+        if($res == FALSE) {
+                echo &quot;Connection failed.\n&quot;;
+        }
+        elseif($res == TRUE){
+                echo &quot;Connection established.\n&quot;;
+        }
+
+A port can also be specified for the hostname.  eg:
+
+        $res = $as-&gt;connect(&quot;my.asterisk.server:1234&quot;, &quot;username&quot;, &quot;port&quot;);
+
+If the no parameters are specified, the defaults from the config will be used.
+
+
+------------------------------------------------------------------------------
+DISCONNECTING
+------------------------------------------------------------------------------
+
+  $as-&gt;disconnect();
+
+------------------------------------------------------------------------------
+SENDING REQUESTS
+------------------------------------------------------------------------------
+
+        $as-&gt;send_request($eventname, $arrayofparameterstopass);
+
+send_request() calls wait_request and returns an array of returned data from
+the manager.  If something went wrong, it returns false.
+
+wait_request() shouldn't need to be called from a script directly unless you 
+are implementing merely an event listener.
+
+wait_request() will also detect events and dispatch any registered event
+handlers for the event.
+
+examples:
+
+        $res = $as-&gt;send_request('EventName',
+                                 array('Channel'=&gt;'Zap/1/16045551212',
+                                                  'SomeParameter'=&gt;'data'));
+        echo &quot;Dump of returned data:\n&quot;;
+        foreach($res as $var=&gt;$val)
+          echo &quot;$var = $val\n&quot;;
+
+
+$res['Response'] will generally be 'Success' on success and 'Error' on
+failure. But this is not always true.  If $res['Response'] == 'Follows', a
+multi-line response will be stored in $res['data'].
+
+Several manager commands have been aliased for convenience. See below.
+
+------------------------------------------------------------------------------
+EVENTS
+------------------------------------------------------------------------------
+
+TODO: non-blocking socket i/o. 
+
+The class uses event callbacks to process events received from the manager.
+
+The event callback prototype looks like:
+
+        function dump_event($ecode, $data, $server, $port)
+        {
+          echo &quot;received event '$ecode' from $server:$port\n&quot;;
+          print_r($data);
+        }
+
+To register an event call back:
+
+        $as-&gt;add_event_handler('eventname', 'eventfunction');
+
+eg:
+
+        $as-&gt;add_event_handler('registry', 'dump_event');
+
+
+The special eventname &quot;*&quot; can also be registered.  any eventname not
+specifically registered will be handled by the &quot;*&quot; handler.  If no &quot;*&quot; handler
+is defined, the event will be silently ignored.
+
+
+------------------------------------------------------------------------------
+PRECANNED FUNCTIONS
+------------------------------------------------------------------------------
+
+The following Manager functions have been aliased for convenience:
+
+AbsoluteTimeout
+ChangeMonitor
+Command
+Events
+ExtensionState
+GetVar
+Hangup
+IAXPeers
+ListCommands
+Logoff
+MailboxCount
+MailboxStatus
+Monitor
+Originate
+ParkedCalls
+Ping
+Queues
+QueueStatus
+Redirect
+SetCDRUserField
+SetVar
+SIPpeers
+Status
+StopMontor
+ZapDialOffhook
+ZapDNDoff
+ZapDNDon
+ZapHangup
+ZapTransfer
+
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsREADMEphpagifastagi"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-fastagi (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-fastagi                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/README.phpagi-fastagi        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+First, in /etc/services, at this line:
+
+fastagi         4573/tcp                        # Asterisk AGI
+
+
+
+Second, create /etc/xnetd.d/fastagi with:
+
+# default: off
+# description: fastagi is a remote AGI interface
+service fastagi
+{
+        socket_type  = stream
+        user         = root
+        group        = nobody
+        server       = &lt;path to phpagi-fastagi.php&gt;
+        wait         = no
+        protocol     = tcp
+        bind         = 127.0.0.1
+        disable      = no
+}
+
+Make sure you set the path to the phpagi-fastagi.php script.  Set the user
+and group to a non-root user if none of your scripts need root access. You
+might consider using posix_setuid and friends to reduce privileges. Change
+the bind address to your outbound IP address or to 0.0.0.0 to allow anyone
+to connect. Be sure to read up about xinetd and take advantage of security
+features it provides.  Fast AGI doesn't provide authentification.  It's up
+to you to keep unwanted visitors from extracting information from your AGI
+implementation.
+
+
+Third, write your code.
+
+Take special notice of how fastagi.php works:
+
+        1. $fastagi is initialized as a new AGI.
+        2. The script determines which script was requested.
+        3. The script is called using
+           reqire_once($fastagi-&gt;request['agi_request']).
+        4. Your script takes over.  You must not create a new AGI, but
+           insead use the $fastagi instance that has already been created.
+
+In your dialplan:
+
+exten =&gt; 5551212, 1, Agi(agi://127.0.0.1/myscript.php)
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsfastagixinetd"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/fastagi.xinetd (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/fastagi.xinetd                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/fastagi.xinetd        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+# default: off
+# description: fastagi is a remote AGI interface
+service fastagi
+{
+        socket_type  = stream
+        user         = root
+        group        = nobody
+        server       = /var/lib/asterisk/agi-bin/phpagi/phpagi-fastagi.php
+        wait         = no
+        protocol     = tcp
+        bind         = 127.0.0.1
+        disable      = no
+}
+
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214docsphpagiexampleconf"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/phpagi.example.conf (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/phpagi.example.conf                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/docs/phpagi.example.conf        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+; example phpagi.conf
+
+[phpagi]
+debug=true                                 enable debuging
+error_handler=true                         use internal error handler
+admin=errors@mydomain.com                 mail errors to
+hostname=sip.mydomain.com                 host name of this server
+tempdir=/var/spool/asterisk/tmp/         temporary directory for storing temporary output
+
+[asmanager]
+server=localhost                         server to connect to
+port=5038                                 default manager port
+username=me_and_only_me                         username for login
+secret=i_am_not_telling                         password for login
+
+[fastagi]
+setuid=true                                 drop privileges to owner of script
+basedir=/var/lib/asterisk/agi-bin/         path to script folder
+
+[festival]                                 text to speech engine
+text2wave=/usr/bin/text2wave                 path to text2wave binary
+
+[cepstral]                                 alternate text to speech engine
+swift=/opt/swift/bin/swift                 path to switft binary
+voice=David                                 default voice
+
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214mkdocsphp"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/mkdocs.php (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/mkdocs.php                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/mkdocs.php        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+#!/usr/local/bin/php -q
+&lt;?php
+  $cwd = getcwd();
+  passthru(&quot;phpdoc -t \&quot;$cwd/api-docs\&quot; -f \&quot;$cwd/phpagi.php,$cwd/phpagi-asmanager.php,$cwd/phpagi-fastagi.php,$cwd/phpagi_1.php\&quot; -pp on -ti \&quot;phpAGI\&quot; -o HTML:frames:earthli -s on&quot;);
+?&gt;
+
+
</ins><span class="cx">Property changes on: freeswitch/trunk/contrib/gled/php/phpagi-2.14/mkdocs.php
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx">   + *
</span></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214phpagiasmanagerphp"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-asmanager.php (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-asmanager.php                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-asmanager.php        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,818 @@
</span><ins>+&lt;?php
+ /**
+  * phpagi-asmanager.php : PHP Asterisk Manager functions
+  * Website: http://phpagi.sourceforge.net
+  *
+  * $Id: phpagi-asmanager.php,v 1.10 2005/05/25 18:43:48 pinhole Exp $
+  *
+  * Copyright (c) 2004, 2005 Matthew Asham &lt;matthewa@bcwireless.net&gt;, David Eder &lt;david@eder.us&gt;
+  * All Rights Reserved.
+  *
+  * This software is released under the terms of the GNU Lesser General Public License v2.1
+  *  A copy of which is available from http://www.gnu.org/copyleft/lesser.html
+  * 
+  * We would be happy to list your phpagi based application on the phpagi
+  * website.  Drop me an Email if you'd like us to list your program.
+  *
+  * @package phpAGI
+  * @version 2.0
+  */
+
+
+ /**
+  * Written for PHP 4.3.4, should work with older PHP 4.x versions.  
+  * Please submit bug reports, patches, etc to http://sourceforge.net/projects/phpagi/
+  * Gracias. :)
+  *
+  */
+
+  if(!class_exists('AGI'))
+  {
+    require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'phpagi.php');
+  }
+
+ /**
+  * Asterisk Manager class
+  *
+  * @link http://www.voip-info.org/wiki-Asterisk+config+manager.conf
+  * @link http://www.voip-info.org/wiki-Asterisk+manager+API
+  * @example examples/sip_show_peer.php Get information about a sip peer
+  * @package phpAGI
+  */
+  class AGI_AsteriskManager
+  {
+   /**
+    * Config variables
+    *
+    * @var array
+    * @access public
+    */
+    var $config;
+
+   /**
+    * Socket
+    *
+    * @access public
+    */
+    var $socket = NULL;
+
+   /**
+    * Server we are connected to
+    *
+    * @access public
+    * @var string
+    */
+    var $server;
+
+   /**
+    * Port on the server we are connected to
+    *
+    * @access public
+    * @var integer
+    */
+    var $port;
+
+   /**
+    * Parent AGI
+    *
+    * @access private
+    * @var AGI
+    */
+    var $pagi;
+
+   /**
+    * Event Handlers
+    *
+    * @access private
+    * @var array
+    */
+    var $event_handlers;
+
+   /**
+    * Constructor
+    *
+    * @param string $config is the name of the config file to parse or a parent agi from which to read the config
+    * @param array $optconfig is an array of configuration vars and vals, stuffed into $this-&gt;config['asmanager']
+    */
+    function AGI_AsteriskManager($config=NULL, $optconfig=array())
+    {
+      // load config
+      if(!is_null($config) &amp;&amp; file_exists($config))
+        $this-&gt;config = parse_ini_file($config, true);
+      elseif(file_exists(DEFAULT_PHPAGI_CONFIG))
+        $this-&gt;config = parse_ini_file(DEFAULT_PHPAGI_CONFIG, true);
+
+      // If optconfig is specified, stuff vals and vars into 'asmanager' config array.
+      foreach($optconfig as $var=&gt;$val)
+        $this-&gt;config['asmanager'][$var] = $val;
+
+      // add default values to config for uninitialized values
+      if(!isset($this-&gt;config['asmanager']['server'])) $this-&gt;config['asmanager']['server'] = 'localhost';
+      if(!isset($this-&gt;config['asmanager']['port'])) $this-&gt;config['asmanager']['port'] = 5038;
+      if(!isset($this-&gt;config['asmanager']['username'])) $this-&gt;config['asmanager']['username'] = 'placecalls';
+      if(!isset($this-&gt;config['asmanager']['secret'])) $this-&gt;config['asmanager']['secret'] = 'asecret';
+    }
+
+   /**
+    * Send a request
+    *
+    * @param string $action
+    * @param array $parameters
+    * @return array of parameters
+    */
+    function send_request($action, $parameters=array())
+    {
+      $req = &quot;Action: $action\r\n&quot;;
+      foreach($parameters as $var=&gt;$val)
+        $req .= &quot;$var: $val\r\n&quot;;
+      $req .= &quot;\r\n&quot;;
+      fwrite($this-&gt;socket, $req);
+      return $this-&gt;wait_response();
+    }
+
+   /**
+    * Wait for a response
+    *
+    * If a request was just sent, this will return the response.
+    * Otherwise, it will loop forever, handling events.
+    *
+    * @param boolean $allow_timeout if the socket times out, return an empty array
+    * @return array of parameters, empty on timeout
+    */
+    function wait_response($allow_timeout=false)
+    {
+      $timeout = false;
+      do
+      {
+        $type = NULL;
+        $parameters = array();
+
+        $buffer = trim(fgets($this-&gt;socket, 4096));
+        while($buffer != '')
+        {
+          $a = strpos($buffer, ':');
+          if($a)
+          {
+            if(!count($parameters)) // first line in a response?
+            {
+              $type = strtolower(substr($buffer, 0, $a));
+              if(substr($buffer, $a + 2) == 'Follows')
+              {
+                // A follows response means there is a miltiline field that follows.
+                $parameters['data'] = '';
+                $buff = fgets($this-&gt;socket, 4096);
+                while(substr($buff, 0, 6) != '--END ')
+                {
+                  $parameters['data'] .= $buff;
+                  $buff = fgets($this-&gt;socket, 4096);
+                }
+              }
+            }
+
+            // store parameter in $parameters
+            $parameters[substr($buffer, 0, $a)] = substr($buffer, $a + 2);
+          }
+          $buffer = trim(fgets($this-&gt;socket, 4096));
+        }
+
+        // process response
+        switch($type)
+        {
+          case '': // timeout occured
+            $timeout = $allow_timeout;
+            break;
+          case 'event':
+            $this-&gt;process_event($parameters);
+            break;
+          case 'response':
+            break;
+          default:
+            $this-&gt;log('Unhandled response packet from Manager: ' . print_r($parameters, true));
+            break;
+        }
+      } while($type != 'response' &amp;&amp; !$timeout);
+      return $parameters;
+    }
+
+   /**
+    * Connect to Asterisk
+    *
+    * @example examples/sip_show_peer.php Get information about a sip peer
+    *
+    * @param string $server
+    * @param string $username
+    * @param string $secret
+    * @return boolean true on success
+    */
+    function connect($server=NULL, $username=NULL, $secret=NULL)
+    {
+      // use config if not specified
+      if(is_null($server)) $server = $this-&gt;config['asmanager']['server'];
+      if(is_null($username)) $username = $this-&gt;config['asmanager']['username'];
+      if(is_null($secret)) $secret = $this-&gt;config['asmanager']['secret'];
+
+      // get port from server if specified
+      if(strpos($server, ':') !== false)
+      {
+        $c = explode(':', $server);
+        $this-&gt;server = $c[0];
+        $this-&gt;port = $c[1];
+      }
+      else
+      {
+        $this-&gt;server = $server;
+        $this-&gt;port = $this-&gt;config['asmanager']['port'];
+      }
+
+      // connect the socket
+      $errno = $errstr = NULL;
+      $this-&gt;socket = @fsockopen($this-&gt;server, $this-&gt;port, $errno, $errstr);
+      if($this-&gt;socket == false)
+      {
+        $this-&gt;log(&quot;Unable to connect to manager {$this-&gt;server}:{$this-&gt;port} ($errno): $errstr&quot;);
+        return false;
+      }
+
+      // read the header
+      $str = fgets($this-&gt;socket);
+      if($str == false)
+      {
+        // a problem.
+        $this-&gt;log(&quot;Asterisk Manager header not received.&quot;);
+        return false;
+      }
+      else
+      {
+        // note: don't $this-&gt;log($str) until someone looks to see why it mangles the logging
+      }
+
+      // login
+      $res = $this-&gt;send_request('login', array('Username'=&gt;$username, 'Secret'=&gt;$secret, 'Events' =&gt; 'off'));
+      if($res['Response'] != 'Success')
+      {
+        $this-&gt;log(&quot;Failed to login.&quot;);
+        $this-&gt;disconnect();
+        return false;
+      }
+      return true;
+    }
+
+   /**
+    * Disconnect
+    *
+    * @example examples/sip_show_peer.php Get information about a sip peer
+    */
+    function disconnect()
+    {
+      $this-&gt;logoff();
+      fclose($this-&gt;socket);
+    }
+
+   // *********************************************************************************************************
+   // **                       COMMANDS                                                                      **
+   // *********************************************************************************************************
+
+   /**
+    * Set Absolute Timeout
+    *
+    * Hangup a channel after a certain time.
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+AbsoluteTimeout
+    * @param string $channel Channel name to hangup
+    * @param integer $timeout Maximum duration of the call (sec)
+    */
+    function AbsoluteTimeout($channel, $timeout)
+    {
+      return $this-&gt;send_request('AbsoluteTimeout', array('Channel'=&gt;$channel, 'Timeout'=&gt;$timeout));
+    }
+
+   /**
+    * Change monitoring filename of a channel
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ChangeMonitor
+    * @param string $channel the channel to record.
+    * @param string $file the new name of the file created in the monitor spool directory.
+    */
+    function ChangeMonitor($channel, $file)
+    {
+      return $this-&gt;send_request('ChangeMontior', array('Channel'=&gt;$channel, 'File'=&gt;$file));
+    }
+
+   /**
+    * Execute Command
+    *
+    * @example examples/sip_show_peer.php Get information about a sip peer
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Command
+    * @link http://www.voip-info.org/wiki-Asterisk+CLI
+    * @param string $command
+    * @param string $actionid message matching variable
+    */
+    function Command($command, $actionid=NULL)
+    {
+      $parameters = array('Command'=&gt;$command);
+      if($actionid) $parameters['ActionID'] = $actionid;
+      return $this-&gt;send_request('Command', $parameters);
+    }
+
+   /**
+    * Enable/Disable sending of events to this manager
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Events
+    * @param string $eventmask is either 'on', 'off', or 'system,call,log'
+    */
+    function Events($eventmask)
+    {
+      return $this-&gt;send_request('Events', array('EventMask'=&gt;$eventmask));
+    }
+
+   /**
+    * Check Extension Status
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ExtensionState
+    * @param string $exten Extension to check state on
+    * @param string $context Context for extension
+    * @param string $actionid message matching variable
+    */
+    function ExtensionState($exten, $context, $actionid=NULL)
+    {
+      $parameters = array('Exten'=&gt;$exten, 'Context'=&gt;$context);
+      if($actionid) $parameters['ActionID'] = $actionid;
+      return $this-&gt;send_request('ExtensionState', $parameters);
+    }
+
+   /**
+    * Gets a Channel Variable
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+GetVar
+    * @link http://www.voip-info.org/wiki-Asterisk+variables
+    * @param string $channel Channel to read variable from
+    * @param string $variable
+    * @param string $actionid message matching variable
+    */
+    function GetVar($channel, $variable, $actionid=NULL)
+    {
+      $parameters = array('Channel'=&gt;$channel, 'Variable'=&gt;$variable);
+      if($actionid) $parameters['ActionID'] = $actionid;
+      return $this-&gt;send_request('GetVar', $parameters);
+    }
+
+   /**
+    * Hangup Channel
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Hangup
+    * @param string $channel The channel name to be hungup
+    */
+    function Hangup($channel)
+    {
+      return $this-&gt;send_request('Hangup', array('Channel'=&gt;$channel));
+    }
+
+   /**
+    * List IAX Peers
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+IAXpeers
+    */
+    function IAXPeers()
+    {
+      return $this-&gt;send_request('IAXPeers');
+    }
+
+   /**
+    * List available manager commands
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ListCommands
+    * @param string $actionid message matching variable
+    */
+    function ListCommands($actionid=NULL)
+    {
+      if($actionid)
+        return $this-&gt;send_request('ListCommands', array('ActionID'=&gt;$actionid));
+      else
+        return $this-&gt;send_request('ListCommands');
+    }
+
+   /**
+    * Logoff Manager
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Logoff
+    */
+    function Logoff()
+    {
+      return $this-&gt;send_request('Logoff');
+    }
+
+   /**
+    * Check Mailbox Message Count
+    *
+    * Returns number of new and old messages.
+    *   Message: Mailbox Message Count
+    *   Mailbox: &lt;mailboxid&gt;
+    *   NewMessages: &lt;count&gt;
+    *   OldMessages: &lt;count&gt;
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+MailboxCount
+    * @param string $mailbox Full mailbox ID &lt;mailbox&gt;@&lt;vm-context&gt;
+    * @param string $actionid message matching variable
+    */
+    function MailboxCount($mailbox, $actionid=NULL)
+    {
+      $parameters = array('Mailbox'=&gt;$mailbox);
+      if($actionid) $parameters['ActionID'] = $actionid;
+      return $this-&gt;send_request('MailboxCount', $parameters);
+    }
+
+   /**
+    * Check Mailbox
+    *
+    * Returns number of messages.
+    *   Message: Mailbox Status
+    *   Mailbox: &lt;mailboxid&gt;
+    *   Waiting: &lt;count&gt;
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+MailboxStatus
+    * @param string $mailbox Full mailbox ID &lt;mailbox&gt;@&lt;vm-context&gt;
+    * @param string $actionid message matching variable
+    */
+    function MailboxStatus($mailbox, $actionid=NULL)
+    {        
+      $parameters = array('Mailbox'=&gt;$mailbox);
+      if($actionid) $parameters['ActionID'] = $actionid;
+      return $this-&gt;send_request('MailboxStatus', $parameters);
+    }
+
+   /**
+    * Monitor a channel
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Monitor
+    * @param string $channel
+    * @param string $file
+    * @param string $format
+    * @param boolean $mix
+    */
+    function Monitor($channel, $file=NULL, $format=NULL, $mix=NULL)
+    {
+      $parameters = array('Channel'=&gt;$channel);
+      if($file) $parameters['File'] = $file;
+      if($format) $parameters['Format'] = $format;
+      if(!is_null($file)) $parameters['Mix'] = ($mix) ? 'true' : 'false';
+      return $this-&gt;send_request('Monitor', $parameters);
+    }
+
+   /**
+    * Originate Call
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Originate
+    * @param string $channel Channel name to call
+    * @param string $exten Extension to use (requires 'Context' and 'Priority')
+    * @param string $context Context to use (requires 'Exten' and 'Priority')
+    * @param string $priority Priority to use (requires 'Exten' and 'Context')
+    * @param string $application Application to use
+    * @param string $data Data to use (requires 'Application')
+    * @param integer $timeout How long to wait for call to be answered (in ms)
+    * @param string $callerid Caller ID to be set on the outgoing channel
+    * @param string $variable Channel variable to set (VAR1=value1|VAR2=value2)
+    * @param string $account Account code
+    * @param boolean $async true fast origination
+    * @param string $actionid message matching variable
+    */
+    function Originate($channel,
+                       $exten=NULL, $context=NULL, $priority=NULL,
+                       $application=NULL, $data=NULL,
+                       $timeout=NULL, $callerid=NULL, $variable=NULL, $account=NULL, $async=NULL, $actionid=NULL)
+    {
+      $parameters = array('Channel'=&gt;$channel);
+
+      if($exten) $parameters['Exten'] = $exten;
+      if($context) $parameters['Context'] = $context;
+      if($priority) $parameters['Priority'] = $priority;
+
+      if($application) $parameters['Application'] = $application;
+      if($data) $parameters['Data'] = $data;
+
+      if($timeout) $parameters['Timeout'] = $timeout;
+      if($callerid) $parameters['CallerID'] = $callerid;
+      if($variable) $parameters['Variable'] = $variable;
+      if($account) $parameters['Account'] = $account;
+      if(!is_null($async)) $parameters['Async'] = ($async) ? 'true' : 'false';
+      if($actionid) $parameters['ActionID'] = $actionid;
+
+      return $this-&gt;send_request('Originate', $parameters);
+    }        
+
+   /**
+    * List parked calls
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ParkedCalls
+    * @param string $actionid message matching variable
+    */
+    function ParkedCalls($actionid=NULL)
+    {
+      if($actionid)
+        return $this-&gt;send_request('ParkedCalls', array('ActionID'=&gt;$actionid));
+      else
+        return $this-&gt;send_request('ParkedCalls');
+    }
+
+   /**
+    * Ping
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Ping
+    */
+    function Ping()
+    {
+      return $this-&gt;send_request('Ping');
+    }
+
+   /**
+    * Queue Add
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueAdd
+    * @param string $queue
+    * @param string $interface
+    * @param integer $penalty
+    */
+    function QueueAdd($queue, $interface, $penalty=0)
+    {
+      $parameters = array('Queue'=&gt;$queue, 'Interface'=&gt;$interface);
+      if($penalty) $parameters['Penalty'] = $penalty;
+      return $this-&gt;send_request('QueueAdd', $parameters);
+    }
+
+   /**
+    * Queue Remove
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueRemove
+    * @param string $queue
+    * @param string $interface
+    */
+    function QueueRemove($queue, $interface)
+    {
+      return $this-&gt;send_request('QueueRemove', array('Queue'=&gt;$queue, 'Interface'=&gt;$interface));
+    }
+
+   /**
+    * Queues
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Queues
+    */
+    function Queues()
+    {
+      return $this-&gt;send_request('Queues');
+    }
+
+   /**
+    * Queue Status
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+QueueStatus
+    * @param string $actionid message matching variable
+    */
+    function QueueStatus($actionid=NULL)
+    {
+      if($actionid)
+        return $this-&gt;send_request('QueueStatus', array('ActionID'=&gt;$actionid));
+      else
+        return $this-&gt;send_request('QueueStatus');
+    }
+
+   /**
+    * Redirect
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Redirect
+    * @param string $channel
+    * @param string $extrachannel
+    * @param string $exten
+    * @param string $context
+    * @param string $priority
+    */
+    function Redirect($channel, $extrachannel, $exten, $context, $priority)
+    {
+      return $this-&gt;send_request('Redirect', array('Channel'=&gt;$channel, 'ExtraChannel'=&gt;$extrachannel, 'Exten'=&gt;$exten,
+                                                   'Context'=&gt;$context, 'Priority'=&gt;$priority));
+    }
+
+   /**
+    * Set the CDR UserField
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+SetCDRUserField
+    * @param string $userfield
+    * @param string $channel
+    * @param string $append
+    */
+    function SetCDRUserField($userfield, $channel, $append=NULL)
+    {
+      $parameters = array('UserField'=&gt;$userfield, 'Channel'=&gt;$channel);
+      if($append) $parameters['Append'] = $append;
+      return $this-&gt;send_request('SetCDRUserField', $parameters);
+    }
+
+   /**
+    * Set Channel Variable
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+SetVar
+    * @param string $channel Channel to set variable for
+    * @param string $variable name
+    * @param string $value
+    */
+    function SetVar($channel, $variable, $value)
+    {
+      return $this-&gt;send_request('SetVar', array('Channel'=&gt;$channel, 'Variable'=&gt;$variable, 'Value'=&gt;$value));
+    }
+
+   /**
+    * Channel Status
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+Status
+    * @param string $channel
+    * @param string $actionid message matching variable
+    */
+    function Status($channel=NULL, $actionid=NULL)
+    {
+      if ($channel) {
+       $parameters = array('Channel'=&gt;$channel);
+      }
+      else {
+       $parameters = array();
+      }
+      if($actionid) $parameters['ActionID'] = $actionid;
+      return $this-&gt;send_request('Status', $parameters);
+    }
+
+   /**
+    * Stop monitoring a channel
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+StopMonitor
+    * @param string $channel
+    */
+    function StopMontor($channel)
+    {
+      return $this-&gt;send_request('StopMonitor', array('Channel'=&gt;$channel));
+    }
+
+   /**
+    * Dial over Zap channel while offhook
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDialOffhook
+    * @param string $zapchannel
+    * @param string $number
+    */
+    function ZapDialOffhook($zapchannel, $number)
+    {
+      return $this-&gt;send_request('ZapDialOffhook', array('ZapChannel'=&gt;$zapchannel, 'Number'=&gt;$number));
+    }
+
+   /**
+    * Toggle Zap channel Do Not Disturb status OFF
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDNDoff
+    * @param string $zapchannel
+    */
+    function ZapDNDoff($zapchannel)
+    {
+      return $this-&gt;send_request('ZapDNDoff', array('ZapChannel'=&gt;$zapchannel));
+    }
+
+   /**
+    * Toggle Zap channel Do Not Disturb status ON
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapDNDon
+    * @param string $zapchannel
+    */
+    function ZapDNDon($zapchannel)
+    {
+      return $this-&gt;send_request('ZapDNDon', array('ZapChannel'=&gt;$zapchannel));
+    }
+
+   /**
+    * Hangup Zap Channel
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapHangup
+    * @param string $zapchannel
+    */
+    function ZapHangup($zapchannel)
+    {
+      return $this-&gt;send_request('ZapHangup', array('ZapChannel'=&gt;$zapchannel));
+    }
+
+   /**
+    * Transfer Zap Channel
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapTransfer
+    * @param string $zapchannel
+    */
+    function ZapTransfer($zapchannel)
+    {
+      return $this-&gt;send_request('ZapTransfer', array('ZapChannel'=&gt;$zapchannel));
+    }
+
+   /**
+    * Zap Show Channels
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+Manager+API+Action+ZapShowChannels
+    * @param string $actionid message matching variable
+    */
+    function ZapShowChannels($actionid=NULL)
+    {
+      if($actionid)
+        return $this-&gt;send_request('ZapShowChannels', array('ActionID'=&gt;$actionid));
+      else
+        return $this-&gt;send_request('ZapShowChannels');
+    }
+
+   // *********************************************************************************************************
+   // **                       MISC                                                                          **
+   // *********************************************************************************************************
+
+   /*
+    * Log a message
+    *
+    * @param string $message
+    * @param integer $level from 1 to 4
+    */
+    function log($message, $level=1)
+    {
+      if($this-&gt;pagi != false)
+        $this-&gt;pagi-&gt;conlog($message, $level);
+      else
+        error_log(date('r') . ' - ' . $message);
+    }
+
+   /**
+    * Add event handler
+    *
+    * Known Events include ( http://www.voip-info.org/wiki-asterisk+manager+events )
+    *   Link - Fired when two voice channels are linked together and voice data exchange commences.
+    *   Unlink - Fired when a link between two voice channels is discontinued, for example, just before call completion.
+    *   Newexten -
+    *   Hangup -
+    *   Newchannel -
+    *   Newstate -
+    *   Reload - Fired when the &quot;RELOAD&quot; console command is executed.
+    *   Shutdown -
+    *   ExtensionStatus -
+    *   Rename -
+    *   Newcallerid -
+    *   Alarm -
+    *   AlarmClear -
+    *   Agentcallbacklogoff -
+    *   Agentcallbacklogin -
+    *   Agentlogoff -
+    *   MeetmeJoin -
+    *   MessageWaiting -
+    *   join -
+    *   leave -
+    *   AgentCalled -
+    *   ParkedCall - Fired after ParkedCalls
+    *   Cdr -
+    *   ParkedCallsComplete -
+    *   QueueParams -
+    *   QueueMember -
+    *   QueueStatusEnd -
+    *   Status -
+    *   StatusComplete -
+    *   ZapShowChannels - Fired after ZapShowChannels
+    *   ZapShowChannelsComplete -
+    *
+    * @param string $event type or * for default handler
+    * @param string $callback function
+    * @return boolean sucess
+    */
+    function add_event_handler($event, $callback)
+    {
+      $event = strtolower($event);
+      if(isset($this-&gt;event_handlers[$event]))
+      {
+        $this-&gt;log(&quot;$event handler is already defined, not over-writing.&quot;);
+        return false;
+      }
+      $this-&gt;event_handlers[$event] = $callback;
+      return true;
+    }
+
+   /**
+    * Process event
+    *
+    * @access private
+    * @param array $parameters
+    * @return mixed result of event handler or false if no handler was found
+    */
+    function process_event($parameters)
+    {
+      $ret = false;
+      $e = strtolower($parameters['Event']);
+      // $this-&gt;log(&quot;Got event.. $e&quot;);                
+
+      $handler = '';
+      if(isset($this-&gt;event_handlers[$e])) $handler = $this-&gt;event_handlers[$e];
+      elseif(isset($this-&gt;event_handlers['*'])) $handler = $this-&gt;event_handlers['*'];
+
+      if(function_exists($handler))
+      {
+        // $this-&gt;log(&quot;Execute handler $handler&quot;);
+        $ret = $handler($e, $parameters, $this-&gt;server, $this-&gt;port);
+      }
+      else
+        $this-&gt;log(&quot;No event handler for event '$e'&quot;);
+      return $ret;
+    }
+  }
+?&gt;
</ins></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214phpagifastagiphp"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-fastagi.php (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-fastagi.php                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-fastagi.php        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,79 @@
</span><ins>+#!/usr/local/bin/php -q
+&lt;?php
+ /**
+  * phpagi-fastagi.php : PHP FastAGI bootstrap
+  * Website: http://phpagi.sourceforge.net
+  *
+  * $Id: phpagi-fastagi.php,v 1.2 2005/05/25 18:43:48 pinhole Exp $
+  *
+  * Copyright (c) 2004, 2005 Matthew Asham &lt;matthewa@bcwireless.net&gt;, David Eder &lt;david@eder.us&gt;
+  * All Rights Reserved.
+  *
+  * This software is released under the terms of the GNU Lesser General Public License v2.1
+  * A copy of which is available from http://www.gnu.org/copyleft/lesser.html
+  *
+  * We would be happy to list your phpagi based application on the phpagi
+  * website.  Drop me an Email if you'd like us to list your program.
+  *
+  * @package phpAGI
+  * @version 2.0
+  * @example docs/fastagi.xinetd Example xinetd config file
+  */
+
+ /**
+  * Written for PHP 4.3.4, should work with older PHP 4.x versions.
+  * Please submit bug reports, patches, etc to http://sourceforge.net/projects/phpagi/
+  * Gracias. :)
+  *
+  */
+
+  require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'phpagi.php');
+
+  $fastagi = new AGI();
+
+  $fastagi-&gt;verbose(print_r($fastagi, true));
+
+  if(!isset($fastagi-&gt;config['fastagi']['basedir']))
+    $fastagi-&gt;config['fastagi']['basedir'] = dirname(__FILE__);
+
+  // perform some security checks
+
+  $script = $fastagi-&gt;config['fastagi']['basedir'] . DIRECTORY_SEPARATOR . $fastagi-&gt;request['agi_network_script'];
+
+  // in the same directory (or subdirectory)
+  $mydir = dirname($fastagi-&gt;config['fastagi']['basedir']) . DIRECTORY_SEPARATOR;
+  $dir = dirname($script) . DIRECTORY_SEPARATOR;
+  if(substr($dir, 0, strlen($mydir)) != $mydir)
+  {
+    $fastagi-&gt;conlog(&quot;$script is not allowed to execute.&quot;);
+    exit;
+  }
+
+  // make sure it exists
+  if(!file_exists($script))
+  {
+    $fastagi-&gt;conlog(&quot;$script does not exist.&quot;);
+    exit;
+  }
+
+  // drop privileges
+  if(isset($fastagi-&gt;config['fastagi']['setuid']) &amp;&amp; $fastagi-&gt;config['fastagi']['setuid'])
+  {
+    $owner = fileowner($script);
+    $group = filegroup($script);
+    if(!posix_setgid($group) || !posix_setegid($group) || !posix_setuid($owner) || !posix_seteuid($owner))
+    {
+      $fastagi-&gt;conlog(&quot;failed to lower privileges.&quot;);
+      exit;      
+    }
+  }
+
+  // make sure script is still readable
+  if(!is_readable($script))
+  {
+    $fastagi-&gt;conlog(&quot;$script is not readable.&quot;);
+    exit;
+  }
+
+  require_once($script);
+?&gt;
</ins><span class="cx">Property changes on: freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi-fastagi.php
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:executable
</span><span class="cx">   + *
</span></span></pre></div>
<a id="freeswitchtrunkcontribgledphpphpagi214phpagiphp"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi.php (0 => 15082)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi.php                                (rev 0)
+++ freeswitch/trunk/contrib/gled/php/phpagi-2.14/phpagi.php        2009-10-05 12:40:50 UTC (rev 15082)
</span><span class="lines">@@ -0,0 +1,1753 @@
</span><ins>+&lt;?php
+
+ /**
+  * phpagi.php : PHP AGI Functions for Asterisk
+  * Website: http://phpagi.sourceforge.net/
+  *
+  * $Id: phpagi.php,v 2.14 2005/05/25 20:30:46 pinhole Exp $
+  *
+  * Copyright (c) 2003, 2004, 2005 Matthew Asham &lt;matthewa@bcwireless.net&gt;, David Eder &lt;david@eder.us&gt;
+  * All Rights Reserved.
+  *
+  * This software is released under the terms of the GNU Lesser General Public License v2.1
+  * A copy of which is available from http://www.gnu.org/copyleft/lesser.html
+  *
+  * We would be happy to list your phpagi based application on the phpagi
+  * website.  Drop me an Email if you'd like us to list your program.
+  *
+  *
+  * Written for PHP 4.3.4, should work with older PHP 4.x versions.
+  *
+  * Please submit bug reports, patches, etc to http://sourceforge.net/projects/phpagi/
+  * Gracias. :)
+  *
+  *
+  * @package phpAGI
+  * @version 2.0
+  */
+
+/*
+ PATCH
+*/
+
+ function logthis($str) {
+        file_put_contents('/telephony/freeswitch/log/ivr.log',date(&quot;Y-m-d H:i:s&quot;).&quot;: $str\n&quot;,FILE_APPEND);
+ }
+
+ /**
+  */
+
+  if(!class_exists('AGI_AsteriskManager'))
+  {
+    require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'phpagi-asmanager.php');
+  }
+
+  define('AST_CONFIG_DIR', '/pstn/confs/asterisk');
+  define('AST_SPOOL_DIR', '/pstn/system/var/spool/asterisk/');
+  define('AST_TMP_DIR', AST_SPOOL_DIR . '/tmp/');
+  define('DEFAULT_PHPAGI_CONFIG', AST_CONFIG_DIR . '/phpagi.conf');
+
+  define('AST_DIGIT_ANY', '0123456789#*');
+
+  define('AGIRES_OK', 200);
+
+  define('AST_STATE_DOWN', 0);
+  define('AST_STATE_RESERVED', 1);
+  define('AST_STATE_OFFHOOK', 2);
+  define('AST_STATE_DIALING', 3);
+  define('AST_STATE_RING', 4);
+  define('AST_STATE_RINGING', 5);
+  define('AST_STATE_UP', 6);
+  define('AST_STATE_BUSY', 7);
+  define('AST_STATE_DIALING_OFFHOOK', 8);
+  define('AST_STATE_PRERING', 9);
+
+  define('AUDIO_FILENO', 3); // STDERR_FILENO + 1
+
+ /**
+  * AGI class
+  *
+  * @package phpAGI
+  * @link http://www.voip-info.org/wiki-Asterisk+agi
+  * @example examples/dtmf.php Get DTMF tones from the user and say the digits
+  * @example examples/input.php Get text input from the user and say it back
+  * @example examples/ping.php Ping an IP address
+  */
+  class AGI
+  {
+   /**
+    * Request variables read in on initialization.
+    *
+    * Often contains any/all of the following:
+    *   agi_request - name of agi script
+    *   agi_channel - current channel
+    *   agi_language - current language
+    *   agi_type - channel type (SIP, ZAP, IAX, ...)
+    *   agi_uniqueid - unique id based on unix time
+    *   agi_callerid - callerID string
+    *   agi_dnid - dialed number id
+    *   agi_rdnis - referring DNIS number
+    *   agi_context - current context
+    *   agi_extension - extension dialed
+    *   agi_priority - current priority
+    *   agi_enhanced - value is 1.0 if started as an EAGI script
+    *   agi_accountcode - set by SetAccount in the dialplan
+    *   agi_network - value is yes if this is a fastagi
+    *   agi_network_script - name of the script to execute
+    *
+    * NOTE: program arguments are still in $_SERVER['argv'].
+    *
+    * @var array
+    * @access public
+    */
+    var $request;
+
+   /**
+    * Config variables
+    *
+    * @var array
+    * @access public
+    */
+    var $config;
+
+   /**
+    * Asterisk Manager
+    *
+    * @var AGI_AsteriskManager
+    * @access public
+    */
+    var $asmanager;
+
+   /**
+    * Input Stream
+    *
+    * @access private
+    */
+    var $in = NULL;
+
+   /**
+    * Output Stream
+    *
+    * @access private
+    */
+    var $out = NULL;
+
+   /**
+    * Audio Stream
+    *
+    * @access public
+    */
+    var $audio = NULL;
+
+   /**
+    * Constructor
+    *
+    * @param string $config is the name of the config file to parse
+    * @param array $optconfig is an array of configuration vars and vals, stuffed into $this-&gt;config['phpagi']
+    */
+    function AGI($config=NULL, $optconfig=array())
+    {
+      // load config
+      if(!is_null($config) &amp;&amp; file_exists($config))
+        $this-&gt;config = parse_ini_file($config, true);
+      elseif(file_exists(DEFAULT_PHPAGI_CONFIG))
+        $this-&gt;config = parse_ini_file(DEFAULT_PHPAGI_CONFIG, true);
+
+      // If optconfig is specified, stuff vals and vars into 'phpagi' config array.
+      foreach($optconfig as $var=&gt;$val)
+        $this-&gt;config['phpagi'][$var] = $val;
+
+      // add default values to config for uninitialized values
+      if(!isset($this-&gt;config['phpagi']['error_handler'])) $this-&gt;config['phpagi']['error_handler'] = true;
+      if(!isset($this-&gt;config['phpagi']['debug'])) $this-&gt;config['phpagi']['debug'] = false;
+      if(!isset($this-&gt;config['phpagi']['admin'])) $this-&gt;config['phpagi']['admin'] = NULL;
+      if(!isset($this-&gt;config['phpagi']['tempdir'])) $this-&gt;config['phpagi']['tempdir'] = AST_TMP_DIR;
+
+      // festival TTS config
+      if(!isset($this-&gt;config['festival']['text2wave'])) $this-&gt;config['festival']['text2wave'] = $this-&gt;which('text2wave');
+
+      // swift TTS config
+      if(!isset($this-&gt;config['cepstral']['swift'])) $this-&gt;config['cepstral']['swift'] = $this-&gt;which('swift');
+
+      ob_implicit_flush(true);
+
+      // open stdin &amp; stdout
+      $this-&gt;in = defined('STDIN') ? STDIN : fopen('php://stdin', 'r');
+      $this-&gt;out = defined('STDOUT') ? STDOUT : fopen('php://stdout', 'w');
+
+      // initialize error handler
+      if($this-&gt;config['phpagi']['error_handler'] == true)
+      {
+        set_error_handler('phpagi_error_handler');
+        global $phpagi_error_handler_email;
+        $phpagi_error_handler_email = $this-&gt;config['phpagi']['admin'];
+        error_reporting(E_ALL);
+      }
+
+      // make sure temp folder exists
+      $this-&gt;make_folder($this-&gt;config['phpagi']['tempdir']);
+
+      // read the request
+      $str = fgets($this-&gt;in);
+      while($str != &quot;\n&quot;)
+      {
+        $this-&gt;request[substr($str, 0, strpos($str, ':'))] = trim(substr($str, strpos($str, ':') + 1));
+        $str = fgets($this-&gt;in);
+      }
+
+      // open audio if eagi detected
+      if($this-&gt;request['agi_enhanced'] == '1.0')
+      {
+        if(file_exists('/proc/' . getmypid() . '/fd/3'))
+          $this-&gt;audio = fopen('/proc/' . getmypid() . '/fd/3', 'r');
+        elseif(file_exists('/dev/fd/3'))
+        {
+          // may need to mount fdescfs
+          $this-&gt;audio = fopen('/dev/fd/3', 'r');
+        }
+        else
+          $this-&gt;conlog('Unable to open audio stream');
+
+        if($this-&gt;audio) stream_set_blocking($this-&gt;audio, 0);
+      }
+
+//       $this-&gt;conlog('AGI Request:');
+//       $this-&gt;conlog(print_r($this-&gt;request, true));
+//       $this-&gt;conlog('PHPAGI internal configuration:');
+//       $this-&gt;conlog(print_r($this-&gt;config, true));
+    }
+
+   // *********************************************************************************************************
+   // **                       COMMANDS                                                                      **
+   // *********************************************************************************************************
+
+   /**
+    * Answer channel if not already in answer state.
+    *
+    * @link http://www.voip-info.org/wiki-answer
+    * @example examples/dtmf.php Get DTMF tones from the user and say the digits
+    * @example examples/input.php Get text input from the user and say it back
+    * @example examples/ping.php Ping an IP address
+    *
+    * @return array, see evaluate for return information.  ['result'] is 0 on success, -1 on failure.
+    */
+    function answer()
+    {
+      return $this-&gt;evaluate('ANSWER');
+    }
+
+   /**
+    * Get the status of the specified channel. If no channel name is specified, return the status of the current channel.
+    *
+    * @link http://www.voip-info.org/wiki-channel+status
+    * @param string $channel
+    * @return array, see evaluate for return information. ['data'] contains description.
+    */
+    function channel_status($channel='')
+    {
+      $ret = $this-&gt;evaluate(&quot;CHANNEL STATUS $channel&quot;);
+      switch($ret['result'])
+      {
+        case -1: $ret['data'] = trim(&quot;There is no channel that matches $channel&quot;); break;
+        case AST_STATE_DOWN: $ret['data'] = 'Channel is down and available'; break;
+        case AST_STATE_RESERVED: $ret['data'] = 'Channel is down, but reserved'; break;
+        case AST_STATE_OFFHOOK: $ret['data'] = 'Channel is off hook'; break;
+        case AST_STATE_DIALING: $ret['data'] = 'Digits (or equivalent) have been dialed'; break;
+        case AST_STATE_RING: $ret['data'] = 'Line is ringing'; break;
+        case AST_STATE_RINGING: $ret['data'] = 'Remote end is ringing'; break;
+        case AST_STATE_UP: $ret['data'] = 'Line is up'; break;
+        case AST_STATE_BUSY: $ret['data'] = 'Line is busy'; break;
+        case AST_STATE_DIALING_OFFHOOK: $ret['data'] = 'Digits (or equivalent) have been dialed while offhook'; break;
+        case AST_STATE_PRERING: $ret['data'] = 'Channel has detected an incoming call and is waiting for ring'; break;
+        default: $ret['data'] = &quot;Unknown ({$ret['result']})&quot;; break;
+      }
+      return $ret;
+    }
+
+   /**
+    * Deletes an entry in the Asterisk database for a given family and key.
+    *
+    * @link http://www.voip-info.org/wiki-database+del
+    * @param string $family
+    * @param string $key
+    * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise.
+    */
+    function database_del($family, $key)
+    {
+      return $this-&gt;evaluate(&quot;DATABASE DEL \&quot;$family\&quot; \&quot;$key\&quot;&quot;);
+    }
+
+   /**
+    * Deletes a family or specific keytree within a family in the Asterisk database.
+    *
+    * @link http://www.voip-info.org/wiki-database+deltree
+    * @param string $family
+    * @param string $keytree
+    * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise.
+    */
+    function database_deltree($family, $keytree='')
+    {
+      $cmd = &quot;DATABASE DELTREE \&quot;$family\&quot;&quot;;
+      if($keytree != '') $cmd .= &quot; \&quot;$keytree\&quot;&quot;;
+      return $this-&gt;evaluate($cmd);
+    }
+
+   /**
+    * Retrieves an entry in the Asterisk database for a given family and key.
+    *
+    * @link http://www.voip-info.org/wiki-database+get
+    * @param string $family
+    * @param string $key
+    * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 failure. ['data'] holds the value
+    */
+    function database_get($family, $key)
+    {
+      return $this-&gt;evaluate(&quot;DATABASE GET \&quot;$family\ \&quot;$key\&quot;&quot;);
+    }
+
+   /**
+    * Adds or updates an entry in the Asterisk database for a given family, key, and value.
+    *
+    * @param string $family
+    * @param string $key
+    * @param string $value
+    * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 otherwise
+    */
+    function database_put($family, $key, $value)
+    {
+      $value = str_replace(&quot;\n&quot;, '\n', addslashes($value));
+      return $this-&gt;evaluate(&quot;DATABASE PUT \&quot;$family\&quot; \&quot;$key\&quot; \&quot;$value\&quot;&quot;);
+    }
+
+   /**
+    * Executes the specified Asterisk application with given options.
+    *
+    * @link http://www.voip-info.org/wiki-exec
+    * @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands
+    * @param string $application
+    * @param mixed $options
+    * @return array, see evaluate for return information. ['result'] is whatever the application returns, or -2 on failure to find application
+    */
+    function exec($application, $options='')
+    {
+      if(is_array($options)) $options = join('|', $options);
+      return $this-&gt;evaluate(&quot;EXEC $application $options&quot;);
+    }
+
+   /**
+    * Plays the given file and receives DTMF data.
+    *
+    * This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
+    * while STREAM FILE returns immediately after the first DTMF digit is detected.
+    *
+    * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
+    *
+    * If the user doesn't press any keys when the message plays, there is $timeout milliseconds
+    * of silence then the command ends.
+    *
+    * The user has the opportunity to press a key at any time during the message or the
+    * post-message silence. If the user presses a key while the message is playing, the
+    * message stops playing. When the first key is pressed a timer starts counting for
+    * $timeout milliseconds. Every time the user presses another key the timer is restarted.
+    * The command ends when the counter goes to zero or the maximum number of digits is entered,
+    * whichever happens first.
+    *
+    * If you don't specify a time out then a default timeout of 2000 is used following a pressed
+    * digit. If no digits are pressed then 6 seconds of silence follow the message.
+    *
+    * If you don't specify $max_digits then the user can enter as many digits as they want.
+    *
+    * Pressing the # key has the same effect as the timer running out: the command ends and
+    * any previously keyed digits are returned. A side effect of this is that there is no
+    * way to read a # key using this command.
+    *
+    * @example examples/ping.php Ping an IP address
+    *
+    * @link http://www.voip-info.org/wiki-get+data
+    * @param string $filename file to play. Do not include file extension.
+    * @param integer $timeout milliseconds
+    * @param integer $max_digits
+    * @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present.
+    *
+    * This differs from other commands with return DTMF as numbers representing ASCII characters.
+    */
+    function get_data($filename, $timeout=NULL, $max_digits=NULL)
+    {
+      return $this-&gt;evaluate(rtrim(&quot;GET DATA $filename $timeout $max_digits&quot;));
+    }
+
+   /**
+    * Fetch the value of a variable.
+    *
+    * Does not work with global variables. Does not work with some variables that are generated by modules.
+    *
+    * @link http://www.voip-info.org/wiki-get+variable
+    * @link http://www.voip-info.org/wiki-Asterisk+variables
+    * @param string $variable name
+    * @return array, see evaluate for return information. ['result'] is 0 if variable hasn't been set, 1 if it has. ['data'] holds the value.
+    */
+    function get_variable($variable)
+    {
+      return $this-&gt;evaluate(&quot;GET VARIABLE $variable&quot;);
+    }
+
+   /**
+    * Hangup the specified channel. If no channel name is given, hang up the current channel.
+    *
+    * With power comes responsibility. Hanging up channels other than your own isn't something
+    * that is done routinely. If you are not sure why you are doing so, then don't.
+    *
+    * @link http://www.voip-info.org/wiki-hangup
+    * @example examples/dtmf.php Get DTMF tones from the user and say the digits
+    * @example examples/input.php Get text input from the user and say it back
+    * @example examples/ping.php Ping an IP address
+    *
+    * @param string $channel
+    * @return array, see evaluate for return information. ['result'] is 1 on success, -1 on failure.
+    */
+    function hangup($channel='')
+    {
+      return $this-&gt;evaluate(&quot;HANGUP $channel&quot;);
+    }
+
+   /**
+    * Does nothing.
+    *
+    * @link http://www.voip-info.org/wiki-noop
+    * @return array, see evaluate for return information.
+    */
+    function noop()
+    {
+      return $this-&gt;evaluate('NOOP');
+    }
+
+   /**
+    * Receive a character of text from a connected channel. Waits up to $timeout milliseconds for
+    * a character to arrive, or infinitely if $timeout is zero.
+    *
+    * @link http://www.voip-info.org/wiki-receive+char
+    * @param integer $timeout milliseconds
+    * @return array, see evaluate for return information. ['result'] is 0 on timeout or not supported, -1 on failure. Otherwise
+    * it is the decimal value of the DTMF tone. Use chr() to convert to ASCII.
+    */
+    function receive_char($timeout=-1)
+    {
+      return $this-&gt;evaluate(&quot;RECEIVE CHAR $timeout&quot;);
+    }
+
+   /**
+    * Record sound to a file until an acceptable DTMF digit is received or a specified amount of
+    * time has passed. Optionally the file BEEP is played before recording begins.
+    *
+    * @link http://www.voip-info.org/wiki-record+file
+    * @param string $file to record, without extension, often created in /var/lib/asterisk/sounds
+    * @param string $format of the file. GSM and WAV are commonly used formats. MP3 is read-only and thus cannot be used.
+    * @param string $escape_digits
+    * @param integer $timeout is the maximum record time in milliseconds, or -1 for no timeout.
+    * @param integer $offset to seek to without exceeding the end of the file.
+    * @param boolean $beep
+    * @param integer $silence number of seconds of silence allowed before the function returns despite the
+    * lack of dtmf digits or reaching timeout.
+    * @return array, see evaluate for return information. ['result'] is -1 on error, 0 on hangup, otherwise a decimal value of the
+    * DTMF tone. Use chr() to convert to ASCII.
+    */
+    function record_file($file, $format, $escape_digits='', $timeout=-1, $offset=NULL, $beep=false, $silence=NULL)
+    {
+      $cmd = trim(&quot;RECORD FILE $file $format \&quot;$escape_digits\&quot; $timeout $offset&quot;);
+      if($beep) $cmd .= ' BEEP';
+      if(!is_null($silence)) $cmd .= &quot; s=$silence&quot;;
+      return $this-&gt;evaluate($cmd);
+    }
+
+   /**
+    * Say the given digit string, returning early if any of the given DTMF escape digits are received on the channel.
+    *
+    * @link http://www.voip-info.org/wiki-say+digits
+    * @param integer $digits
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+    function say_digits($digits, $escape_digits='')
+    {
+      return $this-&gt;evaluate(&quot;SAY DIGITS $digits \&quot;$escape_digits\&quot;&quot;);
+    }
+
+   /**
+    * Say the given number, returning early if any of the given DTMF escape digits are received on the channel.
+    *
+    * @link http://www.voip-info.org/wiki-say+number
+    * @param integer $number
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+    function say_number($number, $escape_digits='')
+    {
+      return $this-&gt;evaluate(&quot;SAY NUMBER $number \&quot;$escape_digits\&quot;&quot;);
+    }
+
+   /**
+    * Say the given character string, returning early if any of the given DTMF escape digits are received on the channel.
+    *
+    * @link http://www.voip-info.org/wiki-say+phonetic
+    * @param string $text
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+    function say_phonetic($text, $escape_digits='')
+    {
+      return $this-&gt;evaluate(&quot;SAY PHONETIC $text \&quot;$escape_digits\&quot;&quot;);
+    }
+
+   /**
+    * Say a given time, returning early if any of the given DTMF escape digits are received on the channel.
+    *
+    * @link http://www.voip-info.org/wiki-say+time
+    * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+    function say_time($time=NULL, $escape_digits='')
+    {
+      if(is_null($time)) $time = time();
+      return $this-&gt;evaluate(&quot;SAY TIME $time \&quot;$escape_digits\&quot;&quot;);
+    }
+
+   /**
+    * Send the specified image on a channel.
+    *
+    * Most channels do not support the transmission of images.
+    *
+    * @link http://www.voip-info.org/wiki-send+image
+    * @param string $image without extension, often in /var/lib/asterisk/images
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if the image is sent or
+    * channel does not support image transmission.
+    */
+    function send_image($image)
+    {
+      return $this-&gt;evaluate(&quot;SEND IMAGE $image&quot;);
+    }
+
+   /**
+    * Send the given text to the connected channel.
+    *
+    * Most channels do not support transmission of text.
+    *
+    * @link http://www.voip-info.org/wiki-send+text
+    * @param $text
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if the text is sent or
+    * channel does not support text transmission.
+    */
+    function send_text($text)
+    {
+      return $this-&gt;evaluate(&quot;SEND TEXT \&quot;$text\&quot;&quot;);
+    }
+
+   /**
+    * Cause the channel to automatically hangup at $time seconds in the future.
+    * If $time is 0 then the autohangup feature is disabled on this channel.
+    *
+    * If the channel is hungup prior to $time seconds, this setting has no effect.
+    *
+    * @link http://www.voip-info.org/wiki-set+autohangup
+    * @param integer $time until automatic hangup
+    * @return array, see evaluate for return information.
+    */
+    function set_autohangup($time=0)
+    {
+      return $this-&gt;evaluate(&quot;SET AUTOHANGUP $time&quot;);
+    }
+
+   /**
+    * Changes the caller ID of the current channel.
+    *
+    * @link http://www.voip-info.org/wiki-set+callerid
+    * @param string $cid example: &quot;John Smith&quot;&lt;1234567&gt;
+    * This command will let you take liberties with the &lt;caller ID specification&gt; but the format shown in the example above works
+    * well: the name enclosed in double quotes followed immediately by the number inside angle brackets. If there is no name then
+    * you can omit it. If the name contains no spaces you can omit the double quotes around it. The number must follow the name
+    * immediately; don't put a space between them. The angle brackets around the number are necessary; if you omit them the
+    * number will be considered to be part of the name.
+    * @return array, see evaluate for return information.
+    */
+    function set_callerid($cid)
+    {
+      return $this-&gt;evaluate(&quot;SET CALLERID $cid&quot;);
+    }
+
+   /**
+    * Sets the context for continuation upon exiting the application.
+    *
+    * Setting the context does NOT automatically reset the extension and the priority; if you want to start at the top of the new
+    * context you should set extension and priority yourself.
+    *
+    * If you specify a non-existent context you receive no error indication (['result'] is still 0) but you do get a
+    * warning message on the Asterisk console.
+    *
+    * @link http://www.voip-info.org/wiki-set+context
+    * @param string $context
+    * @return array, see evaluate for return information.
+    */
+    function set_context($context)
+    {
+      return $this-&gt;evaluate(&quot;SET CONTEXT $context&quot;);
+    }
+
+   /**
+    * Set the extension to be used for continuation upon exiting the application.
+    *
+    * Setting the extension does NOT automatically reset the priority. If you want to start with the first priority of the
+    * extension you should set the priority yourself.
+    *
+    * If you specify a non-existent extension you receive no error indication (['result'] is still 0) but you do
+    * get a warning message on the Asterisk console.
+    *
+    * @link http://www.voip-info.org/wiki-set+extension
+    * @param string $extension
+    * @return array, see evaluate for return information.
+    */
+    function set_extension($extension)
+    {
+      return $this-&gt;evaluate(&quot;SET EXTENSION $extension&quot;);
+    }
+
+   /**
+    * Enable/Disable Music on hold generator.
+    *
+    * @link http://www.voip-info.org/wiki-set+music
+    * @param boolean $enabled
+    * @param string $class
+    * @return array, see evaluate for return information.
+    */
+    function set_music($enabled=true, $class='')
+    {
+      $enabled = ($enabled) ? 'ON' : 'OFF';
+      return $this-&gt;evaluate(&quot;SET MUSIC $enabled $class&quot;);
+    }
+
+   /**
+    * Set the priority to be used for continuation upon exiting the application.
+    *
+    * If you specify a non-existent priority you receive no error indication (['result'] is still 0)
+    * and no warning is issued on the Asterisk console.
+    *
+    * @link http://www.voip-info.org/wiki-set+priority
+    * @param integer $priority
+    * @return array, see evaluate for return information.
+    */
+    function set_priority($priority)
+    {
+      return $this-&gt;evaluate(&quot;SET PRIORITY $priority&quot;);
+    }
+
+   /**
+    * Sets a variable to the specified value. The variables so created can later be used by later using ${&lt;variablename&gt;}
+    * in the dialplan.
+    *
+    * These variables live in the channel Asterisk creates when you pickup a phone and as such they are both local and temporary.
+    * Variables created in one channel can not be accessed by another channel. When you hang up the phone, the channel is deleted
+    * and any variables in that channel are deleted as well.
+    *
+    * @link http://www.voip-info.org/wiki-set+variable
+    * @param string $variable is case sensitive
+    * @param string $value
+    * @return array, see evaluate for return information.
+    */
+    function set_variable($variable, $value)
+    {
+      $value = str_replace(&quot;\n&quot;, '\n', addslashes($value));
+      return $this-&gt;evaluate(&quot;SET VARIABLE $variable \&quot;$value\&quot;&quot;);
+    }
+
+   /**
+    * Play the given audio file, allowing playback to be interrupted by a DTMF digit. This command is similar to the GET DATA
+    * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of
+    * digits before returning.
+    *
+    * @example examples/ping.php Ping an IP address
+    *
+    * @link http://www.voip-info.org/wiki-stream+file
+    * @param string $filename without extension, often in /var/lib/asterisk/sounds
+    * @param string $escape_digits
+    * @param integer $offset
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+    function stream_file($filename, $escape_digits='', $offset=0)
+    {
+      return $this-&gt;evaluate(&quot;STREAM FILE $filename \&quot;$escape_digits\&quot; $offset&quot;);
+    }
+
+   /**
+    * Enable or disable TDD transmission/reception on the current channel.
+    *
+    * @link http://www.voip-info.org/wiki-tdd+mode
+    * @param string $setting can be on, off or mate
+    * @return array, see evaluate for return information. ['result'] is 1 on sucess, 0 if the channel is not TDD capable.
+    */
+    function tdd_mode($setting)
+    {
+      return $this-&gt;evaluate(&quot;TDD MODE $setting&quot;);
+    }
+
+   /**
+    * Sends $message to the Asterisk console via the 'verbose' message system.
+    *
+    * If the Asterisk verbosity level is $level or greater, send $message to the console.
+    *
+    * The Asterisk verbosity system works as follows. The Asterisk user gets to set the desired verbosity at startup time or later
+    * using the console 'set verbose' command. Messages are displayed on the console if their verbose level is less than or equal
+    * to desired verbosity set by the user. More important messages should have a low verbose level; less important messages
+    * should have a high verbose level.
+    *
+    * @link http://www.voip-info.org/wiki-verbose
+    * @param string $message
+    * @param integer $level from 1 to 4
+    * @return array, see evaluate for return information.
+    */
+    function verbose($message, $level=1)
+    {
+      foreach(explode(&quot;\n&quot;, str_replace(&quot;\r\n&quot;, &quot;\n&quot;, print_r($message, true))) as $msg)
+      {
+        @syslog(LOG_WARNING, $msg);
+        $ret = $this-&gt;evaluate(&quot;VERBOSE \&quot;$msg\&quot; $level&quot;);
+      }
+      return $ret;
+    }
+
+   /**
+    * Waits up to $timeout milliseconds for channel to receive a DTMF digit.
+    *
+    * @link http://www.voip-info.org/wiki-wait+for+digit
+    * @param integer $timeout in millisecons. Use -1 for the timeout value if you want the call to wait indefinitely.
+    * @return array, see evaluate for return information. ['result'] is 0 if wait completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+    function wait_for_digit($timeout=-1)
+    {
+      return $this-&gt;evaluate(&quot;WAIT FOR DIGIT $timeout&quot;);
+    }
+
+
+   // *********************************************************************************************************
+   // **                       APPLICATIONS                                                                  **
+   // *********************************************************************************************************
+
+   /**
+    * Set absolute maximum time of call.
+    *
+    * Note that the timeout is set from the current time forward, not counting the number of seconds the call has already been up.
+    * Each time you call AbsoluteTimeout(), all previous absolute timeouts are cancelled.
+    * Will return the call to the T extension so that you can playback an explanatory note to the calling party (the called party
+    * will not hear that)
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+-+documentation+of+application+commands
+    * @link http://www.dynx.net/ASTERISK/AGI/ccard/agi-ccard.agi
+    * @param $seconds allowed, 0 disables timeout
+    * @return array, see evaluate for return information.
+    */
+    function exec_absolutetimeout($seconds=0)
+    {
+      return $this-&gt;exec('AbsoluteTimeout', $seconds);
+    }
+
+   /**
+    * Executes an AGI compliant application.
+    *
+    * @param string $command
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or if application requested hangup, or 0 on non-hangup exit.
+    * @param string $args
+    */
+    function exec_agi($command, $args)
+    {
+      return $this-&gt;exec(&quot;AGI $command&quot;, $args);
+    }
+
+   /**
+    * Set Language.
+    *
+    * @param string $language code
+    * @return array, see evaluate for return information.
+    */
+    function exec_setlanguage($language='en')
+    {
+      return $this-&gt;exec('SetLanguage', $language);
+    }
+
+   /**
+    * Do ENUM Lookup.
+    *
+    * Note: to retrieve the result, use
+    *   get_variable('ENUM');
+    *
+    * @param $exten
+    * @return array, see evaluate for return information.
+    */
+    function exec_enumlookup($exten)
+    {
+      return $this-&gt;exec('EnumLookup', $exten);
+    }
+
+   /**
+    * Dial.
+    *
+    * Dial takes input from ${VXML_URL} to send XML Url to Cisco 7960
+    * Dial takes input from ${ALERT_INFO} to set ring cadence for Cisco phones
+    * Dial returns ${CAUSECODE}: If the dial failed, this is the errormessage.
+    * Dial returns ${DIALSTATUS}: Text code returning status of last dial attempt.
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+cmd+Dial
+    * @param string $type
+    * @param string $identifier
+    * @param integer $timeout
+    * @param string $options
+    * @param string $url
+    * @return array, see evaluate for return information.
+    */
+    function exec_dial($type, $identifier, $timeout=NULL, $options=NULL, $url=NULL)
+    {
+      return $this-&gt;exec('Dial', trim(&quot;$type/$identifier|$timeout|$options|$url&quot;, '|'));
+    }
+
+   /**
+    * Goto.
+    *
+    * This function takes three arguments: context,extension, and priority, but the leading arguments
+    * are optional, not the trailing arguments.  Thuse goto($z) sets the priority to $z.
+    *
+    * @param string $a
+    * @param string $b;
+    * @param string $c;
+    * @return array, see evaluate for return information.
+    */
+    function exec_goto($a, $b=NULL, $c=NULL)
+    {
+      return $this-&gt;exec('Goto', trim(&quot;$a|$b|$c&quot;, '|'));
+    }
+
+
+   // *********************************************************************************************************
+   // **                       FAST PASSING                                                                  **
+   // *********************************************************************************************************
+
+   /**
+    * Say the given digit string, returning early if any of the given DTMF escape digits are received on the channel.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.voip-info.org/wiki-say+digits
+    * @param string $buffer
+    * @param integer $digits
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+   function fastpass_say_digits(&amp;$buffer, $digits, $escape_digits='')
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;say_digits($digits, $escape_digits);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}));
+   }
+
+   /**
+    * Say the given number, returning early if any of the given DTMF escape digits are received on the channel.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.voip-info.org/wiki-say+number
+    * @param string $buffer
+    * @param integer $number
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+   function fastpass_say_number(&amp;$buffer, $number, $escape_digits='')
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;say_number($number, $escape_digits);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}));
+   }
+
+   /**
+    * Say the given character string, returning early if any of the given DTMF escape digits are received on the channel.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.voip-info.org/wiki-say+phonetic
+    * @param string $buffer
+    * @param string $text
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+   function fastpass_say_phonetic(&amp;$buffer, $text, $escape_digits='')
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;say_phonetic($text, $escape_digits);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}));
+   }
+
+   /**
+    * Say a given time, returning early if any of the given DTMF escape digits are received on the channel.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.voip-info.org/wiki-say+time
+    * @param string $buffer
+    * @param integer $time number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
+    * @param string $escape_digits
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+   function fastpass_say_time(&amp;$buffer, $time=NULL, $escape_digits='')
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;say_time($time, $escape_digits);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}));
+   }
+
+   /**
+    * Play the given audio file, allowing playback to be interrupted by a DTMF digit. This command is similar to the GET DATA
+    * command but this command returns after the first DTMF digit has been pressed while GET DATA can accumulated any number of
+    * digits before returning.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.voip-info.org/wiki-stream+file
+    * @param string $buffer
+    * @param string $filename without extension, often in /var/lib/asterisk/sounds
+    * @param string $escape_digits
+    * @param integer $offset
+    * @return array, see evaluate for return information. ['result'] is -1 on hangup or error, 0 if playback completes with no
+    * digit received, otherwise a decimal value of the DTMF tone.  Use chr() to convert to ASCII.
+    */
+   function fastpass_stream_file(&amp;$buffer, $filename, $escape_digits='', $offset=0)
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;stream_file($filename, $escape_digits, $offset);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}), 'endpos'=&gt;0);
+   }
+
+   /**
+    * Use festival to read text.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.cstr.ed.ac.uk/projects/festival/
+    * @param string $buffer
+    * @param string $text
+    * @param string $escape_digits
+    * @param integer $frequency
+    * @return array, see evaluate for return information.
+    */
+   function fastpass_text2wav(&amp;$buffer, $text, $escape_digits='', $frequency=8000)
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;text2wav($text, $escape_digits, $frequency);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}), 'endpos'=&gt;0);
+   }
+
+   /**
+    * Use Cepstral Swift to read text.
+    * Return early if $buffer is adequate for request.
+    *
+    * @link http://www.cepstral.com/
+    * @param string $buffer
+    * @param string $text
+    * @param string $escape_digits
+    * @param integer $frequency
+    * @return array, see evaluate for return information.
+    */
+   function fastpass_swift(&amp;$buffer, $text, $escape_digits='', $frequency=8000, $voice=NULL)
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;swift($text, $escape_digits, $frequency, $voice);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}), 'endpos'=&gt;0);
+   }
+
+   /**
+    * Say Puncutation in a string.
+    * Return early if $buffer is adequate for request.
+    *
+    * @param string $buffer
+    * @param string $text
+    * @param string $escape_digits
+    * @param integer $frequency
+    * @return array, see evaluate for return information.
+    */
+   function fastpass_say_punctuation(&amp;$buffer, $text, $escape_digits='', $frequency=8000)
+   {
+     $proceed = false;
+     if($escape_digits != '' &amp;&amp; $buffer != '')
+     {
+       if(!strpos(chr(255) . $escape_digits, $buffer{strlen($buffer)-1}))
+         $proceed = true;
+     }
+     if($buffer == '' || $proceed)
+     {
+       $res = $this-&gt;say_punctuation($text, $escape_digits, $frequency);
+       if($res['code'] == AGIRES_OK &amp;&amp; $res['result'] &gt; 0)
+         $buffer .= chr($res['result']);
+       return $res;
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;ord($buffer{strlen($buffer)-1}));
+   }
+
+   /**
+    * Plays the given file and receives DTMF data.
+    * Return early if $buffer is adequate for request.
+    *
+    * This is similar to STREAM FILE, but this command can accept and return many DTMF digits,
+    * while STREAM FILE returns immediately after the first DTMF digit is detected.
+    *
+    * Asterisk looks for the file to play in /var/lib/asterisk/sounds by default.
+    *
+    * If the user doesn't press any keys when the message plays, there is $timeout milliseconds
+    * of silence then the command ends.
+    *
+    * The user has the opportunity to press a key at any time during the message or the
+    * post-message silence. If the user presses a key while the message is playing, the
+    * message stops playing. When the first key is pressed a timer starts counting for
+    * $timeout milliseconds. Every time the user presses another key the timer is restarted.
+    * The command ends when the counter goes to zero or the maximum number of digits is entered,
+    * whichever happens first.
+    *
+    * If you don't specify a time out then a default timeout of 2000 is used following a pressed
+    * digit. If no digits are pressed then 6 seconds of silence follow the message.
+    *
+    * If you don't specify $max_digits then the user can enter as many digits as they want.
+    *
+    * Pressing the # key has the same effect as the timer running out: the command ends and
+    * any previously keyed digits are returned. A side effect of this is that there is no
+    * way to read a # key using this command.
+    *
+    * @link http://www.voip-info.org/wiki-get+data
+    * @param string $buffer
+    * @param string $filename file to play. Do not include file extension.
+    * @param integer $timeout milliseconds
+    * @param integer $max_digits
+    * @return array, see evaluate for return information. ['result'] holds the digits and ['data'] holds the timeout if present.
+    *
+    * This differs from other commands with return DTMF as numbers representing ASCII characters.
+    */
+   function fastpass_get_data(&amp;$buffer, $filename, $timeout=NULL, $max_digits=NULL)
+   {
+     if(is_null($max_digits) || strlen($buffer) &lt; $max_digits)
+     {
+       if($buffer == '')
+       {
+         $res = $this-&gt;get_data($filename, $timeout, $max_digits);
+         if($res['code'] == AGIRES_OK)
+           $buffer .= $res['result'];
+         return $res;
+       }
+       else
+       {
+         while(is_null($max_digits) || strlen($buffer) &lt; $max_digits)
+         {
+           $res = $this-&gt;wait_for_digit();
+           if($res['code'] != AGIRES_OK) return $res;
+           if($res['result'] == ord('#')) break;
+           $buffer .= chr($res['result']);
+         }
+       }
+     }
+     return array('code'=&gt;AGIRES_OK, 'result'=&gt;$buffer);
+   }
+
+   // *********************************************************************************************************
+   // **                       DERIVED                                                                       **
+   // *********************************************************************************************************
+
+   /**
+    * Menu.
+    *
+    * This function presents the user with a menu and reads the response
+    *
+    * @param array $choices has the following structure:
+    *   array('1'=&gt;'*Press 1 for this', // festival reads if prompt starts with *
+    *         '2'=&gt;'some-gsm-without-extension',
+    *         '*'=&gt;'*Press star for help');
+    * @return mixed key pressed on sucess, -1 on failure
+    */
+    function menu($choices, $timeout=2000)
+    {
+      $keys = join('', array_keys($choices));
+      $choice = NULL;
+      while(is_null($choice))
+      {
+        foreach($choices as $prompt)
+        {
+          if($prompt{0} == '*')
+            $ret = $this-&gt;text2wav(substr($prompt, 1), $keys);
+          else
+            $ret = $this-&gt;stream_file($prompt, $keys);
+
+          if($ret['code'] != AGIRES_OK || $ret['result'] == -1)
+          {
+            $choice = -1;
+            break;
+          }
+
+          if($ret['result'] != 0)
+          {
+            $choice = chr($ret['result']);
+            break;
+          }
+        }
+
+        if(is_null($choice))
+        {
+          $ret = $this-&gt;get_data('beep', $timeout, 1);
+          if($ret['code'] != AGIRES_OK || $ret['result'] == -1)
+            $choice = -1;
+          elseif($ret['result'] != '' &amp;&amp; strpos(' '.$keys, $ret['result']))
+            $choice = $ret['result'];
+        }
+      }
+      return $choice;
+    }
+
+   /**
+    * Goto - Set context, extension and priority.
+    *
+    * @param string $context
+    * @param string $extension
+    * @param string $priority
+    */
+    function goto($context, $extension='s', $priority=1)
+    {
+      $this-&gt;set_context($context);
+      $this-&gt;set_extension($extension);
+      $this-&gt;set_priority($priority);
+    }
+
+   /**
+    * Parse caller id.
+    *
+    * @example examples/dtmf.php Get DTMF tones from the user and say the digits
+    * @example examples/input.php Get text input from the user and say it back
+    *
+    * &quot;name&quot; &lt;proto:user@server:port&gt;
+    *
+    * @param string $callerid
+    * @return array('Name'=&gt;$name, 'Number'=&gt;$number)
+    */
+    function parse_callerid($callerid=NULL)
+    {
+      if(is_null($callerid))
+        $callerid = $this-&gt;request['agi_callerid'];
+
+      $ret = array('name'=&gt;'', 'protocol'=&gt;'', 'username'=&gt;'', 'host'=&gt;'', 'port'=&gt;'');
+      $callerid = trim($callerid);
+
+      if($callerid{0} == '&quot;' || $callerid{0} == &quot;'&quot;)
+      {
+        $d = $callerid{0};
+        $callerid = explode($d, substr($callerid, 1));
+        $ret['name'] = array_shift($callerid);
+        $callerid = join($d, $callerid);
+      }
+
+      $callerid = explode('@', trim($callerid, '&lt;&gt; '));
+      $username  = explode(':', array_shift($callerid));
+      if(count($username) == 1)
+        $ret['username'] = $username[0];
+      else
+      {
+        $ret['protocol'] = array_shift($username);
+        $ret['username'] = join(':', $username);
+      }
+
+      $callerid = join('@', $callerid);
+      $host = explode(':', $callerid);
+      if(count($host) == 1)
+        $ret['host'] =  $host[0];
+      else
+      {
+        $ret['host'] = array_shift($host);
+        $ret['port'] = join(':', $host);
+      }
+
+      return $ret;
+    }
+
+   /**
+    * Use festival to read text.
+    *
+    * @example examples/dtmf.php Get DTMF tones from the user and say the digits
+    * @example examples/input.php Get text input from the user and say it back
+    * @example examples/ping.php Ping an IP address
+    *
+    * @link http://www.cstr.ed.ac.uk/projects/festival/
+    * @param string $text
+    * @param string $escape_digits
+    * @param integer $frequency
+    * @return array, see evaluate for return information.
+    */
+    function text2wav($text, $escape_digits='', $frequency=8000)
+    {
+      $text = trim($text);
+      if($text == '') return true;
+
+      $hash = md5($text);
+      $fname = $this-&gt;config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR;
+      $fname .= 'text2wav_' . $hash;
+
+      // create wave file
+      if(!file_exists(&quot;$fname.wav&quot;))
+      {
+        // write text file
+        if(!file_exists(&quot;$fname.txt&quot;))
+        {
+          $fp = fopen(&quot;$fname.txt&quot;, 'w');
+          fputs($fp, $text);
+          fclose($fp);
+        }
+
+        shell_exec(&quot;{$this-&gt;config['festival']['text2wave']} -F $frequency -o $fname.wav $fname.txt&quot;);
+      }
+      else
+      {
+        touch(&quot;$fname.txt&quot;);
+        touch(&quot;$fname.wav&quot;);
+      }
+
+      // stream it
+      $ret = $this-&gt;stream_file($fname, $escape_digits);
+
+      // clean up old files
+      $delete = time() - 2592000; // 1 month
+      foreach(glob($this-&gt;config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR . 'text2wav_*') as $file)
+        if(filemtime($file) &lt; $delete)
+          unlink($file);
+
+      return $ret;
+    }
+
+   /**
+    * Use Cepstral Swift to read text.
+    *
+    * @link http://www.cepstral.com/
+    * @param string $text
+    * @param string $escape_digits
+    * @param integer $frequency
+    * @return array, see evaluate for return information.
+    */
+    function swift($text, $escape_digits='', $frequency=8000, $voice=NULL)
+    {
+      if(!is_null($voice))
+        $voice = &quot;-n $voice&quot;;
+      elseif(isset($this-&gt;config['cepstral']['voice']))
+        $voice = &quot;-n {$this-&gt;config['cepstral']['voice']}&quot;;
+
+      $text = trim($text);
+      if($text == '') return true;
+
+      $hash = md5($text);
+      $fname = $this-&gt;config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR;
+      $fname .= 'swift_' . $hash;
+
+      // create wave file
+      if(!file_exists(&quot;$fname.wav&quot;))
+      {
+        // write text file
+        if(!file_exists(&quot;$fname.txt&quot;))
+        {
+          $fp = fopen(&quot;$fname.txt&quot;, 'w');
+          fputs($fp, $text);
+          fclose($fp);
+        }
+
+        shell_exec(&quot;{$this-&gt;config['cepstral']['swift']} -p audio/channels=1,audio/sampling-rate=$frequency $voice -o $fname.wav -f $fname.txt&quot;);
+      }
+
+      // stream it
+      $ret = $this-&gt;stream_file($fname, $escape_digits);
+
+      // clean up old files
+      $delete = time() - 2592000; // 1 month
+      foreach(glob($this-&gt;config['phpagi']['tempdir'] . DIRECTORY_SEPARATOR . 'swift_*') as $file)
+        if(filemtime($file) &lt; $delete)
+          unlink($file);
+
+      return $ret;
+    }
+
+   /**
+    * Text Input.
+    *
+    * Based on ideas found at http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText
+    *
+    * Example:
+    *              UC   H     LC   i      ,     SP   h     o      w    SP   a    r      e     SP   y      o      u     ?
+    *   $string = '*8'.'44*'.'*5'.'444*'.'00*'.'0*'.'44*'.'666*'.'9*'.'0*'.'2*'.'777*'.'33*'.'0*'.'999*'.'666*'.'88*'.'0000*';
+    *
+    * @link http://www.voip-info.org/wiki-Asterisk+cmd+DTMFToText
+    * @example examples/input.php Get text input from the user and say it back
+    *
+    * @return string
+    */
+    function text_input($mode='NUMERIC')
+    {
+      $alpha = array( 'k0'=&gt;' ', 'k00'=&gt;',', 'k000'=&gt;'.', 'k0000'=&gt;'?', 'k00000'=&gt;'0',
+                      'k1'=&gt;'!', 'k11'=&gt;':', 'k111'=&gt;';', 'k1111'=&gt;'#', 'k11111'=&gt;'1',
+                      'k2'=&gt;'A', 'k22'=&gt;'B', 'k222'=&gt;'C', 'k2222'=&gt;'2',
+                      'k3'=&gt;'D', 'k33'=&gt;'E', 'k333'=&gt;'F', 'k3333'=&gt;'3',
+                      'k4'=&gt;'G', 'k44'=&gt;'H', 'k444'=&gt;'I', 'k4444'=&gt;'4',
+                      'k5'=&gt;'J', 'k55'=&gt;'K', 'k555'=&gt;'L', 'k5555'=&gt;'5',
+                      'k6'=&gt;'M', 'k66'=&gt;'N', 'k666'=&gt;'O', 'k6666'=&gt;'6',
+                      'k7'=&gt;'P', 'k77'=&gt;'Q', 'k777'=&gt;'R', 'k7777'=&gt;'S', 'k77777'=&gt;'7',
+                      'k8'=&gt;'T', 'k88'=&gt;'U', 'k888'=&gt;'V', 'k8888'=&gt;'8',
+                      'k9'=&gt;'W', 'k99'=&gt;'X', 'k999'=&gt;'Y', 'k9999'=&gt;'Z', 'k99999'=&gt;'9');
+      $symbol = array('k0'=&gt;'=',
+                      'k1'=&gt;'&lt;', 'k11'=&gt;'(', 'k111'=&gt;'[', 'k1111'=&gt;'{', 'k11111'=&gt;'1',
+                      'k2'=&gt;'@', 'k22'=&gt;'$', 'k222'=&gt;'&amp;', 'k2222'=&gt;'%', 'k22222'=&gt;'2',
+                      'k3'=&gt;'&gt;', 'k33'=&gt;')', 'k333'=&gt;']', 'k3333'=&gt;'}', 'k33333'=&gt;'3',
+                      'k4'=&gt;'+', 'k44'=&gt;'-', 'k444'=&gt;'*', 'k4444'=&gt;'/', 'k44444'=&gt;'4',
+                      'k5'=&gt;&quot;'&quot;, 'k55'=&gt;'`', 'k555'=&gt;'5',
+                      'k6'=&gt;'&quot;', 'k66'=&gt;'6',
+                      'k7'=&gt;'^', 'k77'=&gt;'7',
+                      'k8'=&gt;&quot;\\&quot;,'k88'=&gt;'|', 'k888'=&gt;'8',
+                      'k9'=&gt;'_', 'k99'=&gt;'~', 'k999'=&gt;'9');
+      $text = '';
+      do
+      {
+        $command = false;
+        $result = $this-&gt;get_data('beep');
+        foreach(explode('*', $result['result']) as $code)
+        {
+          if($command)
+          {
+            switch($code{0})
+            {
+              case '2': $text = substr($text, 0, strlen($text) - 1); break; // backspace
+              case '5': $mode = 'LOWERCASE'; break;
+              case '6': $mode = 'NUMERIC'; break;
+              case '7': $mode = 'SYMBOL'; break;
+              case '8': $mode = 'UPPERCASE'; break;
+              case '9': $text = explode(' ', $text); unset($text[count($text)-1]); $text = join(' ', $text); break; // backspace a word
+            }
+            $code = substr($code, 1);
+            $command = false;
+          }
+          if($code == '')
+            $command = true;
+          elseif($mode == 'NUMERIC')
+            $text .= $code;
+          elseif($mode == 'UPPERCASE' &amp;&amp; isset($alpha['k'.$code]))
+            $text .= $alpha['k'.$code];
+          elseif($mode == 'LOWERCASE' &amp;&amp; isset($alpha['k'.$code]))
+            $text .= strtolower($alpha['k'.$code]);
+          elseif($mode == 'SYMBOL' &amp;&amp; isset($symbol['k'.$code]))
+            $text .= $symbol['k'.$code];
+        }
+        $this-&gt;say_punctuation($text);
+      } while(substr($result['result'], -2) == '**');
+      return $text;
+    }
+
+   /**
+    * Say Puncutation in a string.
+    *
+    * @param string $text
+    * @param string $escape_digits
+    * @param integer $frequency
+    * @return array, see evaluate for return information.
+    */
+    function say_punctuation($text, $escape_digits='', $frequency=8000)
+    {
+      for($i = 0; $i &lt; strlen($text); $i++)
+      {
+        switch($text{$i})
+        {
+          case ' ': $ret .= 'SPACE ';
+          case ',': $ret .= 'COMMA '; break;
+          case '.': $ret .= 'PERIOD '; break;
+          case '?': $ret .= 'QUESTION MARK '; break;
+          case '!': $ret .= 'EXPLANATION POINT '; break;
+          case ':': $ret .= 'COLON '; break;
+          case ';': $ret .= 'SEMICOLON '; break;
+          case '#': $ret .= 'POUND '; break;
+          case '=': $ret .= 'EQUALS '; break;
+          case '&lt;': $ret .= 'LESS THAN '; break;
+          case '(': $ret .= 'LEFT PARENTHESIS '; break;
+          case '[': $ret .= 'LEFT BRACKET '; break;
+          case '{': $ret .= 'LEFT BRACE '; break;
+          case '@': $ret .= 'AT '; break;
+          case '$': $ret .= 'DOLLAR SIGN '; break;
+          case '&amp;': $ret .= 'AMPERSAND '; break;
+          case '%': $ret .= 'PERCENT '; break;
+          case '&gt;': $ret .= 'GREATER THAN '; break;
+          case ')': $ret .= 'RIGHT PARENTHESIS '; break;
+          case ']': $ret .= 'RIGHT BRACKET '; break;
+          case '}': $ret .= 'RIGHT BRACE '; break;
+          case '+': $ret .= 'PLUS '; break;
+          case '-': $ret .= 'MINUS '; break;
+          case '*': $ret .= 'ASTERISK '; break;
+          case '/': $ret .= 'SLASH '; break;
+          case &quot;'&quot;: $ret .= 'SINGLE QUOTE '; break;
+          case '`': $ret .= 'BACK TICK '; break;
+          case '&quot;': $ret .= 'QUOTE '; break;
+          case '^': $ret .= 'CAROT '; break;
+          case &quot;\\&quot;: $ret .= 'BACK SLASH '; break;
+          case '|': $ret .= 'BAR '; break;
+          case '_': $ret .= 'UNDERSCORE '; break;
+          case '~': $ret .= 'TILDE '; break;
+          default: $ret .= $text{$i} . ' '; break;
+        }
+      }
+      return $this-&gt;text2wav($ret, $escape_digits, $frequency);
+    }
+
+   /**
+    * Create a new AGI_AsteriskManager.
+    */
+    function &amp;new_AsteriskManager()
+    {
+      $this-&gt;asm = new AGI_AsteriskManager(NULL, $this-&gt;config);
+      $this-&gt;asm-&gt;pagi =&amp; $this;
+      $this-&gt;config =&amp; $this-&gt;asm-&gt;config;
+      return $this-&gt;asm;
+    }
+
+
+   // *********************************************************************************************************
+   // **                       PRIVATE                                                                       **
+   // *********************************************************************************************************
+
+
+   /**
+    * Evaluate an AGI command.
+    *
+    * @access private
+    * @param string $command
+    * @return array ('code'=&gt;$code, 'result'=&gt;$result, 'data'=&gt;$data)
+    */
+    function evaluate($command)
+    {
+      $broken = array('code'=&gt;500, 'result'=&gt;-1, 'data'=&gt;'');
+
+      // write command
+      if(!@fwrite($this-&gt;out, trim($command) . &quot;\n&quot;)) return $broken;
+      fflush($this-&gt;out);
+
+      // Read result.  Occasionally, a command return a string followed by an extra new line.
+      // When this happens, our script will ignore the new line, but it will still be in the
+      // buffer.  So, if we get a blank line, it is probably the result of a previous
+      // command.  We read until we get a valid result or asterisk hangs up.  One offending
+      // command is SEND TEXT.
+      $count = 0;
+      do
+      {
+        $str = trim(fgets($this-&gt;in, 4096));
+      } while($str == '' &amp;&amp; $count++ &lt; 5);
+    
+/*
+ PATCH
+*/  
+      logthis(&quot;AGI EVALUATE '$command' returned: '$str' in $count reads&quot;);
+
+      if($count &gt;= 5)
+      {
+//        $this-&gt;conlog(&quot;evaluate error on read for $command&quot;);
+        return $broken;
+      }
+
+      // parse result
+      $ret['code'] = substr($str, 0, 3);
+      $str = trim(substr($str, 3));
+
+      if($str{0} == '-') // we have a multiline response!
+      {
+        $count = 0;
+        $str = substr($str, 1) . &quot;\n&quot;;
+        $line = fgets($this-&gt;in, 4096);
+        while(substr($line, 0, 3) != $ret['code'] &amp;&amp; $count &lt; 5)
+        {
+          $str .= $line;
+          $line = fgets($this-&gt;in, 4096);
+          $count = (trim($line) == '') ? $count + 1 : 0;
+        }
+        if($count &gt;= 5)
+        {
+//          $this-&gt;conlog(&quot;evaluate error on multiline read for $command&quot;);
+          return $broken;
+        }
+      }
+
+      $ret['result'] = NULL;
+      $ret['data'] = '';
+      if($ret['code'] != AGIRES_OK) // some sort of error
+      {
+        $ret['data'] = $str;
+        $this-&gt;conlog(print_r($ret, true));
+      }
+      else // normal AGIRES_OK response
+      {
+        $parse = explode(' ', trim($str));
+        $in_token = false;
+        foreach($parse as $token)
+        {
+          if($in_token) // we previously hit a token starting with ')' but not ending in ')'
+          {
+            $ret['data'] .= ' ' . trim($token, '() ');
+            if($token{strlen($token)-1} == ')') $in_token = false;
+          }
+          elseif($token{0} == '(')
+          {
+            if($token{strlen($token)-1} != ')') $in_token = true;
+            $ret['data'] .= ' ' . trim($token, '() ');
+          }
+          elseif(strpos($token, '='))
+          {
+            $token = explode('=', $token);
+            $ret[$token[0]] = $token[1];
+          }
+          elseif($token != '')
+            $ret['data'] .= ' ' . $token;
+        }
+        $ret['data'] = trim($ret['data']);
+      }
+
+      // log some errors
+      if($ret['result'] &lt; 0)
+        $this-&gt;conlog(&quot;$command returned {$ret['result']}&quot;);
+
+      return $ret;
+    }
+
+   /**
+    * Log to console if debug mode.
+    *
+    * @example examples/ping.php Ping an IP address
+    *
+    * @param string $str
+    * @param integer $vbl verbose level
+    */
+    function conlog($str, $vbl=1)
+    {
+      static $busy = false;
+
+      if($this-&gt;config['phpagi']['debug'] != false)
+      {
+        if(!$busy) // no conlogs inside conlog!!!
+        {
+          $busy = true;
+          $this-&gt;verbose($str, $vbl);
+          $busy = false;
+        }
+      }
+    }
+
+   /**
+    * Find an execuable in the path.
+    *
+    * @access private
+    * @param string $cmd command to find
+    * @param string $checkpath path to check
+    * @return string the path to the command
+    */
+    function which($cmd, $checkpath=NULL)
+    {
+      global $_ENV;
+      $chpath = is_null($checkpath) ? $_ENV['PATH'] : $checkpath;
+
+      foreach(explode(':', $chpath) as $path)
+        if(is_executable(&quot;$path/$cmd&quot;))
+          return &quot;$path/$cmd&quot;;
+
+      if(is_null($checkpath))
+        return $this-&gt;which($cmd, '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:'.
+                                  '/usr/X11R6/bin:/usr/local/apache/bin:/usr/local/mysql/bin');
+      return false;
+    }
+
+   /**
+    * Make a folder recursively.
+    *
+    * @access private
+    * @param string $folder
+    * @param integer $perms
+    */
+    function make_folder($folder, $perms=0755)
+    {
+      $f = explode(DIRECTORY_SEPARATOR, $folder);
+      $base = '';
+      for($i = 0; $i &lt; count($f); $i++)
+      {
+        $base .= $f[$i];
+        if($f[$i] != '' &amp;&amp; !file_exists($base))
+          mkdir($base, $perms);
+        $base .= DIRECTORY_SEPARATOR;
+      }
+    }
+  }
+
+/**
+ * error handler for phpagi.
+ *
+ * @param integer $level PHP error level
+ * @param string $message error message
+ * @param string $file path to file
+ * @param integer $line line number of error
+ * @param array $context variables in the current scope
+ */
+  function phpagi_error_handler($level, $message, $file, $line, $context)
+  {
+    if(ini_get('error_reporting') == 0) return; // this happens with an @
+
+    @syslog(LOG_WARNING, $file . '[' . $line . ']: ' . $message);
+
+    global $phpagi_error_handler_email;
+    if(function_exists('mail') &amp;&amp; !is_null($phpagi_error_handler_email)) // generate email debugging information
+    {
+      // decode error level
+      switch($level)
+      {
+        case E_WARNING:
+        case E_USER_WARNING:
+          $level = &quot;Warning&quot;;
+          break;
+        case E_NOTICE:
+        case E_USER_NOTICE:
+          $level = &quot;Notice&quot;;
+          break;
+        case E_USER_ERROR:
+          $level = &quot;Error&quot;;
+          break;
+      }
+
+      // build message
+      $basefile = basename($file);
+      $subject = &quot;$basefile/$line/$level: $message&quot;;
+      $message = &quot;$level: $message in $file on line $line\n\n&quot;;
+
+      if(function_exists('mysql_errno') &amp;&amp; strpos(' '.strtolower($message), 'mysql'))
+        $message .= 'MySQL error ' . mysql_errno() . &quot;: &quot; . mysql_error() . &quot;\n\n&quot;;
+
+      // figure out who we are
+      if(function_exists('socket_create'))
+      {
+        $addr = NULL;
+        $port = 80;
+        $socket = @socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
+        @socket_connect($socket, '64.0.0.0', $port);
+        @socket_getsockname($socket, $addr, $port);
+        @socket_close($socket);
+        $message .= &quot;\n\nIP Address: $addr\n&quot;;
+      }
+
+      // include variables
+      $message .= &quot;\n\nContext:\n&quot; . print_r($context, true);
+      $message .= &quot;\n\nGLOBALS:\n&quot; . print_r($GLOBALS, true);
+      $message .= &quot;\n\nBacktrace:\n&quot; . print_r(debug_backtrace(), true);
+
+      // include code fragment
+      if(file_exists($file))
+      {
+        $message .= &quot;\n\n$file:\n&quot;;
+        $code = @file($file);
+        for($i = max(0, $line - 10); $i &lt; min($line + 10, count($code)); $i++)
+          $message .= ($i + 1).&quot;\t$code[$i]&quot;;
+      }
+
+      // make sure message is fully readable (convert unprintable chars to hex representation)
+      $ret = '';
+      for($i = 0; $i &lt; strlen($message); $i++)
+      {
+        $c = ord($message{$i});
+        if($c == 10 || $c == 13 || $c == 9)
+          $ret .= $message{$i};
+        elseif($c &lt; 16)
+          $ret .= '\x0' . dechex($c);
+        elseif($c &lt; 32 || $c &gt; 127)
+          $ret .= '\x' . dechex($c);
+        else
+          $ret .= $message{$i};
+      }
+      $message = $ret;
+
+      // send the mail if less than 5 errors
+      static $mailcount = 0;
+      if($mailcount &lt; 5)
+        @mail($phpagi_error_handler_email, $subject, $message);
+      $mailcount++;
+    }
+  }
+  $phpagi_error_handler_email = NULL;
+?&gt;
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>