+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-\f
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
+++ /dev/null
-# Makefile
-# David Rowe 1 Jan 2010
-#
-# Makefile for Easy Asterisk GUI
-#
-# 1/ Download files to development box for testing:
-#
-# usage: make HOST=test.machine.ip|hostname test
-# make HOST=192.168.1.150 test
-# make HOST=boris test
-#
-# 2/ Create static copy of web pages from HOST for static demo
-#
-# usage: make HOST=test.machine.ip static
-
-test:
- rcp cgi-bin/*.html cgi-bin/*.sh cgi-bin/*.pl cgi-bin/*.js cgi-bin/*.css \
- cgi-bin/*.png root@$(HOST):/www
- rcp etc/asterisk/*.conf root@$(HOST):/etc/asterisk
-
-.PHONY : static
-static:
- # generate static pages
-
- rm -Rf static; mkdir static; cd static; \
- wget -rEk --header="Cookie: loggedin=1" http://$(HOST)/phones.sh
-
- # modify links to non-existent scripts on static demo
-
- sed -i "s,http://$(HOST)/set_network.sh,network.sh.html," static/$(HOST)/network.sh.html
- sed -i "s,http://$(HOST)/set_ring.sh,phones.sh.html," static/$(HOST)/phones.sh.html
- sed -i "s,http://$(HOST)/set_voiplines.sh,voiplines.sh.html," static/$(HOST)/voiplines.sh.html
-
-
+++ /dev/null
-Mini Asterisk
-=============
-
-A simple, light weight GUI for Asterisk.
-
-image::/images/ip04/mini.png["Mini Asterisk Demo", link="mini/phones.sh.html"]
-
-Click on the screen shot above for an on line demo.
-
-[[intro]]
-Introduction
-------------
-
-Mini Asterisk is a simple Web GUI for Asterisk with comprehensive tool
-tip documentation and a learning curve of a few minutes. Analog ports
-and IP Phones are automatically detected, and no knowledge of Asterisk
-configuration is required.
-
-Mini Asterisk is "unfeatured" - many of the Asterisk options are not
-available. Instead it tries to make very basic, very common Asterisk
-installations fast and simple, for example:
-
-* An Asterisk server running on your home gateway/firewall/server.
- You want to connect a few IP Phones and make cheap phones calls
- using VOIP. An Asterisk distro on a CD is a possibility but you
- don't want to dedicate a full PC just for Asterisk. You don't
- really want to learn obscure dial plan syntax and yet another conf
- file format.
-
-* A small office that already has an old analog phone system. You
- want to keep your current analog lines for incoming calls, but
- install 8 IP Phones and use VOIP for outgoing calls. You know
- enough to set up a DSL router but don't want to rely on "the Phone
- Guy" or "The Computer Guy" at $100/hr to maintain your phone
- system.
-
-* You are a "Phone Guy" who doesn't understand Linux and Asterisk but
- you want to install IP-PBXes.
-
-[[why]]
-Why Another Asterisk GUI?
--------------------------
-
-There are http://www.voip-info.org/wiki/view/Asterisk+GUI[a lot of
-Asterisk GUIs] out there already. So why do we need another one?
-
-Well I needed an Asterisk GUI that was very easy to use for the
-link:ip04.html[IP0X devices] I sell. Something that would lower the
-technical skill required to install and maintain an Asterisk Phone
-system. Something my wife and kids could use.
-
-I was also interested in exploring the ease-of-use meme, as we have
-been discussing it a lot on the http://villagetelco.org[Village Telco]
-project. Just how easy can we make Asterisk to use? So I scratched
-the itch.
-
-Mini Asterisk has the following features that make it reasonably
-unique. They may be good or bad features depending on your point of
-view!
-
-* Mini Asterisk is "un-featured" - it hides many of the advanced
- Asterisk features in the interest of simple and fast configuration.
-
-* Light weight so it can run on embedded boxes like the IP0X family.
- No SQL database or PHP or LAMP. Only a basic web server and a very
- basic perl are required (e.g. microperl - no CPAN libraries).
-
-* Works directly on extensions.conf and sip.conf, but honors any edits
- you make to these files. So all the powerful Asterisk features are
- available in the background.
-
-* Doesn't use AJAX or the built-in Asterisk web server or users.conf
- magic. Plain old HTML, a little Java-script and CGIs written in
- shell script and Perl.
-
-* Doesn't use the Asterisk programming "model". For example you don't
- have to understand what a dial-plan is, much less understand how to
- code one. Plain English terms are used instead, for example "Phones
- and Phone lines". Terms like Asterisk, Linux, SIP, Zap/1 don't even
- get a mention.
-
-* Extensive tool tip documentation. No manual.
-
-* Doesn't require a dedicated PC, not installed from an ISO CD. So
- you can use it as a GUI for Asterisk on a little SOHO Linux box that
- is also your firewall, server etc.
-
-* Mini Asterisk tells you when something is wrong, for example you get
- a warning if your Phone System can't see the Internet.
-
-* Extensive pre-configuration of extensions.conf and sip.conf,
- pre-selected phone numbers, SIP trunks are selected from a pull-down
- menu (except they are called VOIP lines). Analog ports are auto
- detected, at least on the IP0X. This makes adding IP phones very
- fast and simple.
-
-[[status]]
-Status
-------
-
-Alpha:
-
-* Works on IP0X.
-* Not tested on x86. Several IP0X features are n/a for x86 and should be
- disabled when the x86 (or non-IP0X) platform is detected.
-* Needs feedback from real users to see how useful the concept is and what
- (un)features need to be added.
-* Need a few more (un)features to be added, and Voip Line screen
- populated with more ITSPs.
-* But quite useable as it stands.
-
-[[notes]]
-Implementation Notes
---------------------
-
-Mini Asterisk is written for the
-http://rowetel.com/ucasterisk/ip04.html[IP0X embedded Asterisk]
-hardware but will also run on x86 and probably many other platforms.
-
-Mini Asterisk has been written to be compatible with regular Asterisk
-conf file configuration. Just leave the conf file lines with
-"mini-asterisk" comments alone. The Asterisk conf files
-extensions.conf and sip.conf are directly modified by Mini Asterisk,
-but changes are limited to the "mini-asterisk" lines.
-
-For Auto-detection of Zap ports Mini Asterisk looks at
-/etc/zapata.conf, so you may need this set up correctly for your
-analog hardware. On the IP0X this happens automatically.
-
-[[install]]
-Installation
-------------
-
-Note: this process may overwrite your Asterisk extensions.conf and
-sip.conf files - back them up if you have an existing Asterisk
-installation that you want to keep. The IP0X ipkg does attempt to
-backup the modified conf files to *.bak but no guarantees....
-
-However once mini-asterisk is installed it should honor any manual
-changes made to extensions.conf and sip.conf.
-
-IP0X Installation
-~~~~~~~~~~~~~~~~~
-
-Installation instructions for IP0X boxes running link:baps.html[BAPS],
-with some version of Asterisk and Zaptel installed.
-
--------------------------------------------------------------------
-root~> ipkg install mini-asterisk
--------------------------------------------------------------------
-
-x86 Installation
-~~~~~~~~~~~~~~~~
-
-. You need a web server, Asterisk and some sort of Perl installed
-(very basic Perl installation is fine). Configure your web server to
-run CGIs (.sh and .pl) from /www (lighttpd config instructions below).
-Mini Asterisk expects all files (shell, perl, html etc) to be in the
-same directory. If you find this painful please <<support, let me know>>.
-
-. The process below places the web files in /www, you may like to
-place the files somewhere else like /www/asterisk. One of the files
-is named index.html so make sure you don't overwrite an existing
-index.html.
-
-. Login as root to install the Mini Asterisk files:
-+
-Remember to backup your existing extensions.conf & sip.conf in
-/etc/asterisk
-+
--------------------------------------------------------------------
-# cd ~
-# svn co https://freetel.svn.sourceforge.net/svnroot/freetel/mini-asterisk-gui
-# ./update_revision.sh
-# cp mini-asterisk-gui/etc/asterisk/* /etc/asterisk
-# cp mini-asterisk-gui/cgi-bin/* /www
-# cd /etc/asterisk
-# cp extensions.conf extensions.conf.def
-# cp sip.conf sip.conf.def
-# mv etc/asterisk/users.conf etc/asterisk/users.conf.bak
--------------------------------------------------------------------
-+
-The final step above may not be required on your machine if you don't
-have a users.conf. The .def copies are required by the "reset
-defaults" feature on the admin screen.
-
-. Switch off the internal Asterisk web server by editing
-/etc/asterisk.httpd.conf. Make sure the enabled line reads like this:
-
- enabled=no
-+
-Then stop and restart Asterisk.
-
-. I use lighttpd as the web server, the /etc/lighttpd.conf lines
-required are:
-+
--------------------------------------------------------------------
-cgi.assign = ( ".sh" => "/bin/sh",".pl" => "/usr/sbin/microperl" )
--------------------------------------------------------------------
-
-[[contribute]]
-Contributions
--------------
-
-I welcome sip.conf entries for your favourite ITSP (VOIP service) to
-help populate the Provider field of the
-link:mini/voiplines.sh.html[Voip Line Screen].
-
-[[support]]
-Support
--------
-
-Comments, features request, bugs please let me know using Free
-Telephony Project http://www.rowetel.com/ucasterisk/#support[Support].
-
-[[source]]
-Source Code
------------
-
-Browse:
-
-http://freetel.svn.sourceforge.net/viewvc/freetel/mini-asterisk-gui/[http://freetel.svn.sourceforge.net/viewvc/freetel/mini-asterisk-gui/]
-
-Check Out:
-
- $ svn co https://freetel.svn.sourceforge.net/svnroot/freetel/mini-asterisk-gui
-
+++ /dev/null
-#!/bin/sh
-# about.sh
-# David Rowe 7 Jan 2010
-# About screen for Mini Asterisk GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
-
-cat << EOF
-<html>
-<title>Mini Asterisk - About</title>
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <table align="right" width=600>
- <tr><td align="left" valign="top"><h2>About</h2></td></tr>
-EOF
-echo ' <tr><td><a href="http://rowetel.com/ucasterisk/mini.html">Mini Asterisk</a> Revision: 122 </td></tr> '
-echo ' <tr><td> </td></tr>'
-echo ' <tr><td>Brought to you by the <a href="http://rowetel.com/ucasterisk/index.html">Free Telephony Project</a></td></tr>'
-echo ' <tr><td><a href="http://rowetel.com/ucasterisk/ip04.html"><img src="http://rowetel.com/images/ip04/ip04_case.jpg" border="0" /></a></td></tr>'
-
-more=`echo "$QUERY_STRING" | grep -oe "more=[^&?]*" | sed -n "s/more=//p"`
-if [ $more -eq 1 ]; then
- echo
-else
- echo " <tr><td> </td></tr>"
- echo ' <tr><td><a href="about.sh?more=1">More</a></td></tr>';
-cat <<EOF
- </table>
- </td>
- </tr>
-</table>
-</body>
-</html>
-EOF
-exit
-fi
-
-echo " <tr><td> </td></tr>"
-echo " <tr><td><h3>cat /proc/version</h3></td></tr>"
-echo " <tr><td>"
-cat /proc/version
-echo " </td></tr>"
-
-which ipkg >> /dev/null
-if [ $? -eq 0 ]; then
- echo " <tr><td> </td></tr>"
- echo " <tr><td><h3>ipkg list_installed</h3></td></tr>"
- echo " <tr><td>"
- ipkg list_installed | tr '\n' '#' | sed -n 's/\#/<br>/pg'
- echo " </td></tr>"
-fi
-
-echo " <tr><td> </td></tr>"
-echo " <tr><td><h3>cat /proc/loadavg</h3></td></tr>"
-echo " <tr><td>"
-cat /proc/loadavg
-echo " </td></tr>"
-
-echo " <tr><td> </td></tr>"
-echo " <tr><td><h3>uptime</h3></td></tr>"
-echo " <tr><td>"
-uptime
-echo " </td></tr>"
-
-echo " <tr><td> </td></tr>"
-echo " <tr><td><h3>cat /proc/meminfo</h3></td></tr>"
-echo " <tr><td>"
-cat /proc/meminfo | tr '\n' '#' | sed -n 's/\#/<br>/pg'
-echo " </td></tr>"
-
-echo " <tr><td> </td></tr>"
-echo " <tr><td><h3>cat /proc/cmdline</h3></td></tr>"
-echo " <tr><td>"
-cat /proc/cmdline
-echo " </td></tr>"
-
-echo " <tr><td> </td></tr>"
-echo " <tr><td><h3>cat /proc/cpuinfo</h3></td></tr>"
-echo " <tr><td>"
-cat /proc/cpuinfo
-echo " </td></tr>"
-
-if [ -f /proc/mtd ]; then
- echo " <tr><td> </td></tr>"
- echo " <tr><td><h3>cat /proc/mtd</h3></td></tr>"
- echo " <tr><td>"
- cat /proc/mtd | tr '\n' '#' | sed -n 's/\#/<br>/pg'
- echo " </td></tr>"
-fi
-
-if [ -f /proc/yaffs ]; then
- echo " <tr><td> </td></tr>"
- echo " <tr><td><h3>cat /proc/yaffs</h3></td></tr>"
- echo " <tr><td>"
- cat /proc/yaffs | tr '\n' '#' | sed -n 's/\#/<br>/pg'
- echo " </td></tr>"
-fi
-
-echo " <tr><td> </td></tr>"
-echo ' <tr><td><a href="about.sh">Less</a></td></tr>';
-
-cat <<EOF
- </table>
-
- </td>
-
- </tr>
-
-</table>
-</body>
-</html>
-EOF
-
+++ /dev/null
-#!/bin/sh
-# admin.sh
-# David Rowe 7 Jan 2010
-# Admin screen for Mini Asterisk GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-# set password CGI -----------------------------------------------
-
-echo "$QUERY_STRING" | grep -oe "pass=" > /dev/null
-if [ $? -eq 0 ]; then
- pass=`echo "$QUERY_STRING" | grep -oe "pass=[^&?]*" | sed -n "s/pass=//p"`
- passwd_cmdline $pass
-fi
-
-# restart CGI ----------------------------------------------------
-
-echo "$QUERY_STRING" | grep -oe "restart=1" > /dev/null
-if [ $? -eq 0 ]; then
-
-# kill cookie to log out. This ensures hitting refresh wont run
-# the restart process again
-
-cat <<EOF
-Content-type: text/html
-Set-Cookie: loggedin=1; expires=Thursday, 01-Jan-98 12:00:00 GMT
-
-<head>
-<title>Mini Asterisk - Restart</title>
-</head>
-<body>
-<h2>Restarting...come back in 1 minute</h2>
-</body>
-EOF
-reboot
-fi
-
-# set defaults CGI ----------------------------------------------------
-
-echo "$QUERY_STRING" | grep -oe "defaults=1" > /dev/null
-if [ $? -eq 0 ]; then
- cp /etc/asterisk/extensions.conf.def /etc/asterisk/extensions.conf
- cp /etc/asterisk/sip.conf.def /etc/asterisk/sip.conf
- asterisk -rx "sip reload" 2>/dev/null 1 > /dev/null
- asterisk -rx "dialplan reload" 2>/dev/null 1 > /dev/null
-fi
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
-
-cat << EOF
-<html>
-<title>Mini Asterisk - Admin</title>
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <table align="right" width=600>
- <tr><td> </td></tr>
- <form action="admin.sh" method="get">
- <tr><td align="left" valign="top"><h2>Admin</h2></td></tr>
-
- <tr><td> </td></tr>
- <tr><td colspan="2"><h3>Change Phone System Password</h3></td></tr>
- <tr><td>New Password:</td><td><input type="password" name="pass" ></td>
- <td><input type="submit" value="Set Password"></td>
- </tr>
- <tr><td> </td></tr>
- <tr><td></td><td>Default password is uClinux</td>
- </form>
-
- <tr><td> </td></tr>
- <tr><td colspan="2"><h3>Restart Phone System</h3></td>
- <td onMouseOver="popUp(event,'admin_restart')" onmouseout="popUp(event,'admin_restart')">
- <form action="admin.sh" method="get">
- <input type="hidden" name="restart" value="1">
- <input type="submit" value="Restart">
- </form>
- </td>
- </tr>
-
- <tr><td> </td></tr>
- <tr><td colspan="2"><h3>Reset Phone System Defaults</h3></td>
- <td>
- <form action="admin.sh" method="get">
- <input type="hidden" name="defaults" value="1">
- <input type="submit" value="Reset">
- </form>
- </td>
- </tr>
-
- <tr><td> </td></tr>
- <tr onMouseOver="popUp(event,'admin_upgrade')" onmouseout="popUp(event,'admin_upgrade')">
- <td colspan="2"><h3>Upgrade Mini Asterisk</h3></td>
- <td>
- <form action="admin.sh" method="get">
- <input type="hidden" name="upgrade" value="1">
- <input type="submit" value="Upgrade">
- </td>
- </tr>
-
- <tr><td> </td></tr>
- <tr><td colspan="2"><h3>Install New Firmware</h3>
- <form action="admin.sh" method="get">
- <tr onMouseOver="popUp(event,'admin_firmware')" onmouseout="popUp(event,'admin_firmware')">
- <td>Firmware URL:</td>
- <td><input type="text" name="firmwareurl" ></td>
- <td><input type="submit" value="Install"></td>
- </tr>
- </form>
-
- </table>
- </form>
-
- </td>
-
- </tr>
-
-</table>
-</body>
-</html>
-EOF
-
+++ /dev/null
-<ol>
-<li>Connect the WAN port of the AT-530 to your network, it will boot and obtain an IP via DHCP.
-<li>Find the <strong>IP</strong> of the phone by pressing the <strong>Sysinfo</strong> button a few times.
-<li>Open another browser window. Go to the phones <strong>IP</strong>, for example <strong>http://192.168.1.160</strong>
-<li>Login to the phone using the username/password <strong>admin/admin</strong>.
-<li>Optional: set a static IP using the WAN menu (I like static IPs for SIP phones).
-<li>Go to the phone <strong>SIP Config</strong> menu.
-<li>Set <strong>Register Server Address</strong> to your Phone System IP Address.
-<li>Set <strong>Register Username</strong> to the phone number (e.g. 6011).
-<li>Also set </strong>Register Password</strong> to the phone number (e.g. 6011) and
-the </strong>Phone Number</strong> to the phone number (e.g. 6011).
-<li>Check the <strong>Enable Register</strong> box.
-<li>Then click on <strong>Apply</strong>.
-<li>On your browser refresh this page to see if the phone is connected to your phone system.
-</ol>
+++ /dev/null
- <tr><td colspan="2"><h2> </h2></td></tr>
+++ /dev/null
-<ol>
-
-<li><strong>Transfer a Call</strong>
-
-<li><strong>Answer a call on another ringing phone</strong>: If you hear another phone ringing and
-want to answer the call on your phone, just pick up your phone and
-dial *8. Note an IP phone can pick up a call on a ringing IP phone
-but not an Analog phone. An Analog pohone can pick up another
-ringing Analog phone but not an IP phone.
-
-</ol>
-
-<h2>Resources and Links</h2>
-<ol>
-<li>A good book on Asterisk is <a href="http://astbook.asteriskdocs.org">Asterisk - The Future of Telephony</a>
-</ol>
+++ /dev/null
-#!/bin/sh
-# faq.sh
-# David Rowe 7 Jan 2010
-# FAQ screen for Mini Asterisk GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
-
-cat << EOF
-<html>
-<title>Mini Asterisk - FAQ</title>
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <table align="right" width=600>
- <tr><td align="left" valign="top"><h2>FAQ</h2></td></tr>
- <tr><td>
-EOF
-cat faq.html
-cat <<EOF
- </td></tr>
- </table>
-
- </td>
-
- </tr>
-
-</table>
-</body>
-</html>
-EOF
-
+++ /dev/null
-<html>
-<head>
-<meta http-equiv="REFRESH" content="0;url=http:login.sh">
-</head>
-</html>
\ No newline at end of file
+++ /dev/null
-function localInit() {
-}
-
+++ /dev/null
-#!usr/bin/perl
-# ipphones.pl
-# David Rowe 6 Jan 2010
-#
-# Text processing for the ipphones screen
-
-$ipaddress = $ARGV[0];
-$more = $ARGV[1];
-
-# Slurp up SIP extension (Sip) data from extensions.conf
-
-my %ip = (); # ip extension keyed on sip.conf name
-
-open EXT, "/etc/asterisk/extensions.conf";
-while (<EXT>) {
- if (/.*=>[ ]*([0-9]*),1.*SIP\/([0-9]*)\)/) {
- $ip{$2} = $1;
- #print "'$1' '$2' $ip{$2}\n";
- }
-}
-close EXT;
-
-my %sip = (); # SIP IP phone status keyed on sip.conf names
- # if no entry we can't see IP phone device
-my %voip = (); # SIP trunks status keyed on sip.conf names
- # if no entry we can't see SIP trunk
-my %ipad = (); # IP address of SIP device keyed on sip.conf names
-
-open SIP, "sipshowpeers.txt";
-while (<SIP>) {
- if (/^([0-9]*)[\s\/].*(OK)/) {
- $sip{$1} = $2;
- #print "'$1' '$2' $sip{$1}\n";
- $e = $1;
- if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
- $ipad{$e} = $1;
- #print "'$1'\n";
- }
- }
- if (/^(voip[0-9]*)[\s\/].*(OK)/) {
- $voip{$1} = $2;
- #print "'$1' '$2' $voip{$1}\n";
- $e = $1;
- if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
- $ipad{$e} = $1;
- #print "'$1'\n";
- }
- }
-}
-
-close SIP;
-
-# print list of IP phones with connection status
-
-$unconnected = 0;
-foreach $e (sort keys %ip) {
- if ($sip{$e} eq "OK") {
- $icon = "<img src=\"tick.png\" alt=\"Connected\" />";
- $tooltip_status = "onMouseOver=\"popUp(event,'ipphones_connected')\" onmouseout=\"popUp(event,'ipphones_connected')\"";
- $comment=$ipad{$e};
- $tooltip_ext = "onMouseOver=\"popUp(event,'phone_ext')\" onmouseout=\"popUp(event,'phone_ext')\"";
- $tooltip_ip = "onMouseOver=\"popUp(event,'phone_ipphone_ip')\" onmouseout=\"popUp(event,'phone_ipphone_ip')\"";
- $unconnected = 0;
- }
- else {
- $unconnected = $unconnected + 1;
- $icon = "<img src=\"cross.png\" alt=\"Not Connected\" />";
- $tooltip_status = "onMouseOver=\"popUp(event,'ipphones_notconnected')\" onmouseout=\"popUp(event,'ipphones_notconnected')\"";
- $comment="Available";
- $tooltip_id = "iphones_$e";
- print "<div id=\"$tooltip_id\" class=\"tip\"> Configure your IP phone with username/password $e/$e, SIP Server IP $ipaddress</div>";
- $tooltip_ext = "onMouseOver=\"popUp(event,'$tooltip_id')\" onmouseout=\"popUp(event,'$tooltip_id')\"";
- $tooltip_ip = "";
- }
-
- if ($more == 1 || ($unconnected < 5)) {
- print "<tr><td $tooltip_ext>$e</td><td></td><td $tooltip_ip>$comment</td><td $tooltip_status>$icon</td></tr>\n";
- }
-}
-
-if ($more == 0) {
- print '<tr><td><a href="ipphones.sh?more=1">More</a></td></tr>';
-}
-else {
- print '<tr><td><a href="ipphones.sh">Less</a></td></tr>';
-}
-
-
+++ /dev/null
-#!/bin/sh
-# dashboard.sh
-# David Rowe 6 Jan 2010
-# Dashboard screen for Mini Asterisk GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-more=`echo "$QUERY_STRING" | grep -oe "more=[^&?]*" | sed -n "s/more=//p"`
-ipaddress=`ifconfig eth0 | sed -n 's/.*inet addr:\(.*\) Bcast.*/\1/p'`
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
-
-echo "<script>"
-echo 'var init_internet="'$internet'";'
-cat ipphones.js
-echo "</script>"
-
-cat << EOF
-<html>
-<title>Mini Asterisk - IP Phones</title>
-<body onload="localInit()">
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800 border=0>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <table align="right" width=600 border=0>
- <tr><td onMouseOver="popUp(event,'ipphones_ipphones')" onmouseout="popUp(event,'ipphones_ipphones')"
- colspan="4" align="left" valign="top" ><h2>IP Phones</h2></td></tr>
- <tr onMouseOver="popUp(event,'phone_ipaddress')" onmouseout="popUp(event,'phone_ipaddress')">
- <td colspan="3">Phone System IP Address:</td>
-EOF
-echo "<td>$ipaddress</td></tr><td> </td><tr></tr>"
-
- # use perl to construct list of IP phones for us
- asterisk "-rx sip show peers" 2>/dev/null > sipshowpeers.txt
- ./ipphones.pl $ipaddress $more
-
-cat <<EOF
- </table>
-
- <h2> <br>How to Configure IP Phones</h2>
- <h3>1. Atcom AT-530</h3>
-EOF
-cat at-530.html
-cat <<EOF
- </td>
- </tr>
-
-</table>
-</body>
-</html>
-EOF
-
+++ /dev/null
-#!/bin/sh
-# login.sh
-# David Rowe 4 Jan 2010
-# CGI for Mini Asterisk login GUI
-
-pass=`echo "$QUERY_STRING" | grep -oe "pass=[^&?]*" | sed -n "s/pass=//p"`
-
-echo $QUERY_STRING | grep pass > /dev/null
-if [ $? -eq 1 ]; then
- # Display form -------------------------------
-
- cat <<EOF
- <script src="prototype.js"></script>
- <script type="text/javascript" src="tooltip.js"></script>
- <link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
- cat << EOF
- <html>
- <title>Mini Asterisk - Login</title>
- <form action="login.sh" method="get">
- <table align="center" width=600>
- <tr><td colspan="2" align="left"><h2>Login</h2></td>
- <tr>
- <tr><td>Password:</td><td><input type="password" name="pass" ></td></tr>
- <tr><td><input type="submit" value="Login"></td></tr>
- </tr>
- <tr><td></td><td>Default password is uClinux</td>
- </table>
- </form>
- </html>
-EOF
-else
- testuser root $pass
- if [ $? -eq 0 ]; then
-
- # login sucessful
- echo "Content-type: text/html"
- echo "Set-Cookie: loggedin=1"
- echo ""
- echo "<head>"
- echo "<title>Mini Asterisk - Login</title>"
- echo '<meta http-equiv="REFRESH" content="0;url=phones.sh">'
- echo "</head>"
- echo "<body>"
- echo "Please wait a few seconds....."
- echo "</body>"
-
- # load mini asterisk conf files in case this is our first login
-
- asterisk -rx "sip reload" 2>/dev/null 1 > /dev/null
- asterisk -rx "dialplan reload" 2>/dev/null 1 > /dev/null
-
- else
- # login failed
- cat <<EOF
- <html>
- <head>
- <title>Mini Asterisk - Login</title>
- <meta http-equiv="REFRESH" content="0;url=login.sh">
- <body>
- Please wait a few seconds.....
- </body>
- </head>
- </html>
-EOF
- fi
-fi
-
+++ /dev/null
-#!/bin/sh
-# logout.sh
-# David Rowe 4 Jan 2010
-# CGI for Mini Asterisk logout GUI
-
-cat <<EOF
-Content-type: text/html
-Set-Cookie: loggedin=1; expires=Thursday, 01-Jan-98 12:00:00 GMT
-
-<title>Mini Asterisk - Logout</title>
-<meta http-equiv="REFRESH" content="0;url=login.sh"
-EOF
-#echo $HTTP_COOKIE
+++ /dev/null
- <div id="admin_tip" class="tip">Change your password, reset the default settings, upgrade software</div>
- <div id="network_tip" class="tip">Connect the phone system to your network and the Internet</div>
- <div id="phones_tip" class="tip">Lists your phones and phone lines</div>
- <div id="ipphones_tip" class="tip">Set up your IP phones</div>
- <div id="about_tip" class="tip">Boring information like software version numbers</div>
- <div id="faq_tip" class="tip">Frequently asked questions and links to further information</div>
- <div id="logout_tip" class="tip">I think you can work this one out....</div>
- <div id="voipline_tip" class="tip">Set up your VOIP phone line</div>
- <td valign="top" >
- <table align="right" width=200>
- <tr><td><h2> </h2></td></tr>
- <tr onMouseOver="popUp(event,'about_tip')" onmouseout="popUp(event,'about_tip')">
- <td><a href="about.sh">About</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'admin_tip')" onmouseout="popUp(event,'admin_tip')">
- <td><a href="admin.sh">Admin</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'faq_tip')" onmouseout="popUp(event,'faq_tip')">
- <td><a href="faq.sh">FAQ</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'ipphones_tip')" onmouseout="popUp(event,'ipphones_tip')">
- <td><a href="ipphones.sh">IP Phones</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'logout_tip')" onmouseout="popUp(event,'logout_tip')">
- <td><a href="logout.sh">Logout</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'phones_tip')" onmouseout="popUp(event,'phones_tip')">
- <td><a href="phones.sh">Phone System</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'network_tip')" onmouseout="popUp(event,'network_tip')">
- <td><a href="network.sh">Network</a></td>
- </tr>
- <tr onMouseOver="popUp(event,'voipline_tip')" onmouseout="popUp(event,'voipline_tip')">
- <td><a href="voiplines.sh">VOIP Line</a></td>
- </tr>
- </table>
- </td>
+++ /dev/null
-var script_path = "cgi-bin/";
-
-function doStatic() {
- $('ipaddress').disabled = 0;
- $('netmask').disabled = 0;
- $('gateway').disabled = 0;
- $('dns').disabled = 0;
-}
-
-function doDHCP() {
- $('ipaddress').disabled = 1;
- $('netmask').disabled = 1;
- $('gateway').disabled = 1;
- $('dns').disabled = 1;
-}
-
-// http://moblog.bradleyit.com/2009/06/javascript-ip-address-validation.html
-
-function isIP(obj) {
- var ary = obj.value.split(".");
- var ip = true;
-
- for (var i=0; i<4; i++) {
- ip = (!ary[i].match(/^\d{1,3}$/) || (Number(ary[i]) > 255)) ? false : ip;
- }
-
- if (ip)
- ip = (ary.length == 4);
-
- if (!ip) {
- // the value is NOT a valid IP address
- obj.style.background = "red";
- obj.select();
- }
- else { obj.style.background = ""; } // the value IS a valid IP address
-
- return ip;
-}
-
-function localInit() {
-
- if (init_dhcp == "yes") {
- $('dhcp').checked = true;
- $('ipaddress').disabled = 1;
- $('netmask').disabled = 1;
- $('gateway').disabled = 1;
- $('dns').disabled = 1;
- }
- else {
- $('static').checked = true;
- $('ipaddress').disabled = 0;
- $('netmask').disabled = 0;
- $('gateway').disabled = 0;
- $('dns').disabled = 0;
- }
- $('ipaddress').value = init_ipaddress;
- $('netmask').value = init_netmask;
- $('gateway').value = init_gateway;
- $('dns').value = init_dns;
- $('backdoor').value = init_backdoor;
- if (init_internet == "yes")
- $('internet').innerHTML = '<img src="tick.png" alt="tick" />';
- else
- $('internet').innerHTML = '<img src="cross.png" alt="tick" />';
-
-}
-
-function validate_form(form)
-{
- var valid = true;
-
- if ($('dhcp').checked == false)
- valid = isIP(form.ipaddress) && isIP(form.ipaddress) && isIP(form.gateway) && isIP(form.dns);
-
- return valid;
-}
+++ /dev/null
-#!/bin/sh
-# network.sh
-# David Rowe 4 Jan 2010
-# CGI for Mini Asterisk network GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-grok_network=0
-
-if [ -f /etc/rc.d/S10network ]; then
- grok_network=1
- dhcp=yes
- ipaddress=`ifconfig eth0 | sed -n 's/.*inet addr:\(.*\) Bcast.*/\1/p'`
- netmask=`ifconfig eth0 | sed -n 's/.*Mask:\(.*\)\s*/\1/p'`
- gateway=`route -n | awk '/^0.0.0.0/ {print $2}'`
- dns=`cat /etc/resolv.conf | awk '/^nameserver/ {print $2}'`
-fi
-
-if [ -f /etc/rc.d/S10network-static ]
-then
- grok_network=1
- dhcp=no
- ipaddress=`sed -n 's/IPADDRESS="\(.*\)"/\1/p' /etc/init.d/network-static`
- netmask=`sed -n 's/NETMASK="\(.*\)"/\1/p' /etc/init.d/network-static`
- gateway=`sed -n 's/GATEWAY="\(.*\)"/\1/p' /etc/init.d/network-static`
- dns=`sed -n 's/DNS="\(.*\)"/\1/p' /etc/init.d/network-static`
-fi
-
-# if we don't understand this machines network config then bail
-
-if [ $groknetwork -eq 0 ]; then
-cat << EOF
-<html>
-<title>Mini Asterisk - Network</title>
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800 border=0>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
- <table align="center" width=600 border=0>
- <tr><td colspan="2" align="left" valign="top"><h2>Network</h2></td></tr>
- <tr><td>Sorry - I can't edit the Network configuration on this machine</td></tr>
- </td>
- </table>
- </td>
- </tr>
-
-</table>
-
-</html>
-EOF
-fi
-
-if [ -f /etc/rc.d/S05network-backdoor ]; then
- backdoor=`sed -n 's/IPADDRESS="\(.*\)"/\1/p' /etc/init.d/network-backdoor`
-fi
-
-# See if we have Internet connectivity, first check dns as time outs can be very slow
-
-dns_packet_loss=`ping $dns -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
-internet="no";
-if [ $dns_packet_loss == "0" ]; then
- packet_loss=`ping google.com -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
- if [ $packet_loss == "0" ]; then
- internet="yes";
- fi
-fi
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
-
-echo "<script>"
-echo 'var init_dhcp="'$dhcp'";'
-echo 'var init_ipaddress="'$ipaddress'";'
-echo 'var init_netmask="'$netmask'";'
-echo 'var init_gateway="'$gateway'";'
-echo 'var init_dns="'$dns'";'
-echo 'var init_backdoor="'$backdoor'";'
-echo 'var init_internet="'$internet'";'
-cat network.js
-echo "</script>"
-
-cat << EOF
-<html>
-<title>Mini Asterisk - Network</title>
-<body onload="localInit()">
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800 border=0>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <form action="set_network.sh" onsubmit="return validate_form(this)" method="get">
- <table align="center" width=600 border=0>
- <tr><td colspan="2" align="left" valign="top"><h2>Network</h2></td></tr>
- <tr>
- <td><input type="radio" id="static" name="dhcp" value="no" onClick="doStatic()">Static</td>
- <td><input type="radio" id="dhcp" name="dhcp" value="yes" onClick="doDHCP()">DHCP</td>
- </tr>
- <tr><td>IP Address:</td><td><input type="text" name="ipaddress" id="ipaddress" onBlur="isIP(this)"></td></tr>
- <tr><td>Netmask:</td><td><input type="text" name="netmask" id="netmask" onBlur="isIP(this)"></td></tr>
- <tr><td>Gateway:</td><td><input type="text" name="gateway" id="gateway" onBlur="isIP(this)"></td></tr>
- <tr><td>DNS:</td><td><input type="text" name="dns" id="dns" onBlur="isIP(this)"></td></tr>
- <tr onMouseOver="popUp(event,'network_backdoor')" onmouseout="popUp(event,'network_backdoor')">
- <td>Emergency IP:</td><td><input type="text" name="backdoor" id="backdoor" onBlur="isIP(this)"></td>
- </tr>
- <tr onMouseOver="popUp(event,'network_internet')" onmouseout="popUp(event,'network_internet')">
- <td>Internet Connection:</td>
- <td><div id="internet" >
- <span style="margin-left: 4px;font-weight:bold"> </span></div></td>
-
- </tr>
- <tr><td><input id="networkapply" type="submit" value="Apply"></td></tr>
- </table>
- </form>
-
- </td>
-
- </tr>
-
-</table>
-
-</html>
-EOF
-
+++ /dev/null
-function localInit() {
- if (init_internet == "yes")
- $('internet').innerHTML = '<img src="tick.png" alt="tick" />';
- else
- $('internet').innerHTML = '<img src="cross.png" alt="tick" />';
-}
-
+++ /dev/null
-#!/usr/bin/perl
-# phones.pl
-# David Rowe 5 Jan 2010
-#
-# Text processing for the phones screen.
-
-$tool_tip = "onMouseOver=\"popUp(event,'network_internet')\" onmouseout=\"popUp(event,'network_internet')\"";
-
-# Slurp up analog port (Zap) data from extensions.conf
-
-my %analog = (); # analog extension keyed on zap port
-
-open EXT, "/etc/asterisk/extensions.conf";
-while (<EXT>) {
- if (/.*=>[ ]*([0-9]*),1.*Zap\/([0-9]*)\)/) {
- $analog{$2} = $1;
- #print "'$1' '$2' $analog{$2}\n";
- }
-}
-close EXT;
-
-# Slurp up data on installed zaptel ports from /etc/zaptel.conf
-
-my %zap = (); # zaptel port type keyed on zap port
- # (fxs/fxo or no entry if not live)
-open ZAP, "/etc/zaptel.conf";
-while (<ZAP>) {
- if (/fxoks=(.*)/) {
- @fxs = split(/,/, $1);
- foreach (@fxs) {
- $zap{$_} = "fxs";
- }
- }
- if (/fxsks=(.*)/) {
- @fxo = split(/,/, $1);
- foreach (@fxo) {
- $zap{$_} = "fxo";
- }
- }
-}
-close ZAP;
-
-# Slurp up SIP extension (Sip) data from extensions.conf
-
-my %ip = (); # ip extension keyed on sip.conf name
-
-open EXT, "/etc/asterisk/extensions.conf";
-while (<EXT>) {
- if (/.*=>[ ]*([0-9]*),1.*Sip\/([0-9]*)\)/) {
- $ip{$2} = $1;
- #print "'$1' '$2' $ip{$2}\n";
- }
-}
-close EXT;
-
-# Determine which extenions are "Reception", i.e. set to ring on incoming
-# calls
-
-my %zap_ring = (); # ring flag keyed on Zap port (1,2...)
-my %sip_ring = (); # ring flag keyed on sip.cong ext name (6011,6012 etc)
-
-open EXT, "/etc/asterisk/extensions.conf";
-while (<EXT>) {
- if (/s,1,Dial\((.*)\) ;; mini/) {
- @ring = split(/&/, $1);
- #print "'$1' '@ring'\n foreach:\n";
- foreach (@ring) {
- #print " $_\n";
- if (/Zap\/([0-9]*)/) {
- $zap_ring{$1} = 1;
- #print "'$_' $1 \n";
- }
- if (/SIP\/([0-9]*)/) {
- $sip_ring{$1} = 1;
- #print "'$_' $1 \n";
- }
- }
- }
-}
-close EXT;
-
-
-# work out which IP phones are registered -----------------------------------
-
-my %sip = (); # SIP IP phone status keyed on sip.conf names (6011,6012 etc)
- # if no entry we can't see IP phone device
-my %ipad = (); # IP address of SIP device keyed on sip.conf names
-
-open SIP, "sipshowpeers.txt";
-while (<SIP>) {
- if (/^([0-9]*)[\s\/].*(OK)/) {
- $sip{$1} = $2;
- #print "'$1' '$2' $sip{$1}\n";
- $e = $1;
- if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
- $ipad{$e} = $1;
- #print "'$1'\n";
- }
- }
-
- if (/^(.*)\/.*(OK)/) {
- #$sip{$1} = $2;
- #print "'$1' '$2' $sip{$1}\n";
- $e = $1;
- if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
- $ipad{$e} = $1;
- #print "'$1'\n";
- }
- }
-}
-
-close SIP;
-
-# Determine if Asterisk can see current voip line (SIP trunk)
-# sipshowpeers.txt needs to be generated before calling this perl
-# script
-
-my %voip = (); # SIP trunks status keyed on sip.conf stanza name/username
- # if no entry we can't see SIP trunk
-
-open SIP, "sipshowregistry.txt";
-while (<SIP>) {
- if (/^(.*):.*(Registered)/) {
- $voip{$1} = $2;
- #print "'$1' '$2' $voip{$1}\n";
- }
-}
-
-close SIP;
-
-# start phones ringing form -------------------------------------------
-
-print '<form action="set_ring.sh" method="get">';
-
-# print list of analog phones
-
-$tooltip_anphone = "onMouseOver=\"popUp(event,'phone_anphone')\" onmouseout=\"popUp(event,'phone_anphone')\"";
-$tooltip_ext = "onMouseOver=\"popUp(event,'phone_ext')\" onmouseout=\"popUp(event,'phone_ext')\"";
-$tooltip_port = "onMouseOver=\"popUp(event,'phone_port_phone')\" onmouseout=\"popUp(event,'phone_port_phone')\"";
-$tooltip_reception = "onMouseOver=\"popUp(event,'phone_reception')\" onmouseout=\"popUp(event,'phone_reception')\"";
-
-foreach $a (sort keys %analog) {
- if ($zap{$a} eq "fxs") {
- $icon = "<img src=\"tick.png\" alt=\"Analog Phone OK\" />";
- print "<tr><td $tooltip_ext>$analog{$a}</td><td $tooltip_anphone>Analog Phone</td><td $tooltip_port>Port $a</td>";
- if ($zap_ring{$a} == 1) {
- $checked = "checked";
- }
- else {
- $checked = "";
- }
- print "<td $tooltip_reception><input type=\"checkbox\" name=\"Zap_$a\" $checked>Reception</td><td>$icon</td></tr>\n";
- }
-}
-
-# print list of IP phones
-
-$tooltip_ipphone = "onMouseOver=\"popUp(event,'phone_ipphone')\" onmouseout=\"popUp(event,'phone_ipphone')\"";
-$tooltip_ipphone_ip = "onMouseOver=\"popUp(event,'phone_ipphone_ip')\" onmouseout=\"popUp(event,'phone_ipphone_ip')\"";
-$tooltip_reception = "onMouseOver=\"popUp(event,'phone_reception')\" onmouseout=\"popUp(event,'phone_reception')\"";
-
-foreach $s (sort keys %sip) {
- if ($sip{$s} eq "OK") {
- $icon = "<img src=\"tick.png\" alt=\"IP Phone OK\" />";
- print "<tr><td $tooltip_ext>$s</td><td $tooltip_ipphone>IP Phone</td><td $tooltip_ipphone_ip>$ipad{$s}</td>";
- if ($sip_ring{$s} == 1) {
- $checked = "checked";
- }
- else {
- $checked = "";
- }
- print "<td $tooltip_reception><input type=\"checkbox\" name=\"SIP_$s\" $checked>Reception</td><td>$icon</td></tr>\n";
- }
-}
-
-print '<tr><td> </td></tr>';
-print "<tr><td onMouseOver=\"popUp(event,'phone_addipphone')\" onmouseout=\"popUp(event,'phone_addipphone')\">";
-print "<a href=\"ipphones.sh\">Add IP Phone</a></td><td></td><td></td><td><input type=\"submit\" value=\"Update Reception\"></td></tr>";
-
-$tool_tip = "onMouseOver=\"popUp(event,'phone_lines')\" onmouseout=\"popUp(event,'phone_lines')\"";
-
-print '<tr><td> </td></tr>';
-print "<tr $tool_tip><td colspan=\"4\" align=\"left\" valign=\"top\" ><h2>Phone Lines</h2></td></tr>
-";
-
-print "</form>";
-
-# print list of analog phone lines
-
-$tooltip_phoneline = "onMouseOver=\"popUp(event,'phone_phoneline')\" onmouseout=\"popUp(event,'phone_phoneline')\"";
-$tooltip_port = "onMouseOver=\"popUp(event,'phone_port_line')\" onmouseout=\"popUp(event,'phone_port_line')\"";
-$tooltip_line_prefix = "onMouseOver=\"popUp(event,'phone_line_prefix')\" onmouseout=\"popUp(event,'phone_line_prefix')\"";
-
-foreach $a (sort keys %analog) {
- if ($zap{$a} eq "fxo") {
- $icon = "<img src=\"tick.png\" alt=\"Phone Line OK\" />";
- print "<tr><td $tooltip_line_prefix>0</td><td $tooltip_phoneline>Analog Line</td><td $tooltip_port>Port $a</td><td></td><td>$icon</td></tr>\n";
- }
-}
-
-# print list of SIP VOIP trunks
-
-$tooltip_voipline = "onMouseOver=\"popUp(event,'phone_voipline')\" onmouseout=\"popUp(event,'phone_voipline')\"";
-$tooltip_voipline_ip = "onMouseOver=\"popUp(event,'phone_voipline_ip')\" onmouseout=\"popUp(event,'phone_voipline_ip')\"";
-$tooltip_voipline_prefix = "onMouseOver=\"popUp(event,'phone_voipline_prefix')\" onmouseout=\"popUp(event,'phone_voipline_prefix')\"";
-
-foreach $s (sort keys %voip) {
- if ($voip{$s} eq "Registered") {
- $icon = "<img src=\"tick.png\" alt=\"VOIP Line OK\" />";
- print "<tr><td $tooltip_voipline_prefix>1</td><td $tooltip_voipline>VOIP Line</td><td $tooltip_voipline_ip>$ipad{$s}</td><td></td><td>$icon</td></tr>\n";
- }
-}
-
-print '<tr><td> </td></tr>';
-print "<tr><td colspan=2 onMouseOver=\"popUp(event,'phone_addvoipline')\" onmouseout=\"popUp(event,'phone_addvoipline')\">";
-print "<a href=\"voiplines.sh\">Set Up VOIP Line</a></td></tr>";
+++ /dev/null
-#!/bin/sh
-# phones.sh
-# David Rowe 4 Jan 2010
-# Phones screen for Mini Asterisk GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-# See if we have Internet connectivity, first check dns as time outs can be very slow
-
-dns=`cat /etc/resolv.conf | awk '/^nameserver/ {print $2}'`
-dns_packet_loss=`ping $dns -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
-internet="no";
-if [ $dns_packet_loss == "0" ]; then
- packet_loss=`ping google.com -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
- if [ $packet_loss == "0" ]; then
- internet="yes";
- fi
-fi
-
-ipaddress=`ifconfig eth0 | sed -n 's/.*inet addr:\(.*\) Bcast.*/\1/p'`
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-EOF
-
-echo "<script>"
-echo 'var init_internet="'$internet'";'
-cat phones.js
-echo "</script>"
-
-cat << EOF
-<html>
-<title>Mini Asterisk - Phones</title>
-<body onload="localInit()">
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <table align="right" width=600>
- <tr>
- <td onMouseOver="popUp(event,'phone_system')" onmouseout="popUp(event,'phone_system')" colspan="4" align="left" valign="top"><h2>Phone System</h2></td>
- </tr>
- <tr>
- <td colspan="3" onMouseOver="popUp(event,'network_internet')" onmouseout="popUp(event,'network_internet')">Internet Connection:</td>
- <td></td><td><div id="internet" > </div></td>
- </tr>
- <tr onMouseOver="popUp(event,'phone_ipaddress')" onmouseout="popUp(event,'phone_ipaddress')">
- <td colspan="4">Phone System IP Address:</td>
-EOF
-echo "<td>$ipaddress</td>"
-cat <<EOF
- </tr>
- <tr><td> </td></tr>
- <tr>
- <td onMouseOver="popUp(event,'phone_phones')" onmouseout="popUp(event,'phone_phones')"
- colspan="3" align="left" valign="top" ><h2>Phones</h2></td>
- </tr>
-EOF
-
-# use perl to construct list of phones and phone lines for us
-asterisk "-rx sip show peers" 2>/dev/null > sipshowpeers.txt
-./phones.pl
-
-cat<<EOF
- </table>
-
- </td>
-
- </tr>
-
-</table>
-</body>
-</html>
-EOF
-
+++ /dev/null
-/* Prototype JavaScript framework, version 1.4.0
- * (c) 2005 Sam Stephenson <sam@conio.net>
- *
- * Prototype is freely distributable under the terms of an MIT-style license.
- * For details, see the Prototype web site: http://prototype.conio.net/
- *
-/*--------------------------------------------------------------------------*/
-
-var Prototype = {
- Version: '1.4.0',
- ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
-
- emptyFunction: function() {},
- K: function(x) {return x}
-}
-
-var Class = {
- create: function() {
- return function() {
- this.initialize.apply(this, arguments);
- }
- }
-}
-
-var Abstract = new Object();
-
-Object.extend = function(destination, source) {
- for (property in source) {
- destination[property] = source[property];
- }
- return destination;
-}
-
-Object.inspect = function(object) {
- try {
- if (object == undefined) return 'undefined';
- if (object == null) return 'null';
- return object.inspect ? object.inspect() : object.toString();
- } catch (e) {
- if (e instanceof RangeError) return '...';
- throw e;
- }
-}
-
-Function.prototype.bind = function() {
- var __method = this, args = $A(arguments), object = args.shift();
- return function() {
- return __method.apply(object, args.concat($A(arguments)));
- }
-}
-
-Function.prototype.bindAsEventListener = function(object) {
- var __method = this;
- return function(event) {
- return __method.call(object, event || window.event);
- }
-}
-
-Object.extend(Number.prototype, {
- toColorPart: function() {
- var digits = this.toString(16);
- if (this < 16) return '0' + digits;
- return digits;
- },
-
- succ: function() {
- return this + 1;
- },
-
- times: function(iterator) {
- $R(0, this, true).each(iterator);
- return this;
- }
-});
-
-var Try = {
- these: function() {
- var returnValue;
-
- for (var i = 0; i < arguments.length; i++) {
- var lambda = arguments[i];
- try {
- returnValue = lambda();
- break;
- } catch (e) {}
- }
-
- return returnValue;
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var PeriodicalExecuter = Class.create();
-PeriodicalExecuter.prototype = {
- initialize: function(callback, frequency) {
- this.callback = callback;
- this.frequency = frequency;
- this.currentlyExecuting = false;
-
- this.registerCallback();
- },
-
- registerCallback: function() {
- setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
- },
-
- onTimerEvent: function() {
- if (!this.currentlyExecuting) {
- try {
- this.currentlyExecuting = true;
- this.callback();
- } finally {
- this.currentlyExecuting = false;
- }
- }
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-function $() {
- var elements = new Array();
-
- for (var i = 0; i < arguments.length; i++) {
- var element = arguments[i];
- if (typeof element == 'string')
- element = document.getElementById(element);
-
- if (arguments.length == 1)
- return element;
-
- elements.push(element);
- }
-
- return elements;
-}
-Object.extend(String.prototype, {
- stripTags: function() {
- return this.replace(/<\/?[^>]+>/gi, '');
- },
-
- stripScripts: function() {
- return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
- },
-
- extractScripts: function() {
- var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
- var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
- return (this.match(matchAll) || []).map(function(scriptTag) {
- return (scriptTag.match(matchOne) || ['', ''])[1];
- });
- },
-
- evalScripts: function() {
- return this.extractScripts().map(eval);
- },
-
- escapeHTML: function() {
- var div = document.createElement('div');
- var text = document.createTextNode(this);
- div.appendChild(text);
- return div.innerHTML;
- },
-
- unescapeHTML: function() {
- var div = document.createElement('div');
- div.innerHTML = this.stripTags();
- return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
- },
-
- toQueryParams: function() {
- var pairs = this.match(/^\??(.*)$/)[1].split('&');
- return pairs.inject({}, function(params, pairString) {
- var pair = pairString.split('=');
- params[pair[0]] = pair[1];
- return params;
- });
- },
-
- toArray: function() {
- return this.split('');
- },
-
- camelize: function() {
- var oStringList = this.split('-');
- if (oStringList.length == 1) return oStringList[0];
-
- var camelizedString = this.indexOf('-') == 0
- ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
- : oStringList[0];
-
- for (var i = 1, len = oStringList.length; i < len; i++) {
- var s = oStringList[i];
- camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
- }
-
- return camelizedString;
- },
-
- inspect: function() {
- return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
- }
-});
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
-var $break = new Object();
-var $continue = new Object();
-
-var Enumerable = {
- each: function(iterator) {
- var index = 0;
- try {
- this._each(function(value) {
- try {
- iterator(value, index++);
- } catch (e) {
- if (e != $continue) throw e;
- }
- });
- } catch (e) {
- if (e != $break) throw e;
- }
- },
-
- all: function(iterator) {
- var result = true;
- this.each(function(value, index) {
- result = result && !!(iterator || Prototype.K)(value, index);
- if (!result) throw $break;
- });
- return result;
- },
-
- any: function(iterator) {
- var result = true;
- this.each(function(value, index) {
- if (result = !!(iterator || Prototype.K)(value, index))
- throw $break;
- });
- return result;
- },
-
- collect: function(iterator) {
- var results = [];
- this.each(function(value, index) {
- results.push(iterator(value, index));
- });
- return results;
- },
-
- detect: function (iterator) {
- var result;
- this.each(function(value, index) {
- if (iterator(value, index)) {
- result = value;
- throw $break;
- }
- });
- return result;
- },
-
- findAll: function(iterator) {
- var results = [];
- this.each(function(value, index) {
- if (iterator(value, index))
- results.push(value);
- });
- return results;
- },
-
- grep: function(pattern, iterator) {
- var results = [];
- this.each(function(value, index) {
- var stringValue = value.toString();
- if (stringValue.match(pattern))
- results.push((iterator || Prototype.K)(value, index));
- })
- return results;
- },
-
- include: function(object) {
- var found = false;
- this.each(function(value) {
- if (value == object) {
- found = true;
- throw $break;
- }
- });
- return found;
- },
-
- inject: function(memo, iterator) {
- this.each(function(value, index) {
- memo = iterator(memo, value, index);
- });
- return memo;
- },
-
- invoke: function(method) {
- var args = $A(arguments).slice(1);
- return this.collect(function(value) {
- return value[method].apply(value, args);
- });
- },
-
- max: function(iterator) {
- var result;
- this.each(function(value, index) {
- value = (iterator || Prototype.K)(value, index);
- if (value >= (result || value))
- result = value;
- });
- return result;
- },
-
- min: function(iterator) {
- var result;
- this.each(function(value, index) {
- value = (iterator || Prototype.K)(value, index);
- if (value <= (result || value))
- result = value;
- });
- return result;
- },
-
- partition: function(iterator) {
- var trues = [], falses = [];
- this.each(function(value, index) {
- ((iterator || Prototype.K)(value, index) ?
- trues : falses).push(value);
- });
- return [trues, falses];
- },
-
- pluck: function(property) {
- var results = [];
- this.each(function(value, index) {
- results.push(value[property]);
- });
- return results;
- },
-
- reject: function(iterator) {
- var results = [];
- this.each(function(value, index) {
- if (!iterator(value, index))
- results.push(value);
- });
- return results;
- },
-
- sortBy: function(iterator) {
- return this.collect(function(value, index) {
- return {value: value, criteria: iterator(value, index)};
- }).sort(function(left, right) {
- var a = left.criteria, b = right.criteria;
- return a < b ? -1 : a > b ? 1 : 0;
- }).pluck('value');
- },
-
- toArray: function() {
- return this.collect(Prototype.K);
- },
-
- zip: function() {
- var iterator = Prototype.K, args = $A(arguments);
- if (typeof args.last() == 'function')
- iterator = args.pop();
-
- var collections = [this].concat(args).map($A);
- return this.map(function(value, index) {
- iterator(value = collections.pluck(index));
- return value;
- });
- },
-
- inspect: function() {
- return '#<Enumerable:' + this.toArray().inspect() + '>';
- }
-}
-
-Object.extend(Enumerable, {
- map: Enumerable.collect,
- find: Enumerable.detect,
- select: Enumerable.findAll,
- member: Enumerable.include,
- entries: Enumerable.toArray
-});
-var $A = Array.from = function(iterable) {
- if (!iterable) return [];
- if (iterable.toArray) {
- return iterable.toArray();
- } else {
- var results = [];
- for (var i = 0; i < iterable.length; i++)
- results.push(iterable[i]);
- return results;
- }
-}
-
-Object.extend(Array.prototype, Enumerable);
-
-Array.prototype._reverse = Array.prototype.reverse;
-
-Object.extend(Array.prototype, {
- _each: function(iterator) {
- for (var i = 0; i < this.length; i++)
- iterator(this[i]);
- },
-
- clear: function() {
- this.length = 0;
- return this;
- },
-
- first: function() {
- return this[0];
- },
-
- last: function() {
- return this[this.length - 1];
- },
-
- compact: function() {
- return this.select(function(value) {
- return value != undefined || value != null;
- });
- },
-
- flatten: function() {
- return this.inject([], function(array, value) {
- return array.concat(value.constructor == Array ?
- value.flatten() : [value]);
- });
- },
-
- without: function() {
- var values = $A(arguments);
- return this.select(function(value) {
- return !values.include(value);
- });
- },
-
- indexOf: function(object) {
- for (var i = 0; i < this.length; i++)
- if (this[i] == object) return i;
- return -1;
- },
-
- reverse: function(inline) {
- return (inline !== false ? this : this.toArray())._reverse();
- },
-
- shift: function() {
- var result = this[0];
- for (var i = 0; i < this.length - 1; i++)
- this[i] = this[i + 1];
- this.length--;
- return result;
- },
-
- inspect: function() {
- return '[' + this.map(Object.inspect).join(', ') + ']';
- }
-});
-var Hash = {
- _each: function(iterator) {
- for (key in this) {
- var value = this[key];
- if (typeof value == 'function') continue;
-
- var pair = [key, value];
- pair.key = key;
- pair.value = value;
- iterator(pair);
- }
- },
-
- keys: function() {
- return this.pluck('key');
- },
-
- values: function() {
- return this.pluck('value');
- },
-
- merge: function(hash) {
- return $H(hash).inject($H(this), function(mergedHash, pair) {
- mergedHash[pair.key] = pair.value;
- return mergedHash;
- });
- },
-
- toQueryString: function() {
- return this.map(function(pair) {
- return pair.map(encodeURIComponent).join('=');
- }).join('&');
- },
-
- inspect: function() {
- return '#<Hash:{' + this.map(function(pair) {
- return pair.map(Object.inspect).join(': ');
- }).join(', ') + '}>';
- }
-}
-
-function $H(object) {
- var hash = Object.extend({}, object || {});
- Object.extend(hash, Enumerable);
- Object.extend(hash, Hash);
- return hash;
-}
-ObjectRange = Class.create();
-Object.extend(ObjectRange.prototype, Enumerable);
-Object.extend(ObjectRange.prototype, {
- initialize: function(start, end, exclusive) {
- this.start = start;
- this.end = end;
- this.exclusive = exclusive;
- },
-
- _each: function(iterator) {
- var value = this.start;
- do {
- iterator(value);
- value = value.succ();
- } while (this.include(value));
- },
-
- include: function(value) {
- if (value < this.start)
- return false;
- if (this.exclusive)
- return value < this.end;
- return value <= this.end;
- }
-});
-
-var $R = function(start, end, exclusive) {
- return new ObjectRange(start, end, exclusive);
-}
-
-var Ajax = {
- getTransport: function() {
- return Try.these(
- function() {return new ActiveXObject('Msxml2.XMLHTTP')},
- function() {return new ActiveXObject('Microsoft.XMLHTTP')},
- function() {return new XMLHttpRequest()}
- ) || false;
- },
-
- activeRequestCount: 0
-}
-
-Ajax.Responders = {
- responders: [],
-
- _each: function(iterator) {
- this.responders._each(iterator);
- },
-
- register: function(responderToAdd) {
- if (!this.include(responderToAdd))
- this.responders.push(responderToAdd);
- },
-
- unregister: function(responderToRemove) {
- this.responders = this.responders.without(responderToRemove);
- },
-
- dispatch: function(callback, request, transport, json) {
- this.each(function(responder) {
- if (responder[callback] && typeof responder[callback] == 'function') {
- try {
- responder[callback].apply(responder, [request, transport, json]);
- } catch (e) {}
- }
- });
- }
-};
-
-Object.extend(Ajax.Responders, Enumerable);
-
-Ajax.Responders.register({
- onCreate: function() {
- Ajax.activeRequestCount++;
- },
-
- onComplete: function() {
- Ajax.activeRequestCount--;
- }
-});
-
-Ajax.Base = function() {};
-Ajax.Base.prototype = {
- setOptions: function(options) {
- this.options = {
- method: 'post',
- asynchronous: true,
- parameters: ''
- }
- Object.extend(this.options, options || {});
- },
-
- responseIsSuccess: function() {
- return this.transport.status == undefined
- || this.transport.status == 0
- || (this.transport.status >= 200 && this.transport.status < 300);
- },
-
- responseIsFailure: function() {
- return !this.responseIsSuccess();
- }
-}
-
-Ajax.Request = Class.create();
-Ajax.Request.Events =
- ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
-Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
- initialize: function(url, options) {
- this.transport = Ajax.getTransport();
- this.setOptions(options);
- this.request(url);
- },
-
- request: function(url) {
- var parameters = this.options.parameters || '';
- if (parameters.length > 0) parameters += '&_=';
-
- try {
- this.url = url;
- if (this.options.method == 'get' && parameters.length > 0)
- this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
-
- Ajax.Responders.dispatch('onCreate', this, this.transport);
-
- this.transport.open(this.options.method, this.url,
- this.options.asynchronous);
-
- if (this.options.asynchronous) {
- this.transport.onreadystatechange = this.onStateChange.bind(this);
- setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
- }
-
- this.setRequestHeaders();
-
- var body = this.options.postBody ? this.options.postBody : parameters;
- this.transport.send(this.options.method == 'post' ? body : null);
-
- } catch (e) {
- this.dispatchException(e);
- }
- },
-
- setRequestHeaders: function() {
- var requestHeaders =
- ['X-Requested-With', 'XMLHttpRequest',
- 'X-Prototype-Version', Prototype.Version];
-
- if (this.options.method == 'post') {
- requestHeaders.push('Content-type',
- 'application/x-www-form-urlencoded');
-
- /* Force "Connection: close" for Mozilla browsers to work around
- * a bug where XMLHttpReqeuest sends an incorrect Content-length
- * header. See Mozilla Bugzilla #246651.
- */
- if (this.transport.overrideMimeType)
- requestHeaders.push('Connection', 'close');
- }
-
- if (this.options.requestHeaders)
- requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
-
- for (var i = 0; i < requestHeaders.length; i += 2)
- this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
- },
-
- onStateChange: function() {
- var readyState = this.transport.readyState;
- if (readyState != 1)
- this.respondToReadyState(this.transport.readyState);
- },
-
- header: function(name) {
- try {
- return this.transport.getResponseHeader(name);
- } catch (e) {}
- },
-
- evalJSON: function() {
- try {
- return eval(this.header('X-JSON'));
- } catch (e) {}
- },
-
- evalResponse: function() {
- try {
- return eval(this.transport.responseText);
- } catch (e) {
- this.dispatchException(e);
- }
- },
-
- respondToReadyState: function(readyState) {
- var event = Ajax.Request.Events[readyState];
- var transport = this.transport, json = this.evalJSON();
-
- if (event == 'Complete') {
- try {
- (this.options['on' + this.transport.status]
- || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
- || Prototype.emptyFunction)(transport, json);
- } catch (e) {
- this.dispatchException(e);
- }
-
- if ((this.header('Content-type') || '').match(/^text\/javascript/i))
- this.evalResponse();
- }
-
- try {
- (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
- Ajax.Responders.dispatch('on' + event, this, transport, json);
- } catch (e) {
- this.dispatchException(e);
- }
-
- /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
- if (event == 'Complete')
- this.transport.onreadystatechange = Prototype.emptyFunction;
- },
-
- dispatchException: function(exception) {
- (this.options.onException || Prototype.emptyFunction)(this, exception);
- Ajax.Responders.dispatch('onException', this, exception);
- }
-});
-
-Ajax.Updater = Class.create();
-
-Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
- initialize: function(container, url, options) {
- this.containers = {
- success: container.success ? $(container.success) : $(container),
- failure: container.failure ? $(container.failure) :
- (container.success ? null : $(container))
- }
-
- this.transport = Ajax.getTransport();
- this.setOptions(options);
-
- var onComplete = this.options.onComplete || Prototype.emptyFunction;
- this.options.onComplete = (function(transport, object) {
- this.updateContent();
- onComplete(transport, object);
- }).bind(this);
-
- this.request(url);
- },
-
- updateContent: function() {
- var receiver = this.responseIsSuccess() ?
- this.containers.success : this.containers.failure;
- var response = this.transport.responseText;
-
- if (!this.options.evalScripts)
- response = response.stripScripts();
-
- if (receiver) {
- if (this.options.insertion) {
- new this.options.insertion(receiver, response);
- } else {
- Element.update(receiver, response);
- }
- }
-
- if (this.responseIsSuccess()) {
- if (this.onComplete)
- setTimeout(this.onComplete.bind(this), 10);
- }
- }
-});
-
-Ajax.PeriodicalUpdater = Class.create();
-Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
- initialize: function(container, url, options) {
- this.setOptions(options);
- this.onComplete = this.options.onComplete;
-
- this.frequency = (this.options.frequency || 2);
- this.decay = (this.options.decay || 1);
-
- this.updater = {};
- this.container = container;
- this.url = url;
-
- this.start();
- },
-
- start: function() {
- this.options.onComplete = this.updateComplete.bind(this);
- this.onTimerEvent();
- },
-
- stop: function() {
- this.updater.onComplete = undefined;
- clearTimeout(this.timer);
- (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
- },
-
- updateComplete: function(request) {
- if (this.options.decay) {
- this.decay = (request.responseText == this.lastText ?
- this.decay * this.options.decay : 1);
-
- this.lastText = request.responseText;
- }
- this.timer = setTimeout(this.onTimerEvent.bind(this),
- this.decay * this.frequency * 1000);
- },
-
- onTimerEvent: function() {
- this.updater = new Ajax.Updater(this.container, this.url, this.options);
- }
-});
-document.getElementsByClassName = function(className, parentElement) {
- var children = ($(parentElement) || document.body).getElementsByTagName('*');
- return $A(children).inject([], function(elements, child) {
- if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
- elements.push(child);
- return elements;
- });
-}
-
-/*--------------------------------------------------------------------------*/
-
-if (!window.Element) {
- var Element = new Object();
-}
-
-Object.extend(Element, {
- visible: function(element) {
- return $(element).style.display != 'none';
- },
-
- toggle: function() {
- for (var i = 0; i < arguments.length; i++) {
- var element = $(arguments[i]);
- Element[Element.visible(element) ? 'hide' : 'show'](element);
- }
- },
-
- hide: function() {
- for (var i = 0; i < arguments.length; i++) {
- var element = $(arguments[i]);
- element.style.display = 'none';
- }
- },
-
- show: function() {
- for (var i = 0; i < arguments.length; i++) {
- var element = $(arguments[i]);
- element.style.display = '';
- }
- },
-
- remove: function(element) {
- element = $(element);
- element.parentNode.removeChild(element);
- },
-
- update: function(element, html) {
- $(element).innerHTML = html.stripScripts();
- setTimeout(function() {html.evalScripts()}, 10);
- },
-
- getHeight: function(element) {
- element = $(element);
- return element.offsetHeight;
- },
-
- classNames: function(element) {
- return new Element.ClassNames(element);
- },
-
- hasClassName: function(element, className) {
- if (!(element = $(element))) return;
- return Element.classNames(element).include(className);
- },
-
- addClassName: function(element, className) {
- if (!(element = $(element))) return;
- return Element.classNames(element).add(className);
- },
-
- removeClassName: function(element, className) {
- if (!(element = $(element))) return;
- return Element.classNames(element).remove(className);
- },
-
- // removes whitespace-only text node children
- cleanWhitespace: function(element) {
- element = $(element);
- for (var i = 0; i < element.childNodes.length; i++) {
- var node = element.childNodes[i];
- if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
- Element.remove(node);
- }
- },
-
- empty: function(element) {
- return $(element).innerHTML.match(/^\s*$/);
- },
-
- scrollTo: function(element) {
- element = $(element);
- var x = element.x ? element.x : element.offsetLeft,
- y = element.y ? element.y : element.offsetTop;
- window.scrollTo(x, y);
- },
-
- getStyle: function(element, style) {
- element = $(element);
- var value = element.style[style.camelize()];
- if (!value) {
- if (document.defaultView && document.defaultView.getComputedStyle) {
- var css = document.defaultView.getComputedStyle(element, null);
- value = css ? css.getPropertyValue(style) : null;
- } else if (element.currentStyle) {
- value = element.currentStyle[style.camelize()];
- }
- }
-
- if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
- if (Element.getStyle(element, 'position') == 'static') value = 'auto';
-
- return value == 'auto' ? null : value;
- },
-
- setStyle: function(element, style) {
- element = $(element);
- for (name in style)
- element.style[name.camelize()] = style[name];
- },
-
- getDimensions: function(element) {
- element = $(element);
- if (Element.getStyle(element, 'display') != 'none')
- return {width: element.offsetWidth, height: element.offsetHeight};
-
- // All *Width and *Height properties give 0 on elements with display none,
- // so enable the element temporarily
- var els = element.style;
- var originalVisibility = els.visibility;
- var originalPosition = els.position;
- els.visibility = 'hidden';
- els.position = 'absolute';
- els.display = '';
- var originalWidth = element.clientWidth;
- var originalHeight = element.clientHeight;
- els.display = 'none';
- els.position = originalPosition;
- els.visibility = originalVisibility;
- return {width: originalWidth, height: originalHeight};
- },
-
- makePositioned: function(element) {
- element = $(element);
- var pos = Element.getStyle(element, 'position');
- if (pos == 'static' || !pos) {
- element._madePositioned = true;
- element.style.position = 'relative';
- // Opera returns the offset relative to the positioning context, when an
- // element is position relative but top and left have not been defined
- if (window.opera) {
- element.style.top = 0;
- element.style.left = 0;
- }
- }
- },
-
- undoPositioned: function(element) {
- element = $(element);
- if (element._madePositioned) {
- element._madePositioned = undefined;
- element.style.position =
- element.style.top =
- element.style.left =
- element.style.bottom =
- element.style.right = '';
- }
- },
-
- makeClipping: function(element) {
- element = $(element);
- if (element._overflow) return;
- element._overflow = element.style.overflow;
- if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
- element.style.overflow = 'hidden';
- },
-
- undoClipping: function(element) {
- element = $(element);
- if (element._overflow) return;
- element.style.overflow = element._overflow;
- element._overflow = undefined;
- }
-});
-
-var Toggle = new Object();
-Toggle.display = Element.toggle;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.Insertion = function(adjacency) {
- this.adjacency = adjacency;
-}
-
-Abstract.Insertion.prototype = {
- initialize: function(element, content) {
- this.element = $(element);
- this.content = content.stripScripts();
-
- if (this.adjacency && this.element.insertAdjacentHTML) {
- try {
- this.element.insertAdjacentHTML(this.adjacency, this.content);
- } catch (e) {
- if (this.element.tagName.toLowerCase() == 'tbody') {
- this.insertContent(this.contentFromAnonymousTable());
- } else {
- throw e;
- }
- }
- } else {
- this.range = this.element.ownerDocument.createRange();
- if (this.initializeRange) this.initializeRange();
- this.insertContent([this.range.createContextualFragment(this.content)]);
- }
-
- setTimeout(function() {content.evalScripts()}, 10);
- },
-
- contentFromAnonymousTable: function() {
- var div = document.createElement('div');
- div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
- return $A(div.childNodes[0].childNodes[0].childNodes);
- }
-}
-
-var Insertion = new Object();
-
-Insertion.Before = Class.create();
-Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
- initializeRange: function() {
- this.range.setStartBefore(this.element);
- },
-
- insertContent: function(fragments) {
- fragments.each((function(fragment) {
- this.element.parentNode.insertBefore(fragment, this.element);
- }).bind(this));
- }
-});
-
-Insertion.Top = Class.create();
-Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
- initializeRange: function() {
- this.range.selectNodeContents(this.element);
- this.range.collapse(true);
- },
-
- insertContent: function(fragments) {
- fragments.reverse(false).each((function(fragment) {
- this.element.insertBefore(fragment, this.element.firstChild);
- }).bind(this));
- }
-});
-
-Insertion.Bottom = Class.create();
-Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
- initializeRange: function() {
- this.range.selectNodeContents(this.element);
- this.range.collapse(this.element);
- },
-
- insertContent: function(fragments) {
- fragments.each((function(fragment) {
- this.element.appendChild(fragment);
- }).bind(this));
- }
-});
-
-Insertion.After = Class.create();
-Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
- initializeRange: function() {
- this.range.setStartAfter(this.element);
- },
-
- insertContent: function(fragments) {
- fragments.each((function(fragment) {
- this.element.parentNode.insertBefore(fragment,
- this.element.nextSibling);
- }).bind(this));
- }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Element.ClassNames = Class.create();
-Element.ClassNames.prototype = {
- initialize: function(element) {
- this.element = $(element);
- },
-
- _each: function(iterator) {
- this.element.className.split(/\s+/).select(function(name) {
- return name.length > 0;
- })._each(iterator);
- },
-
- set: function(className) {
- this.element.className = className;
- },
-
- add: function(classNameToAdd) {
- if (this.include(classNameToAdd)) return;
- this.set(this.toArray().concat(classNameToAdd).join(' '));
- },
-
- remove: function(classNameToRemove) {
- if (!this.include(classNameToRemove)) return;
- this.set(this.select(function(className) {
- return className != classNameToRemove;
- }).join(' '));
- },
-
- toString: function() {
- return this.toArray().join(' ');
- }
-}
-
-Object.extend(Element.ClassNames.prototype, Enumerable);
-var Field = {
- clear: function() {
- for (var i = 0; i < arguments.length; i++)
- $(arguments[i]).value = '';
- },
-
- focus: function(element) {
- $(element).focus();
- },
-
- present: function() {
- for (var i = 0; i < arguments.length; i++)
- if ($(arguments[i]).value == '') return false;
- return true;
- },
-
- select: function(element) {
- $(element).select();
- },
-
- activate: function(element) {
- element = $(element);
- element.focus();
- if (element.select)
- element.select();
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var Form = {
- serialize: function(form) {
- var elements = Form.getElements($(form));
- var queryComponents = new Array();
-
- for (var i = 0; i < elements.length; i++) {
- var queryComponent = Form.Element.serialize(elements[i]);
- if (queryComponent)
- queryComponents.push(queryComponent);
- }
-
- return queryComponents.join('&');
- },
-
- getElements: function(form) {
- form = $(form);
- var elements = new Array();
-
- for (tagName in Form.Element.Serializers) {
- var tagElements = form.getElementsByTagName(tagName);
- for (var j = 0; j < tagElements.length; j++)
- elements.push(tagElements[j]);
- }
- return elements;
- },
-
- getInputs: function(form, typeName, name) {
- form = $(form);
- var inputs = form.getElementsByTagName('input');
-
- if (!typeName && !name)
- return inputs;
-
- var matchingInputs = new Array();
- for (var i = 0; i < inputs.length; i++) {
- var input = inputs[i];
- if ((typeName && input.type != typeName) ||
- (name && input.name != name))
- continue;
- matchingInputs.push(input);
- }
-
- return matchingInputs;
- },
-
- disable: function(form) {
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
- element.blur();
- element.disabled = 'true';
- }
- },
-
- enable: function(form) {
- var elements = Form.getElements(form);
- for (var i = 0; i < elements.length; i++) {
- var element = elements[i];
- element.disabled = '';
- }
- },
-
- findFirstElement: function(form) {
- return Form.getElements(form).find(function(element) {
- return element.type != 'hidden' && !element.disabled &&
- ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
- });
- },
-
- focusFirstElement: function(form) {
- Field.activate(Form.findFirstElement(form));
- },
-
- reset: function(form) {
- $(form).reset();
- }
-}
-
-Form.Element = {
- serialize: function(element) {
- element = $(element);
- var method = element.tagName.toLowerCase();
- var parameter = Form.Element.Serializers[method](element);
-
- if (parameter) {
- var key = encodeURIComponent(parameter[0]);
- if (key.length == 0) return;
-
- if (parameter[1].constructor != Array)
- parameter[1] = [parameter[1]];
-
- return parameter[1].map(function(value) {
- return key + '=' + encodeURIComponent(value);
- }).join('&');
- }
- },
-
- getValue: function(element) {
- element = $(element);
- var method = element.tagName.toLowerCase();
- var parameter = Form.Element.Serializers[method](element);
-
- if (parameter)
- return parameter[1];
- }
-}
-
-Form.Element.Serializers = {
- input: function(element) {
- switch (element.type.toLowerCase()) {
- case 'submit':
- case 'hidden':
- case 'password':
- case 'text':
- return Form.Element.Serializers.textarea(element);
- case 'checkbox':
- case 'radio':
- return Form.Element.Serializers.inputSelector(element);
- }
- return false;
- },
-
- inputSelector: function(element) {
- if (element.checked)
- return [element.name, element.value];
- },
-
- textarea: function(element) {
- return [element.name, element.value];
- },
-
- select: function(element) {
- return Form.Element.Serializers[element.type == 'select-one' ?
- 'selectOne' : 'selectMany'](element);
- },
-
- selectOne: function(element) {
- var value = '', opt, index = element.selectedIndex;
- if (index >= 0) {
- opt = element.options[index];
- value = opt.value;
- if (!value && !('value' in opt))
- value = opt.text;
- }
- return [element.name, value];
- },
-
- selectMany: function(element) {
- var value = new Array();
- for (var i = 0; i < element.length; i++) {
- var opt = element.options[i];
- if (opt.selected) {
- var optValue = opt.value;
- if (!optValue && !('value' in opt))
- optValue = opt.text;
- value.push(optValue);
- }
- }
- return [element.name, value];
- }
-}
-
-/*--------------------------------------------------------------------------*/
-
-var $F = Form.Element.getValue;
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.TimedObserver = function() {}
-Abstract.TimedObserver.prototype = {
- initialize: function(element, frequency, callback) {
- this.frequency = frequency;
- this.element = $(element);
- this.callback = callback;
-
- this.lastValue = this.getValue();
- this.registerCallback();
- },
-
- registerCallback: function() {
- setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
- },
-
- onTimerEvent: function() {
- var value = this.getValue();
- if (this.lastValue != value) {
- this.callback(this.element, value);
- this.lastValue = value;
- }
- }
-}
-
-Form.Element.Observer = Class.create();
-Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
- getValue: function() {
- return Form.Element.getValue(this.element);
- }
-});
-
-Form.Observer = Class.create();
-Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
- getValue: function() {
- return Form.serialize(this.element);
- }
-});
-
-/*--------------------------------------------------------------------------*/
-
-Abstract.EventObserver = function() {}
-Abstract.EventObserver.prototype = {
- initialize: function(element, callback) {
- this.element = $(element);
- this.callback = callback;
-
- this.lastValue = this.getValue();
- if (this.element.tagName.toLowerCase() == 'form')
- this.registerFormCallbacks();
- else
- this.registerCallback(this.element);
- },
-
- onElementEvent: function() {
- var value = this.getValue();
- if (this.lastValue != value) {
- this.callback(this.element, value);
- this.lastValue = value;
- }
- },
-
- registerFormCallbacks: function() {
- var elements = Form.getElements(this.element);
- for (var i = 0; i < elements.length; i++)
- this.registerCallback(elements[i]);
- },
-
- registerCallback: function(element) {
- if (element.type) {
- switch (element.type.toLowerCase()) {
- case 'checkbox':
- case 'radio':
- Event.observe(element, 'click', this.onElementEvent.bind(this));
- break;
- case 'password':
- case 'text':
- case 'textarea':
- case 'select-one':
- case 'select-multiple':
- Event.observe(element, 'change', this.onElementEvent.bind(this));
- break;
- }
- }
- }
-}
-
-Form.Element.EventObserver = Class.create();
-Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
- getValue: function() {
- return Form.Element.getValue(this.element);
- }
-});
-
-Form.EventObserver = Class.create();
-Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
- getValue: function() {
- return Form.serialize(this.element);
- }
-});
-if (!window.Event) {
- var Event = new Object();
-}
-
-Object.extend(Event, {
- KEY_BACKSPACE: 8,
- KEY_TAB: 9,
- KEY_RETURN: 13,
- KEY_ESC: 27,
- KEY_LEFT: 37,
- KEY_UP: 38,
- KEY_RIGHT: 39,
- KEY_DOWN: 40,
- KEY_DELETE: 46,
-
- element: function(event) {
- return event.target || event.srcElement;
- },
-
- isLeftClick: function(event) {
- return (((event.which) && (event.which == 1)) ||
- ((event.button) && (event.button == 1)));
- },
-
- pointerX: function(event) {
- return event.pageX || (event.clientX +
- (document.documentElement.scrollLeft || document.body.scrollLeft));
- },
-
- pointerY: function(event) {
- return event.pageY || (event.clientY +
- (document.documentElement.scrollTop || document.body.scrollTop));
- },
-
- stop: function(event) {
- if (event.preventDefault) {
- event.preventDefault();
- event.stopPropagation();
- } else {
- event.returnValue = false;
- event.cancelBubble = true;
- }
- },
-
- // find the first node with the given tagName, starting from the
- // node the event was triggered on; traverses the DOM upwards
- findElement: function(event, tagName) {
- var element = Event.element(event);
- while (element.parentNode && (!element.tagName ||
- (element.tagName.toUpperCase() != tagName.toUpperCase())))
- element = element.parentNode;
- return element;
- },
-
- observers: false,
-
- _observeAndCache: function(element, name, observer, useCapture) {
- if (!this.observers) this.observers = [];
- if (element.addEventListener) {
- this.observers.push([element, name, observer, useCapture]);
- element.addEventListener(name, observer, useCapture);
- } else if (element.attachEvent) {
- this.observers.push([element, name, observer, useCapture]);
- element.attachEvent('on' + name, observer);
- }
- },
-
- unloadCache: function() {
- if (!Event.observers) return;
- for (var i = 0; i < Event.observers.length; i++) {
- Event.stopObserving.apply(this, Event.observers[i]);
- Event.observers[i][0] = null;
- }
- Event.observers = false;
- },
-
- observe: function(element, name, observer, useCapture) {
- var element = $(element);
- useCapture = useCapture || false;
-
- if (name == 'keypress' &&
- (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
- || element.attachEvent))
- name = 'keydown';
-
- this._observeAndCache(element, name, observer, useCapture);
- },
-
- stopObserving: function(element, name, observer, useCapture) {
- var element = $(element);
- useCapture = useCapture || false;
-
- if (name == 'keypress' &&
- (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
- || element.detachEvent))
- name = 'keydown';
-
- if (element.removeEventListener) {
- element.removeEventListener(name, observer, useCapture);
- } else if (element.detachEvent) {
- element.detachEvent('on' + name, observer);
- }
- }
-});
-
-/* prevent memory leaks in IE */
-Event.observe(window, 'unload', Event.unloadCache, false);
-var Position = {
- // set to true if needed, warning: firefox performance problems
- // NOT neeeded for page scrolling, only if draggable contained in
- // scrollable elements
- includeScrollOffsets: false,
-
- // must be called before calling withinIncludingScrolloffset, every time the
- // page is scrolled
- prepare: function() {
- this.deltaX = window.pageXOffset
- || document.documentElement.scrollLeft
- || document.body.scrollLeft
- || 0;
- this.deltaY = window.pageYOffset
- || document.documentElement.scrollTop
- || document.body.scrollTop
- || 0;
- },
-
- realOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.scrollTop || 0;
- valueL += element.scrollLeft || 0;
- element = element.parentNode;
- } while (element);
- return [valueL, valueT];
- },
-
- cumulativeOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- element = element.offsetParent;
- } while (element);
- return [valueL, valueT];
- },
-
- positionedOffset: function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- element = element.offsetParent;
- if (element) {
- p = Element.getStyle(element, 'position');
- if (p == 'relative' || p == 'absolute') break;
- }
- } while (element);
- return [valueL, valueT];
- },
-
- offsetParent: function(element) {
- if (element.offsetParent) return element.offsetParent;
- if (element == document.body) return element;
-
- while ((element = element.parentNode) && element != document.body)
- if (Element.getStyle(element, 'position') != 'static')
- return element;
-
- return document.body;
- },
-
- // caches x/y coordinate pair to use with overlap
- within: function(element, x, y) {
- if (this.includeScrollOffsets)
- return this.withinIncludingScrolloffsets(element, x, y);
- this.xcomp = x;
- this.ycomp = y;
- this.offset = this.cumulativeOffset(element);
-
- return (y >= this.offset[1] &&
- y < this.offset[1] + element.offsetHeight &&
- x >= this.offset[0] &&
- x < this.offset[0] + element.offsetWidth);
- },
-
- withinIncludingScrolloffsets: function(element, x, y) {
- var offsetcache = this.realOffset(element);
-
- this.xcomp = x + offsetcache[0] - this.deltaX;
- this.ycomp = y + offsetcache[1] - this.deltaY;
- this.offset = this.cumulativeOffset(element);
-
- return (this.ycomp >= this.offset[1] &&
- this.ycomp < this.offset[1] + element.offsetHeight &&
- this.xcomp >= this.offset[0] &&
- this.xcomp < this.offset[0] + element.offsetWidth);
- },
-
- // within must be called directly before
- overlap: function(mode, element) {
- if (!mode) return 0;
- if (mode == 'vertical')
- return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
- element.offsetHeight;
- if (mode == 'horizontal')
- return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
- element.offsetWidth;
- },
-
- clone: function(source, target) {
- source = $(source);
- target = $(target);
- target.style.position = 'absolute';
- var offsets = this.cumulativeOffset(source);
- target.style.top = offsets[1] + 'px';
- target.style.left = offsets[0] + 'px';
- target.style.width = source.offsetWidth + 'px';
- target.style.height = source.offsetHeight + 'px';
- },
-
- page: function(forElement) {
- var valueT = 0, valueL = 0;
-
- var element = forElement;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
-
- // Safari fix
- if (element.offsetParent==document.body)
- if (Element.getStyle(element,'position')=='absolute') break;
-
- } while (element = element.offsetParent);
-
- element = forElement;
- do {
- valueT -= element.scrollTop || 0;
- valueL -= element.scrollLeft || 0;
- } while (element = element.parentNode);
-
- return [valueL, valueT];
- },
-
- clone: function(source, target) {
- var options = Object.extend({
- setLeft: true,
- setTop: true,
- setWidth: true,
- setHeight: true,
- offsetTop: 0,
- offsetLeft: 0
- }, arguments[2] || {})
-
- // find page position of source
- source = $(source);
- var p = Position.page(source);
-
- // find coordinate system to use
- target = $(target);
- var delta = [0, 0];
- var parent = null;
- // delta [0,0] will do fine with position: fixed elements,
- // position:absolute needs offsetParent deltas
- if (Element.getStyle(target,'position') == 'absolute') {
- parent = Position.offsetParent(target);
- delta = Position.page(parent);
- }
-
- // correct by body offsets (fixes Safari)
- if (parent == document.body) {
- delta[0] -= document.body.offsetLeft;
- delta[1] -= document.body.offsetTop;
- }
-
- // set position
- if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
- if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
- if(options.setWidth) target.style.width = source.offsetWidth + 'px';
- if(options.setHeight) target.style.height = source.offsetHeight + 'px';
- },
-
- absolutize: function(element) {
- element = $(element);
- if (element.style.position == 'absolute') return;
- Position.prepare();
-
- var offsets = Position.positionedOffset(element);
- var top = offsets[1];
- var left = offsets[0];
- var width = element.clientWidth;
- var height = element.clientHeight;
-
- element._originalLeft = left - parseFloat(element.style.left || 0);
- element._originalTop = top - parseFloat(element.style.top || 0);
- element._originalWidth = element.style.width;
- element._originalHeight = element.style.height;
-
- element.style.position = 'absolute';
- element.style.top = top + 'px';;
- element.style.left = left + 'px';;
- element.style.width = width + 'px';;
- element.style.height = height + 'px';;
- },
-
- relativize: function(element) {
- element = $(element);
- if (element.style.position == 'relative') return;
- Position.prepare();
-
- element.style.position = 'relative';
- var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
- var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
-
- element.style.top = top + 'px';
- element.style.left = left + 'px';
- element.style.height = element._originalHeight;
- element.style.width = element._originalWidth;
- }
-}
-
-// Safari returns margins on body which is incorrect if the child is absolutely
-// positioned. For performance reasons, redefine Position.cumulativeOffset for
-// KHTML/WebKit only.
-if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
- Position.cumulativeOffset = function(element) {
- var valueT = 0, valueL = 0;
- do {
- valueT += element.offsetTop || 0;
- valueL += element.offsetLeft || 0;
- if (element.offsetParent == document.body)
- if (Element.getStyle(element, 'position') == 'absolute') break;
-
- element = element.offsetParent;
- } while (element);
-
- return [valueL, valueT];
- }
-}
\ No newline at end of file
+++ /dev/null
-#!/bin/sh
-# set_network.sh
-#
-# CGI to set network parameters of an IP0X.
-
-cat <<EOF
-<html>
-<head>
-<title>set_network.sh</title>
-<meta http-equiv="REFRESH" content="0;url=network.sh">
-<body>
-Please wait a few seconds.....
-</body>
-</head>
-</html>
-EOF
-
-dhcp=`echo "$QUERY_STRING" | grep -oe "dhcp=[^&?]*" | sed -n "s/dhcp=//p"`
-ipaddress=`echo "$QUERY_STRING" | grep -oe "ipaddress=[^&?]*" | sed -n "s/ipaddress=//p"`
-netmask=`echo "$QUERY_STRING" | grep -oe "netmask=[^&?]*" | sed -n "s/netmask=//p"`
-gateway=`echo "$QUERY_STRING" | grep -oe "gateway=[^&?]*" | sed -n "s/gateway=//p"`
-dns=`echo "$QUERY_STRING" | grep -oe "dns=[^&?]*" | sed -n "s/dns=//p"`
-backdoor=`echo "$QUERY_STRING" | grep -oe "backdoor=[^&?]*" | sed -n "s/backdoor=//p"`
-
-if [ $dhcp == "yes" ]; then
-
- # DHCP
-
- if [ -f /etc/rc.d/S10network-static ]; then
- /etc/init.d/network-static disable
- /etc/init.d/network-static stop
- /etc/init.d/network enable
- /etc/init.d/network start
- else
- # if already running restart service
- /etc/init.d/network stop
- /etc/init.d/network start
- fi
-fi
-
-if [ $dhcp == "no" ]; then
-
- # Static IP
-
- if [ -f /etc/rc.d/S10network ]; then
- /etc/init.d/network stop
- /etc/init.d/network disable
- /etc/init.d/network-static enable
- fi
-
- sed -i "s/DHCPD=.*/DHCPD=no/g" /etc/init.d/network-static
- sed -i "s/IPADDRESS=.*/IPADDRESS=\"$ipaddress\"/g" /etc/init.d/network-static
- sed -i "s/NETMASK=.*/NETMASK=\"$netmask\"/g" /etc/init.d/network-static
- sed -i "s/GATEWAY=.*/GATEWAY=\"$gateway\"/g" /etc/init.d/network-static
- sed -i "s/DNS=.*/DNS=\"$dns\"/g" /etc/init.d/network-static
- /etc/init.d/network-static stop
- /etc/init.d/network-static start
-fi
-
-if [ -f /etc/rc.d/S05network-backdoor ]; then
- sed -i "s/IPADDRESS=.*/IPADDRESS=\"$backdoor\"/g" /etc/init.d/network-backdoor
- /etc/init.d/network-backdoor stop
- /etc/init.d/network-backdoor start
-fi
+++ /dev/null
-#!/bin/sh -x
-# set_ring.sh
-# David Rowe 4 Jan 2010
-# CGI to set which extensions ring on uncoming calls
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-# extract extensions to ring and reload extensions.conf
-
-a=`echo "$QUERY_STRING" | sed -n "s/=on*//pg" | sed -n 's,_,/,pg'`
-
-# escape & if present
-echo "$a" | grep "&" >> /dev/null
-if [ $? -eq 0 ]; then
- a=`echo $a | sed -n "s/&/\\\\&/pg"`
-fi
-
-sed -i "s_s,1,Dial(.*) ;; mini-asterisk_s,1,Dial($a) ;; mini-asterisk_" /etc/asterisk/extensions.conf
-asterisk -rx "dialplan reload" 2>/dev/null 1 > /dev/null
-
-# bounce us back to Phones screen
-
-cat <<EOF
-<html>
-<head>
-<title>Mini Asterisk - Set Ring</title>
-<meta http-equiv="REFRESH" content="0;url=phones.sh">
-<body>
-Please wait a few seconds.....
-EOF
-#echo $QUERY_STRING "<br>"
-#echo "$QUERY_STRING" | sed -n "s/=on*//pg" | sed -n 's,_,/,pg'
-#echo "<br>"
-#echo $a
-
-cat <<EOF
-</body>
-</head>
-</html>
-EOF
-
+++ /dev/null
-#!/usr/bin/perl
-# set_voiplines.pl
-# David Rowe 12 Jan 2010
-#
-# Replaces fields in sip.conf, outputs new sip.conf contents to stdout
-
-$user = $ARGV[0];
-$pass = $ARGV[1];
-$host = $ARGV[2];
-$stanza_new = $ARGV[3];
-
-# We need to slurp up the mini asterisk provider and spit them
-# back out. All must be commented out except for the one that
-# is selected. Hopefully non-mini asterisk content of sip.conf
-# won't be affected.
-
-open SIP, "/etc/asterisk/sip.conf";
-$provider = "";
-while (<SIP>) {
-
- # start of any new stanza switches off parsing. It may get
- # switched back on below if it contains mini-asterisk
- # keyword. This allows non-mini asterisk SIP stanzas to be
- # included in sip.conf
-
- if (/\[/) {
- $stanza = "";
- }
-
- # look for commented or uncommented mini asterisk provider stanza
-
- if (/\[(.*)\] .* mini-asterisk/) {
- $stanza = $1;
- }
-
- if ($stanza eq "") {
- # we are not in an mini-asterisk provider stanza
-
- if (/;*register => (\S*)@(\S*).*;.*(mini-asterisk.*)/) {
- # an mini-asterisk register line
-
- #print "XX stanza_new='$stanza_new' '$1' '$2' '$3'\n";
-
- if ($2 eq $stanza_new) {
- print "register => $user\@$stanza_new; $3\n";
- }
- else {
- print ";register => $1\@$2 ; $3\n";
- }
- }
- else {
- # OK so this is a regular sip.conf line, just echo to stdout
- print $_;
- }
- }
- else {
- # OK, we are in an mini-asterisk stanza
-
- # strip off any leading ";"
-
- $_ =~ s/^\;//;
-
- if ($stanza eq $stanza_new) {
-
- # this stanza should be uncommented
-
- if (/^user=/) {
- print "user=$user\n";
- }
- if (/^username=/) {
- print "username=$user\n";
- }
- elsif (/^fromuser=/) {
- print "fromuser=$user\n";
- }
- elsif (/^secret=/) {
- print "secret=$pass\n";
- }
- elsif (/^host=/) {
- print "host=$host\n";
- }
- else {
- print $_;
- }
- }
- else {
- # comment out unused mini-asterisk stanzas
- print ";$_";
- }
- }
-
-}
-close SIP;
-
+++ /dev/null
-#!/bin/sh
-# set_voipline.sh
-# # David Rowe 12 Jan 2010
-#
-# CGI to set voip line parameters in sip.conf.
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-user=`echo "$QUERY_STRING" | grep -oe "user=[^&?]*" | sed -n "s/user=//p"`
-pass=`echo "$QUERY_STRING" | grep -oe "pass=[^&?]*" | sed -n "s/pass=//p"`
-host=`echo "$QUERY_STRING" | grep -oe "host=[^&?]*" | sed -n "s/host=//p"`
-stanza=`echo "$QUERY_STRING" | grep -oe "stanza=[^&?]*" | sed -n "s/stanza=//p"`
-
-# create new sip.conf with selected provider uncommented
-
-echo "set_voiplines.sh" $user $pass $host $stanza >> /tmp/log.txt
-./set_voiplines.pl $user $pass $host $stanza > /etc/asterisk/sip.conf.new
-mv /etc/asterisk/sip.conf /etc/asterisk/sip.conf.bak
-mv /etc/asterisk/sip.conf.new /etc/asterisk/sip.conf
-
-# get asterisk to load changes
-
-asterisk -rx "sip reload" 2>/dev/null 1 > /dev/null
-
-cat <<EOF
-<html>
-<head>
-<title>set_voiplines.sh</title>
-<meta http-equiv="REFRESH" content="0;url=voiplines.sh">
-<body>
-Please wait a few seconds.....
-</body>
-</head>
-</html>
-EOF
-
+++ /dev/null
-.tip {font:12px/14px
-Arial,Helvetica,sans-serif; border:solid 1px
-#666666; width:270px; padding:1px;
-position:absolute; z-index:100;
-visibility:hidden; color:#333333; top:20px;
-left:90px; background-color:#ffffcc;
-layer-background-color:#ffffcc;}
+++ /dev/null
-// Extended Tooltip Javascript
-// copyright 9th August 2002, 3rd July 2005, 24th August 2008
-// by Stephen Chapman, Felgall Pty Ltd
-
-// permission is granted to use this javascript provided that the below code is not altered
-function pw() {return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth}; function mouseX(evt) {return evt.clientX ? evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) : evt.pageX;} function mouseY(evt) {return evt.clientY ? evt.clientY + (document.documentElement.scrollTop || document.body.scrollTop) : evt.pageY} function popUp(evt,oi) {if (document.getElementById) {var wp = pw(); dm = document.getElementById(oi); ds = dm.style; st = ds.visibility; if (dm.offsetWidth) ew = dm.offsetWidth; else if (dm.clip.width) ew = dm.clip.width; if (st == "visible" || st == "show") { ds.visibility = "hidden"; } else {tv = mouseY(evt) + 20; lv = mouseX(evt) - (ew/4); if (lv < 2) lv = 2; else if (lv + ew > wp) lv -= ew/2; lv += 'px';tv += 'px'; ds.left = lv; ds.top = tv; ds.visibility = "visible";}}}
-
+++ /dev/null
-<div id="network_internet" class="tip">
- A tick means your phone system can reach the Internet. You need the Internet for VOIP calls
- and software upgrades.
- If you have a problem reaching the Internet check your Network settings, in
- particular Gateway and DNS.</div>
-
-<div id="network_backdoor" class="tip">
- Emergency backdoor IP. Useful if you get locked out of the main network connection, for
- example due to DHCP problems on your network or a configuration mistake.
- Write this number down somewhere!</div>
-
-<div id="phone_reception" class="tip">
- If ticked this phone will ring when some one
- calls the phone system from an outside Analog
- or VOIP Line. More than one phone can be
- ticked. You can answer a call on another
- ringing phone by dialling *8 on your phone -
- see FAQ for details.</div>
-
-<div id="phone_anphone" class="tip">
- Analog Phone: Normal telephone plugged into a port on your phone system.
- </div>
-<div id="phone_ipphone" class="tip">
- IP Phone plugged into your network.
- </div>
-<div id="phone_line" class="tip">
- Analog Phone Line: Analog telephone line plugged into a port on your phone system.
- </div>
-<div id="phone_voipline" class="tip">
- VOIP Phone Line: Make and receive phone calls over the Internet.
- </div>
-
-<div id="phone_system" class="tip">
- Important information about your Phone System.</div>
-
-<div id="phone_ipaddress" class="tip">
- The address of your Phone System
- on your network. Use this address to connect
- IP Phones to your Phone System. </div>
-
-<div id="phone_phones" class="tip">
- List of phones connected to your Phone
- System. You can connect Analog or IP Phones
- to your system. When IP Phones are
- configured correctly, they appear on this
- list. If an IP phone is not configured
- correctly, it will not appear on this list.
- Analog phones require hardware to be
- installed in your Phone system.</div>
-
-<div id="phone_lines" class="tip">
- List of phone lines available. Phone lines
- are used to make and receive outside calls.
- You can use regular Analog phone lines or
- VOIP. VOIP phone lines require an account
- with an Internet Telephone Service Provider.
- Analog phone lines require hardware to be
- installed in your Phone System.</div>
-
-<div id="phone_ext" class="tip">
- Dial this number to call this phone</div>
-
-<div id="phone_port_phone" class="tip">
- Port (socket) on the rear of your Phone System. Plug the phone into this Port.</div>
-
-<div id="phone_port_line" class="tip">
- Port (socket) on the rear of your Phone
- System. Plug the phone line into this
- Port.</div>
-
-<div id="phone_line_prefix" class="tip">
- Dial 0 for an Analog outside line. For example to call 5551234 dial 05551234</div>
-
-<div id="phone_ipphone_ip" class="tip">
- IP Address of this phone on your network</div>
-
-<div id="phone_voipline_ip" class="tip">
- IP Address of the VOIP Internet Telephone Service Provider</div>
-
-<div id="phone_voipline_prefix" class="tip">
- Dial 1 for a VOIP outside line. For example to call 5551234 dial 15551234</div>
-
-<div id="phone_addipphone" class="tip">
- Instructions and help on adding a new IP phone</div>
-
-<div id="phone_addvoipline" class="tip">
- Instructions and help on VOIP Line set up</div>
-
-<div id="ipphones_ipphones" class="tip">
- List of possible IP phones. For a new phone
- choose any Available number. Refresh this
- page to update</div>
-
-<div id="ipphones_connected" class="tip">
- The IP phone is connected to your phone system and ready to use</div>
-
-<div id="ipphones_notconnected" class="tip">
- No IP phone is connected. Either no IP phone
- is present, or the IP phone has not been set
- up.</div>
-
-<div id="voiplines_voiplines" class="tip">
- A VOIP line allows you to make and receive
- phones calls over the Internet. Normally a
- VOIP line is provided by an Internet Telephony
- Service Provider (ITSP). They will give you
- an account, which includes the user and
- password details that you can fill in below.
- Refresh this page on your browser to see if
- your VOIP line is working. </div>
-
-<div id="voiplines_provider" class="tip">
- Your Internet Telephony Service Provider.
- They will give you an account with a user name
- and password.</div>
-
-<div id="voiplines_user" class="tip">
- Your account name with your Internet Telephony Service Provider</div>
-
-<div id="voiplines_pass" class="tip">
- The password for your Internet Telephony Service Provider account</div>
-
-<div id="voiplines_host" class="tip">
- The Internet address of your Internet
- Telephony Service Provider. This will usually
- be filled in automatically.</div>
-
-<div id="voiplines_status" class="tip">
- A tick means you are connected to your
- Internet Telephony Service Provider. Refresh
- your browser to update.</div>
-
-<div id="admin_restart" class="tip">
- Press this button to restart your phone
- system. This is the same as turning the power
- off and back on. </div>
-
-<div id="admin_upgrade" class="tip">
- Press this button to the latest version of
- Mini Asterisk. An Mini Asterisk upgrade
- requires an Internet connection.</div>
-
-<div id="admin_firmware" class="tip">
- Enter the URL of a firmware update script.
- This option can be used to install new
- firmware on your Phone System. Installing new
- firmware requires an Internet
- connection.</div>
-
+++ /dev/null
-function changeProvider() {
- provider = $('provider').value;
- $('user').value = users[provider];
- $('pass').value = passwords[provider];
- $('host').value = hosts[provider];
- $('stanza').value = stanzas[provider];
-}
+++ /dev/null
-#!/usr/bin/perl
-# voiplines.pl
-# David Rowe 12 Jan 2010
-#
-# Text processing for the voiplines screen
-
-# slurp up list of possible voip line providers --------------------------------
-# one of these will be currently selected
-
-open SIP, "/etc/asterisk/sip.conf";
-my $provider = ""; # current provider bring parsed in sip.conf
-my @providers=(); # list of all providers
-my %stanza = (); # stanza name keyed on provider
-my %user = (); # user keyed on provider
-my %pass = (); # password keyed on provider
-my %host = (); # host name keyed on provider
-
-while (<SIP>) {
-
- # start of any stanza switches off parsing. It may get switched
- # back on below if it contains mini-asterisk keyword. This allows
- # non-mini asterisk SIP devices to be included in sip.conf
-
- if (/\[/) {
- $provider = "";
- }
-
- # currently disabled mini-asterisk provider
-
- if (/^;\[(.*)\].* \"(.*)\" mini-asterisk/) {
- push (@providers, $2);
- $provider = $2;
- $stanza{$2} = $1;
- #print "'$1' '$2'\n";
- }
-
- # current mini-asterisk provider
-
- if (/^\[(.*)\].* \"(.*)\" mini-asterisk/) {
- push (@providers, $2);
- $provider = $2;
- $provider_current = $2;
- $stanza{$2} = $1;
- #print "'$1' '$2'\n";
- }
-
- if ($provider ne "") {
- #print $_;
-
- if (/^;*user=(.*)/) {
- $user{$provider} = $1;
- }
- if (/^;*username=(.*)/) {
- $user{$provider} = $1;
- }
- if (/^;*secret=(.*)/) {
- $pass{$provider} = $1;
- }
- if (/^;*host=(.*)/) {
- $host{$provider} = $1;
- }
- }
-
- $state = $next_state;
-}
-close SIP;
-
-# Determine if Asterisk can see current voip line (SIP trunk)
-# sipshowpeers.txt needs to be generated before calling this perl
-# script
-
-my %voip = (); # SIP trunks status keyed on sip.conf stanza name/username
- # if no entry we can't see SIP trunk
-
-open SIP, "sipshowregistry.txt";
-while (<SIP>) {
- if (/^(.*):.*(Registered)/) {
- $voip{$1} = $2;
- #print "'$1' '$2' $voip{$1}\n";
- }
-}
-
-close SIP;
-
-# javascript to handle changing providers
-
-print "<script>\n";
-print "var hosts = new Array();\n";
-print "var users = new Array();\n";
-print "var passwords = new Array();\n";
-print "var stanzas = new Array();\n";
-foreach (@providers) {
- print "hosts[\'$_\'] = \'$host{$_}\';\n";
- print "users[\'$_\'] = \'$user{$_}\';\n";
- print "passwords[\'$_\'] = \'$pass{$_}\';\n";
- print "stanzas[\'$_\'] = \'$stanza{$_}\';\n";
-}
-print "</script>\n";
-
-# generate form fields -------------------------------------------
-
-$tt_provider = "onMouseOver=\"popUp(event,'voiplines_provider')\" onmouseout=\"popUp(event,'voiplines_provider')\"";
-$tt_user = "onMouseOver=\"popUp(event,'voiplines_user')\" onmouseout=\"popUp(event,'voiplines_user')\"";
-$tt_pass = "onMouseOver=\"popUp(event,'voiplines_pass')\" onmouseout=\"popUp(event,'voiplines_pass')\"";
-$tt_host = "onMouseOver=\"popUp(event,'voiplines_host')\" onmouseout=\"popUp(event,'voiplines_host')\"";
-$tt_status = "onMouseOver=\"popUp(event,'voiplines_status')\" onmouseout=\"popUp(event,'voiplines_status')\"";
-
-print "<tr $tt_provider><td>Provider</td><td>\n";
-print "<select name=\"provider\" id=\"provider\" onchange=\"changeProvider()\">\n";
-foreach (@providers) {
- if ($_ eq $provider_current) {
- print "<option selected=\"yes\">$_</option>\n";
- }
- else {
- print "<option>$_</option>\n";
- }
-}
-print "</select></td></tr>\n";
-
-print "<tr $tt_user><td>User:</td><td><input type=\"text\" name=\"user\" id=\"user\" value=\"$user{$provider_current}\"></td></tr>\n";
-print "<tr $tt_pass><td>Password:</td><td><input type=\"password\" name=\"pass\" id=\"pass\" value=\"$pass{$provider_current}\"></td></tr>\n";
-print "<tr $tt_host><td>Host:</td><td><input type=\"text\" name=\"host\" id=\"host\" value=\"$host{$provider_current}\"></td></tr>\n";
-
-#print "\nXXX $provider_current $stanza{$provider_current} $voip{$stanza{$provider_current}}\n";
-
-if ($voip{$stanza{$provider_current}} eq "Registered") {
- $icon = "<img src=\"tick.png\" alt=\"OK\" />";
-}
-else {
- $icon = "<img src=\"cross.png\" alt=\"Not OK\" />";
-}
-print "<tr $tt_status><td>Voip Line Status:</td><td>$icon</td></tr>\n";
-
-# hidden field to pass stanza with form
-
-print "<tr><td><input type=\"hidden\" name=\"stanza\" id=\"stanza\" value=\"$stanza{$provider_current}\"></td></tr>";
+++ /dev/null
-#!/bin/sh
-# voiplines.sh
-# David Rowe 12 Jan 2010
-# VOIP Line screen for Mini Asterisk GUI
-
-# check we are logged in
-
-echo $HTTP_COOKIE | grep "loggedin" > /dev/null
-if [ $? -eq 1 ]; then
- echo "<html>"
- echo "<head>"
- echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
- echo "</head>"
- echo "</html>"
- exit
-fi
-
-# See if we have can reach the VOIP Line provider
-
-asterisk "-rx sip show registry" 2>/dev/null > sipshowregistry.txt
-
-# Construct the web page -------------------------------
-
-cat <<EOF
-<script src="prototype.js"></script>
-<script type="text/javascript" src="tooltip.js"></script>
-<link rel="stylesheet" href="tooltip.css" type="text/css" />
-<script>
-EOF
-
-cat voiplines.js
-
-cat << EOF
-</script>
-<html>
-<title>Mini Asterisk - VOIP Line</title>
-EOF
-
-cat tooltips.html
-echo '<table align="center" width=800>'
-cat banner.html
-echo " <tr>"
-cat menu.html
-cat <<EOF
-
- <td valign="top">
-
- <table align="right" width=600>
- <tr><td> </td></tr>
- <form action="set_voiplines.sh" method="get">
- <tr><td onMouseOver="popUp(event,'voiplines_voiplines')" onmouseout="popUp(event,'voiplines_voiplines')" align="left" valign="top"><h2>VOIP Line</h2></td></tr>
-
- <tr><td> </td></tr>
-EOF
-
-./voiplines.pl
-
-cat <<EOF
- <tr><td> </td></tr>
- <tr><td><input type="submit" value="OK"></td></tr>
-
- </form>
-
- </table>
- </form>
-
- </td>
-
- </tr>
-
-</table>
-</body>
-</html>
-EOF
-
+++ /dev/null
-; extensions.conf
-; David Rowe 4 Jan 2010
-;
-
-; Designed for Mini Asterisk GUI. However you can hand modify as much
-; as you like, as GUI scripts read/and write regular extensions.conf
-; without messing with your custom dialplan
-
-
-[general]
-static = yes
-writeprotect = no
-autofallthrough = yes
-clearglobalvars = no
-priorityjumping = no
-
-[default]
-
-; Pre-configured analog extensions, depends on IP0X model and what modules
-; are installed. Some of these may map to FXO ports
-
-exten => 6001,1,Dial(Zap/1)
-exten => 6002,1,Dial(Zap/2)
-exten => 6003,1,Dial(Zap/3)
-exten => 6004,1,Dial(Zap/4)
-exten => 6005,1,Dial(Zap/5)
-exten => 6006,1,Dial(Zap/6)
-exten => 6007,1,Dial(Zap/7)
-exten => 6008,1,Dial(Zap/8)
-
-; Pre-configured SIP-phone extensions. Primary use case is multiple SIP
-; extensions and FXO analog Ports
-
-exten => 6011,1,Dial(SIP/6011)
-exten => 6012,1,Dial(SIP/6012)
-exten => 6013,1,Dial(SIP/6013)
-exten => 6014,1,Dial(SIP/6014)
-exten => 6015,1,Dial(SIP/6015)
-exten => 6016,1,Dial(SIP/6016)
-exten => 6017,1,Dial(SIP/6017)
-exten => 6018,1,Dial(SIP/6018)
-exten => 6019,1,Dial(SIP/6019)
-exten => 6020,1,Dial(SIP/6020)
-exten => 6021,1,Dial(SIP/6021)
-exten => 6022,1,Dial(SIP/6022)
-exten => 6023,1,Dial(SIP/6023)
-exten => 6024,1,Dial(SIP/6024)
-exten => 6025,1,Dial(SIP/6025)
-exten => 6026,1,Dial(SIP/6026)
-exten => 6027,1,Dial(SIP/6027)
-exten => 6028,1,Dial(SIP/6028)
-exten => 6029,1,Dial(SIP/6029)
-exten => 6030,1,Dial(SIP/6030)
-
-;; Pre-configured mini-asterisk outgoing Analog group
-
-exten => _0.,1,Dial(Zap/g1/${EXTEN:1})
-
-;; Pre-configured mini-asterisk outgoing VOIP line
-
-exten => _1.,1,Dial(SIP/voip/${EXTEN:1})
-
-;; Pre-configured incoming calls
-
-exten => s,1,Dial(SIP/6011) ;; mini-asterisk - don't remove this comment
+++ /dev/null
-;
-; SIP Configuration example for Asterisk
-;
-; Syntax for specifying a SIP device in extensions.conf is
-; SIP/devicename where devicename is defined in a section below.
-;
-; You may also use
-; SIP/username@domain to call any SIP user on the Internet
-; (Don't forget to enable DNS SRV records if you want to use this)
-;
-; If you define a SIP proxy as a peer below, you may call
-; SIP/proxyhostname/user or SIP/user@proxyhostname
-; where the proxyhostname is defined in a section below
-;
-; Useful CLI commands to check peers/users:
-; sip show peers Show all SIP peers (including friends)
-; sip show users Show all SIP users (including friends)
-; sip show registry Show status of hosts we register with
-;
-; sip debug Show all SIP messages
-;
-; reload chan_sip.so Reload configuration file
-; Active SIP peers will not be reconfigured
-;
-
-[general]
-context=default ; Default context for incoming calls
-;allowguest=no ; Allow or reject guest calls (default is yes, this can also be set to 'osp'
- ; if asterisk was compiled with OSP support.
-;realm=mydomain.tld ; Realm for digest authentication
- ; defaults to "asterisk"
- ; Realms MUST be globally unique according to RFC 3261
- ; Set this to your host name or domain name
-bindport=5060 ; UDP Port to bind to (SIP standard port is 5060)
-bindaddr=0.0.0.0 ; IP address to bind to (0.0.0.0 binds to all)
-srvlookup=yes ; Enable DNS SRV lookups on outbound calls
- ; Note: Asterisk only uses the first host
- ; in SRV records
- ; Disabling DNS SRV lookups disables the
- ; ability to place SIP calls based on domain
- ; names to some other SIP users on the Internet
-
-;domain=mydomain.tld ; Set default domain for this host
- ; If configured, Asterisk will only allow
- ; INVITE and REFER to non-local domains
- ; Use "sip show domains" to list local domains
-;domain=mydomain.tld,mydomain-incoming
- ; Add domain and configure incoming context
- ; for external calls to this domain
-;domain=1.2.3.4 ; Add IP address as local domain
- ; You can have several "domain" settings
-;allowexternalinvites=no ; Disable INVITE and REFER to non-local domains
- ; Default is yes
-;autodomain=yes ; Turn this on to have Asterisk add local host
- ; name and local IP to domain list.
-;pedantic=yes ; Enable slow, pedantic checking for Pingtel
- ; and multiline formatted headers for strict
- ; SIP compatibility (defaults to "no")
-;tos=184 ; Set IP QoS to either a keyword or numeric val
-;tos=lowdelay ; lowdelay,throughput,reliability,mincost,none
-;maxexpiry=3600 ; Max length of incoming registration we allow
-;defaultexpiry=120 ; Default length of incoming/outoing registration
-;notifymimetype=text/plain ; Allow overriding of mime type in MWI NOTIFY
-;checkmwi=10 ; Default time between mailbox checks for peers
-;vmexten=voicemail ; dialplan extension to reach mailbox sets the
- ; Message-Account in the MWI notify message
- ; defaults to "asterisk"
-;videosupport=yes ; Turn on support for SIP video
-;recordhistory=yes ; Record SIP history by default
- ; (see sip history / sip no history)
-
-;disallow=all ; First disallow all codecs
-;allow=ulaw ; Allow codecs in order of preference
-;allow=ilbc ;
-;musicclass=default ; Sets the default music on hold class for all SIP calls
- ; This may also be set for individual users/peers
-;language=en ; Default language setting for all users/peers
- ; This may also be set for individual users/peers
-;relaxdtmf=yes ; Relax dtmf handling
-;rtptimeout=60 ; Terminate call if 60 seconds of no RTP activity
- ; when we're not on hold
-;rtpholdtimeout=300 ; Terminate call if 300 seconds of no RTP activity
- ; when we're on hold (must be > rtptimeout)
-;trustrpid = no ; If Remote-Party-ID should be trusted
-;sendrpid = yes ; If Remote-Party-ID should be sent
-;progressinband=never ; If we should generate in-band ringing always
- ; use 'never' to never use in-band signalling, even in cases
- ; where some buggy devices might not render it
-;useragent=Asterisk PBX ; Allows you to change the user agent string
-;promiscredir = no ; If yes, allows 302 or REDIR to non-local SIP address
- ; Note that promiscredir when redirects are made to the
- ; local system will cause loops since SIP is incapable
- ; of performing a "hairpin" call.
-;usereqphone = no ; If yes, ";user=phone" is added to uri that contains
- ; a valid phone number
-;dtmfmode = rfc2833 ; Set default dtmfmode for sending DTMF. Default: rfc2833
- ; Other options:
- ; info : SIP INFO messages
- ; inband : Inband audio (requires 64 kbit codec -alaw, ulaw)
- ; auto : Use rfc2833 if offered, inband otherwise
-
-;compactheaders = yes ; send compact sip headers.
-;sipdebug = yes ; Turn on SIP debugging by default, from
- ; the moment the channel loads this configuration
-;subscribecontext = default ; Set a specific context for SUBSCRIBE requests
- ; Useful to limit subscriptions to local extensions
- ; Settable per peer/user also
-;notifyringing = yes ; Notify subscriptions on RINGING state
-
-;
-; If regcontext is specified, Asterisk will dynamically create and destroy a
-; NoOp priority 1 extension for a given peer who registers or unregisters with
-; us. The actual extension is the 'regexten' parameter of the registering
-; peer or its name if 'regexten' is not provided. More than one regexten may
-; be supplied if they are separated by '&'. Patterns may be used in regexten.
-;
-;regcontext=sipregistrations
-;
-; Asterisk can register as a SIP user agent to a SIP proxy (provider)
-; Format for the register statement is:
-; register => user[:secret[:authuser]]@host[:port][/extension]
-;
-; If no extension is given, the 's' extension is used. The extension needs to
-; be defined in extensions.conf to be able to accept calls from this SIP proxy
-; (provider).
-;
-; host is either a host name defined in DNS or the name of a section defined
-; below.
-;
-; Examples:
-;
-;register => 1234:password@mysipprovider.com
-;
-; This will pass incoming calls to the 's' extension
-;
-;
-;register => 2345:password@sip_proxy/1234
-;
-; Register 2345 at sip provider 'sip_proxy'. Calls from this provider
-; connect to local extension 1234 in extensions.conf, default context,
-; unless you configure a [sip_proxy] section below, and configure a
-; context.
-; Tip 1: Avoid assigning hostname to a sip.conf section like [provider.com]
-; Tip 2: Use separate type=peer and type=user sections for SIP providers
-; (instead of type=friend) if you have calls in both directions
-
-;registertimeout=20 ; retry registration calls every 20 seconds (default)
-;registerattempts=10 ; Number of registration attempts before we give up
- ; 0 = continue forever, hammering the other server until it
- ; accepts the registration
- ; Default is 0 tries, continue forever
-;callevents=no ; generate manager events when sip ua performs events (e.g. hold)
-
-; register mini-asterisk voip line providers here
-
-register => user@generic ; mini-asterisk - do not change this comment
-;register => user@oeg ; mini-asterisk - do not change this comment
-
-;----------------------------------------- NAT SUPPORT ------------------------
-; The externip, externhost and localnet settings are used if you use Asterisk
-; behind a NAT device to communicate with services on the outside.
-
-;externip = 200.201.202.203 ; Address that we're going to put in outbound SIP messages
- ; if we're behind a NAT
-
- ; The externip and localnet is used
- ; when registering and communicating with other proxies
- ; that we're registered with
-;externhost=foo.dyndns.net ; Alternatively you can specify an
- ; external host, and Asterisk will
- ; perform DNS queries periodically. Not
- ; recommended for production
- ; environments! Use externip instead
-;externrefresh=10 ; How often to refresh externhost if
- ; used
- ; You may add multiple local networks. A reasonable set of defaults
- ; are:
-;localnet=192.168.0.0/255.255.0.0; All RFC 1918 addresses are local networks
-;localnet=10.0.0.0/255.0.0.0 ; Also RFC1918
-;localnet=172.16.0.0/12 ; Another RFC1918 with CIDR notation
-;localnet=169.254.0.0/255.255.0.0 ;Zero conf local network
-
-; The nat= setting is used when Asterisk is on a public IP, communicating with
-; devices hidden behind a NAT device (broadband router). If you have one-way
-; audio problems, you usually have problems with your NAT configuration or your
-; firewall's support of SIP+RTP ports. You configure Asterisk choice of RTP
-; ports for incoming audio in rtp.conf
-;
-;nat=no ; Global NAT settings (Affects all peers and users)
- ; yes = Always ignore info and assume NAT
- ; no = Use NAT mode only according to RFC3581
- ; never = Never attempt NAT mode or RFC3581 support
- ; route = Assume NAT, don't send rport
- ; (work around more UNIDEN bugs)
-
-;rtcachefriends=yes ; Cache realtime friends by adding them to the internal list
- ; just like friends added from the config file only on a
- ; as-needed basis? (yes|no)
-
-;rtupdate=yes ; Send registry updates to database using realtime? (yes|no)
- ; If set to yes, when a SIP UA registers successfully, the ip address,
- ; the origination port, the registration period, and the username of
- ; the UA will be set to database via realtime. If not present, defaults to 'yes'.
-
-;rtautoclear=yes ; Auto-Expire friends created on the fly on the same schedule
- ; as if it had just registered? (yes|no|<seconds>)
- ; If set to yes, when the registration expires, the friend will vanish from
- ; the configuration until requested again. If set to an integer,
- ; friends expire within this number of seconds instead of the
- ; registration interval.
-
-;ignoreregexpire=yes ; Enabling this setting has two functions:
- ;
- ; For non-realtime peers, when their registration expires, the information
- ; will _not_ be removed from memory or the Asterisk database; if you attempt
- ; to place a call to the peer, the existing information will be used in spite
- ; of it having expired
- ;
- ; For realtime peers, when the peer is retrieved from realtime storage,
- ; the registration information will be used regardless of whether
- ; it has expired or not; if it expires while the realtime peer is still in
- ; memory (due to caching or other reasons), the information will not be
- ; removed from realtime storage
-
-; Incoming INVITE and REFER messages can be matched against a list of 'allowed'
-; domains, each of which can direct the call to a specific context if desired.
-; By default, all domains are accepted and sent to the default context or the
-; context associated with the user/peer placing the call.
-; Domains can be specified using:
-; domain=<domain>[,<context>]
-; Examples:
-; domain=myasterisk.dom
-; domain=customer.com,customer-context
-;
-; In addition, all the 'default' domains associated with a server should be
-; added if incoming request filtering is desired.
-; autodomain=yes
-;
-; To disallow requests for domains not serviced by this server:
-; allowexternaldomains=no
-
-; fromdomain=mydomain.tld ; When making outbound SIP INVITEs to
- ; non-peers, use your primary domain "identity"
- ; for From: headers instead of just your IP
- ; address. This is to be polite and
- ; it may be a mandatory requirement for some
- ; destinations which do not have a prior
- ; account relationship with your server.
-
-[authentication]
-; Global credentials for outbound calls, i.e. when a proxy challenges your
-; Asterisk server for authentication. These credentials override
-; any credentials in peer/register definition if realm is matched.
-;
-; This way, Asterisk can authenticate for outbound calls to other
-; realms. We match realm on the proxy challenge and pick an set of
-; credentials from this list
-; Syntax:
-; auth = <user>:<secret>@<realm>
-; auth = <user>#<md5secret>@<realm>
-; Example:
-;auth=mark:topsecret@digium.com
-;
-; You may also add auth= statements to [peer] definitions
-; Peer auth= override all other authentication settings if we match on realm
-
-;------------------------------------------------------------------------------
-; Users and peers have different settings available. Friends have all settings,
-; since a friend is both a peer and a user
-;
-; User config options: Peer configuration:
-; -------------------- -------------------
-; context context
-; permit permit
-; deny deny
-; secret secret
-; md5secret md5secret
-; dtmfmode dtmfmode
-; canreinvite canreinvite
-; nat nat
-; callgroup callgroup
-; pickupgroup pickupgroup
-; language language
-; allow allow
-; disallow disallow
-; insecure insecure
-; trustrpid trustrpid
-; progressinband progressinband
-; promiscredir promiscredir
-; useclientcode useclientcode
-; accountcode accountcode
-; setvar setvar
-; callerid callerid
-; amaflags amaflags
-; call-limit call-limit
-; restrictcid restrictcid
-; subscribecontext subscribecontext
-; videosupport videosupport
-; mailbox
-; username
-; template
-; fromdomain
-; regexten
-; fromuser
-; host
-; port
-; qualify
-; defaultip
-; rtptimeout
-; rtpholdtimeout
-; sendrpid
-
-;[sip_proxy]
-; For incoming calls only. Example: FWD (Free World Dialup)
-; We match on IP address of the proxy for incoming calls
-; since we can not match on username (caller id)
-;type=peer
-;context=from-fwd
-;host=fwd.pulver.com
-
-;[sip_proxy-out]
-;type=peer ; we only want to call out, not be called
-;secret=guessit
-;username=yourusername ; Authentication user for outbound proxies
-;fromuser=yourusername ; Many SIP providers require this!
-;fromdomain=provider.sip.domain
-;host=box.provider.com
-;usereqphone=yes ; This provider requires ";user=phone" on URI
-;call-limit=5 ; permit only 5 simultaneous outgoing calls to this peer
-
-;------------------------------------------------------------------------------
-; Definitions of locally connected SIP phones
-;
-; type = user a device that authenticates to us by "from" field to place calls
-; type = peer a device we place calls to or that calls us and we match by host
-; type = friend two configurations (peer+user) in one
-;
-; For local phones, type=friend works most of the time
-;
-; If you have one-way audio, you propably have NAT problems.
-; If Asterisk is on a public IP, and the phone is inside of a NAT device
-; you will need to configure nat option for those phones.
-; Also, turn on qualify=yes to keep the nat session open
-
-;[grandstream1]
-;type=friend
-;context=from-sip ; Where to start in the dialplan when this phone calls
-;callerid=John Doe <1234> ; Full caller ID, to override the phones config
-;host=192.168.0.23 ; we have a static but private IP address
- ; No registration allowed
-;nat=no ; there is not NAT between phone and Asterisk
-;canreinvite=yes ; allow RTP voice traffic to bypass Asterisk
-;dtmfmode=info ; either RFC2833 or INFO for the BudgeTone
-;call-limit=1 ; permit only 1 outgoing call and 1 incoming call at a time
- ; from the phone to asterisk
- ; (1 for the explicit peer, 1 for the explicit user,
- ; remember that a friend equals 1 peer and 1 user in
- ; memory)
-;mailbox=1234@default ; mailbox 1234 in voicemail context "default"
-;disallow=all ; need to disallow=all before we can use allow=
-;allow=ulaw ; Note: In user sections the order of codecs
- ; listed with allow= does NOT matter!
-;allow=alaw
-;allow=g723.1 ; Asterisk only supports g723.1 pass-thru!
-;allow=g729 ; Pass-thru only unless g729 license obtained
-;astdb=chan2ext/SIP/grandstream1=1234 ; ensures an astDB entry exists
-
-
-;[xlite1]
-; Turn off silence suppression in X-Lite ("Transmit Silence"=YES)!
-; Note that Xlite sends NAT keep-alive packets, so qualify=yes is not needed
-;type=friend
-;regexten=1234 ; When they register, create extension 1234
-;callerid="Jane Smith" <5678>
-;host=dynamic ; This device needs to register
-;nat=yes ; X-Lite is behind a NAT router
-;canreinvite=no ; Typically set to NO if behind NAT
-;disallow=all
-;allow=gsm ; GSM consumes far less bandwidth than ulaw
-;allow=ulaw
-;allow=alaw
-;mailbox=1234@default,1233@default ; Subscribe to status of multiple mailboxes
-
-
-;[snom]
-;type=friend ; Friends place calls and receive calls
-;context=from-sip ; Context for incoming calls from this user
-;secret=blah
-;subscribecontext=localextensions ; Only allow SUBSCRIBE for local extensions
-;language=de ; Use German prompts for this user
-;host=dynamic ; This peer register with us
-;dtmfmode=inband ; Choices are inband, rfc2833, or info
-;defaultip=192.168.0.59 ; IP used until peer registers
-;mailbox=1234@context,2345 ; Mailbox(-es) for message waiting indicator
-;vmexten=voicemail ; dialplan extension to reach mailbox
- ; sets the Message-Account in the MWI notify message
- ; defaults to global vmexten which defaults to "asterisk"
-;restrictcid=yes ; To have the callerid restriced -> sent as ANI
-;disallow=all
-;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw!
-
-
-;[polycom]
-;type=friend ; Friends place calls and receive calls
-;context=from-sip ; Context for incoming calls from this user
-;secret=blahpoly
-;host=dynamic ; This peer register with us
-;dtmfmode=rfc2833 ; Choices are inband, rfc2833, or info
-;username=polly ; Username to use in INVITE until peer registers
- ; Normally you do NOT need to set this parameter
-;disallow=all
-;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw!
-;progressinband=no ; Polycom phones don't work properly with "never"
-
-
-;[pingtel]
-;type=friend
-;secret=blah
-;host=dynamic
-;insecure=port ; Allow matching of peer by IP address without matching port number
-;insecure=invite ; Do not require authentication of incoming INVITEs
-;insecure=port,invite ; (both)
-;qualify=1000 ; Consider it down if it's 1 second to reply
- ; Helps with NAT session
- ; qualify=yes uses default value
-;callgroup=1,3-4 ; We are in caller groups 1,3,4
-;pickupgroup=1,3-5 ; We can do call pick-p for call group 1,3,4,5
-;defaultip=192.168.0.60 ; IP address to use if peer has not registred
-
-;[cisco1]
-;type=friend
-;secret=blah
-;qualify=200 ; Qualify peer is no more than 200ms away
-;nat=yes ; This phone may be natted
- ; Send SIP and RTP to the IP address that packet is
- ; received from instead of trusting SIP headers
-;host=dynamic ; This device registers with us
-;canreinvite=no ; Asterisk by default tries to redirect the
- ; RTP media stream (audio) to go directly from
- ; the caller to the callee. Some devices do not
- ; support this (especially if one of them is
- ; behind a NAT).
-;defaultip=192.168.0.4 ; IP address to use until registration
-;username=goran ; Username to use when calling this device before registration
- ; Normally you do NOT need to set this parameter
-;setvar=CUSTID=5678 ; Channel variable to be set for all calls from this device
-
-; Pre-configured SIP extensions
-
-[6011]
-type=friend
-context=default
-host=dynamic
-secret=6011
-canreinvite=no
-callerid=6011
-disallow=all
-allow=ulaw,g729
-qualify=yes
-
-[6012]
-type=friend
-context=default
-host=dynamic
-secret=6012
-canreinvite=no
-callerid=6012
-disallow=all
-allow=ulaw,g729
-
-[6013]
-type=friend
-context=default
-host=dynamic
-secret=6013
-canreinvite=no
-callerid=6013
-disallow=all
-allow=ulaw,g729
-
-[6014]
-type=friend
-context=default
-host=dynamic
-secret=6014
-canreinvite=no
-callerid=6014
-disallow=all
-allow=ulaw,g729
-
-[6015]
-type=friend
-context=default
-host=dynamic
-secret=6015
-canreinvite=no
-callerid=6015
-disallow=all
-allow=ulaw,g729
-
-[6016]
-type=friend
-context=default
-host=dynamic
-secret=6016
-canreinvite=no
-callerid=6016
-disallow=all
-allow=ulaw,g729
-
-[6017]
-type=friend
-context=default
-host=dynamic
-secret=6017
-canreinvite=no
-callerid=6017
-disallow=all
-allow=ulaw,g729
-
-[6018]
-type=friend
-context=default
-host=dynamic
-secret=6018
-canreinvite=no
-callerid=6018
-disallow=all
-allow=ulaw,g729
-
-; Pre-configured mini-asterisk SIP trunks
-
-[generic] ; "Generic" mini-asterisk do not remove this comment
-type=friend
-context=default
-username=user
-secret=password
-host=192.168.1.28
-canreinvite=no
-disallow=all
-allow=ulaw,g729
-qualify=yes
-
-;[oeg] ; "OEG" mini-asterisk do not remove this comment
-;host=voip.oeg.com.au
-;secret=pass
-;username=your user number
-;fromdomain=voip.oeg.com.au
-;fromuser=your user number
-;insecure=port,invite
-;type=friend
-;disallow=all
-;allow=g729,ulaw
-;dtmfmod=rfc2833
-;qualify=yes
-;canreinvite=no
-;nat=yes
-;context=default
-
+++ /dev/null
-#!/bin/sh
-# update_revision.sh
-#
-# Sets correct Revision number in the about screen. Good idea to
-# run this before installing
-
-ver=`svn info | grep Revision`
-sed -i "s/Revision: [0-9]*/$ver/" cgi-bin/about.sh
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+# Makefile
+# David Rowe 1 Jan 2010
+#
+# Makefile for Easy Asterisk GUI
+#
+# 1/ Download files to development box for testing:
+#
+# usage: make HOST=test.machine.ip|hostname test
+# make HOST=192.168.1.150 test
+# make HOST=boris test
+#
+# 2/ Create static copy of web pages from HOST for static demo
+#
+# usage: make HOST=test.machine.ip static
+
+test:
+ rcp cgi-bin/*.html cgi-bin/*.sh cgi-bin/*.pl cgi-bin/*.js cgi-bin/*.css \
+ cgi-bin/*.png root@$(HOST):/www
+ rcp etc/asterisk/*.conf root@$(HOST):/etc/asterisk
+
+.PHONY : static
+static:
+ # generate static pages
+
+ rm -Rf static; mkdir static; cd static; \
+ wget -rEk --header="Cookie: loggedin=1" http://$(HOST)/phones.sh
+
+ # modify links to non-existent scripts on static demo
+
+ sed -i "s,http://$(HOST)/set_network.sh,network.sh.html," static/$(HOST)/network.sh.html
+ sed -i "s,http://$(HOST)/set_ring.sh,phones.sh.html," static/$(HOST)/phones.sh.html
+ sed -i "s,http://$(HOST)/set_voiplines.sh,voiplines.sh.html," static/$(HOST)/voiplines.sh.html
+
+
--- /dev/null
+Mini Asterisk
+=============
+
+A simple, light weight GUI for Asterisk.
+
+image::/images/ip04/mini.png["Mini Asterisk Demo", link="mini/phones.sh.html"]
+
+Click on the screen shot above for an on line demo.
+
+[[intro]]
+Introduction
+------------
+
+Mini Asterisk is a simple Web GUI for Asterisk with comprehensive tool
+tip documentation and a learning curve of a few minutes. Analog ports
+and IP Phones are automatically detected, and no knowledge of Asterisk
+configuration is required.
+
+Mini Asterisk is "unfeatured" - many of the Asterisk options are not
+available. Instead it tries to make very basic, very common Asterisk
+installations fast and simple, for example:
+
+* An Asterisk server running on your home gateway/firewall/server.
+ You want to connect a few IP Phones and make cheap phones calls
+ using VOIP. An Asterisk distro on a CD is a possibility but you
+ don't want to dedicate a full PC just for Asterisk. You don't
+ really want to learn obscure dial plan syntax and yet another conf
+ file format.
+
+* A small office that already has an old analog phone system. You
+ want to keep your current analog lines for incoming calls, but
+ install 8 IP Phones and use VOIP for outgoing calls. You know
+ enough to set up a DSL router but don't want to rely on "the Phone
+ Guy" or "The Computer Guy" at $100/hr to maintain your phone
+ system.
+
+* You are a "Phone Guy" who doesn't understand Linux and Asterisk but
+ you want to install IP-PBXes.
+
+[[why]]
+Why Another Asterisk GUI?
+-------------------------
+
+There are http://www.voip-info.org/wiki/view/Asterisk+GUI[a lot of
+Asterisk GUIs] out there already. So why do we need another one?
+
+Well I needed an Asterisk GUI that was very easy to use for the
+link:ip04.html[IP0X devices] I sell. Something that would lower the
+technical skill required to install and maintain an Asterisk Phone
+system. Something my wife and kids could use.
+
+I was also interested in exploring the ease-of-use meme, as we have
+been discussing it a lot on the http://villagetelco.org[Village Telco]
+project. Just how easy can we make Asterisk to use? So I scratched
+the itch.
+
+Mini Asterisk has the following features that make it reasonably
+unique. They may be good or bad features depending on your point of
+view!
+
+* Mini Asterisk is "un-featured" - it hides many of the advanced
+ Asterisk features in the interest of simple and fast configuration.
+
+* Light weight so it can run on embedded boxes like the IP0X family.
+ No SQL database or PHP or LAMP. Only a basic web server and a very
+ basic perl are required (e.g. microperl - no CPAN libraries).
+
+* Works directly on extensions.conf and sip.conf, but honors any edits
+ you make to these files. So all the powerful Asterisk features are
+ available in the background.
+
+* Doesn't use AJAX or the built-in Asterisk web server or users.conf
+ magic. Plain old HTML, a little Java-script and CGIs written in
+ shell script and Perl.
+
+* Doesn't use the Asterisk programming "model". For example you don't
+ have to understand what a dial-plan is, much less understand how to
+ code one. Plain English terms are used instead, for example "Phones
+ and Phone lines". Terms like Asterisk, Linux, SIP, Zap/1 don't even
+ get a mention.
+
+* Extensive tool tip documentation. No manual.
+
+* Doesn't require a dedicated PC, not installed from an ISO CD. So
+ you can use it as a GUI for Asterisk on a little SOHO Linux box that
+ is also your firewall, server etc.
+
+* Mini Asterisk tells you when something is wrong, for example you get
+ a warning if your Phone System can't see the Internet.
+
+* Extensive pre-configuration of extensions.conf and sip.conf,
+ pre-selected phone numbers, SIP trunks are selected from a pull-down
+ menu (except they are called VOIP lines). Analog ports are auto
+ detected, at least on the IP0X. This makes adding IP phones very
+ fast and simple.
+
+[[status]]
+Status
+------
+
+Alpha:
+
+* Works on IP0X.
+* Not tested on x86. Several IP0X features are n/a for x86 and should be
+ disabled when the x86 (or non-IP0X) platform is detected.
+* Needs feedback from real users to see how useful the concept is and what
+ (un)features need to be added.
+* Need a few more (un)features to be added, and Voip Line screen
+ populated with more ITSPs.
+* But quite useable as it stands.
+
+[[notes]]
+Implementation Notes
+--------------------
+
+Mini Asterisk is written for the
+http://rowetel.com/ucasterisk/ip04.html[IP0X embedded Asterisk]
+hardware but will also run on x86 and probably many other platforms.
+
+Mini Asterisk has been written to be compatible with regular Asterisk
+conf file configuration. Just leave the conf file lines with
+"mini-asterisk" comments alone. The Asterisk conf files
+extensions.conf and sip.conf are directly modified by Mini Asterisk,
+but changes are limited to the "mini-asterisk" lines.
+
+For Auto-detection of Zap ports Mini Asterisk looks at
+/etc/zapata.conf, so you may need this set up correctly for your
+analog hardware. On the IP0X this happens automatically.
+
+[[install]]
+Installation
+------------
+
+Note: this process may overwrite your Asterisk extensions.conf and
+sip.conf files - back them up if you have an existing Asterisk
+installation that you want to keep. The IP0X ipkg does attempt to
+backup the modified conf files to *.bak but no guarantees....
+
+However once mini-asterisk is installed it should honor any manual
+changes made to extensions.conf and sip.conf.
+
+IP0X Installation
+~~~~~~~~~~~~~~~~~
+
+Installation instructions for IP0X boxes running link:baps.html[BAPS],
+with some version of Asterisk and Zaptel installed.
+
+-------------------------------------------------------------------
+root~> ipkg install mini-asterisk
+-------------------------------------------------------------------
+
+x86 Installation
+~~~~~~~~~~~~~~~~
+
+. You need a web server, Asterisk and some sort of Perl installed
+(very basic Perl installation is fine). Configure your web server to
+run CGIs (.sh and .pl) from /www (lighttpd config instructions below).
+Mini Asterisk expects all files (shell, perl, html etc) to be in the
+same directory. If you find this painful please <<support, let me know>>.
+
+. The process below places the web files in /www, you may like to
+place the files somewhere else like /www/asterisk. One of the files
+is named index.html so make sure you don't overwrite an existing
+index.html.
+
+. Login as root to install the Mini Asterisk files:
++
+Remember to backup your existing extensions.conf & sip.conf in
+/etc/asterisk
++
+-------------------------------------------------------------------
+# cd ~
+# svn co https://freetel.svn.sourceforge.net/svnroot/freetel/mini-asterisk-gui
+# ./update_revision.sh
+# cp mini-asterisk-gui/etc/asterisk/* /etc/asterisk
+# cp mini-asterisk-gui/cgi-bin/* /www
+# cd /etc/asterisk
+# cp extensions.conf extensions.conf.def
+# cp sip.conf sip.conf.def
+# mv etc/asterisk/users.conf etc/asterisk/users.conf.bak
+-------------------------------------------------------------------
++
+The final step above may not be required on your machine if you don't
+have a users.conf. The .def copies are required by the "reset
+defaults" feature on the admin screen.
+
+. Switch off the internal Asterisk web server by editing
+/etc/asterisk.httpd.conf. Make sure the enabled line reads like this:
+
+ enabled=no
++
+Then stop and restart Asterisk.
+
+. I use lighttpd as the web server, the /etc/lighttpd.conf lines
+required are:
++
+-------------------------------------------------------------------
+cgi.assign = ( ".sh" => "/bin/sh",".pl" => "/usr/sbin/microperl" )
+-------------------------------------------------------------------
+
+[[contribute]]
+Contributions
+-------------
+
+I welcome sip.conf entries for your favourite ITSP (VOIP service) to
+help populate the Provider field of the
+link:mini/voiplines.sh.html[Voip Line Screen].
+
+[[support]]
+Support
+-------
+
+Comments, features request, bugs please let me know using Free
+Telephony Project http://www.rowetel.com/ucasterisk/#support[Support].
+
+[[source]]
+Source Code
+-----------
+
+Browse:
+
+http://freetel.svn.sourceforge.net/viewvc/freetel/mini-asterisk-gui/[http://freetel.svn.sourceforge.net/viewvc/freetel/mini-asterisk-gui/]
+
+Check Out:
+
+ $ svn co https://freetel.svn.sourceforge.net/svnroot/freetel/mini-asterisk-gui
+
--- /dev/null
+#!/bin/sh
+# about.sh
+# David Rowe 7 Jan 2010
+# About screen for Mini Asterisk GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+
+cat << EOF
+<html>
+<title>Mini Asterisk - About</title>
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <table align="right" width=600>
+ <tr><td align="left" valign="top"><h2>About</h2></td></tr>
+EOF
+echo ' <tr><td><a href="http://rowetel.com/ucasterisk/mini.html">Mini Asterisk</a> Revision: 122 </td></tr> '
+echo ' <tr><td> </td></tr>'
+echo ' <tr><td>Brought to you by the <a href="http://rowetel.com/ucasterisk/index.html">Free Telephony Project</a></td></tr>'
+echo ' <tr><td><a href="http://rowetel.com/ucasterisk/ip04.html"><img src="http://rowetel.com/images/ip04/ip04_case.jpg" border="0" /></a></td></tr>'
+
+more=`echo "$QUERY_STRING" | grep -oe "more=[^&?]*" | sed -n "s/more=//p"`
+if [ $more -eq 1 ]; then
+ echo
+else
+ echo " <tr><td> </td></tr>"
+ echo ' <tr><td><a href="about.sh?more=1">More</a></td></tr>';
+cat <<EOF
+ </table>
+ </td>
+ </tr>
+</table>
+</body>
+</html>
+EOF
+exit
+fi
+
+echo " <tr><td> </td></tr>"
+echo " <tr><td><h3>cat /proc/version</h3></td></tr>"
+echo " <tr><td>"
+cat /proc/version
+echo " </td></tr>"
+
+which ipkg >> /dev/null
+if [ $? -eq 0 ]; then
+ echo " <tr><td> </td></tr>"
+ echo " <tr><td><h3>ipkg list_installed</h3></td></tr>"
+ echo " <tr><td>"
+ ipkg list_installed | tr '\n' '#' | sed -n 's/\#/<br>/pg'
+ echo " </td></tr>"
+fi
+
+echo " <tr><td> </td></tr>"
+echo " <tr><td><h3>cat /proc/loadavg</h3></td></tr>"
+echo " <tr><td>"
+cat /proc/loadavg
+echo " </td></tr>"
+
+echo " <tr><td> </td></tr>"
+echo " <tr><td><h3>uptime</h3></td></tr>"
+echo " <tr><td>"
+uptime
+echo " </td></tr>"
+
+echo " <tr><td> </td></tr>"
+echo " <tr><td><h3>cat /proc/meminfo</h3></td></tr>"
+echo " <tr><td>"
+cat /proc/meminfo | tr '\n' '#' | sed -n 's/\#/<br>/pg'
+echo " </td></tr>"
+
+echo " <tr><td> </td></tr>"
+echo " <tr><td><h3>cat /proc/cmdline</h3></td></tr>"
+echo " <tr><td>"
+cat /proc/cmdline
+echo " </td></tr>"
+
+echo " <tr><td> </td></tr>"
+echo " <tr><td><h3>cat /proc/cpuinfo</h3></td></tr>"
+echo " <tr><td>"
+cat /proc/cpuinfo
+echo " </td></tr>"
+
+if [ -f /proc/mtd ]; then
+ echo " <tr><td> </td></tr>"
+ echo " <tr><td><h3>cat /proc/mtd</h3></td></tr>"
+ echo " <tr><td>"
+ cat /proc/mtd | tr '\n' '#' | sed -n 's/\#/<br>/pg'
+ echo " </td></tr>"
+fi
+
+if [ -f /proc/yaffs ]; then
+ echo " <tr><td> </td></tr>"
+ echo " <tr><td><h3>cat /proc/yaffs</h3></td></tr>"
+ echo " <tr><td>"
+ cat /proc/yaffs | tr '\n' '#' | sed -n 's/\#/<br>/pg'
+ echo " </td></tr>"
+fi
+
+echo " <tr><td> </td></tr>"
+echo ' <tr><td><a href="about.sh">Less</a></td></tr>';
+
+cat <<EOF
+ </table>
+
+ </td>
+
+ </tr>
+
+</table>
+</body>
+</html>
+EOF
+
--- /dev/null
+#!/bin/sh
+# admin.sh
+# David Rowe 7 Jan 2010
+# Admin screen for Mini Asterisk GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+# set password CGI -----------------------------------------------
+
+echo "$QUERY_STRING" | grep -oe "pass=" > /dev/null
+if [ $? -eq 0 ]; then
+ pass=`echo "$QUERY_STRING" | grep -oe "pass=[^&?]*" | sed -n "s/pass=//p"`
+ passwd_cmdline $pass
+fi
+
+# restart CGI ----------------------------------------------------
+
+echo "$QUERY_STRING" | grep -oe "restart=1" > /dev/null
+if [ $? -eq 0 ]; then
+
+# kill cookie to log out. This ensures hitting refresh wont run
+# the restart process again
+
+cat <<EOF
+Content-type: text/html
+Set-Cookie: loggedin=1; expires=Thursday, 01-Jan-98 12:00:00 GMT
+
+<head>
+<title>Mini Asterisk - Restart</title>
+</head>
+<body>
+<h2>Restarting...come back in 1 minute</h2>
+</body>
+EOF
+reboot
+fi
+
+# set defaults CGI ----------------------------------------------------
+
+echo "$QUERY_STRING" | grep -oe "defaults=1" > /dev/null
+if [ $? -eq 0 ]; then
+ cp /etc/asterisk/extensions.conf.def /etc/asterisk/extensions.conf
+ cp /etc/asterisk/sip.conf.def /etc/asterisk/sip.conf
+ asterisk -rx "sip reload" 2>/dev/null 1 > /dev/null
+ asterisk -rx "dialplan reload" 2>/dev/null 1 > /dev/null
+fi
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+
+cat << EOF
+<html>
+<title>Mini Asterisk - Admin</title>
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <table align="right" width=600>
+ <tr><td> </td></tr>
+ <form action="admin.sh" method="get">
+ <tr><td align="left" valign="top"><h2>Admin</h2></td></tr>
+
+ <tr><td> </td></tr>
+ <tr><td colspan="2"><h3>Change Phone System Password</h3></td></tr>
+ <tr><td>New Password:</td><td><input type="password" name="pass" ></td>
+ <td><input type="submit" value="Set Password"></td>
+ </tr>
+ <tr><td> </td></tr>
+ <tr><td></td><td>Default password is uClinux</td>
+ </form>
+
+ <tr><td> </td></tr>
+ <tr><td colspan="2"><h3>Restart Phone System</h3></td>
+ <td onMouseOver="popUp(event,'admin_restart')" onmouseout="popUp(event,'admin_restart')">
+ <form action="admin.sh" method="get">
+ <input type="hidden" name="restart" value="1">
+ <input type="submit" value="Restart">
+ </form>
+ </td>
+ </tr>
+
+ <tr><td> </td></tr>
+ <tr><td colspan="2"><h3>Reset Phone System Defaults</h3></td>
+ <td>
+ <form action="admin.sh" method="get">
+ <input type="hidden" name="defaults" value="1">
+ <input type="submit" value="Reset">
+ </form>
+ </td>
+ </tr>
+
+ <tr><td> </td></tr>
+ <tr onMouseOver="popUp(event,'admin_upgrade')" onmouseout="popUp(event,'admin_upgrade')">
+ <td colspan="2"><h3>Upgrade Mini Asterisk</h3></td>
+ <td>
+ <form action="admin.sh" method="get">
+ <input type="hidden" name="upgrade" value="1">
+ <input type="submit" value="Upgrade">
+ </td>
+ </tr>
+
+ <tr><td> </td></tr>
+ <tr><td colspan="2"><h3>Install New Firmware</h3>
+ <form action="admin.sh" method="get">
+ <tr onMouseOver="popUp(event,'admin_firmware')" onmouseout="popUp(event,'admin_firmware')">
+ <td>Firmware URL:</td>
+ <td><input type="text" name="firmwareurl" ></td>
+ <td><input type="submit" value="Install"></td>
+ </tr>
+ </form>
+
+ </table>
+ </form>
+
+ </td>
+
+ </tr>
+
+</table>
+</body>
+</html>
+EOF
+
--- /dev/null
+<ol>
+<li>Connect the WAN port of the AT-530 to your network, it will boot and obtain an IP via DHCP.
+<li>Find the <strong>IP</strong> of the phone by pressing the <strong>Sysinfo</strong> button a few times.
+<li>Open another browser window. Go to the phones <strong>IP</strong>, for example <strong>http://192.168.1.160</strong>
+<li>Login to the phone using the username/password <strong>admin/admin</strong>.
+<li>Optional: set a static IP using the WAN menu (I like static IPs for SIP phones).
+<li>Go to the phone <strong>SIP Config</strong> menu.
+<li>Set <strong>Register Server Address</strong> to your Phone System IP Address.
+<li>Set <strong>Register Username</strong> to the phone number (e.g. 6011).
+<li>Also set </strong>Register Password</strong> to the phone number (e.g. 6011) and
+the </strong>Phone Number</strong> to the phone number (e.g. 6011).
+<li>Check the <strong>Enable Register</strong> box.
+<li>Then click on <strong>Apply</strong>.
+<li>On your browser refresh this page to see if the phone is connected to your phone system.
+</ol>
--- /dev/null
+ <tr><td colspan="2"><h2> </h2></td></tr>
--- /dev/null
+<ol>
+
+<li><strong>Transfer a Call</strong>
+
+<li><strong>Answer a call on another ringing phone</strong>: If you hear another phone ringing and
+want to answer the call on your phone, just pick up your phone and
+dial *8. Note an IP phone can pick up a call on a ringing IP phone
+but not an Analog phone. An Analog pohone can pick up another
+ringing Analog phone but not an IP phone.
+
+</ol>
+
+<h2>Resources and Links</h2>
+<ol>
+<li>A good book on Asterisk is <a href="http://astbook.asteriskdocs.org">Asterisk - The Future of Telephony</a>
+</ol>
--- /dev/null
+#!/bin/sh
+# faq.sh
+# David Rowe 7 Jan 2010
+# FAQ screen for Mini Asterisk GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+
+cat << EOF
+<html>
+<title>Mini Asterisk - FAQ</title>
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <table align="right" width=600>
+ <tr><td align="left" valign="top"><h2>FAQ</h2></td></tr>
+ <tr><td>
+EOF
+cat faq.html
+cat <<EOF
+ </td></tr>
+ </table>
+
+ </td>
+
+ </tr>
+
+</table>
+</body>
+</html>
+EOF
+
--- /dev/null
+<html>
+<head>
+<meta http-equiv="REFRESH" content="0;url=http:login.sh">
+</head>
+</html>
\ No newline at end of file
--- /dev/null
+function localInit() {
+}
+
--- /dev/null
+#!usr/bin/perl
+# ipphones.pl
+# David Rowe 6 Jan 2010
+#
+# Text processing for the ipphones screen
+
+$ipaddress = $ARGV[0];
+$more = $ARGV[1];
+
+# Slurp up SIP extension (Sip) data from extensions.conf
+
+my %ip = (); # ip extension keyed on sip.conf name
+
+open EXT, "/etc/asterisk/extensions.conf";
+while (<EXT>) {
+ if (/.*=>[ ]*([0-9]*),1.*SIP\/([0-9]*)\)/) {
+ $ip{$2} = $1;
+ #print "'$1' '$2' $ip{$2}\n";
+ }
+}
+close EXT;
+
+my %sip = (); # SIP IP phone status keyed on sip.conf names
+ # if no entry we can't see IP phone device
+my %voip = (); # SIP trunks status keyed on sip.conf names
+ # if no entry we can't see SIP trunk
+my %ipad = (); # IP address of SIP device keyed on sip.conf names
+
+open SIP, "sipshowpeers.txt";
+while (<SIP>) {
+ if (/^([0-9]*)[\s\/].*(OK)/) {
+ $sip{$1} = $2;
+ #print "'$1' '$2' $sip{$1}\n";
+ $e = $1;
+ if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
+ $ipad{$e} = $1;
+ #print "'$1'\n";
+ }
+ }
+ if (/^(voip[0-9]*)[\s\/].*(OK)/) {
+ $voip{$1} = $2;
+ #print "'$1' '$2' $voip{$1}\n";
+ $e = $1;
+ if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
+ $ipad{$e} = $1;
+ #print "'$1'\n";
+ }
+ }
+}
+
+close SIP;
+
+# print list of IP phones with connection status
+
+$unconnected = 0;
+foreach $e (sort keys %ip) {
+ if ($sip{$e} eq "OK") {
+ $icon = "<img src=\"tick.png\" alt=\"Connected\" />";
+ $tooltip_status = "onMouseOver=\"popUp(event,'ipphones_connected')\" onmouseout=\"popUp(event,'ipphones_connected')\"";
+ $comment=$ipad{$e};
+ $tooltip_ext = "onMouseOver=\"popUp(event,'phone_ext')\" onmouseout=\"popUp(event,'phone_ext')\"";
+ $tooltip_ip = "onMouseOver=\"popUp(event,'phone_ipphone_ip')\" onmouseout=\"popUp(event,'phone_ipphone_ip')\"";
+ $unconnected = 0;
+ }
+ else {
+ $unconnected = $unconnected + 1;
+ $icon = "<img src=\"cross.png\" alt=\"Not Connected\" />";
+ $tooltip_status = "onMouseOver=\"popUp(event,'ipphones_notconnected')\" onmouseout=\"popUp(event,'ipphones_notconnected')\"";
+ $comment="Available";
+ $tooltip_id = "iphones_$e";
+ print "<div id=\"$tooltip_id\" class=\"tip\"> Configure your IP phone with username/password $e/$e, SIP Server IP $ipaddress</div>";
+ $tooltip_ext = "onMouseOver=\"popUp(event,'$tooltip_id')\" onmouseout=\"popUp(event,'$tooltip_id')\"";
+ $tooltip_ip = "";
+ }
+
+ if ($more == 1 || ($unconnected < 5)) {
+ print "<tr><td $tooltip_ext>$e</td><td></td><td $tooltip_ip>$comment</td><td $tooltip_status>$icon</td></tr>\n";
+ }
+}
+
+if ($more == 0) {
+ print '<tr><td><a href="ipphones.sh?more=1">More</a></td></tr>';
+}
+else {
+ print '<tr><td><a href="ipphones.sh">Less</a></td></tr>';
+}
+
+
--- /dev/null
+#!/bin/sh
+# dashboard.sh
+# David Rowe 6 Jan 2010
+# Dashboard screen for Mini Asterisk GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+more=`echo "$QUERY_STRING" | grep -oe "more=[^&?]*" | sed -n "s/more=//p"`
+ipaddress=`ifconfig eth0 | sed -n 's/.*inet addr:\(.*\) Bcast.*/\1/p'`
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+
+echo "<script>"
+echo 'var init_internet="'$internet'";'
+cat ipphones.js
+echo "</script>"
+
+cat << EOF
+<html>
+<title>Mini Asterisk - IP Phones</title>
+<body onload="localInit()">
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800 border=0>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <table align="right" width=600 border=0>
+ <tr><td onMouseOver="popUp(event,'ipphones_ipphones')" onmouseout="popUp(event,'ipphones_ipphones')"
+ colspan="4" align="left" valign="top" ><h2>IP Phones</h2></td></tr>
+ <tr onMouseOver="popUp(event,'phone_ipaddress')" onmouseout="popUp(event,'phone_ipaddress')">
+ <td colspan="3">Phone System IP Address:</td>
+EOF
+echo "<td>$ipaddress</td></tr><td> </td><tr></tr>"
+
+ # use perl to construct list of IP phones for us
+ asterisk "-rx sip show peers" 2>/dev/null > sipshowpeers.txt
+ ./ipphones.pl $ipaddress $more
+
+cat <<EOF
+ </table>
+
+ <h2> <br>How to Configure IP Phones</h2>
+ <h3>1. Atcom AT-530</h3>
+EOF
+cat at-530.html
+cat <<EOF
+ </td>
+ </tr>
+
+</table>
+</body>
+</html>
+EOF
+
--- /dev/null
+#!/bin/sh
+# login.sh
+# David Rowe 4 Jan 2010
+# CGI for Mini Asterisk login GUI
+
+pass=`echo "$QUERY_STRING" | grep -oe "pass=[^&?]*" | sed -n "s/pass=//p"`
+
+echo $QUERY_STRING | grep pass > /dev/null
+if [ $? -eq 1 ]; then
+ # Display form -------------------------------
+
+ cat <<EOF
+ <script src="prototype.js"></script>
+ <script type="text/javascript" src="tooltip.js"></script>
+ <link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+ cat << EOF
+ <html>
+ <title>Mini Asterisk - Login</title>
+ <form action="login.sh" method="get">
+ <table align="center" width=600>
+ <tr><td colspan="2" align="left"><h2>Login</h2></td>
+ <tr>
+ <tr><td>Password:</td><td><input type="password" name="pass" ></td></tr>
+ <tr><td><input type="submit" value="Login"></td></tr>
+ </tr>
+ <tr><td></td><td>Default password is uClinux</td>
+ </table>
+ </form>
+ </html>
+EOF
+else
+ testuser root $pass
+ if [ $? -eq 0 ]; then
+
+ # login sucessful
+ echo "Content-type: text/html"
+ echo "Set-Cookie: loggedin=1"
+ echo ""
+ echo "<head>"
+ echo "<title>Mini Asterisk - Login</title>"
+ echo '<meta http-equiv="REFRESH" content="0;url=phones.sh">'
+ echo "</head>"
+ echo "<body>"
+ echo "Please wait a few seconds....."
+ echo "</body>"
+
+ # load mini asterisk conf files in case this is our first login
+
+ asterisk -rx "sip reload" 2>/dev/null 1 > /dev/null
+ asterisk -rx "dialplan reload" 2>/dev/null 1 > /dev/null
+
+ else
+ # login failed
+ cat <<EOF
+ <html>
+ <head>
+ <title>Mini Asterisk - Login</title>
+ <meta http-equiv="REFRESH" content="0;url=login.sh">
+ <body>
+ Please wait a few seconds.....
+ </body>
+ </head>
+ </html>
+EOF
+ fi
+fi
+
--- /dev/null
+#!/bin/sh
+# logout.sh
+# David Rowe 4 Jan 2010
+# CGI for Mini Asterisk logout GUI
+
+cat <<EOF
+Content-type: text/html
+Set-Cookie: loggedin=1; expires=Thursday, 01-Jan-98 12:00:00 GMT
+
+<title>Mini Asterisk - Logout</title>
+<meta http-equiv="REFRESH" content="0;url=login.sh"
+EOF
+#echo $HTTP_COOKIE
--- /dev/null
+ <div id="admin_tip" class="tip">Change your password, reset the default settings, upgrade software</div>
+ <div id="network_tip" class="tip">Connect the phone system to your network and the Internet</div>
+ <div id="phones_tip" class="tip">Lists your phones and phone lines</div>
+ <div id="ipphones_tip" class="tip">Set up your IP phones</div>
+ <div id="about_tip" class="tip">Boring information like software version numbers</div>
+ <div id="faq_tip" class="tip">Frequently asked questions and links to further information</div>
+ <div id="logout_tip" class="tip">I think you can work this one out....</div>
+ <div id="voipline_tip" class="tip">Set up your VOIP phone line</div>
+ <td valign="top" >
+ <table align="right" width=200>
+ <tr><td><h2> </h2></td></tr>
+ <tr onMouseOver="popUp(event,'about_tip')" onmouseout="popUp(event,'about_tip')">
+ <td><a href="about.sh">About</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'admin_tip')" onmouseout="popUp(event,'admin_tip')">
+ <td><a href="admin.sh">Admin</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'faq_tip')" onmouseout="popUp(event,'faq_tip')">
+ <td><a href="faq.sh">FAQ</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'ipphones_tip')" onmouseout="popUp(event,'ipphones_tip')">
+ <td><a href="ipphones.sh">IP Phones</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'logout_tip')" onmouseout="popUp(event,'logout_tip')">
+ <td><a href="logout.sh">Logout</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'phones_tip')" onmouseout="popUp(event,'phones_tip')">
+ <td><a href="phones.sh">Phone System</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'network_tip')" onmouseout="popUp(event,'network_tip')">
+ <td><a href="network.sh">Network</a></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'voipline_tip')" onmouseout="popUp(event,'voipline_tip')">
+ <td><a href="voiplines.sh">VOIP Line</a></td>
+ </tr>
+ </table>
+ </td>
--- /dev/null
+var script_path = "cgi-bin/";
+
+function doStatic() {
+ $('ipaddress').disabled = 0;
+ $('netmask').disabled = 0;
+ $('gateway').disabled = 0;
+ $('dns').disabled = 0;
+}
+
+function doDHCP() {
+ $('ipaddress').disabled = 1;
+ $('netmask').disabled = 1;
+ $('gateway').disabled = 1;
+ $('dns').disabled = 1;
+}
+
+// http://moblog.bradleyit.com/2009/06/javascript-ip-address-validation.html
+
+function isIP(obj) {
+ var ary = obj.value.split(".");
+ var ip = true;
+
+ for (var i=0; i<4; i++) {
+ ip = (!ary[i].match(/^\d{1,3}$/) || (Number(ary[i]) > 255)) ? false : ip;
+ }
+
+ if (ip)
+ ip = (ary.length == 4);
+
+ if (!ip) {
+ // the value is NOT a valid IP address
+ obj.style.background = "red";
+ obj.select();
+ }
+ else { obj.style.background = ""; } // the value IS a valid IP address
+
+ return ip;
+}
+
+function localInit() {
+
+ if (init_dhcp == "yes") {
+ $('dhcp').checked = true;
+ $('ipaddress').disabled = 1;
+ $('netmask').disabled = 1;
+ $('gateway').disabled = 1;
+ $('dns').disabled = 1;
+ }
+ else {
+ $('static').checked = true;
+ $('ipaddress').disabled = 0;
+ $('netmask').disabled = 0;
+ $('gateway').disabled = 0;
+ $('dns').disabled = 0;
+ }
+ $('ipaddress').value = init_ipaddress;
+ $('netmask').value = init_netmask;
+ $('gateway').value = init_gateway;
+ $('dns').value = init_dns;
+ $('backdoor').value = init_backdoor;
+ if (init_internet == "yes")
+ $('internet').innerHTML = '<img src="tick.png" alt="tick" />';
+ else
+ $('internet').innerHTML = '<img src="cross.png" alt="tick" />';
+
+}
+
+function validate_form(form)
+{
+ var valid = true;
+
+ if ($('dhcp').checked == false)
+ valid = isIP(form.ipaddress) && isIP(form.ipaddress) && isIP(form.gateway) && isIP(form.dns);
+
+ return valid;
+}
--- /dev/null
+#!/bin/sh
+# network.sh
+# David Rowe 4 Jan 2010
+# CGI for Mini Asterisk network GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+grok_network=0
+
+if [ -f /etc/rc.d/S10network ]; then
+ grok_network=1
+ dhcp=yes
+ ipaddress=`ifconfig eth0 | sed -n 's/.*inet addr:\(.*\) Bcast.*/\1/p'`
+ netmask=`ifconfig eth0 | sed -n 's/.*Mask:\(.*\)\s*/\1/p'`
+ gateway=`route -n | awk '/^0.0.0.0/ {print $2}'`
+ dns=`cat /etc/resolv.conf | awk '/^nameserver/ {print $2}'`
+fi
+
+if [ -f /etc/rc.d/S10network-static ]
+then
+ grok_network=1
+ dhcp=no
+ ipaddress=`sed -n 's/IPADDRESS="\(.*\)"/\1/p' /etc/init.d/network-static`
+ netmask=`sed -n 's/NETMASK="\(.*\)"/\1/p' /etc/init.d/network-static`
+ gateway=`sed -n 's/GATEWAY="\(.*\)"/\1/p' /etc/init.d/network-static`
+ dns=`sed -n 's/DNS="\(.*\)"/\1/p' /etc/init.d/network-static`
+fi
+
+# if we don't understand this machines network config then bail
+
+if [ $groknetwork -eq 0 ]; then
+cat << EOF
+<html>
+<title>Mini Asterisk - Network</title>
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800 border=0>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+ <table align="center" width=600 border=0>
+ <tr><td colspan="2" align="left" valign="top"><h2>Network</h2></td></tr>
+ <tr><td>Sorry - I can't edit the Network configuration on this machine</td></tr>
+ </td>
+ </table>
+ </td>
+ </tr>
+
+</table>
+
+</html>
+EOF
+fi
+
+if [ -f /etc/rc.d/S05network-backdoor ]; then
+ backdoor=`sed -n 's/IPADDRESS="\(.*\)"/\1/p' /etc/init.d/network-backdoor`
+fi
+
+# See if we have Internet connectivity, first check dns as time outs can be very slow
+
+dns_packet_loss=`ping $dns -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
+internet="no";
+if [ $dns_packet_loss == "0" ]; then
+ packet_loss=`ping google.com -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
+ if [ $packet_loss == "0" ]; then
+ internet="yes";
+ fi
+fi
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+
+echo "<script>"
+echo 'var init_dhcp="'$dhcp'";'
+echo 'var init_ipaddress="'$ipaddress'";'
+echo 'var init_netmask="'$netmask'";'
+echo 'var init_gateway="'$gateway'";'
+echo 'var init_dns="'$dns'";'
+echo 'var init_backdoor="'$backdoor'";'
+echo 'var init_internet="'$internet'";'
+cat network.js
+echo "</script>"
+
+cat << EOF
+<html>
+<title>Mini Asterisk - Network</title>
+<body onload="localInit()">
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800 border=0>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <form action="set_network.sh" onsubmit="return validate_form(this)" method="get">
+ <table align="center" width=600 border=0>
+ <tr><td colspan="2" align="left" valign="top"><h2>Network</h2></td></tr>
+ <tr>
+ <td><input type="radio" id="static" name="dhcp" value="no" onClick="doStatic()">Static</td>
+ <td><input type="radio" id="dhcp" name="dhcp" value="yes" onClick="doDHCP()">DHCP</td>
+ </tr>
+ <tr><td>IP Address:</td><td><input type="text" name="ipaddress" id="ipaddress" onBlur="isIP(this)"></td></tr>
+ <tr><td>Netmask:</td><td><input type="text" name="netmask" id="netmask" onBlur="isIP(this)"></td></tr>
+ <tr><td>Gateway:</td><td><input type="text" name="gateway" id="gateway" onBlur="isIP(this)"></td></tr>
+ <tr><td>DNS:</td><td><input type="text" name="dns" id="dns" onBlur="isIP(this)"></td></tr>
+ <tr onMouseOver="popUp(event,'network_backdoor')" onmouseout="popUp(event,'network_backdoor')">
+ <td>Emergency IP:</td><td><input type="text" name="backdoor" id="backdoor" onBlur="isIP(this)"></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'network_internet')" onmouseout="popUp(event,'network_internet')">
+ <td>Internet Connection:</td>
+ <td><div id="internet" >
+ <span style="margin-left: 4px;font-weight:bold"> </span></div></td>
+
+ </tr>
+ <tr><td><input id="networkapply" type="submit" value="Apply"></td></tr>
+ </table>
+ </form>
+
+ </td>
+
+ </tr>
+
+</table>
+
+</html>
+EOF
+
--- /dev/null
+function localInit() {
+ if (init_internet == "yes")
+ $('internet').innerHTML = '<img src="tick.png" alt="tick" />';
+ else
+ $('internet').innerHTML = '<img src="cross.png" alt="tick" />';
+}
+
--- /dev/null
+#!/usr/bin/perl
+# phones.pl
+# David Rowe 5 Jan 2010
+#
+# Text processing for the phones screen.
+
+$tool_tip = "onMouseOver=\"popUp(event,'network_internet')\" onmouseout=\"popUp(event,'network_internet')\"";
+
+# Slurp up analog port (Zap) data from extensions.conf
+
+my %analog = (); # analog extension keyed on zap port
+
+open EXT, "/etc/asterisk/extensions.conf";
+while (<EXT>) {
+ if (/.*=>[ ]*([0-9]*),1.*Zap\/([0-9]*)\)/) {
+ $analog{$2} = $1;
+ #print "'$1' '$2' $analog{$2}\n";
+ }
+}
+close EXT;
+
+# Slurp up data on installed zaptel ports from /etc/zaptel.conf
+
+my %zap = (); # zaptel port type keyed on zap port
+ # (fxs/fxo or no entry if not live)
+open ZAP, "/etc/zaptel.conf";
+while (<ZAP>) {
+ if (/fxoks=(.*)/) {
+ @fxs = split(/,/, $1);
+ foreach (@fxs) {
+ $zap{$_} = "fxs";
+ }
+ }
+ if (/fxsks=(.*)/) {
+ @fxo = split(/,/, $1);
+ foreach (@fxo) {
+ $zap{$_} = "fxo";
+ }
+ }
+}
+close ZAP;
+
+# Slurp up SIP extension (Sip) data from extensions.conf
+
+my %ip = (); # ip extension keyed on sip.conf name
+
+open EXT, "/etc/asterisk/extensions.conf";
+while (<EXT>) {
+ if (/.*=>[ ]*([0-9]*),1.*Sip\/([0-9]*)\)/) {
+ $ip{$2} = $1;
+ #print "'$1' '$2' $ip{$2}\n";
+ }
+}
+close EXT;
+
+# Determine which extenions are "Reception", i.e. set to ring on incoming
+# calls
+
+my %zap_ring = (); # ring flag keyed on Zap port (1,2...)
+my %sip_ring = (); # ring flag keyed on sip.cong ext name (6011,6012 etc)
+
+open EXT, "/etc/asterisk/extensions.conf";
+while (<EXT>) {
+ if (/s,1,Dial\((.*)\) ;; mini/) {
+ @ring = split(/&/, $1);
+ #print "'$1' '@ring'\n foreach:\n";
+ foreach (@ring) {
+ #print " $_\n";
+ if (/Zap\/([0-9]*)/) {
+ $zap_ring{$1} = 1;
+ #print "'$_' $1 \n";
+ }
+ if (/SIP\/([0-9]*)/) {
+ $sip_ring{$1} = 1;
+ #print "'$_' $1 \n";
+ }
+ }
+ }
+}
+close EXT;
+
+
+# work out which IP phones are registered -----------------------------------
+
+my %sip = (); # SIP IP phone status keyed on sip.conf names (6011,6012 etc)
+ # if no entry we can't see IP phone device
+my %ipad = (); # IP address of SIP device keyed on sip.conf names
+
+open SIP, "sipshowpeers.txt";
+while (<SIP>) {
+ if (/^([0-9]*)[\s\/].*(OK)/) {
+ $sip{$1} = $2;
+ #print "'$1' '$2' $sip{$1}\n";
+ $e = $1;
+ if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
+ $ipad{$e} = $1;
+ #print "'$1'\n";
+ }
+ }
+
+ if (/^(.*)\/.*(OK)/) {
+ #$sip{$1} = $2;
+ #print "'$1' '$2' $sip{$1}\n";
+ $e = $1;
+ if (/\s([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s/) {
+ $ipad{$e} = $1;
+ #print "'$1'\n";
+ }
+ }
+}
+
+close SIP;
+
+# Determine if Asterisk can see current voip line (SIP trunk)
+# sipshowpeers.txt needs to be generated before calling this perl
+# script
+
+my %voip = (); # SIP trunks status keyed on sip.conf stanza name/username
+ # if no entry we can't see SIP trunk
+
+open SIP, "sipshowregistry.txt";
+while (<SIP>) {
+ if (/^(.*):.*(Registered)/) {
+ $voip{$1} = $2;
+ #print "'$1' '$2' $voip{$1}\n";
+ }
+}
+
+close SIP;
+
+# start phones ringing form -------------------------------------------
+
+print '<form action="set_ring.sh" method="get">';
+
+# print list of analog phones
+
+$tooltip_anphone = "onMouseOver=\"popUp(event,'phone_anphone')\" onmouseout=\"popUp(event,'phone_anphone')\"";
+$tooltip_ext = "onMouseOver=\"popUp(event,'phone_ext')\" onmouseout=\"popUp(event,'phone_ext')\"";
+$tooltip_port = "onMouseOver=\"popUp(event,'phone_port_phone')\" onmouseout=\"popUp(event,'phone_port_phone')\"";
+$tooltip_reception = "onMouseOver=\"popUp(event,'phone_reception')\" onmouseout=\"popUp(event,'phone_reception')\"";
+
+foreach $a (sort keys %analog) {
+ if ($zap{$a} eq "fxs") {
+ $icon = "<img src=\"tick.png\" alt=\"Analog Phone OK\" />";
+ print "<tr><td $tooltip_ext>$analog{$a}</td><td $tooltip_anphone>Analog Phone</td><td $tooltip_port>Port $a</td>";
+ if ($zap_ring{$a} == 1) {
+ $checked = "checked";
+ }
+ else {
+ $checked = "";
+ }
+ print "<td $tooltip_reception><input type=\"checkbox\" name=\"Zap_$a\" $checked>Reception</td><td>$icon</td></tr>\n";
+ }
+}
+
+# print list of IP phones
+
+$tooltip_ipphone = "onMouseOver=\"popUp(event,'phone_ipphone')\" onmouseout=\"popUp(event,'phone_ipphone')\"";
+$tooltip_ipphone_ip = "onMouseOver=\"popUp(event,'phone_ipphone_ip')\" onmouseout=\"popUp(event,'phone_ipphone_ip')\"";
+$tooltip_reception = "onMouseOver=\"popUp(event,'phone_reception')\" onmouseout=\"popUp(event,'phone_reception')\"";
+
+foreach $s (sort keys %sip) {
+ if ($sip{$s} eq "OK") {
+ $icon = "<img src=\"tick.png\" alt=\"IP Phone OK\" />";
+ print "<tr><td $tooltip_ext>$s</td><td $tooltip_ipphone>IP Phone</td><td $tooltip_ipphone_ip>$ipad{$s}</td>";
+ if ($sip_ring{$s} == 1) {
+ $checked = "checked";
+ }
+ else {
+ $checked = "";
+ }
+ print "<td $tooltip_reception><input type=\"checkbox\" name=\"SIP_$s\" $checked>Reception</td><td>$icon</td></tr>\n";
+ }
+}
+
+print '<tr><td> </td></tr>';
+print "<tr><td onMouseOver=\"popUp(event,'phone_addipphone')\" onmouseout=\"popUp(event,'phone_addipphone')\">";
+print "<a href=\"ipphones.sh\">Add IP Phone</a></td><td></td><td></td><td><input type=\"submit\" value=\"Update Reception\"></td></tr>";
+
+$tool_tip = "onMouseOver=\"popUp(event,'phone_lines')\" onmouseout=\"popUp(event,'phone_lines')\"";
+
+print '<tr><td> </td></tr>';
+print "<tr $tool_tip><td colspan=\"4\" align=\"left\" valign=\"top\" ><h2>Phone Lines</h2></td></tr>
+";
+
+print "</form>";
+
+# print list of analog phone lines
+
+$tooltip_phoneline = "onMouseOver=\"popUp(event,'phone_phoneline')\" onmouseout=\"popUp(event,'phone_phoneline')\"";
+$tooltip_port = "onMouseOver=\"popUp(event,'phone_port_line')\" onmouseout=\"popUp(event,'phone_port_line')\"";
+$tooltip_line_prefix = "onMouseOver=\"popUp(event,'phone_line_prefix')\" onmouseout=\"popUp(event,'phone_line_prefix')\"";
+
+foreach $a (sort keys %analog) {
+ if ($zap{$a} eq "fxo") {
+ $icon = "<img src=\"tick.png\" alt=\"Phone Line OK\" />";
+ print "<tr><td $tooltip_line_prefix>0</td><td $tooltip_phoneline>Analog Line</td><td $tooltip_port>Port $a</td><td></td><td>$icon</td></tr>\n";
+ }
+}
+
+# print list of SIP VOIP trunks
+
+$tooltip_voipline = "onMouseOver=\"popUp(event,'phone_voipline')\" onmouseout=\"popUp(event,'phone_voipline')\"";
+$tooltip_voipline_ip = "onMouseOver=\"popUp(event,'phone_voipline_ip')\" onmouseout=\"popUp(event,'phone_voipline_ip')\"";
+$tooltip_voipline_prefix = "onMouseOver=\"popUp(event,'phone_voipline_prefix')\" onmouseout=\"popUp(event,'phone_voipline_prefix')\"";
+
+foreach $s (sort keys %voip) {
+ if ($voip{$s} eq "Registered") {
+ $icon = "<img src=\"tick.png\" alt=\"VOIP Line OK\" />";
+ print "<tr><td $tooltip_voipline_prefix>1</td><td $tooltip_voipline>VOIP Line</td><td $tooltip_voipline_ip>$ipad{$s}</td><td></td><td>$icon</td></tr>\n";
+ }
+}
+
+print '<tr><td> </td></tr>';
+print "<tr><td colspan=2 onMouseOver=\"popUp(event,'phone_addvoipline')\" onmouseout=\"popUp(event,'phone_addvoipline')\">";
+print "<a href=\"voiplines.sh\">Set Up VOIP Line</a></td></tr>";
--- /dev/null
+#!/bin/sh
+# phones.sh
+# David Rowe 4 Jan 2010
+# Phones screen for Mini Asterisk GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+# See if we have Internet connectivity, first check dns as time outs can be very slow
+
+dns=`cat /etc/resolv.conf | awk '/^nameserver/ {print $2}'`
+dns_packet_loss=`ping $dns -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
+internet="no";
+if [ $dns_packet_loss == "0" ]; then
+ packet_loss=`ping google.com -c 1 -q | sed -n 's/.*received, \(.*\)% packet loss/\1/p'`
+ if [ $packet_loss == "0" ]; then
+ internet="yes";
+ fi
+fi
+
+ipaddress=`ifconfig eth0 | sed -n 's/.*inet addr:\(.*\) Bcast.*/\1/p'`
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+EOF
+
+echo "<script>"
+echo 'var init_internet="'$internet'";'
+cat phones.js
+echo "</script>"
+
+cat << EOF
+<html>
+<title>Mini Asterisk - Phones</title>
+<body onload="localInit()">
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <table align="right" width=600>
+ <tr>
+ <td onMouseOver="popUp(event,'phone_system')" onmouseout="popUp(event,'phone_system')" colspan="4" align="left" valign="top"><h2>Phone System</h2></td>
+ </tr>
+ <tr>
+ <td colspan="3" onMouseOver="popUp(event,'network_internet')" onmouseout="popUp(event,'network_internet')">Internet Connection:</td>
+ <td></td><td><div id="internet" > </div></td>
+ </tr>
+ <tr onMouseOver="popUp(event,'phone_ipaddress')" onmouseout="popUp(event,'phone_ipaddress')">
+ <td colspan="4">Phone System IP Address:</td>
+EOF
+echo "<td>$ipaddress</td>"
+cat <<EOF
+ </tr>
+ <tr><td> </td></tr>
+ <tr>
+ <td onMouseOver="popUp(event,'phone_phones')" onmouseout="popUp(event,'phone_phones')"
+ colspan="3" align="left" valign="top" ><h2>Phones</h2></td>
+ </tr>
+EOF
+
+# use perl to construct list of phones and phone lines for us
+asterisk "-rx sip show peers" 2>/dev/null > sipshowpeers.txt
+./phones.pl
+
+cat<<EOF
+ </table>
+
+ </td>
+
+ </tr>
+
+</table>
+</body>
+</html>
+EOF
+
--- /dev/null
+/* Prototype JavaScript framework, version 1.4.0
+ * (c) 2005 Sam Stephenson <sam@conio.net>
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.4.0',
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+
+ emptyFunction: function() {},
+ K: function(x) {return x}
+}
+
+var Class = {
+ create: function() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+ for (property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+Object.inspect = function(object) {
+ try {
+ if (object == undefined) return 'undefined';
+ if (object == null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+}
+
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+ var __method = this;
+ return function(event) {
+ return __method.call(object, event || window.event);
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.callback();
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+function $() {
+ var elements = new Array();
+
+ for (var i = 0; i < arguments.length; i++) {
+ var element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+
+ if (arguments.length == 1)
+ return element;
+
+ elements.push(element);
+ }
+
+ return elements;
+}
+Object.extend(String.prototype, {
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(eval);
+ },
+
+ escapeHTML: function() {
+ var div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = document.createElement('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+ },
+
+ toQueryParams: function() {
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
+ return pairs.inject({}, function(params, pairString) {
+ var pair = pairString.split('=');
+ params[pair[0]] = pair[1];
+ return params;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ camelize: function() {
+ var oStringList = this.split('-');
+ if (oStringList.length == 1) return oStringList[0];
+
+ var camelizedString = this.indexOf('-') == 0
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
+ : oStringList[0];
+
+ for (var i = 1, len = oStringList.length; i < len; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+
+ return camelizedString;
+ },
+
+ inspect: function() {
+ return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
+ }
+});
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function (iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inject: function(memo, iterator) {
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.collect(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (value >= (result || value))
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (value <= (result || value))
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ return this.collect(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.collect(Prototype.K);
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (typeof args.last() == 'function')
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ iterator(value = collections.pluck(index));
+ return value;
+ });
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0; i < iterable.length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0; i < this.length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != undefined || value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0; i < this.length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ shift: function() {
+ var result = this[0];
+ for (var i = 0; i < this.length - 1; i++)
+ this[i] = this[i + 1];
+ this.length--;
+ return result;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+var Hash = {
+ _each: function(iterator) {
+ for (key in this) {
+ var value = this[key];
+ if (typeof value == 'function') continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ return pair.map(encodeURIComponent).join('=');
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+}
+
+function $H(object) {
+ var hash = Object.extend({}, object || {});
+ Object.extend(hash, Enumerable);
+ Object.extend(hash, Hash);
+ return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ do {
+ iterator(value);
+ value = value.succ();
+ } while (this.include(value));
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')},
+ function() {return new XMLHttpRequest()}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+}
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responderToAdd) {
+ if (!this.include(responderToAdd))
+ this.responders.push(responderToAdd);
+ },
+
+ unregister: function(responderToRemove) {
+ this.responders = this.responders.without(responderToRemove);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (responder[callback] && typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) {}
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() {
+ Ajax.activeRequestCount++;
+ },
+
+ onComplete: function() {
+ Ajax.activeRequestCount--;
+ }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+ setOptions: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+ },
+
+ responseIsSuccess: function() {
+ return this.transport.status == undefined
+ || this.transport.status == 0
+ || (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ responseIsFailure: function() {
+ return !this.responseIsSuccess();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(url, options) {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function(url) {
+ var parameters = this.options.parameters || '';
+ if (parameters.length > 0) parameters += '&_=';
+
+ try {
+ this.url = url;
+ if (this.options.method == 'get' && parameters.length > 0)
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.options.method, this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous) {
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
+ }
+
+ this.setRequestHeaders();
+
+ var body = this.options.postBody ? this.options.postBody : parameters;
+ this.transport.send(this.options.method == 'post' ? body : null);
+
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ setRequestHeaders: function() {
+ var requestHeaders =
+ ['X-Requested-With', 'XMLHttpRequest',
+ 'X-Prototype-Version', Prototype.Version];
+
+ if (this.options.method == 'post') {
+ requestHeaders.push('Content-type',
+ 'application/x-www-form-urlencoded');
+
+ /* Force "Connection: close" for Mozilla browsers to work around
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
+ * header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType)
+ requestHeaders.push('Connection', 'close');
+ }
+
+ if (this.options.requestHeaders)
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
+
+ for (var i = 0; i < requestHeaders.length; i += 2)
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState != 1)
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ header: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {}
+ },
+
+ evalJSON: function() {
+ try {
+ return eval(this.header('X-JSON'));
+ } catch (e) {}
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ respondToReadyState: function(readyState) {
+ var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if (event == 'Complete') {
+ try {
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+ if (event == 'Complete')
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function(container, url, options) {
+ this.containers = {
+ success: container.success ? $(container.success) : $(container),
+ failure: container.failure ? $(container.failure) :
+ (container.success ? null : $(container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function(transport, object) {
+ this.updateContent();
+ onComplete(transport, object);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function() {
+ var receiver = this.responseIsSuccess() ?
+ this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
+
+ if (!this.options.evalScripts)
+ response = response.stripScripts();
+
+ if (receiver) {
+ if (this.options.insertion) {
+ new this.options.insertion(receiver, response);
+ } else {
+ Element.update(receiver, response);
+ }
+ }
+
+ if (this.responseIsSuccess()) {
+ if (this.onComplete)
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(container, url, options) {
+ this.setOptions(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = {};
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+document.getElementsByClassName = function(className, parentElement) {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ return $A(children).inject([], function(elements, child) {
+ if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ elements.push(child);
+ return elements;
+ });
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element) {
+ var Element = new Object();
+}
+
+Object.extend(Element, {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ }
+ },
+
+ hide: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ element.style.display = 'none';
+ }
+ },
+
+ show: function() {
+ for (var i = 0; i < arguments.length; i++) {
+ var element = $(arguments[i]);
+ element.style.display = '';
+ }
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ },
+
+ update: function(element, html) {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ },
+
+ getHeight: function(element) {
+ element = $(element);
+ return element.offsetHeight;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).include(className);
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).add(className);
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).remove(className);
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ for (var i = 0; i < element.childNodes.length; i++) {
+ var node = element.childNodes[i];
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ Element.remove(node);
+ }
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.match(/^\s*$/);
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var x = element.x ? element.x : element.offsetLeft,
+ y = element.y ? element.y : element.offsetTop;
+ window.scrollTo(x, y);
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ var value = element.style[style.camelize()];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style.camelize()];
+ }
+ }
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (name in style)
+ element.style[name.camelize()] = style[name];
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'display') != 'none')
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element._overflow = element.style.overflow;
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+ element.style.overflow = 'hidden';
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return;
+ element.style.overflow = element._overflow;
+ element._overflow = undefined;
+ }
+});
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function(element, content) {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if (this.adjacency && this.element.insertAdjacentHTML) {
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ if (this.element.tagName.toLowerCase() == 'tbody') {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
+ } else {
+ this.range = this.element.ownerDocument.createRange();
+ if (this.initializeRange) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function() {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function() {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set(this.toArray().concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set(this.select(function(className) {
+ return className != classNameToRemove;
+ }).join(' '));
+ },
+
+ toString: function() {
+ return this.toArray().join(' ');
+ }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Field = {
+ clear: function() {
+ for (var i = 0; i < arguments.length; i++)
+ $(arguments[i]).value = '';
+ },
+
+ focus: function(element) {
+ $(element).focus();
+ },
+
+ present: function() {
+ for (var i = 0; i < arguments.length; i++)
+ if ($(arguments[i]).value == '') return false;
+ return true;
+ },
+
+ select: function(element) {
+ $(element).select();
+ },
+
+ activate: function(element) {
+ element = $(element);
+ element.focus();
+ if (element.select)
+ element.select();
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var Form = {
+ serialize: function(form) {
+ var elements = Form.getElements($(form));
+ var queryComponents = new Array();
+
+ for (var i = 0; i < elements.length; i++) {
+ var queryComponent = Form.Element.serialize(elements[i]);
+ if (queryComponent)
+ queryComponents.push(queryComponent);
+ }
+
+ return queryComponents.join('&');
+ },
+
+ getElements: function(form) {
+ form = $(form);
+ var elements = new Array();
+
+ for (tagName in Form.Element.Serializers) {
+ var tagElements = form.getElementsByTagName(tagName);
+ for (var j = 0; j < tagElements.length; j++)
+ elements.push(tagElements[j]);
+ }
+ return elements;
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name)
+ return inputs;
+
+ var matchingInputs = new Array();
+ for (var i = 0; i < inputs.length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) ||
+ (name && input.name != name))
+ continue;
+ matchingInputs.push(input);
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.blur();
+ element.disabled = 'true';
+ }
+ },
+
+ enable: function(form) {
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.disabled = '';
+ }
+ },
+
+ findFirstElement: function(form) {
+ return Form.getElements(form).find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ Field.activate(Form.findFirstElement(form));
+ },
+
+ reset: function(form) {
+ $(form).reset();
+ }
+}
+
+Form.Element = {
+ serialize: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter) {
+ var key = encodeURIComponent(parameter[0]);
+ if (key.length == 0) return;
+
+ if (parameter[1].constructor != Array)
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter)
+ return parameter[1];
+ }
+}
+
+Form.Element.Serializers = {
+ input: function(element) {
+ switch (element.type.toLowerCase()) {
+ case 'submit':
+ case 'hidden':
+ case 'password':
+ case 'text':
+ return Form.Element.Serializers.textarea(element);
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ }
+ return false;
+ },
+
+ inputSelector: function(element) {
+ if (element.checked)
+ return [element.name, element.value];
+ },
+
+ textarea: function(element) {
+ return [element.name, element.value];
+ },
+
+ select: function(element) {
+ return Form.Element.Serializers[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function(element) {
+ var value = '', opt, index = element.selectedIndex;
+ if (index >= 0) {
+ opt = element.options[index];
+ value = opt.value;
+ if (!value && !('value' in opt))
+ value = opt.text;
+ }
+ return [element.name, value];
+ },
+
+ selectMany: function(element) {
+ var value = new Array();
+ for (var i = 0; i < element.length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) {
+ var optValue = opt.value;
+ if (!optValue && !('value' in opt))
+ optValue = opt.text;
+ value.push(optValue);
+ }
+ }
+ return [element.name, value];
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+ initialize: function(element, frequency, callback) {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ var elements = Form.getElements(this.element);
+ for (var i = 0; i < elements.length; i++)
+ this.registerCallback(elements[i]);
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ case 'password':
+ case 'text':
+ case 'textarea':
+ case 'select-one':
+ case 'select-multiple':
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) {
+ var Event = new Object();
+}
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+
+ element: function(event) {
+ return event.target || event.srcElement;
+ },
+
+ isLeftClick: function(event) {
+ return (((event.which) && (event.which == 1)) ||
+ ((event.button) && (event.button == 1)));
+ },
+
+ pointerX: function(event) {
+ return event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
+ },
+
+ pointerY: function(event) {
+ return event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop));
+ },
+
+ stop: function(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ event.stopPropagation();
+ } else {
+ event.returnValue = false;
+ event.cancelBubble = true;
+ }
+ },
+
+ // find the first node with the given tagName, starting from the
+ // node the event was triggered on; traverses the DOM upwards
+ findElement: function(event, tagName) {
+ var element = Event.element(event);
+ while (element.parentNode && (!element.tagName ||
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
+ element = element.parentNode;
+ return element;
+ },
+
+ observers: false,
+
+ _observeAndCache: function(element, name, observer, useCapture) {
+ if (!this.observers) this.observers = [];
+ if (element.addEventListener) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.addEventListener(name, observer, useCapture);
+ } else if (element.attachEvent) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.attachEvent('on' + name, observer);
+ }
+ },
+
+ unloadCache: function() {
+ if (!Event.observers) return;
+ for (var i = 0; i < Event.observers.length; i++) {
+ Event.stopObserving.apply(this, Event.observers[i]);
+ Event.observers[i][0] = null;
+ }
+ Event.observers = false;
+ },
+
+ observe: function(element, name, observer, useCapture) {
+ var element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.attachEvent))
+ name = 'keydown';
+
+ this._observeAndCache(element, name, observer, useCapture);
+ },
+
+ stopObserving: function(element, name, observer, useCapture) {
+ var element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.detachEvent))
+ name = 'keydown';
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, observer, useCapture);
+ } else if (element.detachEvent) {
+ element.detachEvent('on' + name, observer);
+ }
+ }
+});
+
+/* prevent memory leaks in IE */
+Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ realOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ p = Element.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ offsetParent: function(element) {
+ if (element.offsetParent) return element.offsetParent;
+ if (element == document.body) return element;
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return element;
+
+ return document.body;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = this.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = this.realOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = this.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ clone: function(source, target) {
+ source = $(source);
+ target = $(target);
+ target.style.position = 'absolute';
+ var offsets = this.cumulativeOffset(source);
+ target.style.top = offsets[1] + 'px';
+ target.style.left = offsets[0] + 'px';
+ target.style.width = source.offsetWidth + 'px';
+ target.style.height = source.offsetHeight + 'px';
+ },
+
+ page: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent==document.body)
+ if (Element.getStyle(element,'position')=='absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ } while (element = element.parentNode);
+
+ return [valueL, valueT];
+ },
+
+ clone: function(source, target) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || {})
+
+ // find page position of source
+ source = $(source);
+ var p = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(target,'position') == 'absolute') {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.style.position == 'absolute') return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';;
+ element.style.left = left + 'px';;
+ element.style.width = width + 'px';;
+ element.style.height = height + 'px';;
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.style.position == 'relative') return;
+ Position.prepare();
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ Position.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return [valueL, valueT];
+ }
+}
\ No newline at end of file
--- /dev/null
+#!/bin/sh
+# set_network.sh
+#
+# CGI to set network parameters of an IP0X.
+
+cat <<EOF
+<html>
+<head>
+<title>set_network.sh</title>
+<meta http-equiv="REFRESH" content="0;url=network.sh">
+<body>
+Please wait a few seconds.....
+</body>
+</head>
+</html>
+EOF
+
+dhcp=`echo "$QUERY_STRING" | grep -oe "dhcp=[^&?]*" | sed -n "s/dhcp=//p"`
+ipaddress=`echo "$QUERY_STRING" | grep -oe "ipaddress=[^&?]*" | sed -n "s/ipaddress=//p"`
+netmask=`echo "$QUERY_STRING" | grep -oe "netmask=[^&?]*" | sed -n "s/netmask=//p"`
+gateway=`echo "$QUERY_STRING" | grep -oe "gateway=[^&?]*" | sed -n "s/gateway=//p"`
+dns=`echo "$QUERY_STRING" | grep -oe "dns=[^&?]*" | sed -n "s/dns=//p"`
+backdoor=`echo "$QUERY_STRING" | grep -oe "backdoor=[^&?]*" | sed -n "s/backdoor=//p"`
+
+if [ $dhcp == "yes" ]; then
+
+ # DHCP
+
+ if [ -f /etc/rc.d/S10network-static ]; then
+ /etc/init.d/network-static disable
+ /etc/init.d/network-static stop
+ /etc/init.d/network enable
+ /etc/init.d/network start
+ else
+ # if already running restart service
+ /etc/init.d/network stop
+ /etc/init.d/network start
+ fi
+fi
+
+if [ $dhcp == "no" ]; then
+
+ # Static IP
+
+ if [ -f /etc/rc.d/S10network ]; then
+ /etc/init.d/network stop
+ /etc/init.d/network disable
+ /etc/init.d/network-static enable
+ fi
+
+ sed -i "s/DHCPD=.*/DHCPD=no/g" /etc/init.d/network-static
+ sed -i "s/IPADDRESS=.*/IPADDRESS=\"$ipaddress\"/g" /etc/init.d/network-static
+ sed -i "s/NETMASK=.*/NETMASK=\"$netmask\"/g" /etc/init.d/network-static
+ sed -i "s/GATEWAY=.*/GATEWAY=\"$gateway\"/g" /etc/init.d/network-static
+ sed -i "s/DNS=.*/DNS=\"$dns\"/g" /etc/init.d/network-static
+ /etc/init.d/network-static stop
+ /etc/init.d/network-static start
+fi
+
+if [ -f /etc/rc.d/S05network-backdoor ]; then
+ sed -i "s/IPADDRESS=.*/IPADDRESS=\"$backdoor\"/g" /etc/init.d/network-backdoor
+ /etc/init.d/network-backdoor stop
+ /etc/init.d/network-backdoor start
+fi
--- /dev/null
+#!/bin/sh -x
+# set_ring.sh
+# David Rowe 4 Jan 2010
+# CGI to set which extensions ring on uncoming calls
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+# extract extensions to ring and reload extensions.conf
+
+a=`echo "$QUERY_STRING" | sed -n "s/=on*//pg" | sed -n 's,_,/,pg'`
+
+# escape & if present
+echo "$a" | grep "&" >> /dev/null
+if [ $? -eq 0 ]; then
+ a=`echo $a | sed -n "s/&/\\\\&/pg"`
+fi
+
+sed -i "s_s,1,Dial(.*) ;; mini-asterisk_s,1,Dial($a) ;; mini-asterisk_" /etc/asterisk/extensions.conf
+asterisk -rx "dialplan reload" 2>/dev/null 1 > /dev/null
+
+# bounce us back to Phones screen
+
+cat <<EOF
+<html>
+<head>
+<title>Mini Asterisk - Set Ring</title>
+<meta http-equiv="REFRESH" content="0;url=phones.sh">
+<body>
+Please wait a few seconds.....
+EOF
+#echo $QUERY_STRING "<br>"
+#echo "$QUERY_STRING" | sed -n "s/=on*//pg" | sed -n 's,_,/,pg'
+#echo "<br>"
+#echo $a
+
+cat <<EOF
+</body>
+</head>
+</html>
+EOF
+
--- /dev/null
+#!/usr/bin/perl
+# set_voiplines.pl
+# David Rowe 12 Jan 2010
+#
+# Replaces fields in sip.conf, outputs new sip.conf contents to stdout
+
+$user = $ARGV[0];
+$pass = $ARGV[1];
+$host = $ARGV[2];
+$stanza_new = $ARGV[3];
+
+# We need to slurp up the mini asterisk provider and spit them
+# back out. All must be commented out except for the one that
+# is selected. Hopefully non-mini asterisk content of sip.conf
+# won't be affected.
+
+open SIP, "/etc/asterisk/sip.conf";
+$provider = "";
+while (<SIP>) {
+
+ # start of any new stanza switches off parsing. It may get
+ # switched back on below if it contains mini-asterisk
+ # keyword. This allows non-mini asterisk SIP stanzas to be
+ # included in sip.conf
+
+ if (/\[/) {
+ $stanza = "";
+ }
+
+ # look for commented or uncommented mini asterisk provider stanza
+
+ if (/\[(.*)\] .* mini-asterisk/) {
+ $stanza = $1;
+ }
+
+ if ($stanza eq "") {
+ # we are not in an mini-asterisk provider stanza
+
+ if (/;*register => (\S*)@(\S*).*;.*(mini-asterisk.*)/) {
+ # an mini-asterisk register line
+
+ #print "XX stanza_new='$stanza_new' '$1' '$2' '$3'\n";
+
+ if ($2 eq $stanza_new) {
+ print "register => $user\@$stanza_new; $3\n";
+ }
+ else {
+ print ";register => $1\@$2 ; $3\n";
+ }
+ }
+ else {
+ # OK so this is a regular sip.conf line, just echo to stdout
+ print $_;
+ }
+ }
+ else {
+ # OK, we are in an mini-asterisk stanza
+
+ # strip off any leading ";"
+
+ $_ =~ s/^\;//;
+
+ if ($stanza eq $stanza_new) {
+
+ # this stanza should be uncommented
+
+ if (/^user=/) {
+ print "user=$user\n";
+ }
+ if (/^username=/) {
+ print "username=$user\n";
+ }
+ elsif (/^fromuser=/) {
+ print "fromuser=$user\n";
+ }
+ elsif (/^secret=/) {
+ print "secret=$pass\n";
+ }
+ elsif (/^host=/) {
+ print "host=$host\n";
+ }
+ else {
+ print $_;
+ }
+ }
+ else {
+ # comment out unused mini-asterisk stanzas
+ print ";$_";
+ }
+ }
+
+}
+close SIP;
+
--- /dev/null
+#!/bin/sh
+# set_voipline.sh
+# # David Rowe 12 Jan 2010
+#
+# CGI to set voip line parameters in sip.conf.
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+user=`echo "$QUERY_STRING" | grep -oe "user=[^&?]*" | sed -n "s/user=//p"`
+pass=`echo "$QUERY_STRING" | grep -oe "pass=[^&?]*" | sed -n "s/pass=//p"`
+host=`echo "$QUERY_STRING" | grep -oe "host=[^&?]*" | sed -n "s/host=//p"`
+stanza=`echo "$QUERY_STRING" | grep -oe "stanza=[^&?]*" | sed -n "s/stanza=//p"`
+
+# create new sip.conf with selected provider uncommented
+
+echo "set_voiplines.sh" $user $pass $host $stanza >> /tmp/log.txt
+./set_voiplines.pl $user $pass $host $stanza > /etc/asterisk/sip.conf.new
+mv /etc/asterisk/sip.conf /etc/asterisk/sip.conf.bak
+mv /etc/asterisk/sip.conf.new /etc/asterisk/sip.conf
+
+# get asterisk to load changes
+
+asterisk -rx "sip reload" 2>/dev/null 1 > /dev/null
+
+cat <<EOF
+<html>
+<head>
+<title>set_voiplines.sh</title>
+<meta http-equiv="REFRESH" content="0;url=voiplines.sh">
+<body>
+Please wait a few seconds.....
+</body>
+</head>
+</html>
+EOF
+
--- /dev/null
+.tip {font:12px/14px
+Arial,Helvetica,sans-serif; border:solid 1px
+#666666; width:270px; padding:1px;
+position:absolute; z-index:100;
+visibility:hidden; color:#333333; top:20px;
+left:90px; background-color:#ffffcc;
+layer-background-color:#ffffcc;}
--- /dev/null
+// Extended Tooltip Javascript
+// copyright 9th August 2002, 3rd July 2005, 24th August 2008
+// by Stephen Chapman, Felgall Pty Ltd
+
+// permission is granted to use this javascript provided that the below code is not altered
+function pw() {return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth}; function mouseX(evt) {return evt.clientX ? evt.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) : evt.pageX;} function mouseY(evt) {return evt.clientY ? evt.clientY + (document.documentElement.scrollTop || document.body.scrollTop) : evt.pageY} function popUp(evt,oi) {if (document.getElementById) {var wp = pw(); dm = document.getElementById(oi); ds = dm.style; st = ds.visibility; if (dm.offsetWidth) ew = dm.offsetWidth; else if (dm.clip.width) ew = dm.clip.width; if (st == "visible" || st == "show") { ds.visibility = "hidden"; } else {tv = mouseY(evt) + 20; lv = mouseX(evt) - (ew/4); if (lv < 2) lv = 2; else if (lv + ew > wp) lv -= ew/2; lv += 'px';tv += 'px'; ds.left = lv; ds.top = tv; ds.visibility = "visible";}}}
+
--- /dev/null
+<div id="network_internet" class="tip">
+ A tick means your phone system can reach the Internet. You need the Internet for VOIP calls
+ and software upgrades.
+ If you have a problem reaching the Internet check your Network settings, in
+ particular Gateway and DNS.</div>
+
+<div id="network_backdoor" class="tip">
+ Emergency backdoor IP. Useful if you get locked out of the main network connection, for
+ example due to DHCP problems on your network or a configuration mistake.
+ Write this number down somewhere!</div>
+
+<div id="phone_reception" class="tip">
+ If ticked this phone will ring when some one
+ calls the phone system from an outside Analog
+ or VOIP Line. More than one phone can be
+ ticked. You can answer a call on another
+ ringing phone by dialling *8 on your phone -
+ see FAQ for details.</div>
+
+<div id="phone_anphone" class="tip">
+ Analog Phone: Normal telephone plugged into a port on your phone system.
+ </div>
+<div id="phone_ipphone" class="tip">
+ IP Phone plugged into your network.
+ </div>
+<div id="phone_line" class="tip">
+ Analog Phone Line: Analog telephone line plugged into a port on your phone system.
+ </div>
+<div id="phone_voipline" class="tip">
+ VOIP Phone Line: Make and receive phone calls over the Internet.
+ </div>
+
+<div id="phone_system" class="tip">
+ Important information about your Phone System.</div>
+
+<div id="phone_ipaddress" class="tip">
+ The address of your Phone System
+ on your network. Use this address to connect
+ IP Phones to your Phone System. </div>
+
+<div id="phone_phones" class="tip">
+ List of phones connected to your Phone
+ System. You can connect Analog or IP Phones
+ to your system. When IP Phones are
+ configured correctly, they appear on this
+ list. If an IP phone is not configured
+ correctly, it will not appear on this list.
+ Analog phones require hardware to be
+ installed in your Phone system.</div>
+
+<div id="phone_lines" class="tip">
+ List of phone lines available. Phone lines
+ are used to make and receive outside calls.
+ You can use regular Analog phone lines or
+ VOIP. VOIP phone lines require an account
+ with an Internet Telephone Service Provider.
+ Analog phone lines require hardware to be
+ installed in your Phone System.</div>
+
+<div id="phone_ext" class="tip">
+ Dial this number to call this phone</div>
+
+<div id="phone_port_phone" class="tip">
+ Port (socket) on the rear of your Phone System. Plug the phone into this Port.</div>
+
+<div id="phone_port_line" class="tip">
+ Port (socket) on the rear of your Phone
+ System. Plug the phone line into this
+ Port.</div>
+
+<div id="phone_line_prefix" class="tip">
+ Dial 0 for an Analog outside line. For example to call 5551234 dial 05551234</div>
+
+<div id="phone_ipphone_ip" class="tip">
+ IP Address of this phone on your network</div>
+
+<div id="phone_voipline_ip" class="tip">
+ IP Address of the VOIP Internet Telephone Service Provider</div>
+
+<div id="phone_voipline_prefix" class="tip">
+ Dial 1 for a VOIP outside line. For example to call 5551234 dial 15551234</div>
+
+<div id="phone_addipphone" class="tip">
+ Instructions and help on adding a new IP phone</div>
+
+<div id="phone_addvoipline" class="tip">
+ Instructions and help on VOIP Line set up</div>
+
+<div id="ipphones_ipphones" class="tip">
+ List of possible IP phones. For a new phone
+ choose any Available number. Refresh this
+ page to update</div>
+
+<div id="ipphones_connected" class="tip">
+ The IP phone is connected to your phone system and ready to use</div>
+
+<div id="ipphones_notconnected" class="tip">
+ No IP phone is connected. Either no IP phone
+ is present, or the IP phone has not been set
+ up.</div>
+
+<div id="voiplines_voiplines" class="tip">
+ A VOIP line allows you to make and receive
+ phones calls over the Internet. Normally a
+ VOIP line is provided by an Internet Telephony
+ Service Provider (ITSP). They will give you
+ an account, which includes the user and
+ password details that you can fill in below.
+ Refresh this page on your browser to see if
+ your VOIP line is working. </div>
+
+<div id="voiplines_provider" class="tip">
+ Your Internet Telephony Service Provider.
+ They will give you an account with a user name
+ and password.</div>
+
+<div id="voiplines_user" class="tip">
+ Your account name with your Internet Telephony Service Provider</div>
+
+<div id="voiplines_pass" class="tip">
+ The password for your Internet Telephony Service Provider account</div>
+
+<div id="voiplines_host" class="tip">
+ The Internet address of your Internet
+ Telephony Service Provider. This will usually
+ be filled in automatically.</div>
+
+<div id="voiplines_status" class="tip">
+ A tick means you are connected to your
+ Internet Telephony Service Provider. Refresh
+ your browser to update.</div>
+
+<div id="admin_restart" class="tip">
+ Press this button to restart your phone
+ system. This is the same as turning the power
+ off and back on. </div>
+
+<div id="admin_upgrade" class="tip">
+ Press this button to the latest version of
+ Mini Asterisk. An Mini Asterisk upgrade
+ requires an Internet connection.</div>
+
+<div id="admin_firmware" class="tip">
+ Enter the URL of a firmware update script.
+ This option can be used to install new
+ firmware on your Phone System. Installing new
+ firmware requires an Internet
+ connection.</div>
+
--- /dev/null
+function changeProvider() {
+ provider = $('provider').value;
+ $('user').value = users[provider];
+ $('pass').value = passwords[provider];
+ $('host').value = hosts[provider];
+ $('stanza').value = stanzas[provider];
+}
--- /dev/null
+#!/usr/bin/perl
+# voiplines.pl
+# David Rowe 12 Jan 2010
+#
+# Text processing for the voiplines screen
+
+# slurp up list of possible voip line providers --------------------------------
+# one of these will be currently selected
+
+open SIP, "/etc/asterisk/sip.conf";
+my $provider = ""; # current provider bring parsed in sip.conf
+my @providers=(); # list of all providers
+my %stanza = (); # stanza name keyed on provider
+my %user = (); # user keyed on provider
+my %pass = (); # password keyed on provider
+my %host = (); # host name keyed on provider
+
+while (<SIP>) {
+
+ # start of any stanza switches off parsing. It may get switched
+ # back on below if it contains mini-asterisk keyword. This allows
+ # non-mini asterisk SIP devices to be included in sip.conf
+
+ if (/\[/) {
+ $provider = "";
+ }
+
+ # currently disabled mini-asterisk provider
+
+ if (/^;\[(.*)\].* \"(.*)\" mini-asterisk/) {
+ push (@providers, $2);
+ $provider = $2;
+ $stanza{$2} = $1;
+ #print "'$1' '$2'\n";
+ }
+
+ # current mini-asterisk provider
+
+ if (/^\[(.*)\].* \"(.*)\" mini-asterisk/) {
+ push (@providers, $2);
+ $provider = $2;
+ $provider_current = $2;
+ $stanza{$2} = $1;
+ #print "'$1' '$2'\n";
+ }
+
+ if ($provider ne "") {
+ #print $_;
+
+ if (/^;*user=(.*)/) {
+ $user{$provider} = $1;
+ }
+ if (/^;*username=(.*)/) {
+ $user{$provider} = $1;
+ }
+ if (/^;*secret=(.*)/) {
+ $pass{$provider} = $1;
+ }
+ if (/^;*host=(.*)/) {
+ $host{$provider} = $1;
+ }
+ }
+
+ $state = $next_state;
+}
+close SIP;
+
+# Determine if Asterisk can see current voip line (SIP trunk)
+# sipshowpeers.txt needs to be generated before calling this perl
+# script
+
+my %voip = (); # SIP trunks status keyed on sip.conf stanza name/username
+ # if no entry we can't see SIP trunk
+
+open SIP, "sipshowregistry.txt";
+while (<SIP>) {
+ if (/^(.*):.*(Registered)/) {
+ $voip{$1} = $2;
+ #print "'$1' '$2' $voip{$1}\n";
+ }
+}
+
+close SIP;
+
+# javascript to handle changing providers
+
+print "<script>\n";
+print "var hosts = new Array();\n";
+print "var users = new Array();\n";
+print "var passwords = new Array();\n";
+print "var stanzas = new Array();\n";
+foreach (@providers) {
+ print "hosts[\'$_\'] = \'$host{$_}\';\n";
+ print "users[\'$_\'] = \'$user{$_}\';\n";
+ print "passwords[\'$_\'] = \'$pass{$_}\';\n";
+ print "stanzas[\'$_\'] = \'$stanza{$_}\';\n";
+}
+print "</script>\n";
+
+# generate form fields -------------------------------------------
+
+$tt_provider = "onMouseOver=\"popUp(event,'voiplines_provider')\" onmouseout=\"popUp(event,'voiplines_provider')\"";
+$tt_user = "onMouseOver=\"popUp(event,'voiplines_user')\" onmouseout=\"popUp(event,'voiplines_user')\"";
+$tt_pass = "onMouseOver=\"popUp(event,'voiplines_pass')\" onmouseout=\"popUp(event,'voiplines_pass')\"";
+$tt_host = "onMouseOver=\"popUp(event,'voiplines_host')\" onmouseout=\"popUp(event,'voiplines_host')\"";
+$tt_status = "onMouseOver=\"popUp(event,'voiplines_status')\" onmouseout=\"popUp(event,'voiplines_status')\"";
+
+print "<tr $tt_provider><td>Provider</td><td>\n";
+print "<select name=\"provider\" id=\"provider\" onchange=\"changeProvider()\">\n";
+foreach (@providers) {
+ if ($_ eq $provider_current) {
+ print "<option selected=\"yes\">$_</option>\n";
+ }
+ else {
+ print "<option>$_</option>\n";
+ }
+}
+print "</select></td></tr>\n";
+
+print "<tr $tt_user><td>User:</td><td><input type=\"text\" name=\"user\" id=\"user\" value=\"$user{$provider_current}\"></td></tr>\n";
+print "<tr $tt_pass><td>Password:</td><td><input type=\"password\" name=\"pass\" id=\"pass\" value=\"$pass{$provider_current}\"></td></tr>\n";
+print "<tr $tt_host><td>Host:</td><td><input type=\"text\" name=\"host\" id=\"host\" value=\"$host{$provider_current}\"></td></tr>\n";
+
+#print "\nXXX $provider_current $stanza{$provider_current} $voip{$stanza{$provider_current}}\n";
+
+if ($voip{$stanza{$provider_current}} eq "Registered") {
+ $icon = "<img src=\"tick.png\" alt=\"OK\" />";
+}
+else {
+ $icon = "<img src=\"cross.png\" alt=\"Not OK\" />";
+}
+print "<tr $tt_status><td>Voip Line Status:</td><td>$icon</td></tr>\n";
+
+# hidden field to pass stanza with form
+
+print "<tr><td><input type=\"hidden\" name=\"stanza\" id=\"stanza\" value=\"$stanza{$provider_current}\"></td></tr>";
--- /dev/null
+#!/bin/sh
+# voiplines.sh
+# David Rowe 12 Jan 2010
+# VOIP Line screen for Mini Asterisk GUI
+
+# check we are logged in
+
+echo $HTTP_COOKIE | grep "loggedin" > /dev/null
+if [ $? -eq 1 ]; then
+ echo "<html>"
+ echo "<head>"
+ echo '<meta http-equiv="REFRESH" content="0;url=login.sh">'
+ echo "</head>"
+ echo "</html>"
+ exit
+fi
+
+# See if we have can reach the VOIP Line provider
+
+asterisk "-rx sip show registry" 2>/dev/null > sipshowregistry.txt
+
+# Construct the web page -------------------------------
+
+cat <<EOF
+<script src="prototype.js"></script>
+<script type="text/javascript" src="tooltip.js"></script>
+<link rel="stylesheet" href="tooltip.css" type="text/css" />
+<script>
+EOF
+
+cat voiplines.js
+
+cat << EOF
+</script>
+<html>
+<title>Mini Asterisk - VOIP Line</title>
+EOF
+
+cat tooltips.html
+echo '<table align="center" width=800>'
+cat banner.html
+echo " <tr>"
+cat menu.html
+cat <<EOF
+
+ <td valign="top">
+
+ <table align="right" width=600>
+ <tr><td> </td></tr>
+ <form action="set_voiplines.sh" method="get">
+ <tr><td onMouseOver="popUp(event,'voiplines_voiplines')" onmouseout="popUp(event,'voiplines_voiplines')" align="left" valign="top"><h2>VOIP Line</h2></td></tr>
+
+ <tr><td> </td></tr>
+EOF
+
+./voiplines.pl
+
+cat <<EOF
+ <tr><td> </td></tr>
+ <tr><td><input type="submit" value="OK"></td></tr>
+
+ </form>
+
+ </table>
+ </form>
+
+ </td>
+
+ </tr>
+
+</table>
+</body>
+</html>
+EOF
+
--- /dev/null
+; extensions.conf
+; David Rowe 4 Jan 2010
+;
+
+; Designed for Mini Asterisk GUI. However you can hand modify as much
+; as you like, as GUI scripts read/and write regular extensions.conf
+; without messing with your custom dialplan
+
+
+[general]
+static = yes
+writeprotect = no
+autofallthrough = yes
+clearglobalvars = no
+priorityjumping = no
+
+[default]
+
+; Pre-configured analog extensions, depends on IP0X model and what modules
+; are installed. Some of these may map to FXO ports
+
+exten => 6001,1,Dial(Zap/1)
+exten => 6002,1,Dial(Zap/2)
+exten => 6003,1,Dial(Zap/3)
+exten => 6004,1,Dial(Zap/4)
+exten => 6005,1,Dial(Zap/5)
+exten => 6006,1,Dial(Zap/6)
+exten => 6007,1,Dial(Zap/7)
+exten => 6008,1,Dial(Zap/8)
+
+; Pre-configured SIP-phone extensions. Primary use case is multiple SIP
+; extensions and FXO analog Ports
+
+exten => 6011,1,Dial(SIP/6011)
+exten => 6012,1,Dial(SIP/6012)
+exten => 6013,1,Dial(SIP/6013)
+exten => 6014,1,Dial(SIP/6014)
+exten => 6015,1,Dial(SIP/6015)
+exten => 6016,1,Dial(SIP/6016)
+exten => 6017,1,Dial(SIP/6017)
+exten => 6018,1,Dial(SIP/6018)
+exten => 6019,1,Dial(SIP/6019)
+exten => 6020,1,Dial(SIP/6020)
+exten => 6021,1,Dial(SIP/6021)
+exten => 6022,1,Dial(SIP/6022)
+exten => 6023,1,Dial(SIP/6023)
+exten => 6024,1,Dial(SIP/6024)
+exten => 6025,1,Dial(SIP/6025)
+exten => 6026,1,Dial(SIP/6026)
+exten => 6027,1,Dial(SIP/6027)
+exten => 6028,1,Dial(SIP/6028)
+exten => 6029,1,Dial(SIP/6029)
+exten => 6030,1,Dial(SIP/6030)
+
+;; Pre-configured mini-asterisk outgoing Analog group
+
+exten => _0.,1,Dial(Zap/g1/${EXTEN:1})
+
+;; Pre-configured mini-asterisk outgoing VOIP line
+
+exten => _1.,1,Dial(SIP/voip/${EXTEN:1})
+
+;; Pre-configured incoming calls
+
+exten => s,1,Dial(SIP/6011) ;; mini-asterisk - don't remove this comment
--- /dev/null
+;
+; SIP Configuration example for Asterisk
+;
+; Syntax for specifying a SIP device in extensions.conf is
+; SIP/devicename where devicename is defined in a section below.
+;
+; You may also use
+; SIP/username@domain to call any SIP user on the Internet
+; (Don't forget to enable DNS SRV records if you want to use this)
+;
+; If you define a SIP proxy as a peer below, you may call
+; SIP/proxyhostname/user or SIP/user@proxyhostname
+; where the proxyhostname is defined in a section below
+;
+; Useful CLI commands to check peers/users:
+; sip show peers Show all SIP peers (including friends)
+; sip show users Show all SIP users (including friends)
+; sip show registry Show status of hosts we register with
+;
+; sip debug Show all SIP messages
+;
+; reload chan_sip.so Reload configuration file
+; Active SIP peers will not be reconfigured
+;
+
+[general]
+context=default ; Default context for incoming calls
+;allowguest=no ; Allow or reject guest calls (default is yes, this can also be set to 'osp'
+ ; if asterisk was compiled with OSP support.
+;realm=mydomain.tld ; Realm for digest authentication
+ ; defaults to "asterisk"
+ ; Realms MUST be globally unique according to RFC 3261
+ ; Set this to your host name or domain name
+bindport=5060 ; UDP Port to bind to (SIP standard port is 5060)
+bindaddr=0.0.0.0 ; IP address to bind to (0.0.0.0 binds to all)
+srvlookup=yes ; Enable DNS SRV lookups on outbound calls
+ ; Note: Asterisk only uses the first host
+ ; in SRV records
+ ; Disabling DNS SRV lookups disables the
+ ; ability to place SIP calls based on domain
+ ; names to some other SIP users on the Internet
+
+;domain=mydomain.tld ; Set default domain for this host
+ ; If configured, Asterisk will only allow
+ ; INVITE and REFER to non-local domains
+ ; Use "sip show domains" to list local domains
+;domain=mydomain.tld,mydomain-incoming
+ ; Add domain and configure incoming context
+ ; for external calls to this domain
+;domain=1.2.3.4 ; Add IP address as local domain
+ ; You can have several "domain" settings
+;allowexternalinvites=no ; Disable INVITE and REFER to non-local domains
+ ; Default is yes
+;autodomain=yes ; Turn this on to have Asterisk add local host
+ ; name and local IP to domain list.
+;pedantic=yes ; Enable slow, pedantic checking for Pingtel
+ ; and multiline formatted headers for strict
+ ; SIP compatibility (defaults to "no")
+;tos=184 ; Set IP QoS to either a keyword or numeric val
+;tos=lowdelay ; lowdelay,throughput,reliability,mincost,none
+;maxexpiry=3600 ; Max length of incoming registration we allow
+;defaultexpiry=120 ; Default length of incoming/outoing registration
+;notifymimetype=text/plain ; Allow overriding of mime type in MWI NOTIFY
+;checkmwi=10 ; Default time between mailbox checks for peers
+;vmexten=voicemail ; dialplan extension to reach mailbox sets the
+ ; Message-Account in the MWI notify message
+ ; defaults to "asterisk"
+;videosupport=yes ; Turn on support for SIP video
+;recordhistory=yes ; Record SIP history by default
+ ; (see sip history / sip no history)
+
+;disallow=all ; First disallow all codecs
+;allow=ulaw ; Allow codecs in order of preference
+;allow=ilbc ;
+;musicclass=default ; Sets the default music on hold class for all SIP calls
+ ; This may also be set for individual users/peers
+;language=en ; Default language setting for all users/peers
+ ; This may also be set for individual users/peers
+;relaxdtmf=yes ; Relax dtmf handling
+;rtptimeout=60 ; Terminate call if 60 seconds of no RTP activity
+ ; when we're not on hold
+;rtpholdtimeout=300 ; Terminate call if 300 seconds of no RTP activity
+ ; when we're on hold (must be > rtptimeout)
+;trustrpid = no ; If Remote-Party-ID should be trusted
+;sendrpid = yes ; If Remote-Party-ID should be sent
+;progressinband=never ; If we should generate in-band ringing always
+ ; use 'never' to never use in-band signalling, even in cases
+ ; where some buggy devices might not render it
+;useragent=Asterisk PBX ; Allows you to change the user agent string
+;promiscredir = no ; If yes, allows 302 or REDIR to non-local SIP address
+ ; Note that promiscredir when redirects are made to the
+ ; local system will cause loops since SIP is incapable
+ ; of performing a "hairpin" call.
+;usereqphone = no ; If yes, ";user=phone" is added to uri that contains
+ ; a valid phone number
+;dtmfmode = rfc2833 ; Set default dtmfmode for sending DTMF. Default: rfc2833
+ ; Other options:
+ ; info : SIP INFO messages
+ ; inband : Inband audio (requires 64 kbit codec -alaw, ulaw)
+ ; auto : Use rfc2833 if offered, inband otherwise
+
+;compactheaders = yes ; send compact sip headers.
+;sipdebug = yes ; Turn on SIP debugging by default, from
+ ; the moment the channel loads this configuration
+;subscribecontext = default ; Set a specific context for SUBSCRIBE requests
+ ; Useful to limit subscriptions to local extensions
+ ; Settable per peer/user also
+;notifyringing = yes ; Notify subscriptions on RINGING state
+
+;
+; If regcontext is specified, Asterisk will dynamically create and destroy a
+; NoOp priority 1 extension for a given peer who registers or unregisters with
+; us. The actual extension is the 'regexten' parameter of the registering
+; peer or its name if 'regexten' is not provided. More than one regexten may
+; be supplied if they are separated by '&'. Patterns may be used in regexten.
+;
+;regcontext=sipregistrations
+;
+; Asterisk can register as a SIP user agent to a SIP proxy (provider)
+; Format for the register statement is:
+; register => user[:secret[:authuser]]@host[:port][/extension]
+;
+; If no extension is given, the 's' extension is used. The extension needs to
+; be defined in extensions.conf to be able to accept calls from this SIP proxy
+; (provider).
+;
+; host is either a host name defined in DNS or the name of a section defined
+; below.
+;
+; Examples:
+;
+;register => 1234:password@mysipprovider.com
+;
+; This will pass incoming calls to the 's' extension
+;
+;
+;register => 2345:password@sip_proxy/1234
+;
+; Register 2345 at sip provider 'sip_proxy'. Calls from this provider
+; connect to local extension 1234 in extensions.conf, default context,
+; unless you configure a [sip_proxy] section below, and configure a
+; context.
+; Tip 1: Avoid assigning hostname to a sip.conf section like [provider.com]
+; Tip 2: Use separate type=peer and type=user sections for SIP providers
+; (instead of type=friend) if you have calls in both directions
+
+;registertimeout=20 ; retry registration calls every 20 seconds (default)
+;registerattempts=10 ; Number of registration attempts before we give up
+ ; 0 = continue forever, hammering the other server until it
+ ; accepts the registration
+ ; Default is 0 tries, continue forever
+;callevents=no ; generate manager events when sip ua performs events (e.g. hold)
+
+; register mini-asterisk voip line providers here
+
+register => user@generic ; mini-asterisk - do not change this comment
+;register => user@oeg ; mini-asterisk - do not change this comment
+
+;----------------------------------------- NAT SUPPORT ------------------------
+; The externip, externhost and localnet settings are used if you use Asterisk
+; behind a NAT device to communicate with services on the outside.
+
+;externip = 200.201.202.203 ; Address that we're going to put in outbound SIP messages
+ ; if we're behind a NAT
+
+ ; The externip and localnet is used
+ ; when registering and communicating with other proxies
+ ; that we're registered with
+;externhost=foo.dyndns.net ; Alternatively you can specify an
+ ; external host, and Asterisk will
+ ; perform DNS queries periodically. Not
+ ; recommended for production
+ ; environments! Use externip instead
+;externrefresh=10 ; How often to refresh externhost if
+ ; used
+ ; You may add multiple local networks. A reasonable set of defaults
+ ; are:
+;localnet=192.168.0.0/255.255.0.0; All RFC 1918 addresses are local networks
+;localnet=10.0.0.0/255.0.0.0 ; Also RFC1918
+;localnet=172.16.0.0/12 ; Another RFC1918 with CIDR notation
+;localnet=169.254.0.0/255.255.0.0 ;Zero conf local network
+
+; The nat= setting is used when Asterisk is on a public IP, communicating with
+; devices hidden behind a NAT device (broadband router). If you have one-way
+; audio problems, you usually have problems with your NAT configuration or your
+; firewall's support of SIP+RTP ports. You configure Asterisk choice of RTP
+; ports for incoming audio in rtp.conf
+;
+;nat=no ; Global NAT settings (Affects all peers and users)
+ ; yes = Always ignore info and assume NAT
+ ; no = Use NAT mode only according to RFC3581
+ ; never = Never attempt NAT mode or RFC3581 support
+ ; route = Assume NAT, don't send rport
+ ; (work around more UNIDEN bugs)
+
+;rtcachefriends=yes ; Cache realtime friends by adding them to the internal list
+ ; just like friends added from the config file only on a
+ ; as-needed basis? (yes|no)
+
+;rtupdate=yes ; Send registry updates to database using realtime? (yes|no)
+ ; If set to yes, when a SIP UA registers successfully, the ip address,
+ ; the origination port, the registration period, and the username of
+ ; the UA will be set to database via realtime. If not present, defaults to 'yes'.
+
+;rtautoclear=yes ; Auto-Expire friends created on the fly on the same schedule
+ ; as if it had just registered? (yes|no|<seconds>)
+ ; If set to yes, when the registration expires, the friend will vanish from
+ ; the configuration until requested again. If set to an integer,
+ ; friends expire within this number of seconds instead of the
+ ; registration interval.
+
+;ignoreregexpire=yes ; Enabling this setting has two functions:
+ ;
+ ; For non-realtime peers, when their registration expires, the information
+ ; will _not_ be removed from memory or the Asterisk database; if you attempt
+ ; to place a call to the peer, the existing information will be used in spite
+ ; of it having expired
+ ;
+ ; For realtime peers, when the peer is retrieved from realtime storage,
+ ; the registration information will be used regardless of whether
+ ; it has expired or not; if it expires while the realtime peer is still in
+ ; memory (due to caching or other reasons), the information will not be
+ ; removed from realtime storage
+
+; Incoming INVITE and REFER messages can be matched against a list of 'allowed'
+; domains, each of which can direct the call to a specific context if desired.
+; By default, all domains are accepted and sent to the default context or the
+; context associated with the user/peer placing the call.
+; Domains can be specified using:
+; domain=<domain>[,<context>]
+; Examples:
+; domain=myasterisk.dom
+; domain=customer.com,customer-context
+;
+; In addition, all the 'default' domains associated with a server should be
+; added if incoming request filtering is desired.
+; autodomain=yes
+;
+; To disallow requests for domains not serviced by this server:
+; allowexternaldomains=no
+
+; fromdomain=mydomain.tld ; When making outbound SIP INVITEs to
+ ; non-peers, use your primary domain "identity"
+ ; for From: headers instead of just your IP
+ ; address. This is to be polite and
+ ; it may be a mandatory requirement for some
+ ; destinations which do not have a prior
+ ; account relationship with your server.
+
+[authentication]
+; Global credentials for outbound calls, i.e. when a proxy challenges your
+; Asterisk server for authentication. These credentials override
+; any credentials in peer/register definition if realm is matched.
+;
+; This way, Asterisk can authenticate for outbound calls to other
+; realms. We match realm on the proxy challenge and pick an set of
+; credentials from this list
+; Syntax:
+; auth = <user>:<secret>@<realm>
+; auth = <user>#<md5secret>@<realm>
+; Example:
+;auth=mark:topsecret@digium.com
+;
+; You may also add auth= statements to [peer] definitions
+; Peer auth= override all other authentication settings if we match on realm
+
+;------------------------------------------------------------------------------
+; Users and peers have different settings available. Friends have all settings,
+; since a friend is both a peer and a user
+;
+; User config options: Peer configuration:
+; -------------------- -------------------
+; context context
+; permit permit
+; deny deny
+; secret secret
+; md5secret md5secret
+; dtmfmode dtmfmode
+; canreinvite canreinvite
+; nat nat
+; callgroup callgroup
+; pickupgroup pickupgroup
+; language language
+; allow allow
+; disallow disallow
+; insecure insecure
+; trustrpid trustrpid
+; progressinband progressinband
+; promiscredir promiscredir
+; useclientcode useclientcode
+; accountcode accountcode
+; setvar setvar
+; callerid callerid
+; amaflags amaflags
+; call-limit call-limit
+; restrictcid restrictcid
+; subscribecontext subscribecontext
+; videosupport videosupport
+; mailbox
+; username
+; template
+; fromdomain
+; regexten
+; fromuser
+; host
+; port
+; qualify
+; defaultip
+; rtptimeout
+; rtpholdtimeout
+; sendrpid
+
+;[sip_proxy]
+; For incoming calls only. Example: FWD (Free World Dialup)
+; We match on IP address of the proxy for incoming calls
+; since we can not match on username (caller id)
+;type=peer
+;context=from-fwd
+;host=fwd.pulver.com
+
+;[sip_proxy-out]
+;type=peer ; we only want to call out, not be called
+;secret=guessit
+;username=yourusername ; Authentication user for outbound proxies
+;fromuser=yourusername ; Many SIP providers require this!
+;fromdomain=provider.sip.domain
+;host=box.provider.com
+;usereqphone=yes ; This provider requires ";user=phone" on URI
+;call-limit=5 ; permit only 5 simultaneous outgoing calls to this peer
+
+;------------------------------------------------------------------------------
+; Definitions of locally connected SIP phones
+;
+; type = user a device that authenticates to us by "from" field to place calls
+; type = peer a device we place calls to or that calls us and we match by host
+; type = friend two configurations (peer+user) in one
+;
+; For local phones, type=friend works most of the time
+;
+; If you have one-way audio, you propably have NAT problems.
+; If Asterisk is on a public IP, and the phone is inside of a NAT device
+; you will need to configure nat option for those phones.
+; Also, turn on qualify=yes to keep the nat session open
+
+;[grandstream1]
+;type=friend
+;context=from-sip ; Where to start in the dialplan when this phone calls
+;callerid=John Doe <1234> ; Full caller ID, to override the phones config
+;host=192.168.0.23 ; we have a static but private IP address
+ ; No registration allowed
+;nat=no ; there is not NAT between phone and Asterisk
+;canreinvite=yes ; allow RTP voice traffic to bypass Asterisk
+;dtmfmode=info ; either RFC2833 or INFO for the BudgeTone
+;call-limit=1 ; permit only 1 outgoing call and 1 incoming call at a time
+ ; from the phone to asterisk
+ ; (1 for the explicit peer, 1 for the explicit user,
+ ; remember that a friend equals 1 peer and 1 user in
+ ; memory)
+;mailbox=1234@default ; mailbox 1234 in voicemail context "default"
+;disallow=all ; need to disallow=all before we can use allow=
+;allow=ulaw ; Note: In user sections the order of codecs
+ ; listed with allow= does NOT matter!
+;allow=alaw
+;allow=g723.1 ; Asterisk only supports g723.1 pass-thru!
+;allow=g729 ; Pass-thru only unless g729 license obtained
+;astdb=chan2ext/SIP/grandstream1=1234 ; ensures an astDB entry exists
+
+
+;[xlite1]
+; Turn off silence suppression in X-Lite ("Transmit Silence"=YES)!
+; Note that Xlite sends NAT keep-alive packets, so qualify=yes is not needed
+;type=friend
+;regexten=1234 ; When they register, create extension 1234
+;callerid="Jane Smith" <5678>
+;host=dynamic ; This device needs to register
+;nat=yes ; X-Lite is behind a NAT router
+;canreinvite=no ; Typically set to NO if behind NAT
+;disallow=all
+;allow=gsm ; GSM consumes far less bandwidth than ulaw
+;allow=ulaw
+;allow=alaw
+;mailbox=1234@default,1233@default ; Subscribe to status of multiple mailboxes
+
+
+;[snom]
+;type=friend ; Friends place calls and receive calls
+;context=from-sip ; Context for incoming calls from this user
+;secret=blah
+;subscribecontext=localextensions ; Only allow SUBSCRIBE for local extensions
+;language=de ; Use German prompts for this user
+;host=dynamic ; This peer register with us
+;dtmfmode=inband ; Choices are inband, rfc2833, or info
+;defaultip=192.168.0.59 ; IP used until peer registers
+;mailbox=1234@context,2345 ; Mailbox(-es) for message waiting indicator
+;vmexten=voicemail ; dialplan extension to reach mailbox
+ ; sets the Message-Account in the MWI notify message
+ ; defaults to global vmexten which defaults to "asterisk"
+;restrictcid=yes ; To have the callerid restriced -> sent as ANI
+;disallow=all
+;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw!
+
+
+;[polycom]
+;type=friend ; Friends place calls and receive calls
+;context=from-sip ; Context for incoming calls from this user
+;secret=blahpoly
+;host=dynamic ; This peer register with us
+;dtmfmode=rfc2833 ; Choices are inband, rfc2833, or info
+;username=polly ; Username to use in INVITE until peer registers
+ ; Normally you do NOT need to set this parameter
+;disallow=all
+;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw!
+;progressinband=no ; Polycom phones don't work properly with "never"
+
+
+;[pingtel]
+;type=friend
+;secret=blah
+;host=dynamic
+;insecure=port ; Allow matching of peer by IP address without matching port number
+;insecure=invite ; Do not require authentication of incoming INVITEs
+;insecure=port,invite ; (both)
+;qualify=1000 ; Consider it down if it's 1 second to reply
+ ; Helps with NAT session
+ ; qualify=yes uses default value
+;callgroup=1,3-4 ; We are in caller groups 1,3,4
+;pickupgroup=1,3-5 ; We can do call pick-p for call group 1,3,4,5
+;defaultip=192.168.0.60 ; IP address to use if peer has not registred
+
+;[cisco1]
+;type=friend
+;secret=blah
+;qualify=200 ; Qualify peer is no more than 200ms away
+;nat=yes ; This phone may be natted
+ ; Send SIP and RTP to the IP address that packet is
+ ; received from instead of trusting SIP headers
+;host=dynamic ; This device registers with us
+;canreinvite=no ; Asterisk by default tries to redirect the
+ ; RTP media stream (audio) to go directly from
+ ; the caller to the callee. Some devices do not
+ ; support this (especially if one of them is
+ ; behind a NAT).
+;defaultip=192.168.0.4 ; IP address to use until registration
+;username=goran ; Username to use when calling this device before registration
+ ; Normally you do NOT need to set this parameter
+;setvar=CUSTID=5678 ; Channel variable to be set for all calls from this device
+
+; Pre-configured SIP extensions
+
+[6011]
+type=friend
+context=default
+host=dynamic
+secret=6011
+canreinvite=no
+callerid=6011
+disallow=all
+allow=ulaw,g729
+qualify=yes
+
+[6012]
+type=friend
+context=default
+host=dynamic
+secret=6012
+canreinvite=no
+callerid=6012
+disallow=all
+allow=ulaw,g729
+
+[6013]
+type=friend
+context=default
+host=dynamic
+secret=6013
+canreinvite=no
+callerid=6013
+disallow=all
+allow=ulaw,g729
+
+[6014]
+type=friend
+context=default
+host=dynamic
+secret=6014
+canreinvite=no
+callerid=6014
+disallow=all
+allow=ulaw,g729
+
+[6015]
+type=friend
+context=default
+host=dynamic
+secret=6015
+canreinvite=no
+callerid=6015
+disallow=all
+allow=ulaw,g729
+
+[6016]
+type=friend
+context=default
+host=dynamic
+secret=6016
+canreinvite=no
+callerid=6016
+disallow=all
+allow=ulaw,g729
+
+[6017]
+type=friend
+context=default
+host=dynamic
+secret=6017
+canreinvite=no
+callerid=6017
+disallow=all
+allow=ulaw,g729
+
+[6018]
+type=friend
+context=default
+host=dynamic
+secret=6018
+canreinvite=no
+callerid=6018
+disallow=all
+allow=ulaw,g729
+
+; Pre-configured mini-asterisk SIP trunks
+
+[generic] ; "Generic" mini-asterisk do not remove this comment
+type=friend
+context=default
+username=user
+secret=password
+host=192.168.1.28
+canreinvite=no
+disallow=all
+allow=ulaw,g729
+qualify=yes
+
+;[oeg] ; "OEG" mini-asterisk do not remove this comment
+;host=voip.oeg.com.au
+;secret=pass
+;username=your user number
+;fromdomain=voip.oeg.com.au
+;fromuser=your user number
+;insecure=port,invite
+;type=friend
+;disallow=all
+;allow=g729,ulaw
+;dtmfmod=rfc2833
+;qualify=yes
+;canreinvite=no
+;nat=yes
+;context=default
+
--- /dev/null
+#!/bin/sh
+# update_revision.sh
+#
+# Sets correct Revision number in the about screen. Good idea to
+# run this before installing
+
+ver=`svn info | grep Revision`
+sed -i "s/Revision: [0-9]*/$ver/" cgi-bin/about.sh