only for backup, still in coding state - no compile!!!

This commit is contained in:
Super User 2007-05-06 15:54:52 +02:00
parent 1bf9bb306b
commit 2ed0fee489
438 changed files with 64798 additions and 0 deletions

16
COPYING Normal file
View File

@ -0,0 +1,16 @@
Copyright Andreas Eversberg (jolly@jolly.de)
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.

342
LICENSE Normal file
View File

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

361
Makefile Normal file
View File

@ -0,0 +1,361 @@
#*****************************************************************************\
#* **
#* PBX4Linux **
#* **
#*---------------------------------------------------------------------------**
#* Copyright: Andreas Eversberg **
#* **
#* Makefile **
#* **
#*****************************************************************************/
WITH-PBX = 42 # MUST BE SET for now
#WITH-H323 = 42 # comment this out, if no h323 should be compiled
#WITH-OPAL = 42 # NOT SUPPORTED YET
WITH-CRYPTO = 42 # comment this out, if no libcrypto should be used
# note: check your location and the names of libraries.
# select location to install
INSTALL_BIN = /usr/local/bin
INSTALL_DATA = /usr/local/pbx
# give locations for the libraries (comment out H323_LIB and PWLIB_LIB, if they are installed on the system)
LINUX_INCLUDE = -I/usr/src/linux/include
H323_INCLUDE = -I/usr/local/include/openh323
#H323_LIB = -L/usr/local/lib
#PWLIB_INCLUDE = -I/usr/local/include/ptlib/unix
#PWLIB_LIB = -L/usr/local/lib
# give location of the mISDN libraries
MISDNUSER_INCLUDE = -I../mISDNuser/include
MISDNUSER_LIB = -L../mISDNuser/lib -L../mISDNuser/i4lnet
LIBS += -lisdnnet -lmISDN -lpthread
# give location of the curses or ncurses library
CURSES = -lncurses
CC = g++
LD = $(CC)
WIZZARD = ./wizzard
PBX = ./pbx
PBXADMIN = ./pbxadmin
PBXWATCH = ./pbxwatch
GEN = ./gentones
GENW = ./genwave
GENRC = ./genrc
GENEXT = ./genextension
CFLAGS = -Wall -g -DINSTALL_DATA=\"$(INSTALL_DATA)\"
CFLAGS += $(LINUX_INCLUDE) $(MISDNUSER_INCLUDE)
ifdef WITH-PBX
CFLAGS += -DPBX
endif
ifdef WITH-CRYPTO
CFLAGS += -DCRYPTO
endif
CFLAGS_OPAL = $(CFLAGS)
CFLAGS_H323 = $(CFLAGS)
LIBDIR += $(MISDNUSER_LIB)
ifdef WITH-OPAL
OPAL = opal.o opal_mgr.o opal_pbxep.o opal_pbxcon.o opal_pbxms.o
CFLAGS += -DOPAL
CFLAGS_OPAL += $(OPAL_INCLUDE) -DOPAL
LIBDIR += $(OPAL_LIB)
endif
ifdef WITH-H323
H323 = h323.o h323_ep.o h323_con.o h323_chan.o
LIBS += -lh323_linux_x86_r -lpt_linux_x86_r -ldl
CFLAGS += -DH323
CFLAGS_H323 += $(H323_INCLUDE) $(PWLIB_INCLUDE) -DH323INCLUDE -DH323 -D_REENTRANT -DPBYTE_ORDER=PLITTLE_ENDIAN -DP_PTHREADS -DP_HAS_SEMAPHORES -DPHAS_TEMPLATES -DP_LINUX -DPTRACING
LIBDIR += $(H323_LIB) $(PWLIB_LIB)
endif
ifdef WITH-CRYPTO
LIBDIR += -L/usr/local/ssl/lib
CFLAGS += -I/usr/local/ssl/include
#LIBS += -lcrypto
LIBS += /usr/local/ssl/lib/libcrypto.a
endif
#all:
# @echo Note that this version is a beta release. It is only for testing purpose.
# @echo Please report any bug. To compile use \"make beta\".
# @exit
all: $(PBXADMIN) $(PBX) $(GEN) $(GENW) $(GENRC) $(GENEXT)
@sh -c 'grep -n strcpy *.c* ; if test $$''? = 0 ; then echo "dont use strcpy, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n strncpy *.c* ; if test $$''? = 0 ; then echo "dont use strncpy, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n strcat *.c* ; if test $$''? = 0 ; then echo "dont use strcat, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n strncat *.c* ; if test $$''? = 0 ; then echo "dont use strncat, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n sprintf *.c* ; if test $$''? = 0 ; then echo "dont use sprintf, use makro instead." ; exit -1 ; fi'
@sh -c 'grep -n snprintf *.c* ; if test $$''? = 0 ; then echo "dont use snprintf, use makro instead." ; exit -1 ; fi'
@echo "All PBX binaries done"
@sync
@exit
main.o: main.c *.h Makefile
$(CC) -c $(CFLAGS_H323) main.c -o main.o
message.o: message.c *.h Makefile
$(CC) -c $(CFLAGS) message.c -o message.o
options.o: options.c *.h Makefile
$(CC) -c $(CFLAGS) options.c -o options.o
interface.o: interface.c *.h Makefile
$(CC) -c $(CFLAGS) interface.c -o interface.o
h323conf.o: h323conf.c *.h Makefile
$(CC) -c $(CFLAGS) h323conf.c -o h323conf.o
extension.o: extension.c *.h Makefile
$(CC) -c $(CFLAGS) extension.c -o extension.o
route.o: route.c *.h Makefile
$(CC) -c $(CFLAGS) route.c -o route.o
port.o: port.cpp *.h Makefile
$(CC) -c $(CFLAGS) port.cpp -o port.o
mISDN.o: mISDN.cpp *.h Makefile
$(CC) -c $(CFLAGS) mISDN.cpp -o mISDN.o
dss1.o: dss1.cpp ie.cpp *.h Makefile
$(CC) -c $(CFLAGS) dss1.cpp -o dss1.o
opal.o: opal.cpp *.h Makefile
$(CC) -c $(CFLAGS) opal.cpp -o opal.o
opal_mgr.o: opal_mgr.cpp *.h Makefile
$(CC) -c $(CFLAGS) opal_mgr.cpp -o opal_mgr.o
opal_pbxep.o: opal_pbxep.cpp *.h Makefile
$(CC) -c $(CFLAGS) opal_pbxep.cpp -o opal_pbxep.o
opal_pbxcon.o: opal_pbxcon.cpp *.h Makefile
$(CC) -c $(CFLAGS) opal_pbxcon.cpp -o opal_pbxcon.o
opal_pbxms.o: opal_pbxms.cpp *.h Makefile
$(CC) -c $(CFLAGS) opal_pbxms.cpp -o opal_pbxms.o
#knock.o: knock.cpp *.h Makefile
# $(CC) -c $(CFLAGS) knock.cpp -o knock.o
#
vbox.o: vbox.cpp *.h Makefile
$(CC) -c $(CFLAGS) vbox.cpp -o vbox.o
mail.o: mail.c *.h Makefile
$(CC) -c $(CFLAGS) mail.c -o mail.o
action.o: action.cpp *.h Makefile
$(CC) -c $(CFLAGS) action.cpp -o action.o
action_vbox.o: action_vbox.cpp *.h Makefile
$(CC) -c $(CFLAGS) action_vbox.cpp -o action_vbox.o
action_efi.o: action_efi.cpp *.h Makefile
$(CC) -c $(CFLAGS) action_efi.cpp -o action_efi.o
endpoint.o: endpoint.cpp *.h Makefile
$(CC) -c $(CFLAGS) endpoint.cpp -o endpoint.o
endpointapp.o: endpointapp.cpp *.h Makefile
$(CC) -c $(CFLAGS) endpointapp.cpp -o endpointapp.o
apppbx.o: apppbx.cpp *.h Makefile
$(CC) -c $(CFLAGS) apppbx.cpp -o apppbx.o
call.o: call.cpp *.h Makefile
$(CC) -c $(CFLAGS) call.cpp -o call.o
callpbx.o: callpbx.cpp *.h Makefile
$(CC) -c $(CFLAGS) callpbx.cpp -o callpbx.o
callchan.o: callchan.cpp *.h Makefile
$(CC) -c $(CFLAGS) callchan.cpp -o callchan.o
cause.o: cause.c *.h Makefile
$(CC) -c $(CFLAGS) cause.c -o cause.o
alawulaw.o: alawulaw.c *.h Makefile
$(CC) -c $(CFLAGS) alawulaw.c -o alawulaw.o
tones.o: tones.c *.h Makefile
$(CC) -c $(CFLAGS) tones.c -o tones.o
crypt.o: crypt.cpp *.h Makefile
$(CC) -c $(CFLAGS) crypt.cpp -o crypt.o
h323.o: h323.cpp *.h Makefile
$(CC) -c $(CFLAGS_H323) h323.cpp -o h323.o
h323_ep.o: h323_ep.cpp *.h Makefile
$(CC) -c $(CFLAGS_H323) h323_ep.cpp -o h323_ep.o
h323_chan.o: h323_chan.cpp *.h Makefile
$(CC) -c $(CFLAGS_H323) h323_chan.cpp -o h323_chan.o
h323_con.o: h323_con.cpp *.h Makefile
$(CC) -c $(CFLAGS_H323) h323_con.cpp -o h323_con.o
genext.o: genext.c *.h Makefile
$(CC) -c $(CFLAGS) genext.c -o genext.o
#admin_client.o: admin_client.c *.h Makefile
# $(CC) -c $(CFLAGS) admin_client.c -o admin_client.o
admin_server.o: admin_server.c *.h Makefile
$(CC) -c $(CFLAGS) admin_server.c -o admin_server.o
#$(WIZZARD): wizzard.c Makefile
# $(CC) $(LIBDIR) $(CFLAGS) -lm wizzard.c \
# -o $(WIZZARD)
$(PBX): $(H323) $(OPAL) \
main.o \
options.o \
interface.o \
h323conf.o \
extension.o \
cause.o \
alawulaw.o \
tones.o \
message.o \
route.o \
port.o \
mISDN.o \
dss1.o \
vbox.o \
endpoint.o \
endpointapp.o \
apppbx.o \
crypt.o \
action.o \
action_vbox.o \
action_efi.o \
mail.o \
call.o \
callpbx.o \
callchan.o \
admin_server.o
$(LD) $(LIBDIR) $(H323) $(OPAL) \
main.o \
options.o \
interface.o \
h323conf.o \
extension.o \
cause.o \
alawulaw.o \
tones.o \
message.o \
route.o \
port.o \
mISDN.o \
dss1.o \
vbox.o \
endpoint.o \
endpointapp.o \
apppbx.o \
crypt.o \
action.o \
action_vbox.o \
action_efi.o \
mail.o \
call.o \
callpbx.o \
callchan.o \
admin_server.o \
$(LIBS) -o $(PBX)
$(PBXADMIN): admin_client.c cause.c *.h Makefile
$(CC) $(LIBDIR) $(CFLAGS) $(CURSES) -lm admin_client.c cause.c \
-o $(PBXADMIN)
$(PBXWATCH): watch.c *.h Makefile
$(CC) $(LIBDIR) $(CFLAGS) -lm watch.c \
-o $(PBXWATCH)
$(GEN): gentones.c *.h Makefile
$(CC) $(LIBDIR) $(CFLAGS) -lm gentones.c \
-o $(GEN)
$(GENW):genwave.c *.h Makefile
$(CC) $(LIBDIR) $(CFLAGS) -lm genwave.c \
-o $(GENW)
$(GENRC): genrc.c *.h Makefile
$(CC) $(LIBDIR) $(CFLAGS) -lm genrc.c \
-o $(GENRC)
$(GENEXT): options.o extension.o genext.o
$(CC) $(CFLAGS) options.o extension.o genext.o -o $(GENEXT)
#install:
# @echo Remember, this is a beta release. To overwrite your current installed
# @echo version, use \"make beta_install\".
# @exit
install:
-killall -9 -w -q pbx # the following error must be ignored
cp $(PBX) $(INSTALL_BIN)
cp $(PBXADMIN) $(INSTALL_BIN)
# cp $(PBXWATCH) $(INSTALL_BIN)
cp $(GEN) $(INSTALL_BIN)
cp $(GENW) $(INSTALL_BIN)
cp $(GENRC) $(INSTALL_BIN)
cp $(GENEXT) $(INSTALL_BIN)
mkdir -p $(INSTALL_DATA)
mkdir -p $(INSTALL_DATA)/extensions
@if test -a $(INSTALL_DATA)/options.conf ; then \
echo "NOTE: options.conf already exists, not changed." ; else \
cp -v default/options.conf $(INSTALL_DATA) ; fi
@if test -a $(INSTALL_DATA)/interface.conf ; then \
echo "NOTE: interface.conf already exists, not changed." ; else \
cp -v default/interface.conf $(INSTALL_DATA) ; fi
@if test -a $(INSTALL_DATA)/routing.conf ; then \
echo "NOTE: routing.conf already exists, not changed." ; else \
cp -v default/routing.conf $(INSTALL_DATA) ; fi
@if test -a $(INSTALL_DATA)/numbering_int.conf ; then \
echo "NOTE: numbering_int.conf is obsolete, please use routing." ; fi
@if test -a $(INSTALL_DATA)/numbering_ext.conf ; then \
echo "NOTE: numbering_ext.conf is obsolete, please use routing." ; fi
@if test -a $(INSTALL_DATA)/h323_gateway.conf ; then \
echo "NOTE: h323_gateway.conf already exists, not changed." ; else \
cp -v default/h323_gateway.conf $(INSTALL_DATA) ; fi
@if test -a $(INSTALL_DATA)/directory.list ; then \
echo "NOTE: directory.list already exists, not changed." ; else \
cp -v default/directory.list $(INSTALL_DATA) ; fi
cp -a tones_* $(INSTALL_DATA)
cp -a vbox_english/ $(INSTALL_DATA)
cp -a vbox_german/ $(INSTALL_DATA)
cp -a tones_efi/ $(INSTALL_DATA)
sync
clean:
touch *
rm -f $(PBX) $(PBXADMIN) $(PBXWATCH) $(GEN) $(GENW) $(GENRC) $(GENEXT)
rm -f *.o
rm -f .*.c.sw* .*.cpp.sw* .*.h.sw*
rm -f bla nohup.out
rm -f debug*.log
tar:
make clean
cd .. && tar -cvzf pbx4linux_`date +%Y%m%d`.tar.gz pbx4linux
start: $(PBX)
sync
-killall -9 -w -q pbx # the following error must be ignored
$(PBX) start
s: $(PBX)
sync
-killall -9 -w -q pbx # the following error must be ignored
$(PBX) start
fork: $(PBX)
sync
-killall -9 -w -q pbx # the following error must be ignored
$(PBX) fork

341
README
View File

@ -0,0 +1,341 @@
Read the documentation at ./doc/ and visit http://isdn.jolly.de.
Changes in Version 20021228
- first release
Changes in Version 20030111 (buggy and unuseable)
- support dtmf for callback and dtmf dialing mode (dial through via dtmf)
- bug fixes
- dialing improvement: dialing h323 now possible with port and alias
- other stuff
- new Makefile: make install will now install binaries and data on your system
Changes in Version 20030118 (buggy and unuseable)
- information exchange between isdn/h323-ports, endpoints and calls are messages now
previousely using direct calls with pointers were dangerous
- removed bug since 200301011, which caued h323 calls to deadlock
Changes in Version 20030120
- login function
- callback authentication
- h323 audio bug. no h323 audio transmission sice version 20030111
- some other bug fixes
Changes in Version 20030206 (first beta release 1.0)
- callerid (CLIP/COLP) is now processed correctly with all features
- hold sound and active/inactive notification
- CD notification
- many callerid display function
- bug fixes
- documentation as word document (partly done)
- Note: This week I have my vakation, so there is no response to any question in the mailing list.
Changes in Version 1.0
- first release
- finished the first version of the documentation
- new style internet page with documentation in html
- all enities (port, endpoint, call) are now c++ objects, rather than structures
- tones may now be played and recorded using wave (8bit mono, 16bit mono, 16bit stereo) or law (alwa/ulaw mono)
- fixed corruption in wave-file creation
- now call forwad (cfb, cfnr) is implemented and working
- an answering machine with playback function is implemented.
- lots of bug fixes
Changes in Version 1.1
- option to fetch tones into memory, causing faster access, then from hard disk
- Memory is now locked using mlockall(), to prevent paging which causes jitter and interruption.
- Answering machine now works with keypad information.
- callback on internal port, if hangup with call on hold.
- A pocket calcularor with simple terms (*, /, +, -) and floating point is added.
- If a calls had more than two endpoints, any message has been ignored.
This caused not to receive the retreive notification, which caused the hold
music to continue to play.
- minor buf fixes
- Disconnect/release "causes" are now processed by priority, if a multipoint call is made.
Changes in Version 1.2
- bugfix: dialing of vbox-caller now works.
- bugfix: minor answering machine announcement bug
- fixed compiling error: h323_con.cpp (p_type not declared) thanx arne!
- added include definition for kernel api in Makefile. Hope it works...
- fix: dummyid is used for external calls when no caller id is available. the
dummy id is transmitted as restricted id. if the police is called, it will
see the dummyid rather than the pbx line id. this is used on forwarded calls
when the caller id is not available.
- doc: added a simple instruction to build a cross over cable.
Changes in Version 2.0pre
- NEW ISDN DRIVER SUPPORT (Forget the HiSax, now use 'mISDN'.)
- NEW KERNEL REALTIME MODULE (mISDN_dsp.o)
- NEW NT-MODE LIBRARY SUPPORT (now MULTIPOINT!!!)
- NEW TE-MODE STACK SUPPORT
- support of call suspension and retrieval (switch between calls)
- call waiting on internal phone (calls when no bchannel is available)
- doc: Now headlines are moved to the next page if they are at the bottom of a
page.
- vbox: minor speech syntax bugfix
- up to 50 (compiler flag) dialed numbers can be recalled.
- up to 50 (compiler flag) received calls are listed and can be replied.
- Dialing informations are now queued by endpoint until port has received
setup acknowledge on the outgoing connection.
- Starting PBX without parameter gives a list of options.
- Query option for listing available ports/cards.
- CNIP (calling name) Some Simens switches and telephones support this.
- Extensions no have names.
- Timeouts can now be specified for different call states on ISDN phones.
- Tones/Announcements can now be overridden at different call states.
- isdn.cpp is completely reworked.
- Tones/Announcements can be played externally, if supported by the external
line.
- Commandline parameters must be given on startup of pbx.
- query option to check out the current isdn cards and protocolls.
- Debug flags can now be used to speciallize the debug output.
- vbox: Recorded calls can now be sent as attached sound file via email, or
just a notifaction mail without sound file can be sent.
- PBX now runs with highest prio (99) to get as much cpu as possible.
- CPU scheduler now runs PBX4Linux as real time process.
- Internal calls now use internal extension number as caller id.
- Rework of hold/conference.
- New option to allow an incoming h323-call to be connected at ringing state.
- New codecs supported with h323 (speex and law)
- COLP now works with h323
- Answering machine now delays to avoid the dtmf tone when start recording
- Answering machine now adds the beep behind the announcement file.
- keypad facility dialing option
- Conference now really works using call hold feature in conjunction with
keypad feature
- Picking of an incoming call on isdn now really works.
- picking of a call forwarded to vbox
- I fixed a bug that did not queue the dialed digits correctly before getting
an external connecting.
- Logfiles of calls now show the correct year.
- Callback now rejects if no password is given or the given extension doesn't
exist.
- Incoming H.323 calls may now instantly connect using a special option.
- H323 compiles faster, because the H323 includes are only used for the H323
code part.
- Using 'curses' for a state debugging. The current state of all instances
is displayed on the screen including calls, endpoints and ports.
- manny, manny more things that I forgot
Changes in Version 2.0
- fixed memory leak
- fixed COLP bug
- finally SUSPEND/RESUME (call parking), resume is allowed from any ISDN-port
- some CRITICAL bugfixes
- Fixed and reworked sample counting when playing tones. Now fast wind and
rewind works correctly. Also 8-bit recording can be played back now.
I hope it works now without problems.
- An internal phone without caller id will now be rejected rather than
treated as an extenal call.
- Fixed bug in rejecting an external call.
- Corrected handeling of 'inbandpatterns'.
- Data calls will not enable DTMF detection.
- Data calls will not use any audio transmission from user space.
- Forward to VBOX only if call is an audio call.
- Fixed library bug, that caused not to process keypad-information during
setup message.
- Fixed a 'release_complete' bug.
- Debug information now have the correct month.
- Fixed bug of wave-playback of voicebox recoding, caused by rework of the
audio routines. It caused a SEGMENTATION FAULT!
- Using threads now to send email and using libcrypto.
- Introducing encryption of external calls using Blowfish.
- Key exchange using RSA.
- Fixed a bug in dialing H323-IP with numerical digits.
- Fixed a bug that causes endpoint, which receives audio data, to crash when
no port is related to it.
- Fixed a bug that did not release endpoint, when it receives a disconnect
if it has no port (parked).
- Fixed a channel assignment bug when retrieving call. (second B-channel)
- Now COLP with H.323 works. No more crash!
- Park attribute was not set, which caused a crash.
- Conference now works correctly with dsp-module.
- Fixed a serious NT-mode process handling problem. (crash after some calls)
- Added log file which is also displayed on the 'state' screen.
- * Happy new year 2004 *
Changes in Version 2.1
- Fixed a bug that caused not to reply external calls (also VBOX).
- 'genrc' now supports loading HFC-4S, HFC-8S and HFC-E1 drivers
- Outgoing setup now expires after 8 seconds!
- Fixed a bug that causes mISDNuser to crash during cleanup.
- Fixed memory bug, thanx Paul!
- hfc-4s/8s driver support (mISDN)
- Improvement of isdn audio processing, hardware support.
- Fixed diplay callerid bug "anonymousunknown anon"
- Added more stable malloc (calloc) / free handling
Changes in Version 2.2
- PRI proof (2 MBit interface support when using HFC-E1)
- Fixed data call bug
- Improved display of PRI channels
- Now VBOX playback says "no messages" if the last message has been deleted
and will not play the last but one, unless the "previous" button has been
pressed.
Changes in Version 2.3
- Fixed HFC_MULTI driver activation problem (HW_RESET was not implemented)
- Fixed login prefix bug. Thanx Karsten V.
- MISDN: better layer 2 check
- Now facility informations are transfered during call to terminal
(finally advice of charge is displayed) MUST BE ENABLED BY SETTINGS!
- Fixed 'reply' dialing bug, that caused a crash. Thanx Karsten V.
- Added L1 activation for NT-Mode. Fixed problems with inactive links.
- Fixed a bug that caused subsequent data calls after a data call. Thanx JC.
- mISDN: layer 1 now works correct with E1 cards.
Changes in Version 2.4
- Fixed parallel ringing to multiple external numbers.
- Fixed login again (was still buggy).
Changes in Version 2.5
- Fixed callback bug. (International numbers were not detected.)
- Fixed typos (mostly "incomming") - thanx Lars.
- Fixed vbox-email bug - thanx Martin. (and also the compiler error)
- Fixed compiler bug, that caused compiling without crypto lib to fail.
- Fixed some mISDN crash problems.
- Now it should also compile with the original CVS tree.
- Fixed hfc_multi unloading bug - thanx Karsten!
- Now disabling DSP_MODULE really causes DSP to be disabled.
- Now disabling real time scheduling really works.
- mISDNuser (CVS) now compiles with the mISDN (CVS)
- Adding the outdial prefix to the caller ID is now possible.
- Fixed bug that caused echo test not to work.
- And finally hardware echo now works on HFC 4s/8s/E1 (hfc_multi)
For echo dial 993 (Test + 3) for standard configuration.
- Added new hfc_multi vendor IDs including "Beronet Cards".
Changes in Version 2.6
- Fixed hookflash bug in conjunction with prefix. Thanx Tobias!
- Fixed cleanup bug when loading of ISDN driver failed.
- Fixed mISDN bug that caused cards not to be found, if loaded in different
order as found by kernel.
- Fixed a bug that causes a segfault when a phone disconnects while
parallel ringing multiple phones/ports.
- Added capability for Point-To-Point in NT mode, including PRI.
- Added L1 link control for NT mode.
- Fixed bug in hfc_multi and mISDN driver that caused mISDN not to work
with kernel > 2.6.7.
- Fixed a but when detecting different cards with hfc_multi.
- Fixed timer bug that caused timers of multiple NT ports not to work
correctly.
Changes in Version 2.7
- Fixed lots of bugs.
- Now receive stream from mISDN is disabled when not needed.
- Added NT mode support for incomming "SETUP_ACKNOWLEDGE".
Changes in Version 3.0
- Advanced routing capability to replace the numbering_*.conf
(Don't worry, internal and external numbering is a feature of the routing
capability and is easy to convert.)
- Now correct cause location is generated and handled.
- New cause display feature. Location is displayed with the cause number.
- Many source cleanups.
- New interface (Unix socket) to administrate. Status informations are now
viewable without restarting PBX. Even may processes may view status info.
Starting / stopping state debugging, doesn't require to restart PBX.
- Status information now has selectable details.
- Better structure for debugging functions and better logging. (code)
- Dialing may also be done via command line interface.
- Now internel/external dialtone and ringing depends on internal/external call.
- Now endpoints (partys) can be released via command line (admin tool).
- Watchdog "pbxwatch" to automatically restart and even debug PBX4Linux.
- Removed problem with uninitialized variable in ISDNPort object causing to
crash. It did not happen very often.(only after some hundred/thousand calls)
- HFC-E1 cards did not correctly synchronize to external lines.
- dsp.o now allocates only one timeslot per call, as expected.
- mISDNuser now correctly connects PRI calls.
- PRI improvements and bugfixes.
- Support for conference rooms.
- Voice box is now able to play announcement before connecting the call.
A special feature on the external line is required to send audio before
answering the call.
- It is now possible to include seconds (time) in the connect message. This
might not be supported by all telephones, so it is an optional feature.
- Moved open and close of recording audio to the "Port" class, where it
belongs. The mixer will be more performant this way.
- Notify is now supported by mISDN and also correctly handled and queued
by PBX.
- Fixed bug that caused not to free broadcast process IDs in certain cases.
This would cause calls to internal phones (from extern or intern) not to
work after a while.
- Added HFC-S USB to 'genrc' tool.
- printisdn now shows corret month.
Changes in Version 3.0-fix1
- Rule for changing the forwarding now works. Enter "pbx rules forward" for
description. Also the example in "defaults/route.conf" is corrected.
- Forking now forks twice and suppresses debug output. Closing of shell is
possible.
Changes in Version 3.0-fix2
- Fixed memory leak bug in pbxadmin that caused to eat all memory and make it
stop.
- Fixed audio handling that cause forking calls to be mute. (Parallel
forwarding causes calls to fork to multiple destinations.)
Changes in Version 3.0-fix3
- Added "nopassword" parameter for login action.
- Fixed bolean condition bug.
- pbxadmin will not exit if terminal size changes.
Changes in Version 3.1
- Internal structure changed. "Endpoints" and "applications" are now two
linked classes. The code is now reusable for other projects than
"PBX4Linux". (No added features!)
- Some source cleanups.
- Now keypad must be enabled for each extension if required. (settings)
- Removed a new bug that caused remotely parked/holded calls not to be removed
from conference. The conference got disturbed by park/hold sound from
remote.
- Removed bug that caused printing of unset pointers.
Changes in Version 3.2
- PBX now works with mqueue branch. This is the latest CVS source:
* HFCmulti is ported
* HFC-PCI is ported
* DSP is ported
* nt-mode lib (libi4l) is ported
* source is now SMP (multiple processors or hyperthreading) save.
- Fixed bug that caused not to record if annoucement is missing
- A prefix may be specified with callback for predefined dialing after
callback.
- Now b-channels are displayed more compressed on admin tool.
Changes in Version 3.3
- * te-mode works
- * te-mode layer 1 and layer 2 control works (SHORTMESSAGE)
Changes in Version 3.3-fix2
- OpenH323 midas release compiles
- Fixed bug in MESSAGE_NOTIFY which cases display information not to dliver.
- OpenH323 midas release works currently only with law-codecs
- Dixed some dial string parsing for Openh323.
Changes in Version 3.3-fix3
- Rework of kernel audio briding. Much faster (less delay), dynamically
handles jitter. Ready for future RTP / ISDNoIP modules.
Changes in Version 3.4
- Removed DSP_MODULE switch, because it will be essential for PBX operation.
- Fixed pbxadmin offset bug.
- Added special feature "efi" to announce caller's ID. You call, and it tells
your caller ID. (if available) Sample set is not complete!
- Now caller ID and type can be given for external call rule.
- Now caller ID and type can be given for changing caller ID.
- Removed a display bug in pbxadmin, that caused busy channels to be omitted.
- Fixed layer 2 handling bug.
- Increased performance of pbx-status screen. Many interfaces/calls caused
lock up of machine.
- Timeout condition seems to work now.
- Timeout action seems to work now.
What you might expect in later versions
-> ISDN over IP (proprietary solution)
-> OPAL, with a new interface between user space audio and kernel space audio (SIP / H323)
-> (maybe later) Kernel space RTP that makes VoIP reeeeeeeeeeeeally fast!

2877
action.cpp Normal file

File diff suppressed because it is too large Load Diff

161
action_efi.cpp Normal file
View File

@ -0,0 +1,161 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** elektronische fernmelder identifikation **
** **
\*****************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "main.h"
enum {
EFI_STATE_DIE,
EFI_STATE_BENUTZERDEFINIERTE,
EFI_STATE_UNTERDRUECKTE,
EFI_STATE_RUFNUMMER_LAUTET,
EFI_STATE_DIGIT,
EFI_STATE_ICH_WIEDERHOLE,
EFI_STATE_STOP,
};
void EndpointAppPBX::action_init_efi(void)
{
// int language = e_ext.vbox_language;
// struct route_param *rparam;
struct message *message;
struct port_list *portlist = ea_endpoint->ep_portlist;
/* if no caller id */
if (e_callerinfo.id[0] == '\0')
{
/* facility rejected */
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message->param.disconnectinfo.cause = CAUSE_FACILITYREJECTED;
message_put(message);
logmessage(message);
new_state(EPOINT_STATE_OUT_DISCONNECT);
set_tone(portlist,"cause_22");
return;
}
/* connect */
new_state(EPOINT_STATE_CONNECT);
/* initialize the vbox */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) initializing efi\n", ea_endpoint->ep_serial);
e_efi_state = EFI_STATE_DIE;
set_tone_efi("die");
e_efi_digit = 0;
}
/*
* the audio file has ended
* this is called by Endpoint::message_port(), whenever an audio of has been received
*/
void EndpointAppPBX::efi_message_eof(void)
{
// char buffer[32];
char digit[] = "number_00";
struct message *message;
struct port_list *portlist = ea_endpoint->ep_portlist;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s end of file during state: %d\n", ea_endpoint->ep_serial, e_terminal, e_vbox_state);
switch(e_efi_state)
{
case EFI_STATE_DIE:
if (e_callerinfo.screen==INFO_SCREEN_USER)
{
e_efi_state = EFI_STATE_BENUTZERDEFINIERTE;
set_tone_efi("benutzerdefinierte");
break;
}
// fall through
case EFI_STATE_BENUTZERDEFINIERTE:
if (e_callerinfo.present==INFO_PRESENT_RESTRICTED)
{
e_efi_state = EFI_STATE_UNTERDRUECKTE;
set_tone_efi("unterdrueckte");
break;
}
// fall through
case EFI_STATE_UNTERDRUECKTE:
e_efi_state = EFI_STATE_RUFNUMMER_LAUTET;
set_tone_efi("rufnummer_lautet");
break;
case EFI_STATE_RUFNUMMER_LAUTET:
e_efi_state = EFI_STATE_DIGIT;
e_efi_digit = 0;
// fall through
case EFI_STATE_DIGIT:
digit[8] = numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype)[e_efi_digit];
if (digit[8])
{
set_tone_efi(digit);
e_efi_digit++;
} else
{
e_efi_state = EFI_STATE_STOP; //EFI_STATE_ICH_WIEDERHOLE;
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message->param.disconnectinfo.cause = CAUSE_NORMAL;
message_put(message);
logmessage(message);
new_state(EPOINT_STATE_OUT_DISCONNECT);
set_tone(portlist,"cause_10");
// set_tone_efi("ich_wiederhole");
}
break;
case EFI_STATE_ICH_WIEDERHOLE:
e_efi_state = EFI_STATE_DIE;
set_tone_efi("die");
break;
case EFI_STATE_STOP:
break;
default:
PERROR("efi_message_eof(ep%d): terminal %s unknown state: %d\n", ea_endpoint->ep_serial, e_terminal, e_vbox_state);
}
}
/*
* set the given vbox-tone with full path (without appending)
* the tone is played and after eof, a message is received
*/
void EndpointAppPBX::set_tone_efi(char *tone)
{
struct message *message;
if (tone == NULL)
tone = "";
if (!ea_endpoint->ep_portlist)
{
PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
}
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_TONE);
SCPY(message->param.tone.dir, (char *)"tones_efi");
SCPY(message->param.tone.name, tone);
message_put(message);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set tone '%s'\n", ea_endpoint->ep_serial, e_terminal, tone);
}

975
action_vbox.cpp Normal file
View File

@ -0,0 +1,975 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** dialing for answering machine is processed here **
** **
\*****************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "main.h"
// note: the given display message (e_vbox_display) may include "%s" for the counter
/*
* these are the state, the vbox is in. if the current tone has been played,
* an action will be calles as defined in vbox_message_eof(), which is called
* from Epoint:handler().
* also this state is used to determine the correct processing of the current key press
*/
enum {
VBOX_STATE_MENU, /* tell the menu */
VBOX_STATE_CALLINFO_BEGIN, /* this value defines the start of callinfo */
VBOX_STATE_CALLINFO_INTRO, /* tell that the "call is received at" */
VBOX_STATE_CALLINFO_MONTH, /* tell the month */
VBOX_STATE_CALLINFO_DAY, /* tell the day */
VBOX_STATE_CALLINFO_HOUR, /* tell the hour */
VBOX_STATE_CALLINFO_OCLOCK, /* tell the word "o'clock" */
VBOX_STATE_CALLINFO_MIN, /* tell the minute */
VBOX_STATE_CALLINFO_MINUTES, /* tell the word "minutes" */
VBOX_STATE_CALLINFO_DIGIT, /* tell the digits */
VBOX_STATE_CALLINFO_END, /* this value defines the end of callingo */
VBOX_STATE_NOTHING, /* tells that no calls are recorded */
VBOX_STATE_PLAY, /* play the current recording */
VBOX_STATE_PAUSE, /* tell that the recording is paused */
VBOX_STATE_RECORD_ASK, /* ask for recording */
VBOX_STATE_RECORD_PLAY, /* play recording */
VBOX_STATE_RECORD_RECORD, /* record recording */
VBOX_STATE_STORE_ASK, /* ask for store */
VBOX_STATE_DELETE_ASK, /* ask for delete */
VBOX_STATE_STORE_DONE, /* tell that message is store */
VBOX_STATE_DELETE_DONE, /* tell that message is delete */
};
char *months_english[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
char *months_german[] = {"Jan","Feb","Maer","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"};
struct vbox_menu {
char digit;
char *english;
char *german;
} vbox_menu[] = {
{'1', "<< previous", "<< zurueck"},
{'2', "-> play", "-> anhoeren"},
{'3', ">> next", ">> vor"},
{'4', "< rewind", "< rueckspulen"},
{'5', "[] stop", "[] stop"},
{'6', "> wind", "> vorspulen"},
{'7', "() record", "() Aufnahme"},
{'8', "= store", "= speichern"},
{'9', "X delete", "X loeschen"},
{'0', "* call", "* anrufen"},
{'\0', NULL, NULL}
};
/*
* initialize the vbox. this is called at process_dialing(), when the VBOX_PLAY
* action has been selected by the caller
*/
void EndpointAppPBX::action_init_vbox_play(void)
{
int language = e_ext.vbox_language;
struct route_param *rparam;
struct message *message;
struct port_list *portlist = ea_endpoint->ep_portlist;
/* get extension */
SCPY(e_vbox, e_terminal);
if ((rparam = routeparam(e_action, PARAM_EXTENSION)))
SCPY(e_vbox, rparam->string_value);
if (e_vbox[0] == '\0')
{
/* facility rejected */
message_disconnect_port(portlist, CAUSE_FACILITYREJECTED, LOCATION_PRIVATE_LOCAL, "");
new_state(EPOINT_STATE_OUT_DISCONNECT);
set_tone(portlist,"cause_22");
return;
}
/* connect, but still accept more digits */
new_state(EPOINT_STATE_IN_OVERLAP);
if (e_terminal[0])
e_dtmf = 1;
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
message_put(message);
logmessage(message);
/* initialize the vbox */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) initializing answering vbox state\n", ea_endpoint->ep_serial);
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
e_vbox_display_refresh = 1;
set_tone_vbox("menu");
e_vbox_menu = -1;
e_vbox_play = 0;
vbox_index_read(e_vbox_play);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) number of calls: %d\n", ea_endpoint->ep_serial, e_vbox_index_num);
if (e_vbox_index_num == 0)
{
e_vbox_state = VBOX_STATE_NOTHING;
SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
e_vbox_display_refresh = 1;
set_tone_vbox("nothing");
}
}
/*
* read index list, and fill the index variables with the given position
* if the index is empty (or doesn't exist), the variables are not filled.
* but alway the e_vbox_index_num is given.
*/
void EndpointAppPBX::vbox_index_read(int num)
{
FILE *fp;
char filename[256];
char buffer[256];
char name[sizeof(buffer)];
char callerid[sizeof(buffer)];
int year, mon, mday, hour, min;
int i;
e_vbox_index_num = 0;
SPRINT(filename, "%s/%s/%s/vbox/index", INSTALL_DATA, options.extensions_dir, e_vbox);
if (!(fp = fopen(filename, "r")))
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no files in index\n", ea_endpoint->ep_serial);
return;
}
fduse++;
i = 0;
while((fgets(buffer,sizeof(buffer),fp)))
{
buffer[sizeof(buffer)-1] = '\0';
if (buffer[0]) buffer[strlen(buffer)-1] = '\0';
name[0] = callerid[0] = '\0';
mon = mday = hour = min = 0;
sscanf(buffer, "%s %d %d %d %d %d %s", name, &year, &mon, &mday, &hour, &min, callerid);
if (name[0]=='\0' || name[0]=='#')
continue;
/* the selected entry */
if (i == num)
{
SCPY(e_vbox_index_file, name);
e_vbox_index_year = year;
e_vbox_index_mon = mon;
e_vbox_index_mday = mday;
e_vbox_index_hour = hour;
e_vbox_index_min = min;
SCPY(e_vbox_index_callerid, callerid);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) read entry #%d: '%s', %02d:%02d %02d:%02d cid='%s'\n", ea_endpoint->ep_serial, i, name, mon+1, mday, hour, min, callerid);
}
i++;
}
e_vbox_index_num = i;
fclose(fp);
fduse--;
}
/*
* removes given index from list
* after removing, the list should be reread, since e_vbox_index_num
* and the current variabled do not change
*/
void EndpointAppPBX::vbox_index_remove(int num)
{
FILE *fpr, *fpw;
char buffer[256];
int i;
char filename1[256], filename2[256];
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing entrie #%d\n", ea_endpoint->ep_serial, num);
SPRINT(filename1, "%s/%s/%s/vbox/index", INSTALL_DATA, options.extensions_dir, e_vbox);
SPRINT(filename2, "%s/%s/%s/vbox/index-temp", INSTALL_DATA, options.extensions_dir, e_vbox);
if (!(fpr = fopen(filename1, "r")))
{
return;
}
if (!(fpw = fopen(filename2, "w")))
{
fclose(fpr);
return;
}
fduse += 2;
i = 0;
while((fgets(buffer,sizeof(buffer),fpr)))
{
buffer[sizeof(buffer)-1] = '\0';
if (buffer[0]) buffer[strlen(buffer)-1] = '\0';
if (buffer[0]=='\0' || buffer[0]=='#')
{
fprintf(fpw, "%s\n", buffer);
continue;
}
/* the selected entry will not be written */
if (i != num)
{
fprintf(fpw, "%s\n", buffer);
}
i++;
}
fclose(fpr);
fclose(fpw);
fduse -= 2;
rename(filename2, filename1);
}
/*
* process dialing of vbox_play (actually the menu)
* it is depended by the state, which action is performed
*/
void EndpointAppPBX::action_dialing_vbox_play(void)
{
int language = e_ext.vbox_language;
struct port_list *portlist;
class Port *port;
portlist = ea_endpoint->ep_portlist;
if (e_extdialing[0] == '\0')
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) called with no digit\n", ea_endpoint->ep_serial);
return;
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing digit: %c\n", ea_endpoint->ep_serial, e_extdialing[0]);
e_vbox_display_refresh = 1;
if (e_vbox_state == VBOX_STATE_RECORD_RECORD)
{
if (e_extdialing[0] == '1')
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) stopping recording of announcement.\n", ea_endpoint->ep_serial);
port = find_port_id(portlist->port_id);
if (port)
port->close_record(6000); /* append beep */
goto record_ask;
}
goto done;
}
if (e_vbox_state == VBOX_STATE_RECORD_PLAY)
{
if (e_extdialing[0] == '1')
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) stopping playback of announcement.\n", ea_endpoint->ep_serial);
goto record_ask;
}
goto done;
}
if (e_vbox_state == VBOX_STATE_RECORD_ASK)
{
switch(e_extdialing[0])
{
case '3':
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) quit recoding menu.\n", ea_endpoint->ep_serial);
ask_abort:
/* abort */
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
set_tone_vbox("menu");
break;
case '2':
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play recoding.\n", ea_endpoint->ep_serial);
/* play announcement */
e_vbox_counter = 0;
e_vbox_counter_last = 0;
e_vbox_counter_max = 0;
e_vbox_speed = 1;
e_vbox_state = VBOX_STATE_RECORD_PLAY;
if (e_ext.vbox_language)
SCPY(e_vbox_display, "Wied., 1=stop %s");
else
SCPY(e_vbox_display, "play, 1=stop %s");
if (e_ext.vbox_display == VBOX_DISPLAY_BRIEF)
SCPY(e_vbox_display, "1=stop %s");
set_play_vbox("announcement", 0);
break;
case '1':
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) record announcement.\n", ea_endpoint->ep_serial);
/* close recording if already recording */
port = find_port_id(portlist->port_id);
if (port)
{
port->close_record(6000); /* append beep */
port->open_record(CODEC_MONO, 1, 5000, e_terminal, 0, "", 0); /* record announcement, skip the first 5000 samples */
}
e_vbox_state = VBOX_STATE_RECORD_RECORD;
if (e_ext.vbox_language)
SCPY(e_vbox_display, "Aufnahme, 1=stop");
else
SCPY(e_vbox_display, "recording, 1=stop");
set_tone_vbox(NULL);
break;
default:
;
}
goto done;
}
if (e_vbox_state==VBOX_STATE_STORE_ASK || e_vbox_state==VBOX_STATE_DELETE_ASK)
{
char filename[256], filename2[256];
switch(e_extdialing[0])
{
case '3':
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) quit store/delete menu.\n", ea_endpoint->ep_serial);
goto ask_abort;
case '1':
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do store/delete.\n", ea_endpoint->ep_serial);
SPRINT(filename, "%s/%s/%s/vbox/%s", INSTALL_DATA, options.extensions_dir, e_vbox, e_vbox_index_file);
/* move file */
if (e_vbox_state == VBOX_STATE_STORE_ASK)
{
SPRINT(filename, "%s/%s/%s/recordings", INSTALL_DATA, options.extensions_dir, e_vbox);
if (mkdir(filename, 0755) < 0)
{
if (errno != EEXIST)
{
PERROR("EPOINT(%d) cannot create directory '%s'\n", ea_endpoint->ep_serial, filename);
goto done;
}
}
SPRINT(filename2, "%s/%s/%s/recordings/%s", INSTALL_DATA, options.extensions_dir, e_vbox, e_vbox_index_file);
rename(filename, filename2);
e_vbox_state = VBOX_STATE_STORE_DONE;
if (e_ext.vbox_language)
SCPY(e_vbox_display, "Nachricht gespeichert!");
else
SCPY(e_vbox_display, "Message stored!");
set_tone_vbox("store_done");
}
/* remove file */
if (e_vbox_state == VBOX_STATE_DELETE_ASK)
{
remove(filename);
e_vbox_state = VBOX_STATE_DELETE_DONE;
if (e_ext.vbox_language)
SCPY(e_vbox_display, "Nachricht geloescht!");
else
SCPY(e_vbox_display, "Message deleted!");
set_tone_vbox("delete_done");
}
/* remove from list */
vbox_index_remove(e_vbox_play);
vbox_index_read(e_vbox_play);
/* stay at the last message+1, so we always get "no messages" */
if (e_vbox_play>e_vbox_index_num && e_vbox_play)
{
e_vbox_play = e_vbox_index_num-1;
}
default:
;
}
goto done;
}
/* dialing during menu */
switch(e_extdialing[0])
{
/* process the vbox functions */
case '1': /* previous */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) previous call is selected.\n", ea_endpoint->ep_serial);
if (e_vbox_index_num == 0) /* nothing to play */
{
no_calls:
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
set_tone_vbox("nothing");
break;
}
e_vbox_play--;
if (e_vbox_play < 0)
{
e_vbox_play = 0;
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"kein vorheriger Anruf":"no previous call"));
set_tone_vbox("nothing");
break;
}
/* announce call */
announce_call:
e_vbox_state = VBOX_STATE_CALLINFO_INTRO;
SPRINT(e_vbox_display, "#%d", e_vbox_play+1);
vbox_index_read(e_vbox_play);
if (e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year)
{
UPRINT(strchr(e_vbox_display,'\0'), " %s", (language)?months_german[e_vbox_index_mon]:months_english[e_vbox_index_mon]);
}
if (e_vbox_index_mday!=now_tm->tm_mday || e_vbox_index_mon!=now_tm->tm_mon || e_vbox_index_year!=now_tm->tm_year)
{
UPRINT(strchr(e_vbox_display,'\0'), " %d", e_vbox_index_mday);
}
UPRINT(strchr(e_vbox_display,'\0'), " %02d:%02d", e_vbox_index_hour, e_vbox_index_min);
if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
set_tone_vbox("intro");
break;
case '2': /* play */
if (e_vbox_play >= e_vbox_index_num)
goto no_messages;
if (e_vbox_index_num == 0) /* nothing to play */
{
goto no_calls;
}
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d.\n", ea_endpoint->ep_serial, e_vbox_play+1);
if (e_vbox_state>VBOX_STATE_CALLINFO_BEGIN && e_vbox_state<VBOX_STATE_CALLINFO_END)
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. abborting announcement and starting with playback\n", ea_endpoint->ep_serial, e_vbox_play+1);
/* the callinfo is played, so we start with the call */
e_vbox_counter = 0;
e_vbox_counter_last = 0;
e_vbox_counter_max = 0;
e_vbox_speed = 1;
e_vbox_state = VBOX_STATE_PLAY;
SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1);
if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
set_play_vbox(e_vbox_index_file, 0);
break;
} else
if (e_vbox_state==VBOX_STATE_PLAY && e_vbox_speed!=1)
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. play speed is different from 1, so we play now with normal speed\n", ea_endpoint->ep_serial, e_vbox_play+1);
/* we set play speed to normal */
e_vbox_speed = 1;
set_play_speed(e_vbox_speed);
} else
if (e_vbox_state == VBOX_STATE_PLAY)
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. play speed is equals 1, so we pause\n", ea_endpoint->ep_serial, e_vbox_play+1);
/* we pause the current play */
e_vbox_state = VBOX_STATE_PAUSE;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
set_tone_vbox("pause");
} else
if (e_vbox_state == VBOX_STATE_PAUSE)
{
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. currently pause, so we continue play\n", ea_endpoint->ep_serial, e_vbox_play+1);
/* we continue the current play */
e_vbox_state = VBOX_STATE_PLAY;
SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1);
if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
set_play_vbox(e_vbox_index_file, e_vbox_counter);
} else
{
/* now we have something else going on, so we announce the call */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. announcing call during any other state\n", ea_endpoint->ep_serial, e_vbox_play+1);
goto announce_call;
}
break;
case '3': /* next */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) next call is selected.\n", ea_endpoint->ep_serial);
if (e_vbox_index_num == 0) /* nothing to play */
{
goto no_calls;
}
e_vbox_play++;
if (e_vbox_play >= e_vbox_index_num)
{
no_messages:
e_vbox_play = e_vbox_index_num;
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"kein weiterer Anruf":"no next call"));
set_tone_vbox("nothing");
break;
}
/* announce call */
goto announce_call;
break;
case '4': /* rewind */
if (e_vbox_state==VBOX_STATE_PLAY)
{
if (e_vbox_speed >= -1)
e_vbox_speed = -1;
e_vbox_speed = e_vbox_speed * 2;
set_play_speed(e_vbox_speed);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rewind speed has been changed to: %d\n", ea_endpoint->ep_serial, e_vbox_speed);
}
break;
case '5': /* stop */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) stop is pressed, so we hear the menu\n", ea_endpoint->ep_serial);
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
set_tone_vbox("menu");
break;
case '6': /* wind */
if (e_vbox_state==VBOX_STATE_PLAY)
{
if (e_vbox_speed <= 1)
e_vbox_speed = 1;
e_vbox_speed = e_vbox_speed * 2;
set_play_speed(e_vbox_speed);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) wind speed has been changed to: %d\n", ea_endpoint->ep_serial, e_vbox_speed);
}
break;
case '7': /* record announcement */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) entering the record announcement menu\n", ea_endpoint->ep_serial);
record_ask:
e_vbox_state = VBOX_STATE_RECORD_ASK;
SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=back"));
set_tone_vbox("record_ask");
break;
case '8': /* store file */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) entering the store menu\n", ea_endpoint->ep_serial);
if (e_vbox_play >= e_vbox_index_num)
goto no_messages;
if (e_vbox_index_num == 0) /* nothing to play */
{
goto no_calls;
}
e_vbox_state = VBOX_STATE_STORE_ASK;
SCPY(e_vbox_display, (char *)((language)?"speichern 1=ja 3=nein":"store 1=yes 3=back"));
set_tone_vbox("store_ask");
break;
case '9': /* delete file */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) entering the delete menu\n", ea_endpoint->ep_serial);
if (e_vbox_play >= e_vbox_index_num)
goto no_messages;
if (e_vbox_index_num == 0) /* nothing to play */
{
goto no_calls;
}
e_vbox_state = VBOX_STATE_DELETE_ASK;
SCPY(e_vbox_display, (char *)((language)?"loeschen 1=ja 3=nein":"delete 1=yes 3=back"));
set_tone_vbox("delete_ask");
break;
/* process the menu */
case '#':
if (e_vbox_menu < 0)
e_vbox_menu = 0;
else
e_vbox_menu++;
if (vbox_menu[e_vbox_menu].english == NULL)
e_vbox_menu = 0;
/* show menu */
show_menu:
SPRINT(e_vbox_display, "%c: %s", vbox_menu[e_vbox_menu].digit, (language)?vbox_menu[e_vbox_menu].german:vbox_menu[e_vbox_menu].english);
break;
case '0':
if (e_vbox_menu < 0) /* only if menu selection is pressed before*/
{
/* call if phonenumber is given */
if (e_vbox_index_num)
if (e_vbox_index_callerid[0]!='\0' && !!strcmp(e_vbox_index_callerid,"anonymous") && !!strcmp(e_vbox_index_callerid,"unknown"))
{
set_tone(portlist, "dialing");
SPRINT(e_dialinginfo.number, "extern:%s", e_vbox_index_callerid);
e_extdialing = e_dialinginfo.number;
e_action = NULL;
process_dialing();
return;
}
break;
}
e_extdialing[0] = vbox_menu[e_vbox_menu].digit;
e_extdialing[1] = '\0';
e_vbox_menu = -1;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) executing selected menu:%d\n", e_extdialing[0]);
action_dialing_vbox_play(); /* redo this method using the digit */
return;
case '*':
if (e_vbox_menu < 0)
e_vbox_menu = 0;
else
e_vbox_menu--;
if (e_vbox_menu < 0)
while(vbox_menu[e_vbox_menu+1].english) /* jump to the end */
e_vbox_menu++;
/* show menu */
goto show_menu;
break;
default:
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported digit '%c'\n", ea_endpoint->ep_serial, e_extdialing);
}
done:
/* reset menu after dialing a function */
if (e_extdialing[0]!='*' && e_extdialing[0]!='#')
e_vbox_menu = -1;
e_extdialing[0] = '\0';
}
/*
* this handler is called by Epoint::handler(), whenever the action is NUMB_ACTION_VBOX_PLAY
*/
void EndpointAppPBX::vbox_handler(void)
{
/* refresh if counter changes */
if (e_vbox_state==VBOX_STATE_PLAY || e_vbox_state==VBOX_STATE_RECORD_PLAY)
if (e_vbox_counter != e_vbox_counter_last)
{
e_vbox_counter_last = e_vbox_counter;
e_vbox_display_refresh = 1;
}
/* refresh display, if required (include counter) */
if (e_vbox_display_refresh && e_ext.vbox_display!=VBOX_DISPLAY_OFF)
{
char counter[32];
struct message *message;
SPRINT(counter, "%02d:%02d", e_vbox_counter/60, e_vbox_counter%60);
if (e_vbox_counter_max)
UPRINT(strchr(counter,'\0'), " of %02d:%02d", e_vbox_counter_max/60, e_vbox_counter_max%60);
e_vbox_display_refresh = 0;
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
SPRINT(message->param.notifyinfo.display, e_vbox_display, counter);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s pending display:%s\n", ea_endpoint->ep_serial, e_terminal, message->param.notifyinfo.display);
message_put(message);
logmessage(message);
}
}
/*
* the audio file has ended
* this is called by Endpoint::message_port(), whenever an audio of has been received
*/
void EndpointAppPBX::vbox_message_eof(void)
{
char buffer[32];
int language = e_ext.vbox_language;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s end of file during state: %d\n", ea_endpoint->ep_serial, e_terminal, e_vbox_state);
switch(e_vbox_state)
{
case VBOX_STATE_MENU:
case VBOX_STATE_NOTHING:
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
e_vbox_display_refresh = 1;
set_tone_vbox("menu");
break;
case VBOX_STATE_PLAY:
if (e_vbox_speed > 0)
{
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 3 f. Naechste":"press 3 for next"));
e_vbox_display_refresh = 1;
set_tone_vbox("menu");
} else
{
/* if we have endoffile because we were playing backwards, we continue to play forward */
e_vbox_speed = 1;
e_vbox_counter = 1;
set_play_vbox(e_vbox_index_file, e_vbox_counter);
}
break;
case VBOX_STATE_PAUSE:
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. weiterspielen":"press 2 to continue"));
e_vbox_display_refresh = 1;
break;
case VBOX_STATE_CALLINFO_INTRO:
if (e_vbox_index_mday==now_tm->tm_mday && e_vbox_index_mon==now_tm->tm_mon && e_vbox_index_year==now_tm->tm_year)
goto skip_day_month;
e_vbox_state = VBOX_STATE_CALLINFO_MONTH; //german day
if (e_ext.vbox_language)
/* german starts with day */
SPRINT(buffer, "day_%02d", e_vbox_index_mday);
else
/* english starts with month */
SPRINT(buffer, "month_%02d", e_vbox_index_mon+1);
set_tone_vbox(buffer);
break;
case VBOX_STATE_CALLINFO_MONTH:
e_vbox_state = VBOX_STATE_CALLINFO_DAY; //german month
if (e_ext.vbox_language)
{
/* done with month, so we send the month*/
SPRINT(buffer, "month_%02d", e_vbox_index_mon+1);
} else
{
/* done with day, so we send the day */
SPRINT(buffer, "day_%02d", e_vbox_index_mday);
}
set_tone_vbox(buffer);
break;
case VBOX_STATE_CALLINFO_DAY: //german month
skip_day_month:
e_vbox_state = VBOX_STATE_CALLINFO_HOUR;
if (e_ext.vbox_language)
{
if (e_vbox_index_hour == 1)
SCPY(buffer, "number_ein");
else
SPRINT(buffer, "number_%02d", e_vbox_index_hour); /* 1-23 hours */
} else
{
SPRINT(buffer, "number_%02d", ((e_vbox_index_hour+11)%12)+1); /* 12 hours am/pm */
}
set_tone_vbox(buffer);
break;
case VBOX_STATE_CALLINFO_HOUR:
e_vbox_state = VBOX_STATE_CALLINFO_OCLOCK;
if (e_ext.vbox_language)
{
set_tone_vbox("oclock");
} else
{
if (e_vbox_index_hour >= 12)
set_tone_vbox("oclock_pm");
else
set_tone_vbox("oclock_am");
}
break;
case VBOX_STATE_CALLINFO_OCLOCK:
e_vbox_state = VBOX_STATE_CALLINFO_MIN;
if (e_ext.vbox_language)
{
// german says "zwölfuhr und eins"
// if (e_vbox_index_min == 1)
// SCPY(buffer, "number_eine");
// else
SPRINT(buffer, "number_%02d", e_vbox_index_min); /* 1-59 minutes */
} else
{
SPRINT(buffer, "number_%02d", e_vbox_index_min);
}
set_tone_vbox(buffer);
break;
case VBOX_STATE_CALLINFO_MIN:
if (e_ext.vbox_language)
goto start_digits;
e_vbox_state = VBOX_STATE_CALLINFO_MINUTES;
if (e_vbox_index_mday == 1)
set_tone_vbox("minute");
else
set_tone_vbox("minutes");
break;
case VBOX_STATE_CALLINFO_MINUTES:
start_digits:
e_vbox_state = VBOX_STATE_CALLINFO_DIGIT;
if (e_vbox_index_callerid[0]=='\0' || !strcmp(e_vbox_index_callerid,"anonymous") || !strcmp(e_vbox_index_callerid,"unknown"))
{
set_tone_vbox("call_anonymous");
e_vbox_index_callerid_index = strlen(e_vbox_index_callerid);
} else
{
set_tone_vbox("call_from");
e_vbox_index_callerid_index = 0;
}
break;
case VBOX_STATE_CALLINFO_DIGIT:
while (e_vbox_index_callerid[e_vbox_index_callerid_index] && (e_vbox_index_callerid[e_vbox_index_callerid_index]<'0' || e_vbox_index_callerid[e_vbox_index_callerid_index]>'9'))
e_vbox_index_callerid_index++;
if (e_vbox_index_callerid[e_vbox_index_callerid_index])
{
SPRINT(buffer, "number_%02d", e_vbox_index_callerid[e_vbox_index_callerid_index]-'0');
set_tone_vbox(buffer);
e_vbox_index_callerid_index ++;
} else
{
/* the callinfo is played, so we start with the call */
e_vbox_counter = 0;
e_vbox_counter_last = 0;
e_vbox_counter_max = 0;
e_vbox_speed = 1;
e_vbox_state = VBOX_STATE_PLAY;
SPRINT(e_vbox_display, "#%d %%s", e_vbox_play);
if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
e_vbox_display_refresh = 1;
set_play_vbox(e_vbox_index_file, 0);
}
break;
case VBOX_STATE_RECORD_ASK:
set_tone_vbox("record_ask");
e_vbox_display_refresh = 1;
break;
case VBOX_STATE_STORE_ASK:
set_tone_vbox("store_ask");
e_vbox_display_refresh = 1;
break;
case VBOX_STATE_DELETE_ASK:
set_tone_vbox("delete_ask");
e_vbox_display_refresh = 1;
break;
case VBOX_STATE_RECORD_PLAY:
e_vbox_state = VBOX_STATE_RECORD_ASK;
SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=no"));
e_vbox_display_refresh = 1;
set_tone_vbox("record_ask");
break;
case VBOX_STATE_STORE_DONE:
case VBOX_STATE_DELETE_DONE:
if (e_vbox_index_num == 0) /* nothing to play */
{
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
e_vbox_display_refresh = 1;
set_tone_vbox("nothing");
} else
{
e_vbox_state = VBOX_STATE_MENU;
SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
e_vbox_display_refresh = 1;
set_tone_vbox("menu");
}
break;
default:
PERROR("vbox_message_eof(ep%d): terminal %s unknown state: %d\n", ea_endpoint->ep_serial, e_terminal, e_vbox_state);
}
}
/*
* set the given vbox-tone with full path (without appending)
* the tone is played and after eof, a message is received
*/
void EndpointAppPBX::set_tone_vbox(char *tone)
{
struct message *message;
if (tone == NULL)
tone = "";
if (!ea_endpoint->ep_portlist)
{
PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
}
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_TONE);
SCPY(message->param.tone.dir, (char *)((e_ext.vbox_language)?"vbox_german":"vbox_english"));
SCPY(message->param.tone.name, tone);
message_put(message);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set tone '%s'\n", ea_endpoint->ep_serial, e_terminal, tone);
}
/*
* set the given recording file
* the appendix is removed
* the file is played and after eof, a message is received
* the current counter value is also received by a message
* set the offset in seconds of the current recording
*/
void EndpointAppPBX::set_play_vbox(char *file, int offset)
{
char filename[256];
struct message *message;
SPRINT(filename, "%s/%s/%s/vbox/%s", INSTALL_DATA, options.extensions_dir, e_vbox, file);
/* remove .wav */
if (!strcmp(filename+strlen(filename)-4, ".wav")) /* filename is always more than 4 digits long */
filename[strlen(filename)-4] = '\0';
else // to not check twice
/* remove .isdn */
if (!strcmp(filename+strlen(filename)-5, ".isdn")) /* filename is always more than 5 digits long */
filename[strlen(filename)-5] = '\0';
if (!ea_endpoint->ep_portlist)
{
PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
}
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_PLAY);
SCPY(message->param.play.file, filename);
message->param.play.offset = offset;
message_put(message);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set play '%s'\n", ea_endpoint->ep_serial, e_terminal, filename);
}
/*
* change speed of the recording file, the default is 1
* negative values cause negative speed
*/
void EndpointAppPBX::set_play_speed(int speed)
{
struct message *message;
if (!ea_endpoint->ep_portlist)
{
PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
}
message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_PLAY_SPEED);
message->param.speed = speed;
message_put(message);
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set speed '%d'\n", ea_endpoint->ep_serial, e_terminal, speed);
}

147
admin.h Normal file
View File

@ -0,0 +1,147 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** Administration tool header file **
** **
\*****************************************************************************/
#define SOCKET_NAME "/var/run/PBX4Linux.socket"
/* structures that define message between admin-tool and pbx */
enum { /* messages */
ADMIN_REQUEST_CMD_INTERFACE,
ADMIN_RESPONSE_CMD_INTERFACE,
ADMIN_REQUEST_CMD_ROUTE,
ADMIN_RESPONSE_CMD_ROUTE,
ADMIN_REQUEST_CMD_DIAL,
ADMIN_RESPONSE_CMD_DIAL,
ADMIN_REQUEST_CMD_RELEASE,
ADMIN_RESPONSE_CMD_RELEASE,
ADMIN_REQUEST_STATE,
ADMIN_RESPONSE_STATE,
ADMIN_RESPONSE_S_INTERFACE,
ADMIN_RESPONSE_S_PORT,
ADMIN_RESPONSE_S_EPOINT,
ADMIN_RESPONSE_S_CALL,
ADMIN_CALL_SETUP,
ADMIN_CALL_SETUP_ACK,
ADMIN_CALL_PROCEEDING,
ADMIN_CALL_ALERTING,
ADMIN_CALL_CONNECT,
ADMIN_CALL_DISCONNECT,
ADMIN_CALL_RELEASE,
ADMIN_CALL_NOTIFY,
};
struct admin_response_cmd {
int error; /* error code 0 = ok*/
char message[256]; /* info / response text */
};
struct admin_response_state {
char version_string[64];
struct tm tm;
char logfile[128];
int interfaces;
int calls;
int epoints;
int ports;
};
struct admin_response_interface {
int portnum;
char interface_name[32];
int ntmode;
int ptp;
int pri;
int iftype;
int use; /* number of ports that use this interface */
int l1link; /* down(0) or up(1) */
int l2link; /* down(0) or up(1) */
int channels;
int busy[256]; /* if port is idle(0) busy(1) */
unsigned long port[256]; /* current port */
};
struct admin_response_call {
unsigned long serial; /* call serial number */
unsigned long partyline;
};
struct admin_response_epoint {
unsigned long serial;
unsigned long call; /* link to call */
// int call_notify; /* if relation notified on hold */
// int call_hold; /* if relation on hold */
int rx_state;
int tx_state;
int state;
char terminal[16];
char callerid[64];
char dialing[64];
char action[32];
int park; /* if parked */
int park_len;
unsigned char park_callid[8];
int crypt; /* crypt state */
};
struct admin_response_port {
unsigned long serial; /* port serial number */
char name[64]; /* name of port */
unsigned long epoint; /* link to epoint */
int state;
int isdn; /* if port is isdn */
int isdn_chan; /* bchannel number */
int isdn_hold; /* on hold */
int isdn_ces; /* ces to use (>=0)*/
};
struct admin_call {
char interface[64]; /* name of port */
char callerid[64]; /* use caller id */
char dialing[64]; /* number to dial */
int present; /* presentation */
int cause; /* cause to send */
int location;
int notify;
int bc_capa;
int bc_mode;
int bc_info1;
int hlc;
int exthlc;
};
struct admin_message {
int message; /* type of admin message */
union u {
struct admin_response_cmd x;
struct admin_response_state s;
struct admin_response_interface i;
struct admin_response_port p;
struct admin_response_epoint e;
struct admin_response_call c;
struct admin_call call;
} u;
};
/* call states */
enum {
ADMIN_STATE_IDLE,
ADMIN_STATE_IN_SETUP,
ADMIN_STATE_OUT_SETUP,
ADMIN_STATE_IN_OVERLAP,
ADMIN_STATE_OUT_OVERLAP,
ADMIN_STATE_IN_PROCEEDING,
ADMIN_STATE_OUT_PROCEEDING,
ADMIN_STATE_IN_ALERTING,
ADMIN_STATE_OUT_ALERTING,
ADMIN_STATE_CONNECT,
ADMIN_STATE_IN_DISCONNECT,
ADMIN_STATE_OUT_DISCONNECT,
};

1323
admin_client.c Normal file

File diff suppressed because it is too large Load Diff

991
admin_server.c Normal file
View File

@ -0,0 +1,991 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** Socket link **
** **
\*****************************************************************************/
#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
#include <sys/types.h>
//#include <sys/stat.h>
//#include <unistd.h>
//#include <signal.h>
//#include <stdarg.h>
//#include <fcntl.h>
#include <sys/ioctl.h>
//#include <sys/file.h>
//#include <errno.h>
//#include <sys/mman.h>
//#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <curses.h>
#include "main.h"
char *socket_name = SOCKET_NAME;
int sock = -1;
struct sockaddr_un sock_address;
struct admin_list *admin_list = NULL;
/*
* initialize admin socket
*/
int admin_init(void)
{
unsigned long on = 1;
/* open and bind socket */
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
{
PERROR("Failed to create admin socket. (errno=%d)\n", errno);
return(-1);
}
fhuse++;
memset(&sock_address, 0, sizeof(sock_address));
sock_address.sun_family = AF_UNIX;
UCPY(sock_address.sun_path, socket_name);
unlink(socket_name);
if (bind(sock, (struct sockaddr *)(&sock_address), SUN_LEN(&sock_address)) < 0)
{
close(sock);
unlink(socket_name);
fhuse--;
sock = -1;
PERROR("Failed to bind admin socket to \"%s\". (errno=%d)\n", sock_address.sun_path, errno);
return(-1);
}
if (listen(sock, 5) < 0)
{
close(sock);
unlink(socket_name);
fhuse--;
sock = -1;
PERROR("Failed to listen to socket \"%s\". (errno=%d)\n", sock_address.sun_path, errno);
return(-1);
}
if (ioctl(sock, FIONBIO, (unsigned char *)(&on)) < 0)
{
close(sock);
unlink(socket_name);
fhuse--;
sock = -1;
PERROR("Failed to set socket \"%s\" into non-blocking mode. (errno=%d)\n", sock_address.sun_path, errno);
return(-1);
}
return(0);
}
/*
* free connection
*/
void free_connection(struct admin_list *admin)
{
struct admin_queue *response;
void *temp;
if (admin->sock >= 0)
{
close(admin->sock);
fhuse--;
}
// printf("new\n", response);
response = admin->response;
while (response)
{
//#warning
// printf("%x\n", response);
temp = response->next;
free(response);
memuse--;
response = (struct admin_queue *)temp;
}
// printf("new2\n", response);
free(admin);
// printf("new3\n", response);
memuse--;
}
/*
* cleanup admin socket
*/
void admin_cleanup(void)
{
struct admin_list *admin, *next;;
admin = admin_list;
while(admin)
{
//printf("clean\n");
next = admin->next;
free_connection(admin);
admin = next;
}
if (sock >= 0)
{
close(sock);
fhuse--;
}
}
/*
* do interface reload
*/
int admin_interface(struct admin_queue **responsep)
{
struct admin_queue *response; /* response pointer */
char *err_txt = "";
int err = 0;
if (read_interfaces())
{
relink_interfaces();
free_interfaces(interface_first);
interface_first = interface_newlist;
interface_newlist = NULL;
} else
{
err_txt = interface_error;
err = -1;
}
/* create state response */
response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
if (!response)
return(-1);
memuse++;
memset(response, 0, sizeof(admin_queue));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_INTERFACE;
/* error */
response->am[0].u.x.error = err;
/* message */
SCPY(response->am[0].u.x.message, err_txt);
/* attach to response chain */
*responsep = response;
responsep = &response->next;
return(0);
}
/*
* do route reload
*/
int admin_route(struct admin_queue **responsep)
{
struct route_ruleset *ruleset_new;
struct admin_queue *response; /* response pointer */
char err_txt[256] = "";
int err = 0;
#if 0
int n;
#endif
class EndpointAppPBX *apppbx;
#if 0
n = 0;
apppbx = apppbx_first;
while(apppbx)
{
n++;
apppbx = apppbx->next;
}
if (apppbx_first)
{
SPRINT(err_txt, "Cannot reload routing, because %d endpoints active\n", n);
err = -1;
goto response;
}
#endif
if (!(ruleset_new = ruleset_parse()))
{
SPRINT(err_txt, ruleset_error);
err = -1;
goto response;
}
ruleset_free(ruleset_first);
ruleset_first = ruleset_new;
ruleset_main = getrulesetbyname("main");
if (!ruleset_main)
{
SPRINT(err_txt, "Ruleset reloaded, but rule 'main' not found.\n");
err = -1;
}
apppbx = apppbx_first;
while(apppbx)
{
if (apppbx->e_action)
{
switch(apppbx->e_action->index)
{
case ACTION_INTERNAL:
apppbx->e_action = &action_internal;
break;
case ACTION_EXTERNAL:
apppbx->e_action = &action_external;
break;
case ACTION_H323:
apppbx->e_action = &action_h323;
break;
case ACTION_CHAN:
apppbx->e_action = &action_chan;
break;
case ACTION_VBOX_RECORD:
apppbx->e_action = &action_vbox;
break;
case ACTION_PARTYLINE:
apppbx->e_action = &action_partyline;
break;
default:
goto release;
}
} else if (apppbx->e_state != EPOINT_STATE_CONNECT)
{
release:
apppbx->e_callback = 0;
apppbx->e_action = NULL;
apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
printlog("%3d endpoint ADMIN Kicking due to reload of routing.\n", apppbx->ea_endpoint->ep_serial);
}
apppbx->e_action_timeout = NULL;
apppbx->e_rule = NULL;
apppbx->e_ruleset = NULL;
apppbx = apppbx->next;
}
response:
/* create state response */
response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
if (!response)
return(-1);
memuse++;
memset(response, 0, sizeof(admin_queue));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_ROUTE;
/* error */
response->am[0].u.x.error = err;
/* message */
SCPY(response->am[0].u.x.message, err_txt);
/* attach to response chain */
*responsep = response;
responsep = &response->next;
return(0);
}
/*
* do dialing
*/
int admin_dial(struct admin_queue **responsep, char *message)
{
struct extension ext; /* temporary extension's settings */
struct admin_queue *response; /* response pointer */
char *p; /* pointer to dialing digits */
/* create state response */
response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
if (!response)
return(-1);
memuse++;
memset(response, 0, sizeof(admin_queue));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_DIAL;
/* process request */
if (!(p = strchr(message,':')))
{
response->am[0].u.x.error = -EINVAL;
SPRINT(response->am[0].u.x.message, "no seperator ':' in message to seperate number from extension");
goto out;
}
*p++ = 0;
/* modify extension */
if (!read_extension(&ext, message))
{
response->am[0].u.x.error = -EINVAL;
SPRINT(response->am[0].u.x.message, "extension doesn't exist");
goto out;
}
SCPY(ext.next, p);
write_extension(&ext, message);
out:
/* attach to response chain */
*responsep = response;
responsep = &response->next;
return(0);
}
/*
* do release
*/
int admin_release(struct admin_queue **responsep, char *message)
{
unsigned long id;
struct admin_queue *response; /* response pointer */
class EndpointAppPBX *apppbx;
/* create state response */
response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
if (!response)
return(-1);
memuse++;
memset(response, 0, sizeof(admin_queue));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_CMD_RELEASE;
id = atoi(message);
apppbx = apppbx_first;
while(apppbx)
{
if (apppbx->ea_endpoint->ep_serial == id)
break;
apppbx = apppbx->next;
}
if (!apppbx)
{
response->am[0].u.x.error = -EINVAL;
SPRINT(response->am[0].u.x.message, "Given endpoint %d doesn't exist.", id);
goto out;
}
apppbx->e_callback = 0;
apppbx->release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
out:
/* attach to response chain */
*responsep = response;
responsep = &response->next;
return(0);
}
/*
* do call
*/
int admin_call(struct admin_list *admin, struct admin_message *msg)
{
class Endpoint *epoint;
class EndpointAppPBX *apppbx;
if (!(epoint = new Endpoint(0,0)))
return(-1);
if (!(epoint->ep_app = apppbx = new DEFAULT_ENDPOINT_APP(epoint)))
{
PERROR("no memory for application\n");
exit(-1);
}
apppbx->e_adminid = admin->sockserial;
admin->epointid = epoint->ep_serial;
SCPY(apppbx->e_callerinfo.id, nationalize_callerinfo(msg->u.call.callerid, &apppbx->e_callerinfo.ntype));
if (msg->u.call.present)
apppbx->e_callerinfo.present = INFO_PRESENT_ALLOWED;
else
apppbx->e_callerinfo.present = INFO_PRESENT_RESTRICTED;
apppbx->e_callerinfo.screen = INFO_SCREEN_NETWORK;
//printf("hh=%d\n", apppbx->e_capainfo.hlc);
apppbx->e_capainfo.bearer_capa = msg->u.call.bc_capa;
apppbx->e_capainfo.bearer_mode = msg->u.call.bc_mode;
apppbx->e_capainfo.bearer_info1 = msg->u.call.bc_info1;
apppbx->e_capainfo.hlc = msg->u.call.hlc;
apppbx->e_capainfo.exthlc = msg->u.call.exthlc;
SCPY(apppbx->e_dialinginfo.number, msg->u.call.dialing);
SCPY(apppbx->e_dialinginfo.interfaces, msg->u.call.interface);
apppbx->e_dialinginfo.sending_complete = 1;
apppbx->new_state(PORT_STATE_OUT_SETUP);
apppbx->out_setup();
return(0);
}
/*
* this function is called for response whenever a call state changes.
*/
void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify)
{
struct admin_list *admin;
struct admin_queue *response, **responsep; /* response pointer */
/* searching for admin id
* maybe there is no admin instance, because the calling port was not
* initiated by admin_call */
admin = admin_list;
while(admin)
{
if (adminid == admin->sockserial)
break;
admin = admin->next;
}
if (!admin)
return;
/* seek to end of response list */
response = admin->response;
responsep = &admin->response;
while(response)
{
responsep = &response->next;
response = response->next;
}
/* create state response */
response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
if (!response)
return;
memuse++;
memset(response, 0, sizeof(admin_queue));
response->num = 1;
/* message */
response->am[0].message = message;
// printf("MESSAGE: %d\n", message);
SCPY(response->am[0].u.call.callerid, connected);
response->am[0].u.call.cause = cause;
response->am[0].u.call.location = location;
response->am[0].u.call.notify = notify;
/* attach to response chain */
*responsep = response;
responsep = &response->next;
}
/*
* do state debugging
*/
int admin_state(struct admin_queue **responsep)
{
class Port *port;
class EndpointAppPBX *apppbx;
class Call *call;
class Pdss1 *pdss1;
struct mISDNport *mISDNport;
int i;
int num;
int anybusy;
struct admin_queue *response;
/* create state response */
response = (struct admin_queue *)malloc(sizeof(struct admin_queue)+sizeof(admin_message));
if (!response)
return(-1);
memuse++;
memset(response, 0, sizeof(admin_queue));
response->num = 1;
/* message */
response->am[0].message = ADMIN_RESPONSE_STATE;
/* version */
SCPY(response->am[0].u.s.version_string, VERSION_STRING);
/* time */
memcpy(&response->am[0].u.s.tm, now_tm, sizeof(struct tm));
/* log file */
SCPY(response->am[0].u.s.logfile, options.log);
/* interface count */
mISDNport = mISDNport_first;
i = 0;
while(mISDNport)
{
i++;
mISDNport = mISDNport->next;
}
response->am[0].u.s.interfaces = i;
/* call count */
call = call_first;
i = 0;
while(call)
{
i++;
call = call->next;
}
response->am[0].u.s.calls = i;
/* apppbx count */
apppbx = apppbx_first;
i = 0;
while(apppbx)
{
i++;
apppbx = apppbx->next;
}
response->am[0].u.s.epoints = i;
/* port count */
port = port_first;
i = 0;
while(port)
{
i++;
port = port->next;
}
response->am[0].u.s.ports = i;
/* attach to response chain */
*responsep = response;
responsep = &response->next;
/* create response for all interfaces */
num = (response->am[0].u.s.interfaces)+(response->am[0].u.s.calls)+(response->am[0].u.s.epoints)+(response->am[0].u.s.ports);
response = (struct admin_queue *)malloc(sizeof(admin_queue)+(num*sizeof(admin_message)));
if (!response)
return(-1);
memuse++;
memset(response, 0, sizeof(admin_queue)+(num*sizeof(admin_queue)));
response->num = num;
*responsep = response;
responsep = &response->next;
mISDNport = mISDNport_first;
num = 0;
while(mISDNport)
{
/* message */
response->am[num].message = ADMIN_RESPONSE_S_INTERFACE;
/* portnum */
response->am[num].u.i.portnum = mISDNport->portnum;
/* interface */
SCPY(response->am[num].u.i.interface_name, mISDNport->interface_name);
/* iftype */
response->am[num].u.i.iftype = mISDNport->iftype;
/* ptp */
response->am[num].u.i.ptp = mISDNport->ptp;
/* ntmode */
response->am[num].u.i.ntmode = mISDNport->ntmode;
/* pri */
response->am[num].u.i.pri = mISDNport->pri;
/* use */
response->am[num].u.i.use = mISDNport->use;
/* l1link */
response->am[num].u.i.l1link = mISDNport->l1link;
/* l2link */
response->am[num].u.i.l2link = mISDNport->l2link;
/* channels */
response->am[num].u.i.channels = mISDNport->b_num;
/* channel info */
i = 0;
anybusy = 0;
while(i < mISDNport->b_num)
{
response->am[num].u.i.busy[i] = mISDNport->b_state[i];
if (mISDNport->b_port[i])
response->am[num].u.i.port[i] = mISDNport->b_port[i]->p_serial;
i++;
}
mISDNport = mISDNport->next;
num++;
}
/* create response for all calls */
call = call_first;
while(call)
{
/* message */
response->am[num].message = ADMIN_RESPONSE_S_CALL;
/* serial */
response->am[num].u.c.serial = call->c_serial;
/* partyline */
if (call->c_type == CALL_TYPE_PBX)
response->am[num].u.c.partyline = ((class CallPBX *)call)->c_partyline;
/* */
call = call->next;
num++;
}
/* create response for all endpoint */
apppbx = apppbx_first;
while(apppbx)
{
/* message */
response->am[num].message = ADMIN_RESPONSE_S_EPOINT;
/* serial */
response->am[num].u.e.serial = apppbx->ea_endpoint->ep_serial;
/* call */
response->am[num].u.e.call = apppbx->ea_endpoint->ep_call_id;
/* rx notification */
response->am[num].u.e.rx_state = apppbx->e_rx_state;
/* tx notification */
response->am[num].u.e.tx_state = apppbx->e_tx_state;
/* state */
switch(apppbx->e_state)
{
case EPOINT_STATE_IN_SETUP:
response->am[num].u.e.state = ADMIN_STATE_IN_SETUP;
break;
case EPOINT_STATE_OUT_SETUP:
response->am[num].u.e.state = ADMIN_STATE_OUT_SETUP;
break;
case EPOINT_STATE_IN_OVERLAP:
response->am[num].u.e.state = ADMIN_STATE_IN_OVERLAP;
break;
case EPOINT_STATE_OUT_OVERLAP:
response->am[num].u.e.state = ADMIN_STATE_OUT_OVERLAP;
break;
case EPOINT_STATE_IN_PROCEEDING:
response->am[num].u.e.state = ADMIN_STATE_IN_PROCEEDING;
break;
case EPOINT_STATE_OUT_PROCEEDING:
response->am[num].u.e.state = ADMIN_STATE_OUT_PROCEEDING;
break;
case EPOINT_STATE_IN_ALERTING:
response->am[num].u.e.state = ADMIN_STATE_IN_ALERTING;
break;
case EPOINT_STATE_OUT_ALERTING:
response->am[num].u.e.state = ADMIN_STATE_OUT_ALERTING;
break;
case EPOINT_STATE_CONNECT:
response->am[num].u.e.state = ADMIN_STATE_CONNECT;
break;
case EPOINT_STATE_IN_DISCONNECT:
response->am[num].u.e.state = ADMIN_STATE_IN_DISCONNECT;
break;
case EPOINT_STATE_OUT_DISCONNECT:
response->am[num].u.e.state = ADMIN_STATE_OUT_DISCONNECT;
break;
default:
response->am[num].u.e.state = ADMIN_STATE_IDLE;
}
/* terminal */
SCPY(response->am[num].u.e.terminal, apppbx->e_terminal);
/* callerid */
SCPY(response->am[num].u.e.callerid, apppbx->e_callerinfo.id);
/* dialing */
SCPY(response->am[num].u.e.dialing, apppbx->e_dialinginfo.number);
/* action string */
if (apppbx->e_action)
SCPY(response->am[num].u.e.action, action_defs[apppbx->e_action->index].name);
// if (apppbx->e_action)
// printf("action=%s\n",action_defs[apppbx->e_action->index].name);
/* park */
response->am[num].u.e.park = apppbx->ea_endpoint->ep_park;
if (apppbx->ea_endpoint->ep_park && apppbx->ea_endpoint->ep_park_len && apppbx->ea_endpoint->ep_park_len<=(int)sizeof(response->am[num].u.e.park_callid))
memcpy(response->am[num].u.e.park_callid, apppbx->ea_endpoint->ep_park_callid, apppbx->ea_endpoint->ep_park_len);
response->am[num].u.e.park_len = apppbx->ea_endpoint->ep_park_len;
/* crypt */
if (apppbx->e_crypt == CRYPT_ON)
response->am[num].u.e.crypt = 1;
/* */
apppbx = apppbx->next;
num++;
}
/* create response for all ports */
port = port_first;
while(port)
{
/* message */
response->am[num].message = ADMIN_RESPONSE_S_PORT;
/* serial */
response->am[num].u.p.serial = port->p_serial;
/* name */
SCPY(response->am[num].u.p.name, port->p_name);
/* epoint */
response->am[num].u.p.epoint = ACTIVE_EPOINT(port->p_epointlist);
/* state */
switch(port->p_state)
{
case PORT_STATE_IN_SETUP:
response->am[num].u.p.state = ADMIN_STATE_IN_SETUP;
break;
case PORT_STATE_OUT_SETUP:
response->am[num].u.p.state = ADMIN_STATE_OUT_SETUP;
break;
case PORT_STATE_IN_OVERLAP:
response->am[num].u.p.state = ADMIN_STATE_IN_OVERLAP;
break;
case PORT_STATE_OUT_OVERLAP:
response->am[num].u.p.state = ADMIN_STATE_OUT_OVERLAP;
break;
case PORT_STATE_IN_PROCEEDING:
response->am[num].u.p.state = ADMIN_STATE_IN_PROCEEDING;
break;
case PORT_STATE_OUT_PROCEEDING:
response->am[num].u.p.state = ADMIN_STATE_OUT_PROCEEDING;
break;
case PORT_STATE_IN_ALERTING:
response->am[num].u.p.state = ADMIN_STATE_IN_ALERTING;
break;
case PORT_STATE_OUT_ALERTING:
response->am[num].u.p.state = ADMIN_STATE_OUT_ALERTING;
break;
case PORT_STATE_CONNECT:
response->am[num].u.p.state = ADMIN_STATE_CONNECT;
break;
case PORT_STATE_IN_DISCONNECT:
response->am[num].u.p.state = ADMIN_STATE_IN_DISCONNECT;
break;
case PORT_STATE_OUT_DISCONNECT:
response->am[num].u.p.state = ADMIN_STATE_OUT_DISCONNECT;
break;
default:
response->am[num].u.p.state = ADMIN_STATE_IDLE;
}
/* isdn */
if ((port->p_type&PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1)
{
response->am[num].u.p.isdn = 1;
pdss1 = (class Pdss1 *)port;
response->am[num].u.p.isdn_chan = pdss1->p_m_b_channel;
response->am[num].u.p.isdn_hold = pdss1->p_m_hold;
response->am[num].u.p.isdn_ces = pdss1->p_m_d_ces;
}
/* */
port = port->next;
num++;
}
return(0);
}
int sockserial = 1; // must start with 1, because 0 is used if no serial is set
/*
* handle admin socket (non blocking)
*/
int admin_handle(void)
{
struct admin_list *admin, **adminp;
void *temp;
struct admin_message msg;
int len;
int new_sock;
socklen_t sock_len = sizeof(sock_address);
unsigned long on = 1;
int work = 0; /* if work was done */
struct Endpoint *epoint;
if (sock < 0)
return(0);
/* check for new incomming connections */
if ((new_sock = accept(sock, (struct sockaddr *)&sock_address, &sock_len)) >= 0)
{
work = 1;
/* insert new socket */
admin = (struct admin_list *)malloc(sizeof(struct admin_list));
if (admin)
{
if (ioctl(new_sock, FIONBIO, (unsigned char *)(&on)) >= 0)
{
//#warning
// PERROR("DEBUG incomming socket %d, serial=%d\n", new_sock, sockserial);
memuse++;
fhuse++;
memset(admin, 0, sizeof(struct admin_list));
admin->sockserial = sockserial++;
admin->next = admin_list;
admin_list = admin;
admin->sock = new_sock;
} else {
close(new_sock);
free(admin);
}
} else
close(new_sock);
} else
{
if (errno != EWOULDBLOCK)
{
PERROR("Failed to accept connection from socket \"%s\". (errno=%d) Closing socket.\n", sock_address.sun_path, errno);
admin_cleanup();
return(1);
}
}
/* loop all current socket connections */
admin = admin_list;
adminp = &admin_list;
while(admin)
{
/* read command */
len = read(admin->sock, &msg, sizeof(msg));
if (len < 0)
{
if (errno != EWOULDBLOCK)
{
work = 1;
brokenpipe:
printf("Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno);
PDEBUG(DEBUG_LOG, "Broken pipe on socket %d. (errno=%d).\n", admin->sock, errno);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
}
goto send_data;
}
work = 1;
//#warning
//PERROR("DEBUG socket %d got data. serial=%d\n", admin->sock, admin->sockserial);
if (len == 0)
{
end:
/*release endpoint if exists */
if (admin->epointid)
{
epoint = find_epoint_id(admin->epointid);
if (epoint)
{
((class DEFAULT_ENDPOINT_APP *)epoint->ep_app)->
release(RELEASE_ALL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, 0, 0);
}
}
//#warning
//PERROR("DEBUG socket %d closed by remote.\n", admin->sock);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
//PERROR("DEBUG (admin_list=%x)\n", admin_list);
continue;
}
if (len != sizeof(msg))
{
PERROR("Short/long read on socket %d. (len=%d != size=%d).\n", admin->sock, len, sizeof(msg));
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
}
/* process socket command */
if (admin->response)
{
PERROR("Data from socket %d while sending response.\n", admin->sock);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
}
switch (msg.message)
{
case ADMIN_REQUEST_CMD_INTERFACE:
if (admin_interface(&admin->response) < 0)
{
PERROR("Failed to create dial response for socket %d.\n", admin->sock);
goto response_error;
}
break;
case ADMIN_REQUEST_CMD_ROUTE:
if (admin_route(&admin->response) < 0)
{
PERROR("Failed to create dial response for socket %d.\n", admin->sock);
goto response_error;
}
break;
case ADMIN_REQUEST_CMD_DIAL:
if (admin_dial(&admin->response, msg.u.x.message) < 0)
{
PERROR("Failed to create dial response for socket %d.\n", admin->sock);
goto response_error;
}
break;
case ADMIN_REQUEST_CMD_RELEASE:
if (admin_release(&admin->response, msg.u.x.message) < 0)
{
PERROR("Failed to create release response for socket %d.\n", admin->sock);
goto response_error;
}
break;
case ADMIN_REQUEST_STATE:
if (admin_state(&admin->response) < 0)
{
PERROR("Failed to create state response for socket %d.\n", admin->sock);
response_error:
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
}
#if 0
#warning DEBUGGING
{
struct admin_queue *response;
printf("Chain: ");
response = admin->response;
while(response)
{
printf("%c", '0'+response->am[0].message);
response=response->next;
}
printf("\n");
}
#endif
break;
case ADMIN_CALL_SETUP:
if (admin_call(admin, &msg))
{
PERROR("Failed to create call for socket %d.\n", admin->sock);
goto response_error;
}
break;
default:
PERROR("Invalid message %d from socket %d.\n", msg.message, admin->sock);
*adminp = admin->next;
free_connection(admin);
admin = *adminp;
continue;
}
/* write queue */
send_data:
if (admin->response)
{
//#warning
//PERROR("DEBUG socket %d sending data.\n", admin->sock);
len = write(admin->sock, ((unsigned char *)(admin->response->am))+admin->response->offset, sizeof(struct admin_message)*(admin->response->num)-admin->response->offset);
if (len < 0)
{
if (errno != EWOULDBLOCK)
{
work = 1;
goto brokenpipe;
}
goto next;
}
work = 1;
if (len == 0)
goto end;
if (len < (int)(sizeof(struct admin_message)*(admin->response->num)-admin->response->offset))
{
admin->response->offset+=len;
goto next;
} else
{
temp = admin->response;
admin->response = admin->response->next;
free(temp);
memuse--;
}
}
/* done with socket instance */
next:
adminp = &admin->next;
admin = admin->next;
}
return(work);
}

35
admin_server.h Normal file
View File

@ -0,0 +1,35 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** Administration tool header file (server) **
** **
\*****************************************************************************/
#include "admin.h"
struct admin_queue {
struct admin_queue *next;
ulong offset; /* current offset writing */
ulong num; /* number of admin messages */
struct admin_message am[0];
};
struct admin_list {
struct admin_list *next;
int sock;
int sockserial;
unsigned long epointid;
struct admin_queue *response;
};
int admin_init(void);
void admin_cleanup(void);
int admin_handle(void);
void admin_call_response(int adminid, int message, char *connected, int cause, int location, int notify);

266
alawulaw.c Normal file
View File

@ -0,0 +1,266 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** audio conversions for alaw and ulaw **
** **
\*****************************************************************************/
signed long *audio_law_to_s32;
/* ulaw -> signed 16-bit */
static signed long audio_ulaw_to_s32[] =
{
0xffff8284, 0xffff8684, 0xffff8a84, 0xffff8e84,
0xffff9284, 0xffff9684, 0xffff9a84, 0xffff9e84,
0xffffa284, 0xffffa684, 0xffffaa84, 0xffffae84,
0xffffb284, 0xffffb684, 0xffffba84, 0xffffbe84,
0xffffc184, 0xffffc384, 0xffffc584, 0xffffc784,
0xffffc984, 0xffffcb84, 0xffffcd84, 0xffffcf84,
0xffffd184, 0xffffd384, 0xffffd584, 0xffffd784,
0xffffd984, 0xffffdb84, 0xffffdd84, 0xffffdf84,
0xffffe104, 0xffffe204, 0xffffe304, 0xffffe404,
0xffffe504, 0xffffe604, 0xffffe704, 0xffffe804,
0xffffe904, 0xffffea04, 0xffffeb04, 0xffffec04,
0xffffed04, 0xffffee04, 0xffffef04, 0xfffff004,
0xfffff0c4, 0xfffff144, 0xfffff1c4, 0xfffff244,
0xfffff2c4, 0xfffff344, 0xfffff3c4, 0xfffff444,
0xfffff4c4, 0xfffff544, 0xfffff5c4, 0xfffff644,
0xfffff6c4, 0xfffff744, 0xfffff7c4, 0xfffff844,
0xfffff8a4, 0xfffff8e4, 0xfffff924, 0xfffff964,
0xfffff9a4, 0xfffff9e4, 0xfffffa24, 0xfffffa64,
0xfffffaa4, 0xfffffae4, 0xfffffb24, 0xfffffb64,
0xfffffba4, 0xfffffbe4, 0xfffffc24, 0xfffffc64,
0xfffffc94, 0xfffffcb4, 0xfffffcd4, 0xfffffcf4,
0xfffffd14, 0xfffffd34, 0xfffffd54, 0xfffffd74,
0xfffffd94, 0xfffffdb4, 0xfffffdd4, 0xfffffdf4,
0xfffffe14, 0xfffffe34, 0xfffffe54, 0xfffffe74,
0xfffffe8c, 0xfffffe9c, 0xfffffeac, 0xfffffebc,
0xfffffecc, 0xfffffedc, 0xfffffeec, 0xfffffefc,
0xffffff0c, 0xffffff1c, 0xffffff2c, 0xffffff3c,
0xffffff4c, 0xffffff5c, 0xffffff6c, 0xffffff7c,
0xffffff88, 0xffffff90, 0xffffff98, 0xffffffa0,
0xffffffa8, 0xffffffb0, 0xffffffb8, 0xffffffc0,
0xffffffc8, 0xffffffd0, 0xffffffd8, 0xffffffe0,
0xffffffe8, 0xfffffff0, 0xfffffff8, 0xffffffff,
0x00007d7c, 0x0000797c, 0x0000757c, 0x0000717c,
0x00006d7c, 0x0000697c, 0x0000657c, 0x0000617c,
0x00005d7c, 0x0000597c, 0x0000557c, 0x0000517c,
0x00004d7c, 0x0000497c, 0x0000457c, 0x0000417c,
0x00003e7c, 0x00003c7c, 0x00003a7c, 0x0000387c,
0x0000367c, 0x0000347c, 0x0000327c, 0x0000307c,
0x00002e7c, 0x00002c7c, 0x00002a7c, 0x0000287c,
0x0000267c, 0x0000247c, 0x0000227c, 0x0000207c,
0x00001efc, 0x00001dfc, 0x00001cfc, 0x00001bfc,
0x00001afc, 0x000019fc, 0x000018fc, 0x000017fc,
0x000016fc, 0x000015fc, 0x000014fc, 0x000013fc,
0x000012fc, 0x000011fc, 0x000010fc, 0x00000ffc,
0x00000f3c, 0x00000ebc, 0x00000e3c, 0x00000dbc,
0x00000d3c, 0x00000cbc, 0x00000c3c, 0x00000bbc,
0x00000b3c, 0x00000abc, 0x00000a3c, 0x000009bc,
0x0000093c, 0x000008bc, 0x0000083c, 0x000007bc,
0x0000075c, 0x0000071c, 0x000006dc, 0x0000069c,
0x0000065c, 0x0000061c, 0x000005dc, 0x0000059c,
0x0000055c, 0x0000051c, 0x000004dc, 0x0000049c,
0x0000045c, 0x0000041c, 0x000003dc, 0x0000039c,
0x0000036c, 0x0000034c, 0x0000032c, 0x0000030c,
0x000002ec, 0x000002cc, 0x000002ac, 0x0000028c,
0x0000026c, 0x0000024c, 0x0000022c, 0x0000020c,
0x000001ec, 0x000001cc, 0x000001ac, 0x0000018c,
0x00000174, 0x00000164, 0x00000154, 0x00000144,
0x00000134, 0x00000124, 0x00000114, 0x00000104,
0x000000f4, 0x000000e4, 0x000000d4, 0x000000c4,
0x000000b4, 0x000000a4, 0x00000094, 0x00000084,
0x00000078, 0x00000070, 0x00000068, 0x00000060,
0x00000058, 0x00000050, 0x00000048, 0x00000040,
0x00000038, 0x00000030, 0x00000028, 0x00000020,
0x00000018, 0x00000010, 0x00000008, 0x00000000
};
/* alaw -> signed 16-bit */
static signed long audio_alaw_to_s32[] =
{
0x000013fc, 0xffffec04, 0x00000144, 0xfffffebc,
0x0000517c, 0xffffae84, 0x0000051c, 0xfffffae4,
0x00000a3c, 0xfffff5c4, 0x00000048, 0xffffffb8,
0x0000287c, 0xffffd784, 0x0000028c, 0xfffffd74,
0x00001bfc, 0xffffe404, 0x000001cc, 0xfffffe34,
0x0000717c, 0xffff8e84, 0x0000071c, 0xfffff8e4,
0x00000e3c, 0xfffff1c4, 0x000000c4, 0xffffff3c,
0x0000387c, 0xffffc784, 0x0000039c, 0xfffffc64,
0x00000ffc, 0xfffff004, 0x00000104, 0xfffffefc,
0x0000417c, 0xffffbe84, 0x0000041c, 0xfffffbe4,
0x0000083c, 0xfffff7c4, 0x00000008, 0xfffffff8,
0x0000207c, 0xffffdf84, 0x0000020c, 0xfffffdf4,
0x000017fc, 0xffffe804, 0x0000018c, 0xfffffe74,
0x0000617c, 0xffff9e84, 0x0000061c, 0xfffff9e4,
0x00000c3c, 0xfffff3c4, 0x00000084, 0xffffff7c,
0x0000307c, 0xffffcf84, 0x0000030c, 0xfffffcf4,
0x000015fc, 0xffffea04, 0x00000164, 0xfffffe9c,
0x0000597c, 0xffffa684, 0x0000059c, 0xfffffa64,
0x00000b3c, 0xfffff4c4, 0x00000068, 0xffffff98,
0x00002c7c, 0xffffd384, 0x000002cc, 0xfffffd34,
0x00001dfc, 0xffffe204, 0x000001ec, 0xfffffe14,
0x0000797c, 0xffff8684, 0x000007bc, 0xfffff844,
0x00000f3c, 0xfffff0c4, 0x000000e4, 0xffffff1c,
0x00003c7c, 0xffffc384, 0x000003dc, 0xfffffc24,
0x000011fc, 0xffffee04, 0x00000124, 0xfffffedc,
0x0000497c, 0xffffb684, 0x0000049c, 0xfffffb64,
0x0000093c, 0xfffff6c4, 0x00000028, 0xffffffd8,
0x0000247c, 0xffffdb84, 0x0000024c, 0xfffffdb4,
0x000019fc, 0xffffe604, 0x000001ac, 0xfffffe54,
0x0000697c, 0xffff9684, 0x0000069c, 0xfffff964,
0x00000d3c, 0xfffff2c4, 0x000000a4, 0xffffff5c,
0x0000347c, 0xffffcb84, 0x0000034c, 0xfffffcb4,
0x000012fc, 0xffffed04, 0x00000134, 0xfffffecc,
0x00004d7c, 0xffffb284, 0x000004dc, 0xfffffb24,
0x000009bc, 0xfffff644, 0x00000038, 0xffffffc8,
0x0000267c, 0xffffd984, 0x0000026c, 0xfffffd94,
0x00001afc, 0xffffe504, 0x000001ac, 0xfffffe54,
0x00006d7c, 0xffff9284, 0x000006dc, 0xfffff924,
0x00000dbc, 0xfffff244, 0x000000b4, 0xffffff4c,
0x0000367c, 0xffffc984, 0x0000036c, 0xfffffc94,
0x00000f3c, 0xfffff0c4, 0x000000f4, 0xffffff0c,
0x00003e7c, 0xffffc184, 0x000003dc, 0xfffffc24,
0x000007bc, 0xfffff844, 0x00000008, 0xfffffff8,
0x00001efc, 0xffffe104, 0x000001ec, 0xfffffe14,
0x000016fc, 0xffffe904, 0x00000174, 0xfffffe8c,
0x00005d7c, 0xffffa284, 0x000005dc, 0xfffffa24,
0x00000bbc, 0xfffff444, 0x00000078, 0xffffff88,
0x00002e7c, 0xffffd184, 0x000002ec, 0xfffffd14,
0x000014fc, 0xffffeb04, 0x00000154, 0xfffffeac,
0x0000557c, 0xffffaa84, 0x0000055c, 0xfffffaa4,
0x00000abc, 0xfffff544, 0x00000058, 0xffffffa8,
0x00002a7c, 0xffffd584, 0x000002ac, 0xfffffd54,
0x00001cfc, 0xffffe304, 0x000001cc, 0xfffffe34,
0x0000757c, 0xffff8a84, 0x0000075c, 0xfffff8a4,
0x00000ebc, 0xfffff144, 0x000000d4, 0xffffff2c,
0x00003a7c, 0xffffc584, 0x0000039c, 0xfffffc64,
0x000010fc, 0xffffef04, 0x00000114, 0xfffffeec,
0x0000457c, 0xffffba84, 0x0000045c, 0xfffffba4,
0x000008bc, 0xfffff744, 0x00000018, 0xffffffe8,
0x0000227c, 0xffffdd84, 0x0000022c, 0xfffffdd4,
0x000018fc, 0xffffe704, 0x0000018c, 0xfffffe74,
0x0000657c, 0xffff9a84, 0x0000065c, 0xfffff9a4,
0x00000cbc, 0xfffff344, 0x00000094, 0xffffff6c,
0x0000327c, 0xffffcd84, 0x0000032c, 0xfffffcd4
};
/* signed 16-bit -> Xlaw */
unsigned char audio_s16_to_law[65536];
/* table is used to generate s16_to_alaw */
static short audio_alaw_relations[] =
{
0x8684, 0x55, 0x8a84, 0xd5, 0x8e84, 0x15, 0x9284, 0x95,
0x9684, 0x75, 0x9a84, 0xf5, 0x9e84, 0x35, 0xa284, 0xb5,
0xa684, 0x45, 0xaa84, 0xc5, 0xae84, 0x05, 0xb284, 0x85,
0xb684, 0x65, 0xba84, 0xe5, 0xbe84, 0x25, 0xc184, 0xa5,
0xc384, 0x5d, 0xc584, 0xdd, 0xc784, 0x1d, 0xc984, 0x9d,
0xcb84, 0x7d, 0xcd84, 0xfd, 0xcf84, 0x3d, 0xd184, 0xbd,
0xd384, 0x4d, 0xd584, 0xcd, 0xd784, 0x0d, 0xd984, 0x8d,
0xdb84, 0x6d, 0xdd84, 0xed, 0xdf84, 0x2d, 0xe104, 0xad,
0xe204, 0x51, 0xe304, 0xd1, 0xe404, 0x11, 0xe504, 0x91,
0xe604, 0x71, 0xe704, 0xf1, 0xe804, 0x31, 0xe904, 0xb1,
0xea04, 0x41, 0xeb04, 0xc1, 0xec04, 0x01, 0xed04, 0x81,
0xee04, 0x61, 0xef04, 0xe1, 0xf004, 0x21, 0xf0c4, 0x59,
0xf0c4, 0xa1, 0xf144, 0xd9, 0xf1c4, 0x19, 0xf244, 0x99,
0xf2c4, 0x79, 0xf344, 0xf9, 0xf3c4, 0x39, 0xf444, 0xb9,
0xf4c4, 0x49, 0xf544, 0xc9, 0xf5c4, 0x09, 0xf644, 0x89,
0xf6c4, 0x69, 0xf744, 0xe9, 0xf7c4, 0x29, 0xf844, 0x57,
0xf844, 0xa9, 0xf8a4, 0xd7, 0xf8e4, 0x17, 0xf924, 0x97,
0xf964, 0x77, 0xf9a4, 0xf7, 0xf9e4, 0x37, 0xfa24, 0xb7,
0xfa64, 0x47, 0xfaa4, 0xc7, 0xfae4, 0x07, 0xfb24, 0x87,
0xfb64, 0x67, 0xfba4, 0xe7, 0xfbe4, 0x27, 0xfc24, 0x5f,
0xfc24, 0xa7, 0xfc64, 0x1f, 0xfc64, 0xdf, 0xfc94, 0x9f,
0xfcb4, 0x7f, 0xfcd4, 0xff, 0xfcf4, 0x3f, 0xfd14, 0xbf,
0xfd34, 0x4f, 0xfd54, 0xcf, 0xfd74, 0x0f, 0xfd94, 0x8f,
0xfdb4, 0x6f, 0xfdd4, 0xef, 0xfdf4, 0x2f, 0xfe14, 0x53,
0xfe14, 0xaf, 0xfe34, 0x13, 0xfe34, 0xd3, 0xfe54, 0x73,
0xfe54, 0x93, 0xfe74, 0x33, 0xfe74, 0xf3, 0xfe8c, 0xb3,
0xfe9c, 0x43, 0xfeac, 0xc3, 0xfebc, 0x03, 0xfecc, 0x83,
0xfedc, 0x63, 0xfeec, 0xe3, 0xfefc, 0x23, 0xff0c, 0xa3,
0xff1c, 0x5b, 0xff2c, 0xdb, 0xff3c, 0x1b, 0xff4c, 0x9b,
0xff5c, 0x7b, 0xff6c, 0xfb, 0xff7c, 0x3b, 0xff88, 0xbb,
0xff98, 0x4b, 0xffa8, 0xcb, 0xffb8, 0x0b, 0xffc8, 0x8b,
0xffd8, 0x6b, 0xffe8, 0xeb, 0xfff8, 0x2b, 0xfff8, 0xab,
0x0008, 0x2a, 0x0008, 0xaa, 0x0018, 0xea, 0x0028, 0x6a,
0x0038, 0x8a, 0x0048, 0x0a, 0x0058, 0xca, 0x0068, 0x4a,
0x0078, 0xba, 0x0084, 0x3a, 0x0094, 0xfa, 0x00a4, 0x7a,
0x00b4, 0x9a, 0x00c4, 0x1a, 0x00d4, 0xda, 0x00e4, 0x5a,
0x00f4, 0xa2, 0x0104, 0x22, 0x0114, 0xe2, 0x0124, 0x62,
0x0134, 0x82, 0x0144, 0x02, 0x0154, 0xc2, 0x0164, 0x42,
0x0174, 0xb2, 0x018c, 0x32, 0x018c, 0xf2, 0x01ac, 0x72,
0x01ac, 0x92, 0x01cc, 0x12, 0x01cc, 0xd2, 0x01ec, 0x52,
0x01ec, 0xae, 0x020c, 0x2e, 0x022c, 0xee, 0x024c, 0x6e,
0x026c, 0x8e, 0x028c, 0x0e, 0x02ac, 0xce, 0x02cc, 0x4e,
0x02ec, 0xbe, 0x030c, 0x3e, 0x032c, 0xfe, 0x034c, 0x7e,
0x036c, 0x9e, 0x039c, 0x1e, 0x039c, 0xde, 0x03dc, 0x5e,
0x03dc, 0xa6, 0x041c, 0x26, 0x045c, 0xe6, 0x049c, 0x66,
0x04dc, 0x86, 0x051c, 0x06, 0x055c, 0xc6, 0x059c, 0x46,
0x05dc, 0xb6, 0x061c, 0x36, 0x065c, 0xf6, 0x069c, 0x76,
0x06dc, 0x96, 0x071c, 0x16, 0x075c, 0xd6, 0x07bc, 0x56,
0x07bc, 0xa8, 0x083c, 0x28, 0x08bc, 0xe8, 0x093c, 0x68,
0x09bc, 0x88, 0x0a3c, 0x08, 0x0abc, 0xc8, 0x0b3c, 0x48,
0x0bbc, 0xb8, 0x0c3c, 0x38, 0x0cbc, 0xf8, 0x0d3c, 0x78,
0x0dbc, 0x98, 0x0e3c, 0x18, 0x0ebc, 0xd8, 0x0f3c, 0x58,
0x0f3c, 0xa0, 0x0ffc, 0x20, 0x10fc, 0xe0, 0x11fc, 0x60,
0x12fc, 0x80, 0x13fc, 0x00, 0x14fc, 0xc0, 0x15fc, 0x40,
0x16fc, 0xb0, 0x17fc, 0x30, 0x18fc, 0xf0, 0x19fc, 0x70,
0x1afc, 0x90, 0x1bfc, 0x10, 0x1cfc, 0xd0, 0x1dfc, 0x50,
0x1efc, 0xac, 0x207c, 0x2c, 0x227c, 0xec, 0x247c, 0x6c,
0x267c, 0x8c, 0x287c, 0x0c, 0x2a7c, 0xcc, 0x2c7c, 0x4c,
0x2e7c, 0xbc, 0x307c, 0x3c, 0x327c, 0xfc, 0x347c, 0x7c,
0x367c, 0x9c, 0x387c, 0x1c, 0x3a7c, 0xdc, 0x3c7c, 0x5c,
0x3e7c, 0xa4, 0x417c, 0x24, 0x457c, 0xe4, 0x497c, 0x64,
0x4d7c, 0x84, 0x517c, 0x04, 0x557c, 0xc4, 0x597c, 0x44,
0x5d7c, 0xb4, 0x617c, 0x34, 0x657c, 0xf4, 0x697c, 0x74,
0x6d7c, 0x94, 0x717c, 0x14, 0x757c, 0xd4, 0x797c, 0x54
};
/* generate tables for conversion of s16 to alaw/ulaw
*/
void generate_tables(char law)
{
int i, j;
if (law == 'a')
{
audio_law_to_s32=audio_alaw_to_s32;
/* generating alaw-table */
i = j = 0;
while(i < 65536) {
if (i-32768 > audio_alaw_relations[j<<1])
j++;
if (j>255)
j=255;
audio_s16_to_law[(i-32768) & 0xffff]
= audio_alaw_relations[(j<<1)|1];
i++;
}
} else
{
audio_law_to_s32=audio_ulaw_to_s32;
/* generating ulaw-table */
i = j = 0;
while(i < 32768) {
if (i-32768 > audio_ulaw_to_s32[j])
j++;
audio_s16_to_law[(i-32768) & 0xffff] = j;
i++;
}
j = 255;
while(i < 65536) {
if (i-0x32768 > audio_ulaw_to_s32[j])
j--;
audio_s16_to_law[(i-32768) & 0xffff] = j;
i++;
}
}
}

5
alawulaw.h Normal file
View File

@ -0,0 +1,5 @@
extern signed long *audio_law_to_s32;
extern unsigned char audio_s16_to_law[65536];
extern short audio_alaw_relations[];
void generate_tables(char law);

4476
apppbx.cpp Normal file

File diff suppressed because it is too large Load Diff

357
apppbx.h Normal file
View File

@ -0,0 +1,357 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** EndpointAppPBX header file **
** **
\*****************************************************************************/
enum { /* release actions: see epoint.release */
RELEASE_NONE,
RELEASE_CALL, /* call, hold */
RELEASE_PORT_CALLONLY, /* call, port */
RELEASE_ALL, /* call, hold, port */
};
enum { /* states as viewed from io port (state of calls are always connected) */
EPOINT_STATE_IDLE, /* no call */
EPOINT_STATE_IN_SETUP, /* setup sent */
EPOINT_STATE_OUT_SETUP, /* setup sent */
EPOINT_STATE_IN_OVERLAP, /* more information */
EPOINT_STATE_OUT_OVERLAP, /* more information */
EPOINT_STATE_IN_PROCEEDING, /* proceeding */
EPOINT_STATE_OUT_PROCEEDING, /* proceeding */
EPOINT_STATE_IN_ALERTING, /* ringing */
EPOINT_STATE_OUT_ALERTING, /* ringing */
EPOINT_STATE_CONNECT, /* connected */
EPOINT_STATE_IN_DISCONNECT, /* disconnected receiving tones */
EPOINT_STATE_OUT_DISCONNECT, /* disconnected sending tones */
};
#define EPOINT_STATE_NAMES \
static char *state_name[] = { \
"EPOINT_STATE_IDLE", \
"EPOINT_STATE_IN_SETUP", \
"EPOINT_STATE_OUT_SETUP", \
"EPOINT_STATE_IN_OVERLAP", \
"EPOINT_STATE_OUT_OVERLAP", \
"EPOINT_STATE_IN_PROCEEDING", \
"EPOINT_STATE_OUT_PROCEEDING", \
"EPOINT_STATE_IN_ALERTING", \
"EPOINT_STATE_OUT_ALERTING", \
"EPOINT_STATE_CONNECT", \
"EPOINT_STATE_IN_DISCONNECT", \
"EPOINT_STATE_OUT_DISCONNECT", \
}; \
int state_name_num = sizeof(state_name) / sizeof(char *);
extern class EndpointAppPBX *apppbx_first;
/* structure of an EndpointAppPBX */
class EndpointAppPBX : public EndpointApp
{
public:
EndpointAppPBX(class Endpoint *epoint);
~EndpointAppPBX();
class EndpointAppPBX *next;
int handler(void);
int e_hold; /* is this endpoint on hold ? */
char e_tone[256]; /* save tone for resuming ports */
unsigned long e_adminid;
/* states */
int e_state; /* state of endpoint */
char e_terminal[32]; /* real id of terminal, "" for external calls */
char e_terminal_interface[32];/* current internal isdn interface (usefull for callback to internal phone) */
struct caller_info e_callerinfo; /* information about the caller */
struct dialing_info e_dialinginfo; /* information about dialing */
struct connect_info e_connectinfo; /* information about connected line */
struct redir_info e_redirinfo; /* info on redirection (to the calling user) */
struct capa_info e_capainfo; /* info on l3,l2 capacity */
time_t e_start, e_stop; /* time */
// int e_origin; /* origin of call */
struct route_ruleset *e_ruleset; /* current ruleset pointer (NULL=no ruleset) */
struct route_rule *e_rule; /* current rule pointer (NULL=no rule) */
struct route_action *e_action; /* current action pointer (NULL=no action) */
double e_action_timeout; /* when to timeout */
int e_rule_nesting; /* 'goto'/'menu' recrusion counter to prevent infinie loops */
double e_match_timeout; /* set for the next possible timeout time */
struct route_action *e_match_to_action; /* what todo when timeout */
char *e_match_to_extdialing; /* dialing after matching timeout rule */
int e_select; /* current selection for various selector options */
char *e_extdialing; /* dialing after matching rule */
int e_overlap; /* is set if additional information is/are received after setup */
struct extension e_ext; /* extension information */
// int e_knocking; /* true, if knocking */
// double e_knocktime; /* next time to knock */
// char e_call_tone[64], e_hold_tone[64]; /* current tone */
int e_call_pattern/*, e_hold_pattern*/; /* pattern available */
/* action */
char e_dialing_queue[32]; /* holds dialing during setup state */
double e_redial; /* time when redialing 0=off */
double e_powerdialing; /* on disconnect redial! 0=off, >0=redial time, -1=on */
double e_powerdelay; /* delay when to redial */
int e_powercount; /* power count */
int e_powerlimit; /* power limit */
double e_callback; /* time when callback (when idle reached) 0=off */
signed long e_cfnr_release; /* time stamp when to do the release for call forward on no response */
signed long e_cfnr_call; /* time stamp when to do the call for call forward on no response */
signed long e_password_timeout; /* time stamp when to do the release for password timeout */
/* port relation */
int e_multipoint_cause; /* cause value of disconnected multiport calls (highest priority) */
int e_multipoint_location; /* location of cause with highest priority */
/* call relation */
int e_call_cause;
int e_call_location;
/* callback */
char e_cbdialing[256]; /* dialing information after callback */
char e_cbcaller[256]; /* extension for the epoint which calls back */
char e_cbto[32]; /* override callerid to call back to */
struct caller_info e_callbackinfo; /* information about the callback caller */
/* dtmf stuff */
int e_connectedmode; /* if the port should stay connected if the enpoint disconnects or releases (usefull for callback) */
int e_dtmf; /* allow dtmf */
/* read doc/keypad.txt for more information */
int e_dtmf_time; /* time when the last key was received. */
int e_dtmf_last; /* last dtmf key */
/* transmit and receive state */
int e_tx_state; /* current endpoint's state */
int e_rx_state; /* current endpoint's state */
/* vbox playback variables */
char e_vbox[32]; /* current vbox extension (during playback) */
int e_vbox_state; /* state of vbox during playback */
int e_vbox_menu; /* currently selected menu using '*' and '#' */
char e_vbox_display[128]; /* current display message */
int e_vbox_display_refresh; /* display must be refreshed du to change */
int e_vbox_counter; /* current playback counter in seconds */
int e_vbox_counter_max; /* size of file in seconds */
int e_vbox_counter_last; /* temp variable to recognise a change in seconds */
int e_vbox_play; /* current file that is played */
int e_vbox_speed; /* current speed to play */
int e_vbox_index_num; /* number of files */
char e_vbox_index_file[128]; /* current file name */
int e_vbox_index_hour; /* current time the file recorded... */
int e_vbox_index_min;
int e_vbox_index_mon;
int e_vbox_index_mday;
int e_vbox_index_year;
char e_vbox_index_callerid[128]; /* current caller id */
int e_vbox_index_callerid_index; /* next digit to speak */
/* efi */
int e_efi_state; /* current spoken sample */
int e_efi_digit; /* current spoken digit */
/* crypt states and vars */
int e_crypt; /* current user level crypt state */
int e_crypt_state; /* current crypt manager state */
char e_crypt_info[33]; /* last information text */
int e_crypt_timeout_sec; /* timer */
int e_crypt_timeout_usec; /* timer */
unsigned long e_crypt_random; /* current random number for ident */
unsigned long e_crypt_bogomips; /* bogomips for ident */
unsigned char e_crypt_key[256]; /* the session key */
int e_crypt_key_len;
unsigned char e_crypt_ckey[256]; /* the encrypted session key */
int e_crypt_ckey_len;
unsigned char e_crypt_rsa_n[512]; /* rsa key */
unsigned char e_crypt_rsa_e[16];
unsigned char e_crypt_rsa_d[512];
unsigned char e_crypt_rsa_p[512];
unsigned char e_crypt_rsa_q[512];
unsigned char e_crypt_rsa_dmp1[512];
unsigned char e_crypt_rsa_dmq1[512];
unsigned char e_crypt_rsa_iqmp[512];
int e_crypt_rsa_n_len;
int e_crypt_rsa_e_len;
int e_crypt_rsa_d_len;
int e_crypt_rsa_p_len;
int e_crypt_rsa_q_len;
int e_crypt_rsa_dmp1_len;
int e_crypt_rsa_dmq1_len;
int e_crypt_rsa_iqmp_len;
int e_crypt_keyengine_busy; /* current job and busy state */
int e_crypt_keyengine_return; /* return */
/* messages */
void hookflash(void);
void ea_message_port(unsigned long port_id, int message, union parameter *param);
void port_setup(struct port_list *portlist, int message_type, union parameter *param);
void port_information(struct port_list *portlist, int message_type, union parameter *param);
void port_dtmf(struct port_list *portlist, int message_type, union parameter *param);
void port_crypt(struct port_list *portlist, int message_type, union parameter *param);
void port_overlap(struct port_list *portlist, int message_type, union parameter *param);
void port_proceeding(struct port_list *portlist, int message_type, union parameter *param);
void port_alerting(struct port_list *portlist, int message_type, union parameter *param);
void port_connect(struct port_list *portlist, int message_type, union parameter *param);
void port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param);
void port_timeout(struct port_list *portlist, int message_type, union parameter *param);
void port_notify(struct port_list *portlist, int message_type, union parameter *param);
void port_facility(struct port_list *portlist, int message_type, union parameter *param);
void port_suspend(struct port_list *portlist, int message_type, union parameter *param);
void port_resume(struct port_list *portlist, int message_type, union parameter *param);
void ea_message_call(unsigned long call_id, int message, union parameter *param);
void call_crypt(struct port_list *portlist, int message_type, union parameter *param);
void call_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param);
void call_setup(struct port_list *portlist, int message_type, union parameter *param);
void call_information(struct port_list *portlist, int message_type, union parameter *param);
void call_overlap(struct port_list *portlist, int message_type, union parameter *param);
void call_proceeding(struct port_list *portlist, int message_type, union parameter *param);
void call_alerting(struct port_list *portlist, int message_type, union parameter *param);
void call_connect(struct port_list *portlist, int message_type, union parameter *param);
void call_disconnect_release(struct port_list *portlist, int message_type, union parameter *param);
void call_notify(struct port_list *portlist, int message_type, union parameter *param);
void call_facility(struct port_list *portlist, int message_type, union parameter *param);
/* epoint */
void new_state(int state);
void release(int release, int calllocation, int callcause, int portlocation, int portcause);
void notify_active(void);
void keypad_function(char digit);
void set_tone(struct port_list *portlist, char *tone);
void out_setup(void);
char *apply_callerid_display(char *id, int itype, int ntype, int present, int screen, char *h323, char *intern, char *name);
void auth(int job, int bit_num);
/* vbox playback stuff */
void vbox_init(void);
void vbox_index_read(int num);
void vbox_index_remove(int num);
void vbox_handler(void);
void efi_message_eof(void);
void vbox_message_eof(void);
void set_tone_vbox(char *tone);
void set_play_vbox(char *file, int offset);
void set_play_speed(int speed);
/* efi */
void set_tone_efi(char *tone);
/* routing */
struct route_ruleset *rulesetbyname(char *name);
struct route_action *route(struct route_ruleset *ruleset);
struct route_param *routeparam(struct route_action *action, unsigned long long id);
/* init / dialing / hangup */
void _action_init_call(int chan);
void action_init_call(void);
void action_init_chan(void);
void action_dialing_internal(void);
void action_dialing_external(void);
void action_dialing_h323(void);
void action_dialing_chan(void);
void action_dialing_vbox_record(void);
void action_init_partyline(void);
void action_hangup_call(void);
void action_dialing_login(void);
void action_init_change_callerid(void);
void _action_callerid_calleridnext(int next);
void action_dialing_callerid(void);
void action_dialing_calleridnext(void);
void action_init_change_forward(void);
void action_dialing_forward(void);
void action_init_redial_reply(void);
void _action_redial_reply(int in);
void action_dialing_redial(void);
void action_dialing_reply(void);
void action_dialing_powerdial(void);
void action_dialing_callback(void);
void action_hangup_callback(void);
void action_dialing_abbrev(void);
void action_dialing_test(void);
void action_init_play(void);
void action_init_vbox_play(void);
void action_init_efi(void);
void action_dialing_vbox_play(void);
void action_dialing_calculator(void);
void action_dialing_timer(void);
void _action_goto_menu(int mode);
void action_dialing_goto(void);
void action_dialing_menu(void);
void action_dialing_disconnect(void);
void action_dialing_help(void);
void action_dialing_deflect(void);
void action_dialing_setforward(void);
void action_hangup_execute(void);
void action_hangup_file(void);
void action_init_pick(void);
void action_dialing_password(void);
void action_dialing_password_wr(void);
void process_dialing(void);
void process_hangup(int cause, int location);
/* facility function */
void pick_call(char *extension);
void join_call(void);
void encrypt_shared(void);
void encrypt_keyex(void);
void encrypt_off(void);
void encrypt_result(int message, char *text);
int check_external(char **errstr, class Port **port);
/* crypt */
void cryptman_keyengine(int job);
void cryptman_handler(void);
void cr_ident(int message, unsigned char *param, int len);
void cr_activate(int message, unsigned char *param, int len);
void cr_deactivate(int message, unsigned char *param, int len);
void cr_master(int message, unsigned char *param, int len);
void cr_slave(int message, unsigned char *param, int len);
void cr_looped(int message, unsigned char *param, int len);
void cr_abort(int message, unsigned char *param, int len);
void cr_abort_engine(int message, unsigned char *param, int len);
void cr_abort_wait(int message, unsigned char *param, int len);
void cr_genrsa(int message, unsigned char *param, int len);
void cr_keyerror(int message, unsigned char *param, int len);
void cr_pubkey(int message, unsigned char *param, int len);
void cr_cptrsa(int message, unsigned char *param, int len);
void cr_cskey(int message, unsigned char *param, int len);
void cr_decrsa(int message, unsigned char *param, int len);
void cr_waitdelay(int message, unsigned char *param, int len);
void cr_bfactive(int message, unsigned char *param, int len);
void cr_crypterror(int message, unsigned char *param, int len);
void cr_release(int message, unsigned char *param, int len);
void cr_sactivate(int message, unsigned char *param, int len);
void cr_sdeactivate(int message, unsigned char *param, int len);
void cr_sbfactive(int message, unsigned char *param, int len);
void cr_scrypterror(int message, unsigned char *param, int len);
void cr_sabort(int message, unsigned char *param, int len);
void cr_info(int message, unsigned char *param, int len);
void cryptman_message(int message, unsigned char *param, int len);
void cryptman_msg2man(unsigned char *param, int len);
void cryptman_addinf(unsigned char *buf, int buf_size, int element, int len, void *data);
int cryptman_sizeofinf(unsigned char *buf, int element);
unsigned char *cryptman_getinf(unsigned char *buf, int element, unsigned char *to);
void cryptman_msg2peer(unsigned char *buf);
void cryptman_msg2user(int msg, char *text);
void cryptman_msg2crengine(int msg, unsigned char *buf, int len);
void cryptman_state(int state);
void cryptman_timeout(int secs);
void message_disconnect_port(struct port_list *portlist, int cause, int location, char *display);
void logmessage(struct message *messsage);
};
char *nationalize_callerinfo(char *string, int *type);
char *numberrize_callerinfo(char *string, int type);
void apply_callerid_restriction(int anon_ignore, int port_type, char *id, int *ntype, int *present, int *screen, char *h323, char *intern, char *name);
void send_mail(char *filename, char *callerid, char *callerintern, char *callername, char *vbox_email, int vbox_year, int vbox_mon, int vbox_mday, int vbox_hour, int vbox_min, char *terminal);

147
call.cpp Normal file
View File

@ -0,0 +1,147 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** call functions **
** **
\*****************************************************************************/
#include <stdio.h>
//#include <string.h>
//#include <stdlib.h>
//#include <unistd.h>
//#include <poll.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <fcntl.h>
#include "main.h"
//#define __u8 unsigned char
//#define __u16 unsigned short
//#define __u32 unsigned long
//#include "linux/isdnif.h"
unsigned long call_serial = 1; /* must be 1, because 0== no call */
//CALL_STATES
class Call *call_first = NULL;
/*
* find the call with call_id
*/
class Call *find_call_id(unsigned long call_id)
{
class Call *call = call_first;
while(call)
{
//printf("comparing: '%s' with '%s'\n", name, call->c_name);
if (call->c_serial == call_id)
return(call);
call = call->next;
}
return(NULL);
}
/*
* constructor for a new call
*/
Call::Call(class Endpoint *epoint)
{
class Call **callp;
if (!epoint)
{
PERROR("software error, epoint is NULL.\n");
exit(-1);
}
c_serial = call_serial++;
c_type = CALL_TYPE_NONE;
/* attach to chain */
next = NULL;
callp = &call_first;
while(*callp)
callp = &((*callp)->next);
*callp = this;
classuse++;
}
/*
* call descructor
*/
Call::~Call()
{
class Call *cl, **clp;
classuse--;
cl = call_first;
clp = &call_first;
while(cl)
{
if (cl == this)
break;
clp = &cl->next;
cl = cl->next;
}
if (!cl)
{
PERROR("software error, call not in chain! exitting\n");
exit(-1);
}
*clp = cl->next; /* detach from chain */
}
/* epoint sends a message to a call
*
*/
void Call::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
{
}
/* call process is called from the main loop
* it processes the current calling state.
* returns 0 if call nothing was done
*/
int Call::handler(void)
{
return(0);
}
void Call::release(unsigned long epoint_id, int hold, int location, int cause)
{
}
/* free all call structures */
void call_free(void)
{
if (!call_first)
{
PDEBUG(DEBUG_CALL, "no more pending call(s), done!\n");
return;
}
while(call_first)
{
if (options.deb & DEBUG_CALL)
{
PDEBUG(DEBUG_CALL, "freeing pending call\n");
}
delete call_first;
}
}

39
call.h Normal file
View File

@ -0,0 +1,39 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** call header file **
** **
\*****************************************************************************/
enum { CALL_TYPE_NONE, CALL_TYPE_PBX, CALL_TYPE_CHAN};
/* call
*
* abstraction for pbx calls and asterisk calls
*/
class Call
{
public:
Call(class Endpoint *epoint);
virtual ~Call();
class Call *next; /* next node in list of calls */
virtual void message_epoint(unsigned long epoint_id, int message, union parameter *param);
virtual int handler(void);
virtual void release(unsigned long epoint_id, int hold, int location, int cause);
unsigned long c_type; /* call type (pbx or asterisk) */
unsigned long c_serial; /* serial/unique number of call */
};
void call_free(void);
extern class Call *call_first;
class Call *find_call_id(unsigned long call_id);

87
callchan.cpp Normal file
View File

@ -0,0 +1,87 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** call functions for channel driver **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <unistd.h>
//#include <poll.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <fcntl.h>
#include "main.h"
//#define __u8 unsigned char
//#define __u16 unsigned short
//#define __u32 unsigned long
//#include "linux/isdnif.h"
/*
* constructor for a new call
* the call will have a relation to the calling endpoint
*/
CallChan::CallChan(class Endpoint *epoint) : Call(epoint)
{
if (!epoint)
{
PERROR("software error, epoint is NULL.\n");
exit(-1);
}
PDEBUG(DEBUG_CALL, "creating new call and connecting it to the endpoint.\n");
c_type = CALL_TYPE_CHAN;
c_epoint_id = epoint->ep_serial;
PDEBUG(DEBUG_CALL, "Constructor(new call)");
}
/*
* call descructor
*/
CallChan::~CallChan()
{
}
/* release call from endpoint
* if the call has two relations, all relations are freed and the call will be
* destroyed
*/
void CallChan::release(unsigned long epoint_id, int hold, int location, int cause)
{
if (!epoint_id)
{
PERROR("software error, epoint is NULL.\n");
return;
}
c_epoint_id = 0;
PDEBUG(DEBUG_CALL, "call_release(): ended.\n");
}
/* call process is called from the main loop
* it processes the current calling state.
* returns 0 if call nothing was done
*/
int CallChan::handler(void)
{
return(0);
}
void CallChan::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
{
}

24
callchan.h Normal file
View File

@ -0,0 +1,24 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** call header file for channel interface **
** **
\*****************************************************************************/
class CallChan : public Call
{
public:
CallChan(class Endpoint *epoint);
~CallChan();
void message_epoint(unsigned long epoint_id, int message, union parameter *param);
int handler(void);
void release(unsigned long epoint_id, int hold, int location, int cause);
unsigned long c_epoint_id;
};

993
callpbx.cpp Normal file
View File

@ -0,0 +1,993 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** call functions **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "main.h"
#define __u8 unsigned char
#define __u16 unsigned short
#define __u32 unsigned long
#include "linux/isdnif.h"
/* notify endpoint about state change (if any) */
static int notify_state_change(int call_id, int epoint_id, int old_state, int new_state)
{
int notify_off = 0, notify_on = 0;
struct message *message;
if (old_state == new_state)
return(old_state);
switch(old_state)
{
case NOTIFY_STATE_ACTIVE:
switch(new_state)
{
case NOTIFY_STATE_HOLD:
notify_on = INFO_NOTIFY_REMOTE_HOLD;
break;
case NOTIFY_STATE_SUSPEND:
notify_on = INFO_NOTIFY_USER_SUSPENDED;
break;
case NOTIFY_STATE_CONFERENCE:
notify_on = INFO_NOTIFY_CONFERENCE_ESTABLISHED;
break;
}
break;
case NOTIFY_STATE_HOLD:
switch(new_state)
{
case NOTIFY_STATE_ACTIVE:
notify_off = INFO_NOTIFY_REMOTE_RETRIEVAL;
break;
case NOTIFY_STATE_SUSPEND:
notify_off = INFO_NOTIFY_REMOTE_RETRIEVAL;
notify_on = INFO_NOTIFY_USER_SUSPENDED;
break;
case NOTIFY_STATE_CONFERENCE:
notify_off = INFO_NOTIFY_REMOTE_RETRIEVAL;
notify_on = INFO_NOTIFY_CONFERENCE_ESTABLISHED;
break;
}
break;
case NOTIFY_STATE_SUSPEND:
switch(new_state)
{
case NOTIFY_STATE_ACTIVE:
notify_off = INFO_NOTIFY_USER_RESUMED;
break;
case NOTIFY_STATE_HOLD:
notify_off = INFO_NOTIFY_USER_RESUMED;
notify_on = INFO_NOTIFY_REMOTE_HOLD;
break;
case NOTIFY_STATE_CONFERENCE:
notify_off = INFO_NOTIFY_USER_RESUMED;
notify_on = INFO_NOTIFY_CONFERENCE_ESTABLISHED;
break;
}
break;
case NOTIFY_STATE_CONFERENCE:
switch(new_state)
{
case NOTIFY_STATE_ACTIVE:
notify_off = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
break;
case NOTIFY_STATE_HOLD:
notify_off = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
notify_on = INFO_NOTIFY_REMOTE_HOLD;
break;
case NOTIFY_STATE_SUSPEND:
notify_off = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
notify_on = INFO_NOTIFY_USER_SUSPENDED;
break;
}
break;
}
if (call_id && notify_off)
{
message = message_create(call_id, epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
message->param.notifyinfo.notify = notify_off;
message_put(message);
}
if (call_id && notify_on)
{
message = message_create(call_id, epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
message->param.notifyinfo.notify = notify_on;
message_put(message);
}
return(new_state);
}
/* debug function for call */
void callpbx_debug(class CallPBX *callpbx, char *function)
{
struct call_relation *relation;
struct port_list *portlist;
class Endpoint *epoint;
class Port *port;
char buffer[512];
if (!(options.deb & DEBUG_CALL))
return;
PDEBUG(DEBUG_CALL, "CALL(%d) start (called from %s)\n", callpbx->c_serial, function);
relation = callpbx->c_relation;
if (!relation)
PDEBUG(DEBUG_CALL, "call has no relations\n");
while(relation)
{
epoint = find_epoint_id(relation->epoint_id);
if (!epoint)
{
PDEBUG(DEBUG_CALL, "warning: relations epoint id=%ld doesn't exists!\n", relation->epoint_id);
relation = relation->next;
continue;
}
buffer[0] = '\0';
UPRINT(strchr(buffer,0), "*** ep%ld", relation->epoint_id);
UPRINT(strchr(buffer,0), " ifs=");
portlist = epoint->ep_portlist;
while(portlist)
{
port = find_port_id(portlist->port_id);
if (port)
UPRINT(strchr(buffer,0), "%s,", port->p_name);
else
UPRINT(strchr(buffer,0), "<port %ld doesn't exist>,", portlist->port_id);
portlist = portlist->next;
}
// UPRINT(strchr(buffer,0), " endpoint=%d on=%s hold=%s", epoint->ep_serial, (epoint->ep_call_id==callpbx->c_serial)?"yes":"no", (epoint->get_hold_id()==callpbx->c_serial)?"yes":"no");
UPRINT(strchr(buffer,0), " endpoint=%d on=%s", epoint->ep_serial, (epoint->ep_call_id==callpbx->c_serial)?"yes":"no");
switch(relation->type)
{
case RELATION_TYPE_CALLING:
UPRINT(strchr(buffer,0), " type=CALLING");
break;
case RELATION_TYPE_SETUP:
UPRINT(strchr(buffer,0), " type=SETUP");
break;
case RELATION_TYPE_CONNECT:
UPRINT(strchr(buffer,0), " type=CONNECT");
break;
default:
UPRINT(strchr(buffer,0), " type=unknown");
break;
}
switch(relation->channel_state)
{
case CHANNEL_STATE_CONNECT:
UPRINT(strchr(buffer,0), " channel=CONNECT");
break;
case CHANNEL_STATE_HOLD:
UPRINT(strchr(buffer,0), " channel=HOLD");
break;
default:
UPRINT(strchr(buffer,0), " channel=unknown");
break;
}
switch(relation->tx_state)
{
case NOTIFY_STATE_ACTIVE:
UPRINT(strchr(buffer,0), " tx_state=ACTIVE");
break;
case NOTIFY_STATE_HOLD:
UPRINT(strchr(buffer,0), " tx_state=HOLD");
break;
case NOTIFY_STATE_SUSPEND:
UPRINT(strchr(buffer,0), " tx_state=SUSPEND");
break;
case NOTIFY_STATE_CONFERENCE:
UPRINT(strchr(buffer,0), " tx_state=CONFERENCE");
break;
default:
UPRINT(strchr(buffer,0), " tx_state=unknown");
break;
}
switch(relation->rx_state)
{
case NOTIFY_STATE_ACTIVE:
UPRINT(strchr(buffer,0), " rx_state=ACTIVE");
break;
case NOTIFY_STATE_HOLD:
UPRINT(strchr(buffer,0), " rx_state=HOLD");
break;
case NOTIFY_STATE_SUSPEND:
UPRINT(strchr(buffer,0), " rx_state=SUSPEND");
break;
case NOTIFY_STATE_CONFERENCE:
UPRINT(strchr(buffer,0), " rx_state=CONFERENCE");
break;
default:
UPRINT(strchr(buffer,0), " rx_state=unknown");
break;
}
PDEBUG(DEBUG_CALL, "%s\n", buffer);
relation = relation->next;
}
PDEBUG(DEBUG_CALL, "end\n");
}
/*
* constructor for a new call
* the call will have a relation to the calling endpoint
*/
CallPBX::CallPBX(class Endpoint *epoint) : Call(epoint)
{
struct call_relation *relation;
// char filename[256];
if (!epoint)
{
PERROR("software error, epoint is NULL.\n");
exit(-1);
}
PDEBUG(DEBUG_CALL, "creating new call and connecting it to the endpoint.\n");
c_type = CALL_TYPE_PBX;
c_caller[0] = '\0';
c_caller_id[0] = '\0';
c_dialed[0] = '\0';
c_todial[0] = '\0';
c_mixer = 0;
c_partyline = 0;
/* initialize a relation only to the calling interface */
relation = c_relation = (struct call_relation *)calloc(1, sizeof(struct call_relation));
if (!relation)
{
PERROR("no memory, exitting..\n");
exit(-1);
}
cmemuse++;
memset(relation, 0, sizeof(struct call_relation));
relation->type = RELATION_TYPE_CALLING;
relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
relation->epoint_id = epoint->ep_serial;
if (options.deb & DEBUG_CALL)
callpbx_debug(this, "CallPBX::Constructor(new call)");
}
/*
* call descructor
*/
CallPBX::~CallPBX()
{
struct call_relation *relation, *rtemp;
relation = c_relation;
while(relation)
{
rtemp = relation->next;
memset(relation, 0, sizeof(struct call_relation));
free(relation);
cmemuse--;
relation = rtemp;
}
}
/* mixer sets the mixer of hisax bchannels
* the mixer() will set the mixer for the hisax ports which is done
* at kernel space.
*/
void CallPBX::mixer(void)
{
struct call_relation *relation;
struct message *message;
int numconnect, relations;
class Endpoint *epoint;
struct port_list *portlist;
class Port *port;
int nodata = 1;
relation = c_relation;
while(relation)
{
epoint = find_epoint_id(relation->epoint_id);
if (!epoint)
{
PERROR("software error: relation without existing endpoints.\n");
relation = relation->next;
continue;
}
portlist = epoint->ep_portlist;
if (!portlist)
{
PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation without interfaces.\n");
//#warning testing: keep on hold until single audio stream available
relation->channel_state = CHANNEL_STATE_HOLD;
relation = relation->next;
continue;
}
if (portlist->next)
{
PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation with ep%d due to port_list.\n", epoint->ep_serial);
//#warning testing: keep on hold until single audio stream available
relation->channel_state = CHANNEL_STATE_HOLD;
relation = relation->next;
continue;
}
port = find_port_id(portlist->port_id);
if (!port)
{
PDEBUG((DEBUG_CALL|DEBUG_PORT), "software error: relation without existing port.\n");
relation = relation->next;
continue;
}
if (port->p_record)
{
PDEBUG(DEBUG_CALL|DEBUG_PORT, "mixer(): relation ep%d does recording, so we must get data from all members.\n", epoint->ep_serial);
if (nodata)
{
PDEBUG(DEBUG_CALL|DEBUG_PORT, "mixer(): at least one endpoint wants data.\n");
nodata = 0;
}
}
if ((port->p_type&PORT_CLASS_MASK)!=PORT_CLASS_mISDN)
{
PDEBUG((DEBUG_CALL|DEBUG_PORT), "ignoring relation ep%d because it is not mISDN.\n", epoint->ep_serial);
if (nodata)
{
PDEBUG((DEBUG_CALL|DEBUG_PORT), "not all endpoints are mISDN.\n");
nodata = 0;
}
relation = relation->next;
continue;
}
// remove unconnected parties from conference, also remove remotely disconnected parties so conference will not be disturbed.
if (relation->channel_state == CHANNEL_STATE_CONNECT
&& relation->rx_state != NOTIFY_STATE_HOLD
&& relation->rx_state != NOTIFY_STATE_SUSPEND)
{
message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
message->param.mISDNsignal.conf = (c_serial<<1) + 1;
PDEBUG(DEBUG_CALL, "%s +on+ id: 0x%08x\n", port->p_name, message->param.mISDNsignal.conf);
message_put(message);
} else
{
message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
message->param.mISDNsignal.message = mISDNSIGNAL_CONF;
message->param.mISDNsignal.conf = 0;
PDEBUG(DEBUG_CALL, "%s +off+ id: 0x%08x\n", port->p_name, message->param.mISDNsignal.conf);
message_put(message);
}
relation = relation->next;
}
/* we notify all relations about rxdata. */
relation = c_relation;
while(relation)
{
message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, MESSAGE_mISDNSIGNAL);
message->param.mISDNsignal.message = mISDNSIGNAL_NODATA;
message->param.mISDNsignal.nodata = nodata;
PDEBUG(DEBUG_CALL, "call %d sets alldata on port %s to %d\n", c_serial, port->p_name, nodata);
message_put(message);
relation = relation->next;
}
/* count relations and states */
relation = c_relation;
numconnect = 0;
relations = 0;
while(relation) /* count audio-connected and active relations */
{
relations ++;
if ((relation->channel_state == CHANNEL_STATE_CONNECT)
&& (relation->rx_state != NOTIFY_STATE_SUSPEND)
&& (relation->rx_state != NOTIFY_STATE_HOLD))
numconnect ++;
relation = relation->next;
}
if (relations==2 && !c_partyline) /* two people just exchange their states */
{
relation = c_relation;
relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, relation->next->rx_state);
relation->next->tx_state = notify_state_change(c_serial, relation->next->epoint_id, relation->next->tx_state, relation->rx_state);
} else
if ((relations==1 || numconnect==1) /*&& !c_partyline*/) /* one member in a call, so we put her on hold */
{
relation = c_relation;
while(relation)
{
if ((relation->channel_state == CHANNEL_STATE_CONNECT)
&& (relation->rx_state != NOTIFY_STATE_SUSPEND)
&& (relation->rx_state != NOTIFY_STATE_HOLD))
relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_HOLD);
relation = relation->next;
}
} else
/* if conference/partyline or (more than two members and more than one is connected), so we set conference state */
{
relation = c_relation;
while(relation)
{
if ((relation->channel_state == CHANNEL_STATE_CONNECT)
&& (relation->rx_state != NOTIFY_STATE_SUSPEND)
&& (relation->rx_state != NOTIFY_STATE_HOLD))
relation->tx_state = notify_state_change(c_serial, relation->epoint_id, relation->tx_state, NOTIFY_STATE_CONFERENCE);
relation = relation->next;
}
}
}
/* send audio data to endpoints which do not come from an endpoint connected
* to an isdn port and do not go to an endpoint which is connected to an
* isdn port. in this case the mixing cannot be done with kernel space
*/
void CallPBX::call_mixer(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param)
{
struct call_relation *relation_to;
struct message *message;
/* skip if source endpoint has NOT audio mode CONNECT */
if (relation_from->channel_state != CHANNEL_STATE_CONNECT)
{
return;
}
/* loop all endpoints and skip the endpoint where the audio is from
* so we do not get a loop (echo)
*/
relation_to = c_relation;
while(relation_to)
{
/* skip source endpoint */
if (relation_to->epoint_id == epoint_from)
{
relation_to = relation_to->next;
continue;
}
/* skip if destination endpoint has audio mode HOLD */
if (relation_to->channel_state != CHANNEL_STATE_CONNECT)
{
relation_to = relation_to->next;
continue;
}
/* now we may send our data to the endpoint where it
* will be delivered to the port
*/
//PDEBUG(DEBUG_CALL, "mixing from %d to %d\n", epoint_from, relation_to->epoint_id);
message = message_create(c_serial, relation_to->epoint_id, CALL_TO_EPOINT, MESSAGE_DATA);
memcpy(&message->param, param, sizeof(union parameter));
message_put(message);
relation_to = relation_to->next;
}
}
/* release call from endpoint
* if the call has two relations, all relations are freed and the call will be
* destroyed
*/
void CallPBX::release(unsigned long epoint_id, int hold, int location, int cause)
{
struct call_relation *relation, **relationpointer;
struct message *message;
class Call *call;
if (!epoint_id)
{
PERROR("software error, epoint is NULL.\n");
return;
}
if (options.deb & DEBUG_CALL)
callpbx_debug(this, "call_release{before}");
/* find relation */
relation = c_relation;
while(relation)
{
if (relation->epoint_id == epoint_id)
break;
relation = relation->next;
}
if (!relation)
{
PERROR("software error, epoint has a call with no relation to the epoint.\n");
return;
}
/* remove from mixer */
if (relation->channel_state != CHANNEL_STATE_HOLD)
{
relation->channel_state = CHANNEL_STATE_HOLD;
c_mixer = 1; /* update mixer flag */
}
/* detach given interface */
relation = c_relation;
relationpointer = &c_relation;
while(relation)
{
/* endpoint of function call */
if (relation->epoint_id == epoint_id)
{
*relationpointer = relation->next;
memset(relation, 0, sizeof(struct call_relation));
free(relation);
cmemuse--;
relation = *relationpointer;
continue;
}
relationpointer = &relation->next;
relation = relation->next;
}
/* if no more relation */
if (!c_relation)
{
PDEBUG(DEBUG_CALL, "call is completely removed.\n");
/* there is no more endpoint related to the call */
delete this;
// end of call object!
PDEBUG(DEBUG_CALL, "call completely removed!\n");
} else
/* if call is a party line */
if (c_partyline)
{
PDEBUG(DEBUG_CALL, "call is a conference room, so we keep it alive until the last party left.\n");
} else
/* if only one relation left */
if (!c_relation->next)
{
PDEBUG(DEBUG_CALL, "call has one relation left, so we send it a release with the given cause %d.\n", cause);
message = message_create(c_serial, c_relation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = cause;
message->param.disconnectinfo.location = location;
message_put(message);
delete this;
// end of call object!
PDEBUG(DEBUG_CALL, "call completely removed!\n");
}
call = call_first;
while(call)
{
if (options.deb & DEBUG_CALL && call->c_type==CALL_TYPE_PBX)
callpbx_debug((class CallPBX *)call, "call_release{all calls left}");
call = call->next;
}
PDEBUG(DEBUG_CALL, "call_release(): ended.\n");
}
/* count number of relations in a call
*/
int callpbx_countrelations(unsigned long call_id)
{
struct call_relation *relation;
int i;
class Call *call;
class CallPBX *callpbx;
call = find_call_id(call_id);
if (!call)
return(0);
if (call->c_type != CALL_TYPE_PBX)
return(0);
callpbx = (class CallPBX *)call;
i = 0;
relation = callpbx->c_relation;
while(relation)
{
i++;
relation = relation->next;
}
return(i);
}
void CallPBX::remove_relation(struct call_relation *relation)
{
struct call_relation *temp, **tempp;
if (!relation)
return;
temp = c_relation;
tempp = &c_relation;
while(temp)
{
if (temp == relation)
break;
tempp = &temp->next;
temp = temp->next;
}
if (!temp)
{
PERROR("relation not in call.\n");
return;
}
PDEBUG(DEBUG_CALL, "removing relation.\n");
*tempp = relation->next;
memset(temp, 0, sizeof(struct call_relation));
free(temp);
cmemuse--;
}
struct call_relation *CallPBX::add_relation(void)
{
struct call_relation *relation;
if (!c_relation)
{
PERROR("there is no first relation to this call\n");
return(NULL);
}
relation = c_relation;
while(relation->next)
relation = relation->next;
relation->next = (struct call_relation *)calloc(1, sizeof(struct call_relation));
if (!relation->next)
{
PERROR("no memory\n");
return(NULL);
}
cmemuse++;
memset(relation->next, 0, sizeof(struct call_relation));
/* the record pointer is set at the first time the data is received for the relation */
// if (options.deb & DEBUG_CALL)
// callpbx_debug(call, "add_relation");
return(relation->next);
}
/* epoint sends a message to a call
*
*/
void CallPBX::message_epoint(unsigned long epoint_id, int message_type, union parameter *param)
{
class Call *cl;
struct call_relation *relation, *rel;
int num;
int new_state;
struct message *message;
// int size, writesize, oldpointer;
class Endpoint *epoint;
char *number;
if (!epoint_id)
{
PERROR("software error, epoint == NULL\n");
return;
}
// if (options.deb & DEBUG_CALL)
// {
// PDEBUG(DEBUG_CALL, "message %d received from ep%d.\n", message, epoint->ep_serial);
// callpbx_debug(call,"Call::message_epoint");
// }
if (options.deb & DEBUG_CALL)
{
if (message_type != MESSAGE_DATA)
{
cl = call_first;
while(cl)
{
if (cl->c_type == CALL_TYPE_PBX)
callpbx_debug((class CallPBX *)cl, "Call::message_epoint{all calls before processing}");
cl = cl->next;
}
}
}
/* check relation */
relation = c_relation;
while(relation)
{
if (relation->epoint_id == epoint_id)
break;
relation = relation->next;
}
if (!relation)
{
// PERROR("no relation back to the endpoint found, ignoring (call=%d, endpoint=%d\n", c_serial, epoint_id);
return;
}
switch(message_type)
{
/* process channel message */
case MESSAGE_CHANNEL:
PDEBUG(DEBUG_CALL, "call received channel message: %d.\n", param->channel);
if (relation->channel_state != param->channel)
{
relation->channel_state = param->channel;
c_mixer = 1; /* update mixer flag */
if (options.deb & DEBUG_CALL)
callpbx_debug(this, "Call::message_epoint{after setting new channel state}");
}
return;
/* track notify */
case MESSAGE_NOTIFY:
switch(param->notifyinfo.notify)
{
case INFO_NOTIFY_USER_SUSPENDED:
case INFO_NOTIFY_USER_RESUMED:
case INFO_NOTIFY_REMOTE_HOLD:
case INFO_NOTIFY_REMOTE_RETRIEVAL:
case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
new_state = track_notify(relation->rx_state, param->notifyinfo.notify);
if (new_state != relation->rx_state)
{
relation->rx_state = new_state;
c_mixer = 1;
if (options.deb & DEBUG_CALL)
callpbx_debug(this, "Call::message_epoint{after setting new rx state}");
}
break;
default:
/* send notification to all other endpoints */
rel = c_relation;
while(rel)
{
if (rel->epoint_id!=epoint_id && rel->epoint_id)
{
message = message_create(c_serial, rel->epoint_id, CALL_TO_EPOINT, MESSAGE_NOTIFY);
memcpy(&message->param, param, sizeof(union parameter));
message_put(message);
}
rel = rel->next;
}
}
return;
/* audio data */
case MESSAGE_DATA:
/* now send audio data to all endpoints connected */
call_mixer(epoint_id, relation, param);
return;
}
/* process party line */
if (message_type == MESSAGE_SETUP) if (param->setup.partyline)
{
PDEBUG(DEBUG_CALL, "respsone with connect in partyline mode.\n");
c_partyline = param->setup.partyline;
message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_CONNECT);
message->param.setup.partyline = c_partyline;
message_put(message);
c_mixer = 1; /* update mixer flag */
}
if (c_partyline)
{
if (message_type == MESSAGE_DISCONNECT)
{
PDEBUG(DEBUG_CALL, "releasing after receiving disconnect, because call in partyline mode.\n");
// remove_relation(relation);
message = message_create(c_serial, epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = CAUSE_NORMAL;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
// c_mixer = 1; /* update mixer flag */
return;
}
}
if (c_partyline)
{
PDEBUG(DEBUG_CALL, "ignoring message, because call in partyline mode.\n");
return;
}
/* count relations */
num=callpbx_countrelations(c_serial);
/* check number of relations */
if (num > 2)
{
PDEBUG(DEBUG_CALL, "call has more than two relations so there is no need to send a message.\n");
return;
}
/* find interfaces not related to calling epoint */
relation = c_relation;
while(relation)
{
if (relation->epoint_id != epoint_id)
break;
relation = relation->next;
}
if (!relation)
{
switch(message_type)
{
case MESSAGE_SETUP:
if (param->dialinginfo.itype == INFO_ITYPE_ISDN_EXTENSION)
{
while(number = strsep(&param->dialinginfo.number, ','))
{
if (out_setup(epoint_id, message_type, param, number))
return; // call destroyed
}
break;
}
if (out_setup(epoint_id, message_type, param, NULL))
return; // call destroyed
break;
default:
PDEBUG(DEBUG_CALL, "no need to send a message because there is no other endpoint than the calling one.\n");
}
} else
{
PDEBUG(DEBUG_CALL, "sending message ep%ld -> ep%ld.\n", epoint_id, relation->epoint_id);
message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
memcpy(&message->param, param, sizeof(union parameter));
message_put(message);
PDEBUG(DEBUG_CALL, "message sent.\n");
}
}
/* call process is called from the main loop
* it processes the current calling state.
* returns 0 if call nothing was done
*/
int CallPBX::handler(void)
{
// struct call_relation *relation;
// char dialing[32][32];
// int port[32];
// int found;
// int i, j;
// char *p;
/* the mixer must be updated */
if (c_mixer)
{
mixer();
c_mixer = 0;
return(1);
}
return(0);
}
int track_notify(int oldstate, int notify)
{
int newstate = oldstate;
switch(notify)
{
case INFO_NOTIFY_USER_RESUMED:
case INFO_NOTIFY_REMOTE_RETRIEVAL:
case INFO_NOTIFY_CONFERENCE_DISCONNECTED:
case INFO_NOTIFY_RESERVED_CT_1:
case INFO_NOTIFY_RESERVED_CT_2:
case INFO_NOTIFY_CALL_IS_DIVERTING:
newstate = NOTIFY_STATE_ACTIVE;
break;
case INFO_NOTIFY_USER_SUSPENDED:
newstate = NOTIFY_STATE_SUSPEND;
break;
case INFO_NOTIFY_REMOTE_HOLD:
newstate = NOTIFY_STATE_HOLD;
break;
case INFO_NOTIFY_CONFERENCE_ESTABLISHED:
newstate = NOTIFY_STATE_CONFERENCE;
break;
}
return(newstate);
}
/*
* setup to exactly one endpoint
* if it fails, the calling endpoint is released.
* if other outgoing endpoints already exists, they are release as well.
* note: if this functions fails, it will destroy its own call object!
*/
int CallPBX::out_setup(unsigned long epoint_id, int message_type, union parameter *param, char *newnumber)
{
struct call_relation *relation;
struct message *message;
class Endpoint *epoint;
PDEBUG(DEBUG_CALL, "no endpoint found, so we will create an endpoint and send the setup message we have.\n");
/* create a new relation */
if (!(relation=add_relation()))
{
/* release due to error */
ressource_error:
relation = c_relation;
while(relation)
{
message = message_create(c_serial, releation->epoint_id, CALL_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = (relation->epoint_id==epoint_id)CAUSE_RESSOURCEUNAVAIL?:CAUSE_NORMAL;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
relation = relation->next;
}
delete this;
return(-ENOMEM);
}
relation->type = RELATION_TYPE_SETUP;
relation->channel_state = CHANNEL_STATE_HOLD; /* audio is assumed on a new call */
relation->tx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
relation->rx_state = NOTIFY_STATE_ACTIVE; /* new calls always assumed to be active */
/* create a new endpoint */
epoint = new Endpoint(0, c_serial);
if (!epoint)
{
remove_relation(relation);
goto ressource_error;
}
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
{
PERROR("ERROR:No endpoint's app.\n");
delete epoint;
remove_relation(relation);
goto ressource_error;
}
relation->epoint_id = epoint->ep_serial;
/* send setup message to new endpoint */
//printf("JOLLY DEBUG: %d\n",call_countrelations(c_serial));
//i if (options.deb & DEBUG_CALL)
// callpbx_debug(call, "Call::message_epoint");
message = message_create(c_serial, relation->epoint_id, CALL_TO_EPOINT, message_type);
memcpy(&message->param, param, sizeof(union parameter));
if (newnumber)
SCPY(message->param.setup.dialinginfo.number, newnumber);
PDEBUG(DEBUG_CALL, "setup message sent to ep %d with number='%s'.\n", relation->epoint_id, message->param.setup.dialinginfo.number);
message_put(message);
return(0);
}
todo: beim release von einem relation_type_setup muss der cause gesammelt werden, bis keine weitere setup-relation mehr existiert
beim letzten den collected cause senden
mixer kann ruhig loslegen, das aber dokumentieren
mixer überdenken: wer sendet, welche töne verfügbar sind, u.s.w

81
callpbx.h Normal file
View File

@ -0,0 +1,81 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** call header file for pbx calls **
** **
\*****************************************************************************/
/* call
*
* calls connect interfaces together
* calls are linked in a chain
* interfaces can have 0, 1 or more references to a call
* the call can have many references to interfaces
* calls receive and send messages
*/
#define RECORD_BUFFER_SIZE 16000
enum { /* relation types */
RELATION_TYPE_CALLING, /* initiator of a call */
RELATION_TYPE_SETUP, /* interface which is to be set up */
RELATION_TYPE_CONNECT, /* interface is connected */
};
enum { /* relation audio state */
CHANNEL_STATE_CONNECT, /* endpoint is connected to the call voice transmission in both dirs */
CHANNEL_STATE_HOLD, /* endpoint is on hold state, no audio */
};
enum { /* states that results from last notification */
NOTIFY_STATE_ACTIVE, /* just the normal case, the party is active */
NOTIFY_STATE_SUSPEND, /* the party is inactive, because she has parked */
NOTIFY_STATE_HOLD, /* the party is inactive, because she holds the line */
NOTIFY_STATE_CONFERENCE, /* the parties joined a conference */
};
struct call_relation { /* relation to an interface */
struct call_relation *next; /* next node */
int type; /* type of relation */
unsigned long epoint_id; /* interface to link call to */
int channel_state; /* if audio is available */
int rx_state; /* current state of what we received from endpoint */
int tx_state; /* current state of what we sent to endpoint */
};
class CallPBX : public Call
{
public:
CallPBX(class Endpoint *epoint);
~CallPBX();
void message_epoint(unsigned long epoint_id, int message, union parameter *param);
int handler(void);
void release(unsigned long epoint_id, int hold, int location, int cause);
char c_caller[32]; /* caller number */
char c_caller_id[32]; /* caller id to signal */
char c_dialed[1024]; /* dial string of (all) number(s) */
char c_todial[32]; /* overlap dialing (part not signalled yet) */
int c_mixer; /* mixer must be updated */
struct call_relation *c_relation; /* list of endpoints that are related to the call */
int c_partyline; /* if set, call is conference room */
void mixer(void);
void call_mixer(unsigned long epoint_from, struct call_relation *relation_from, union parameter *param);
void remove_relation(struct call_relation *relation);
struct call_relation *add_relation(void);
int out_setup(unsigned long epoint_id, int message, union parameter *param, char *newnumber);
};
void callpbx_debug(class CallPBX *callpbx, char *function);
int callpbx_countrelations(unsigned long call_id);
int track_notify(int oldstate, int notify);

375
cause.c Normal file
View File

@ -0,0 +1,375 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** cause database **
** **
\*****************************************************************************/
#include "stdio.h"
#include "sys/types.h"
#include "string.h"
#include "main.h"
struct isdn_cause isdn_cause[128] = {
/********************************* - **/ /*38*/
{ /*0*/ "<No cause>",
"<Kein Grund>" },
{ /*1*/ "Unallocated number",
"Nummer nicht vergeben" },
{ /*2*/ "No route to transit network",
"Keine Verbindung zum Netz" },
{ /*3*/ "No route to destination",
"Zielnummer nicht erreichbar" },
{ /*4*/ "<Listen to announcement...>",
"<Ansage hoeren...>" },
{ /*5*/ "Misdialed trunk prefix.",
"Falscher Carrier-Code" },
{ /*6*/ "Channel unacceptable",
"Kanal nicht akzeptiert" },
{ /*7*/ "",
"" },
{ /*8*/ "Preemption",
"Vorkauf" },
{ /*9*/ "Preemption - circuit reserved",
"Vorkauf - Gasse reserviert" },
{ /*10*/ "",
"" },
{ /*11*/ "",
"" },
{ /*12*/ "",
"" },
{ /*13*/ "",
"" },
{ /*14*/ "",
"" },
{ /*15*/ "",
"" },
{ /*16*/ "Normal call clearing",
"Normaler Verbindungsabbau" },
{ /*17*/ "User busy",
"Teilnehmer besetzt" },
{ /*18*/ "No user responding",
"Teilnehmer antwortet nicht" },
{ /*19*/ "No answer from user",
"Teilnehmer nimmt nicht ab" },
{ /*20*/ "Subscriber absent",
"Teilnehmer nicht anwesend" },
{ /*21*/ "Call rejected",
"Gespraech abgewiesen" },
{ /*22*/ "Number changed",
"Rufnummer hat sich geaendert" },
{ /*23*/ "",
"" },
{ /*24*/ "",
"" },
{ /*25*/ "",
"" },
{ /*26*/ "Non-selected user clearing",
"Gespraech woanders angenommen" },
{ /*27*/ "Destination out of order",
"Gegenstelle ausser Betrieb" },
{ /*28*/ "Invalid number (incomplete)",
"Fehlerhafte Nummer (n. komplett)" },
{ /*29*/ "Facility rejected",
"Funktion nicht verfuegbar" },
{ /*30*/ "",
"" },
{ /*31*/ "Normal, unspecified",
"Normal, unspezifisch" },
{ /*32*/ "",
"" },
{ /*33*/ "",
"" },
{ /*34*/ "No circuit/channel available",
"Keine Gasse/Kanal verfuegbar" },
{ /*35*/ "",
"" },
{ /*36*/ "",
"" },
{ /*37*/ "",
"" },
{ /*38*/ "",
"" },
{ /*39*/ "",
"" },
{ /*40*/ "",
"" },
{ /*41*/ "Temporary failure",
"Vorruebergehende Fehlfunktion" },
{ /*42*/ "Switchting equipment congestion",
"Vermittlungstelle ueberlastet" },
{ /*43*/ "Access informationen discarded",
"Zugriffsinformationen geloescht" },
{ /*44*/ "No requested circuit/channel",
"Keine angeforderte Gasse/Kanal" },
{ /*45*/ "",
"" },
{ /*46*/ "Precedence call blocked",
"Vorverkaufanruf gesperrt" },
{ /*47*/ "Resource unavailable, unspecified",
"" },
{ /*48*/ "",
"" },
{ /*49*/ "Quality of service not available",
"Qualitaetsmerkmal nicht verfuegbar" },
{ /*50*/ "Requested facility not subscribed",
"Funktion nicht freigeschaltet" },
{ /*51*/ "",
"" },
{ /*52*/ "",
"" },
{ /*53*/ "Outgoing calls barred within CUG",
"CUG erlaubt keine gehenden Rufe" },
{ /*54*/ "",
"" },
{ /*55*/ "Incoming calls barred within CUG",
"CUG erlaubt keine kommenden Rufe" },
{ /*56*/ "",
"" },
{ /*57*/ "Bearer capability not authorized",
"Verbindungseigenschaft verboten" },
{ /*58*/ "Bearer capability not present",
"Verb.eigenschaft n. verfuegbar" },
{ /*59*/ "",
"" },
{ /*60*/ "",
"" },
{ /*61*/ "",
"" },
{ /*62*/ "",
"" },
{ /*63*/ "Service or option not available",
"Dienst oder Merkmal nicht verf." },
{ /*64*/ "",
"" },
{ /*65*/ "Bearer capability not implement.",
"Verb.eigenschaft nicht unterstue." },
{ /*66*/ "Channel type not implemented",
"Kanalart nicht unterstuetzt" },
{ /*67*/ "",
"" },
{ /*68*/ "",
"" },
{ /*69*/ "Requested facility not implement.",
"Funktion nicht unterstuetzt" },
{ /*70*/ "restricted digital informat. only",
"Nur eingeschraenkte digitale inf." },
{ /*71*/ "",
"" },
{ /*72*/ "",
"" },
{ /*73*/ "",
"" },
{ /*74*/ "",
"" },
{ /*75*/ "",
"" },
{ /*76*/ "",
"" },
{ /*77*/ "",
"" },
{ /*78*/ "",
"" },
{ /*79*/ "Service or option not implemented",
"Dienst oder Merkmal n. unterstue." },
{ /*80*/ "",
"" },
{ /*81*/ "Invalid call reference value",
"Falsche call reference" },
{ /*82*/ "Identified channel does not exist",
"Erkannter Kanal existiert nicht" },
{ /*83*/ "No suspended call with this id",
"Kein geparktes Gespr. f. diese ID" },
{ /*84*/ "Call identity in use",
"ID in gebrauch" },
{ /*85*/ "No call suspended",
"Kein geparktes Gespraech" },
{ /*86*/ "Suspended call has been cleared",
"Geparktes Gespraech wurde beendet" },
{ /*87*/ "User not member of CUG",
"Teilnehmer nicht in der CUG" },
{ /*88*/ "Incompatibel destination",
"Gegenstelle nicht kompatibel" },
{ /*89*/ "",
"" },
{ /*90*/ "Non-existent CUG",
"CUG existiert nicht" },
{ /*91*/ "Invalid transit network selection",
"Falscher Carrier-Code" },
{ /*92*/ "",
"" },
{ /*93*/ "",
"" },
{ /*94*/ "",
"" },
{ /*95*/ "Invalid message, unspecified",
"Fehlerhafte Daten, unbekannt" },
{ /*96*/ "Information element missing",
"Information wird vermisst" },
{ /*97*/ "Message type non-existent",
"Message exisitiert nicht" },
{ /*98*/ "Message not compatible with state",
"Message nicht komatibel" },
{ /*99*/ "Information element not impl.",
"Information nicht implementiert" },
{ /*100*/ "Invalid info element contents",
"Fehlerhafterhafte Information" },
{ /*101*/ "Message not compatible with state",
"Message not kompatibel" },
{ /*102*/ "Recovery on timer expiry",
"Fehler durch Zeitueberschreitung" },
{ /*103*/ "Parameter non-existent",
"Parameter fehlt" },
{ /*104*/ "",
"" },
{ /*105*/ "",
"" },
{ /*106*/ "",
"" },
{ /*107*/ "",
"" },
{ /*108*/ "",
"" },
{ /*109*/ "",
"" },
{ /*110*/ "",
"" },
{ /*111*/ "Protocol error, unspecified",
"Protokollfehler, unbekannt" },
{ /*112*/ "",
"" },
{ /*113*/ "",
"" },
{ /*114*/ "",
"" },
{ /*115*/ "",
"" },
{ /*116*/ "",
"" },
{ /*117*/ "",
"" },
{ /*118*/ "",
"" },
{ /*119*/ "",
"" },
{ /*120*/ "",
"" },
{ /*121*/ "",
"" },
{ /*122*/ "",
"" },
{ /*123*/ "",
"" },
{ /*124*/ "",
"" },
{ /*125*/ "",
"" },
{ /*126*/ "",
"" },
{ /*127*/ "Interworking, unspecified",
"Zusammenspiel, unbekannt" },
};
struct isdn_cause isdn_cause_class[8] = {
/********************************* - **/ /*38*/
{ /*0*/ "(Normal class)",
"(Normale Fehlerklasse)" },
{ /*16*/ "(Normal class)",
"(Normale Fehlerklasse)" },
{ /*32*/ "(Resource unavailable class)",
"(Ressourcen nicht verfuegbar)" },
{ /*48*/ "(Service or option unavailable)",
"(Dienst oder Merkmal n. verfueg.)" },
{ /*64*/ "(Service or option n.implemented)",
"(Dienst oder Merkmal n. vorhand.)" },
{ /*80*/ "(Invalid message class)",
"(Fehlerhafte Message)" },
{ /*96*/ "(Protocol error class)",
"(Klasse der Protokollfehler)" },
{ /*112*/ "(Interworking class)",
"(Klasse des Zusammenspiels)" },
};
struct isdn_location isdn_location[16] = {
{ /*0*/ "User",
"Endgerät" },
{ /*1*/ "Private (Local)",
"Anlage (Lokal)" },
{ /*2*/ "Public (Local)",
"Vermittlung (Lokal)" },
{ /*3*/ "Transit",
"Knotenvermittlung" },
{ /*4*/ "Public (Remote)",
"Vermittlung (Gegenstelle)" },
{ /*5*/ "Private (Remote)",
"Anlage (Gegenstelle)" },
{ /*6*/ "",
"" },
{ /*7*/ "International",
"Fernvermittlung" },
{ /*8*/ "",
"" },
{ /*9*/ "",
"" },
{ /*10*/ "Beyond Interworking",
"Nicht verfuegbar" },
{ /*11*/ "",
"" },
{ /*12*/ "",
"" },
{ /*13*/ "",
"" },
{ /*14*/ "",
"" },
{ /*15*/ "",
"" },
};
char *get_isdn_cause(int cause, int location, int type)
{
static char result[128];
/* protect us */
if (cause<0 || cause>127)
cause = 0;
switch(type)
{
case DISPLAY_CAUSE_NUMBER:
SPRINT(result, "Cause %d", cause);
break;
case DISPLAY_CAUSE_ENGLISH:
if (isdn_cause[cause].english[0])
SPRINT(result, "%d - %s", cause, isdn_cause[cause].english);
else SPRINT(result, "%d - %s", cause, isdn_cause_class[cause>>4].english);
break;
case DISPLAY_CAUSE_GERMAN:
if (isdn_cause[cause].german[0])
SPRINT(result, "%d - %s", cause, isdn_cause[cause].german);
else SPRINT(result, "%d - %s", cause, isdn_cause_class[cause>>4].german);
break;
case DISPLAY_LOCATION_ENGLISH:
if (isdn_location[location].english[0])
SPRINT(result, "%d - %s", cause, isdn_location[location].english);
else SPRINT(result, "%d - Location code %d", cause, location);
break;
case DISPLAY_LOCATION_GERMAN:
if (isdn_location[location].german[0])
SPRINT(result, "%d - %s", cause, isdn_location[location].german);
else SPRINT(result, "%d - Lokationscode %d", cause, location);
break;
default:
result[0] = '\0';
}
return(result);
}

51
cause.h Normal file
View File

@ -0,0 +1,51 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** cause header file **
** **
\*****************************************************************************/
/* location (equivalent to the q.850 coding) */
#define LOCATION_USER 0
#define LOCATION_PRIVATE_LOCAL 1
#define LOCATION_PUBLIC_LOCAL 2
#define LOCATION_TRANSIT 3
#define LOCATION_PUBLIC_REMOTE 4
#define LOCATION_PRIVATE_REMOTE 5
#define LOCATION_INTERNATIONAL 7
#define LOCATION_BEYOND 10
/* some causes (equivalent to the q.850 coding) */
#define CAUSE_UNALLOCATED 1
#define CAUSE_NORMAL 16
#define CAUSE_BUSY 17
#define CAUSE_NOUSER 18
#define CAUSE_NOANSWER 19
#define CAUSE_REJECTED 21
#define CAUSE_OUTOFORDER 27
#define CAUSE_INVALID 28
#define CAUSE_FACILITYREJECTED 29
#define CAUSE_UNSPECIFIED 31
#define CAUSE_NOCHANNEL 34
#define CAUSE_TEMPOFAIL 41
#define CAUSE_RESSOURCEUNAVAIL 47
#define CAUSE_SERVICEUNAVAIL 63
#define CAUSE_UNIMPLEMENTED 79
struct isdn_cause {
char *english;
char *german;
};
struct isdn_location {
char *english;
char *german;
};
extern struct isdn_cause isdn_cause[128];
extern struct isdn_location isdn_location[16];
char *get_isdn_cause(int cause, int location, int type);

2046
crypt.cpp Normal file

File diff suppressed because it is too large Load Diff

173
crypt.h Normal file
View File

@ -0,0 +1,173 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** crypt header file **
** **
\*****************************************************************************/
enum { /* enpoint's user states */
CRYPT_OFF, /* no encryption */
CRYPT_KWAIT, /* wait for key-exchange mehtod */
CRYPT_SWAIT, /* wait for shared secret method */
CRYPT_ON, /* crypting */
CRYPT_RELEASE, /* wait for deactivation */
};
#define CM_TO_IDENT 10 /* timeout for identifying remote peer */
#define CM_TO_PUBKEY 60 /* timeout for public key generation */
#define CM_TO_CSKEY 5 /* timeout for crypting session key */
enum { /* crypt manager states */
CM_ST_NULL, /* no encryption used */
CM_ST_IDENT, /* find the remote pary */
CM_ST_KEYGEN, /* generating public/private key */
CM_ST_KEYWAIT, /* waiting for public key */
CM_ST_CSKEY, /* generate crypted session key */
CM_ST_CSWAIT, /* wait for CSKey */
CM_ST_SESSION, /* wait for session key decryption */
CM_ST_WAIT_DELAY, /* wait sone time until the cskey is transferred */
CM_ST_WAIT_CRYPT, /* wait for encryption from session engine */
CM_ST_ACTIVE, /* done with encryption */
CM_ST_RELEASE, /* wait until key engine has finished, after abort */
CM_ST_SWAIT, /* wait for share key establishment */
CM_ST_SACTIVE, /* shared key established */
};
#define CM_ST_NAMES \
static char *cm_st_name[] = { \
"NULL", \
"IDENT", \
"KEYGEN", \
"KEYWAIT", \
"CSKEY", \
"CSWAIT", \
"SESSION", \
"WAIT_DELAY", \
"WAIT_CRYPT", \
"ACTIVE", \
"RELEASE", \
"SWAIT", \
"SACTIVE", \
}; \
int cm_st_num = sizeof(cm_st_name) / sizeof(char *);
enum { /* messages */
/* messages to/from peer */
CP_IDENT, /* send random number, cpu power */
CP_SLAVE, /* tell remote to be slave */
CP_MASTER, /* tell remote to be master */
CP_LOOPED, /* tell remote (us) that the call is looped */
CP_PUBKEY, /* send public key */
CP_CSKEY, /* send encrypted session key */
CP_ABORT, /* send abort message */
/* messages to/from "key engine" */
CK_GENRSA_REQ, /* generate rsa key */
CK_GENRSA_CONF, /* rsa key result */
CK_CPTRSA_REQ, /* crypt session key */
CK_CPTRSA_CONF, /* session key result */
CK_DECRSA_REQ, /* decode session key */
CK_DECRSA_CONF, /* session key result */
CK_ERROR_IND, /* error of engine */
/* messages to/from "crypt engine" */
CC_ACTBF_REQ, /* activate blowfish */
CC_ACTBF_CONF, /* blowfish activated */
CC_ERROR_IND, /* failed to activate session encryption */
CC_DACT_REQ, /* deactivate session encryption */
/* messages to/from user interface */
CU_ACTK_REQ, /* request encryption with key exchange */
CU_ACTK_CONF, /* encryption now active */
CU_ACTS_REQ, /* request shared key encryption */
CU_ACTS_CONF, /* encryption now active */
CU_ERROR_IND, /* encryption failed */
CU_INFO_REQ, /* info reques */
CU_INFO_CONF, /* info to the user*/
CU_INFO_IND, /* info to the user*/
CU_DACT_REQ, /* deactivate encryption */
CU_DACT_CONF, /* encryption now inactive */
CU_DACT_IND, /* encryption now inactive */
/* messages to/from message transponder */
CR_LISTEN_REQ, /* start listening to messages */
CR_UNLISTEN_REQ, /* stop listening to messages */
CR_MESSAGE_REQ, /* send message */
CR_MESSAGE_IND, /* receive message */
/* messages from ISDN */
CI_DISCONNECT_IND, /* call is disconnected */
/* message timeout */
CT_TIMEOUT, /* current state timed out */
};
#define CM_MSG_NAMES \
static char *cm_msg_name[] = { \
"CP_IDENT", \
"CP_SLAVE", \
"CP_MASTER", \
"CP_LOOPED", \
"CP_PUBKEY", \
"CP_CSKEY", \
"CP_ABORT", \
"CK_GENRSA_REQ", \
"CK_GENRSA_CONF", \
"CK_CPTRSA_REQ", \
"CK_CPTRSA_CONF", \
"CK_DECRSA_REQ", \
"CK_DECRSA_CONF", \
"CK_ERROR_IND", \
"CC_ACTBF_REQ", \
"CC_ACTBF_CONF", \
"CC_ERROR_IND", \
"CC_DACT_REQ", \
"CU_ACTK_REQ", \
"CU_ACTK_CONF", \
"CU_ACTS_REQ", \
"CU_ACTS_CONF", \
"CU_ERROR_IND", \
"CU_INFO_REQ", \
"CU_INFO_CONF", \
"CU_INFO_IND", \
"CU_DACT_REQ", \
"CU_DACT_CONF", \
"CU_DACT_IND", \
"CR_LISTEN_REQ", \
"CR_UNLISTEN_REQ", \
"CR_MESSAGE_REQ", \
"CR_MESSAGE_IND", \
"CI_DISCONNECT_IND", \
"CT_TIMEOUT", \
}; \
int cm_msg_num = sizeof(cm_msg_name) / sizeof(char *);
/* peer2peer messages */
#define CMSG_IDENT 0x01
#define CMSG_MASTER 0x11
#define CMSG_SLAVE 0x12
#define CMSG_LOOPED 0x13
#define CMSG_PUBKEY 0x21
#define CMSG_CSKEY 0x22
#define CMSG_ABORT 0x81
/* peer2peer info elements */
#define CM_INFO_MESSAGE 0x01
#define CM_INFO_RANDOM 0x10
#define CM_INFO_BOGOMIPS 0x11
#define CM_INFO_PUBKEY 0x12
#define CM_INFO_PUBEXPONENT 0x13
#define CM_INFO_CSKEY 0x14
#define CM_ADDINF(a, b, c) \
cryptman_addinf(buf, sizeof(buf), a, b, c);
#define CM_SIZEOFINF(a) \
cryptman_sizeofinf(param, a);
#define CM_GETINF(a, b) \
cryptman_getinf(param, a, b);
void crc_init(void);
unsigned long crc32(unsigned char *data, int len);
int cryptman_encode_bch(unsigned char *data, int len, unsigned char *buf, int buf_len);

21
default/directory.list Normal file
View File

@ -0,0 +1,21 @@
# The directory translates caller IDs to names.
# Format: <phone number> <Name>\n");
# The number must be given as received:
# National number: The national prefix must be included or 'n' must be used.
# E.g.: n9036681733 or 19036681733 (in case '1' is the national prefix)
# E.g.: n21250993 or 021250993 (in case '0' is the national prefix)
# International number: The international prefix must be included or 'i'.
# E.g.: i4921256483 or 0114921256493 (in case '011' is the intl. prefix)
# E.g.: i19036681733 or 0019036681733 (in case '00' is the intl. prefix)
# Subscriber number: No prefix mus be included or 's' must be used.
# E.g.: s50993 or 1733
# Note: National numbers always require the area code. International numbers
# always require the country code + area code.
021250993 German number
0019036681739 American number
n48416600 German hospital

13
default/h323_gateway.conf Normal file
View File

@ -0,0 +1,13 @@
# Gateway configuration for incoming h323 calls
#
# Incoming calls will be mapped to the given extensions. If calling host
# is not listed here, it will be processed as extenal call.
# IP numbers must be given here, not host names.
# The "connect" option allows to send back a connect before the call is
# actually answered. Some H323 client will only allow entering of digits
# after a connect.
# Using "dtmf" connects and also enables DTMF detection.
#
# <host ip> <extension> [connect | dtmf]
192.168.0.2 200

88
default/interface.conf Normal file
View File

@ -0,0 +1,88 @@
# interface.conf
################
# Example of an ISDN interface on port 1
#[Ext]
#port 1
# Example of a multilink ISDN interface (Anlagenanschluss) on port 3
# and 4
#[Ext]
#port 3
#port 4
# Example of an ISDN interface on port 2, which accepts all extensions
#[Int]
#extension
#port 2
# Example of an ISDN interface on port 2, which accepts only extensions
# 201, 202 and 203
#[Int]
#extension
#msn 201,202,203
#port 2
# Example of three ISDN interfaces on port 2, 3 and 4, which accept
# extension 201 on all interfaces, and extension 202 and 203 on the first port
# only.
# Hint: To make extension ring on all three interfaces parallel, use
# "interface Int1,Int2,In3" in extension's settings file.
#[Int1]
#extension
#msn 201,202,203
#port 2
#[Int2]
#extension
#msn 201
#port 3
#[Int3]
#extension
#msn 201
#port 4
# Example of an ISDN interface on port 1 that requires screening of caller IDs.
# This is required if the connected line doesn't screen caller IDs.
# Also this interface will connect bchannel during call setup, so tones are
# required.
#[Ext]
#screen_out unknown 300 national 21250993300
#screen_out unknown 2* national 212509932*
#tones yes
#port 1
# Example of an ISDN PRI interface on port 1 that has directed channels.
# 10 channels (channel 1-10) are incomming only.
# 10 channels (channel 11-15,17-21) are outgoing only.
# 10 channels (channel 22-31) are both way.
# We prefer to use directed channels first, then we request any channel:
#[Ext]
#port 1
#channel force,11,12,13,14,15,17,18,19,20,21,any
# Add your interfaces here:
[Ext]
port 1
[Int]
extension
msn 201,202,203
port 2

165
default/options.conf Normal file
View File

@ -0,0 +1,165 @@
# PBX options
#############
# Turn debugging all on=0xffff or off=0x0000 (default= 0x0000)
#define DEBUG_CONFIG 0x0001
#define DEBUG_MSG 0x0002
#define DEBUG_STACK 0x0004
#define DEBUG_BCHANNEL 0x0008
#define DEBUG_PORT 0x0100
#define DEBUG_ISDN 0x0110
#define DEBUG_H323 0x0120
#define DEBUG_VBOX 0x0180
#define DEBUG_EPOINT 0x0200
#define DEBUG_CALL 0x0400
#define DEBUG_CRYPT 0x1000
#define DEBUG_ROUTE 0x2000
#define DEBUG_IDLETIME 0x4000
#define DEBUG_LOG 0x7fff
#debug 0x0000
# The log file can be used to track actions by the PBX. Omit the parameter
# to turn off log file. By default, log file is located inside the directory
# "/usr/local/pbx/log".
#log /usr/local/pbx/log
# Use "alaw" (default) or "ulaw" samples.
#alaw
# The pbx should run as real time process. Because audio is streamed and
# ISDN protocol requires a certain response time, we must have high priority.
# By default, the process runs with realtime scheduling and high priority.
# To debug, it is whise to use "schedule" with no parameter to turn off
# realtime scheduling. In case of an endless loop bug, PBX4Linux will take
# all CPU time forever - your machine hangs.
#schedule 0
# Use tone sets (default= tones_american).
# This can be overridden by the extension setting
#tones_dir tones_american
# Fetch tone sets as specified here.
# The tone sets will be loaded during startup, and no harddisk access is
# required. Specify all tone sets seperated by komma.
# By default, no tone is fetched. Tone sets, that are not specified here, will
# be streamed from hard disk.
# Don't use spaces to seperate!
#fetch_tones tones_american,tones_german,vbox_english,vbox_german
# Extensions directory where all configuration files and messages for all
# extensions are stored (default= extensions).
#extensions_dir extensions
# Prefix to dial national call (default= 0).
# If you omit the prefix, all subscriber numbers are national numbers.
# (example: Danmark)
#national 0
# Prefix to dial international call (default= 00).
# If you omit the prefix, all subscriber numbers are international numbers.
#international 00
# On external calls, dialing can be done via normal called party number
# information element or via keypad facility. Some telephone systems require
# dialing via keypad to enable/disable special functions.
# By default keypad facility is disabled.
#keypad
# Internal/external ports (cards connected to your isdn line)
# MUST be the card number. Use "./pbx query" to list.
# Add "ptp" for using internal port as point-to-point. (Only required for NT mode ports.)
# Example: port 2
# port 3 ptp
port 2
port 3
# Specify the H323 endpoint name. If omitted the hostname is used.
#h323_name PBX4Linux
# Incoming H323 calls can be connected prior answer, because some clients will
# not play any inband tones during ringing, they just wait as nothing would
# happen.
# This only works for external calls. If a H323 caller is authenticated via
# h323_gateway.conf, a special "connect" option may be used to connect as
# soon as the call is received.
# By default this feature is turned off.
#h323_ringconnect
# Specify which codecs may be used for H323 calls
# "h323_law" ALaw and muLaw codec which requre more than 64k internet
# connection cause by overhead. The parameter defines the frame
# size. The size range is 10 - 240.
# "h323_g726" The adpcm codec G726. The parameter defines the bits per sample.
# The bits must be 2, 3, 4, or 5. (16, 24, 32, 40 kbits/s)
# The given value will always include all modes with lower value.
# "h323_gsm" GSM0610 and MicrosoftGSM codecs (not compatible with netmeeting)
# The prameter defines the frame size. The frame range is 1 - 7.
# "h323_lpc10" Codec with very low bandwith usage which can even be used on
# slow internetconnections like 9600 kBit (about 300 bytes/s)
# "h323_speex" Non standard Speex codec. The parameter defines the mode.
# The mode range is 2 - 6.
# The given value will always include all modes with lower value.
# "h323_xspeex" Non standard XiphSpeex codec. The parameter defines the mode.
# The mode range is 2 - 6.
# The given value will always include all modes with lower value.
# The priority of the codecs to use is given by it's order.
# By default, no codec is used
h323_gsm 4
h323_g726 2
#h323_lpc10
#h323_speex 4
#h323_xspeex 4
h323_law 64
# To allow incoming calls via H323, the following option is used:
# "h323_icall [<prefix>]"
# The given prefix is used for incoming calls which do not send any dialing
# information. If you like to route calls to an extension, give extension
# dialing as specified at numbering_ext.conf.
# By default no calls are accepted.
# Omit the prefix and it must be dialed by the caller.
h323_icall 0
# Specify the port to listen on incoming H323 connections.
# The default value is 1720.
#h323_port 1720
# To register with a gatekeeper, the following option is used:
# "h323_gatekeeper [<host or ip>]
# If no parameter is given, the gatekeeper is searched automatically.
#h323_gatekeeper
# To use dtmf detection for call from or to ISDN, uncomment the keyword "dtmf".
# By default dtmf detection is used. Note that dtmf detection needs cpu time.
# Dtmf detection is essential when handling the call after connect using
# keypad. (conferrence, callback, ect...)
#nodtmf
# For calls to external where caller id is not available, this id is used.
# It is sent of type "subscriber number". This ID is only usefull if the
# external line will not screen caller id. It will be sent anonymous.
# If you don't know what to use it for, you don't need it.
# Default is nothing.
#dummyid 0
# If your external ISDN line(s) support inband patterns prior call connect,
# you may say 'yes' here. In this case the PBX's tones are used for incoming
# calls. This may require a special subscription because it can be abused
# to transfer audio prior charge of call
#inbandpattern no
# Tones/announcements are streamed from user space. It is possible to use
# the module "mISDN_dsp.o" instead. It provides simple tones with much less cpu
# usage. If supported by special hardware, tones are loops that require no
# bus/cpu load at all, except when the tone changes.
# This works only for ISDN ports. It can be overridden by extension's tone set.
# Defautlt is streaming of tones. Use parameter "american", "german", or
# "oldgerman". "oldgerman" sounds like the old german telephone system (POTS).
#dsptones none
# Source email address of the PBX. E.g. it is used when sending a mail
# from the voice box. It is not the address the mails are sent to.
# Most mail servers require an existing domain in order to accept mails.
#email pbx@jolly.de

65
default/routing.conf Normal file
View File

@ -0,0 +1,65 @@
# PBX4Linux routing configuration "routing.conf"
# Ruleset: MAIN
# Calls with different origins will be processed in different rulesets.
[main]
h323 : goto ruleset=voip
extern : goto ruleset=extern
intern : goto ruleset=intern
: disconnect cause=31
# Ruleset: EXTERN
# All calls from external lines are processed here.
[extern]
dialing=0,1234 : intern extension=200
dialing=200-299 : intern
dialing=81 : partyline room=42
timeout=6 : intern extension=200
default : disconnect cause=1
# Ruleset: INTERN
# All calls from internal ports are processed here.
[intern]
dialing=0 : extern
dialing=1 : extern capability=digital-unrestricted
dialing=200-299 : intern
dialing=3 : pick
dialing=4 : h323
dialing=5 : reply
dialing=6 enblock : redial
dialing=6 : redial select
dialing=7 enblock : abbrev
dialing=7 : abbrev select
dialing=80 : vbox-play
dialing=81 : partyline room=42
dialing=90 : powerdial
dialing=91 : callerid
dialing=92 : calleridnext
#dialing=93 : login
#dialing=94 : powerdial
#dialing=950 real : callback
#dialing=953 : forward diversion=cfu
#dialing=954 : forward diversion=cfb
#dialing=955 : forward diversion=cfnr delay=26
#dialing=956 : forward diversion=cfp
#dialing=957 : forward diversion=cfu dest=vbox
#dialing=958 : forward diversion=cfb dest=vbox
#dialing=959 : forward diversion=cfnr dest=vbox delay=20
#dialing=96 : dtmf
#dialing=970 : calculator connect
dialing=99 : test
default : disconnect cause=1 display="Invalid Code"
# Ruleset: VOIP
# All calls will be forwarded to extension 200
[voip]
: intern extension=200

3370
dss1.cpp Normal file

File diff suppressed because it is too large Load Diff

103
dss1.h Normal file
View File

@ -0,0 +1,103 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** dss1-port header file **
** **
\*****************************************************************************/
/* DSS1 port classes */
class Pdss1 : public PmISDN
{
public:
Pdss1(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel);
~Pdss1();
int p_m_d_l3id; /* current l3 process id */
int p_m_d_ces; /* ntmode: tei&sapi */
int handler(void);
int message_epoint(unsigned long epoint_id, int message, union parameter *param);
void message_isdn(unsigned long prim, unsigned long dinfo, void *data);
int p_m_d_ntmode; /* flags the nt-mode */
struct message *p_m_d_queue; /* queue for SETUP if link is down */
struct message *p_m_d_notify_pending; /* queue for NOTIFY if not connected */
int p_m_d_collect_cause; /* collecting cause and location */
int p_m_d_collect_location;
void new_state(int state); /* set new state */
void isdn_show_send_message(unsigned long prim, msg_t *msg);
int received_first_reply_to_setup(unsigned long prim, int exclusive, int channel);
void information_ind(unsigned long prim, unsigned long dinfo, void *data);
void setup_ind(unsigned long prim, unsigned long dinfo, void *data);
void setup_acknowledge_ind(unsigned long prim, unsigned long dinfo, void *data);
void proceeding_ind(unsigned long prim, unsigned long dinfo, void *data);
void alerting_ind(unsigned long prim, unsigned long dinfo, void *data);
void connect_ind(unsigned long prim, unsigned long dinfo, void *data);
void disconnect_ind(unsigned long prim, unsigned long dinfo, void *data);
void release_ind(unsigned long prim, unsigned long dinfo, void *data);
void release_complete_ind(unsigned long prim, unsigned long dinfo, void *data);
void disconnect_ind_i(unsigned long prim, unsigned long dinfo, void *data);
void t312_timeout(unsigned long prim, unsigned long dinfo, void *data);
void notify_ind(unsigned long prim, unsigned long dinfo, void *data);
void facility_ind(unsigned long prim, unsigned long dinfo, void *data);
void hold_ind(unsigned long prim, unsigned long dinfo, void *data);
void retrieve_ind(unsigned long prim, unsigned long dinfo, void *data);
void suspend_ind(unsigned long prim, unsigned long dinfo, void *data);
void resume_ind(unsigned long prim, unsigned long dinfo, void *data);
void message_information(unsigned long epoint_id, int message_id, union parameter *param);
void message_setup(unsigned long epoint_id, int message_id, union parameter *param);
void message_notify(unsigned long epoint_id, int message_id, union parameter *param);
void message_facility(unsigned long epoint_id, int message_id, union parameter *param);
void message_overlap(unsigned long epoint_id, int message_id, union parameter *param);
void message_proceeding(unsigned long epoint_id, int message_id, union parameter *param);
void message_alerting(unsigned long epoint_id, int message_id, union parameter *param);
void message_connect(unsigned long epoint_id, int message_id, union parameter *param);
void message_disconnect(unsigned long epoint_id, int message_id, union parameter *param);
void message_release(unsigned long epoint_id, int message_id, union parameter *param);
/* IE conversion */
void enc_ie_complete(unsigned char **ntmode, msg_t *msg, int complete);
void dec_ie_complete(unsigned char *p, Q931_info_t *qi, int *complete);
void enc_ie_bearer(unsigned char **ntmode, msg_t *msg, int coding, int capability, int mode, int rate, int multi, int user);
void dec_ie_bearer(unsigned char *p, Q931_info_t *qi, int *coding, int *capability, int *mode, int *rate, int *multi, int *user);
void enc_ie_call_id(unsigned char **ntmode, msg_t *msg, unsigned char *callid, int callid_len);
void dec_ie_call_id(unsigned char *p, Q931_info_t *qi, unsigned char *callid, int *callid_len);
void enc_ie_called_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, unsigned char *number);
void dec_ie_called_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, unsigned char *number, int number_len);
void enc_ie_calling_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, unsigned char *number);
void dec_ie_calling_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len);
void enc_ie_connected_pn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, unsigned char *number);
void dec_ie_connected_pn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, unsigned char *number, int number_len);
void enc_ie_cause(unsigned char **ntmode, msg_t *msg, int location, int cause);
void dec_ie_cause(unsigned char *p, Q931_info_t *qi, int *location, int *cause);
void enc_ie_channel_id(unsigned char **ntmode, msg_t *msg, int exclusive, int channel);
void dec_ie_channel_id(unsigned char *p, Q931_info_t *qi, int *exclusive, int *channel);
void enc_ie_date(unsigned char **ntmode, msg_t *msg, time_t ti, int seconds);
void enc_ie_display(unsigned char **ntmode, msg_t *msg, unsigned char *display);
void dec_ie_display(unsigned char *p, Q931_info_t *qi, unsigned char *display, int display_len);
void enc_ie_keypad(unsigned char **ntmode, msg_t *msg, unsigned char *keypad);
void dec_ie_keypad(unsigned char *p, Q931_info_t *qi, unsigned char *keypad, int keypad_len);
void enc_ie_notify(unsigned char **ntmode, msg_t *msg, int notify);
void dec_ie_notify(unsigned char *p, Q931_info_t *qi, int *notify);
void enc_ie_progress(unsigned char **ntmode, msg_t *msg, int coding, int location, int progress);
void dec_ie_progress(unsigned char *p, Q931_info_t *qi, int *coding, int *location, int *progress);
void enc_ie_hlc(unsigned char **ntmode, msg_t *msg, int coding, int interpretation, int presentation, int hlc, int exthlc);
void dec_ie_hlc(unsigned char *p, Q931_info_t *qi, int *coding, int *interpretation, int *presentation, int *hlc, int *exthlc);
void enc_ie_redir_nr(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, int screen, int reason, unsigned char *number);
void dec_ie_redir_nr(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, int *screen, int *reason, unsigned char *number, int number_len);
void enc_ie_redir_dn(unsigned char **ntmode, msg_t *msg, int type, int plan, int present, unsigned char *number);
void dec_ie_redir_dn(unsigned char *p, Q931_info_t *qi, int *type, int *plan, int *present, unsigned char *number, int number_len);
void enc_ie_facility(unsigned char **ntmode, msg_t *msg, unsigned char *facility, int facility_len);
void dec_ie_facility(unsigned char *p, Q931_info_t *qi, unsigned char *facility, int *facility_len);
void enc_facility_centrex(unsigned char **ntmode, msg_t *msg, unsigned char *cnip, int setup);
void dec_facility_centrex(unsigned char *p, Q931_info_t *qi, unsigned char *cnip, int cnip_len);
void enc_ie_useruser(unsigned char **ntmode, msg_t *msg, int protocol, unsigned char *user, int user_len);
void dec_ie_useruser(unsigned char *p, Q931_info_t *qi, int *protocol, unsigned char *user, int *user_len);
};

219
endpoint.cpp Normal file
View File

@ -0,0 +1,219 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** The Endpoint is the link between the call and the port. **
** **
\*****************************************************************************/
#include <stdio.h>
#include "main.h"
unsigned long epoint_serial = 1; /* initial value must be 1, because 0== no epoint */
class Endpoint *epoint_first = NULL;
/*
* find the epoint with epoint_id
*/
class Endpoint *find_epoint_id(unsigned long epoint_id)
{
class Endpoint *epoint = epoint_first;
while(epoint)
{
//printf("comparing: '%s' with '%s'\n", name, epoint->name);
if (epoint->ep_serial == epoint_id)
return(epoint);
epoint = epoint->next;
}
return(NULL);
}
/*
* endpoint constructor (link with either port or call id)
*/
Endpoint::Endpoint(int port_id, int call_id)
{
class Port *port;
class Endpoint **epointpointer;
/* epoint structure */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Allocating enpoint %d and connecting it with:%s%s\n", epoint_serial, epoint_serial, (port_id)?" ioport":"", (call_id)?" call":"");
ep_portlist = NULL;
ep_app = NULL;
ep_use = 1;
/* add endpoint to chain */
next = NULL;
epointpointer = &epoint_first;
while(*epointpointer)
epointpointer = &((*epointpointer)->next);
*epointpointer = this;
/* serial */
ep_serial = epoint_serial++;
/* link to call or port */
if (port_id)
{
port = find_port_id(port_id);
if (port)
if (!portlist_new(port_id, port->p_type))
{
PERROR("no mem for portlist, exitting...\n");
exit(-1);
}
}
ep_call_id = call_id;
ep_park = 0;
ep_park_len = 0;
classuse++;
}
/*
* endpoint destructor
*/
Endpoint::~Endpoint(void)
{
class Endpoint *temp, **tempp;
struct port_list *portlist, *mtemp;
classuse--;
/* remote application */
if (ep_app)
delete ep_app;
/* free relations */
if (ep_call_id)
{
PERROR("warning: still relation to call.\n");
}
/* free portlist */
portlist = ep_portlist;
while(portlist)
{
if (portlist->port_id)
{
PERROR("warning: still relation to port (portlist list)\n");
}
mtemp = portlist;
portlist = portlist->next;
memset(mtemp, 0, sizeof(struct port_list));
free(mtemp);
ememuse--;
}
/* detach */
temp =epoint_first;
tempp = &epoint_first;
while(temp)
{
if (temp == this)
break;
tempp = &temp->next;
temp = temp->next;
}
if (temp == 0)
{
PERROR("error: endpoint not in endpoint's list, exitting.\n");
exit(-1);
}
*tempp = next;
/* free */
PDEBUG(DEBUG_EPOINT, "removed endpoint %d.\n", ep_serial);
}
/* create new portlist relation
*/
struct port_list *Endpoint::portlist_new(unsigned long port_id, int port_type)
{
struct port_list *portlist, **portlistpointer;
/* portlist structure */
portlist = (struct port_list *)calloc(1, sizeof(struct port_list));
if (!portlist)
{
PERROR("no mem for allocating port_list\n");
return(0);
}
ememuse++;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocating port_list.\n", ep_serial);
memset(portlist, 0, sizeof(struct port_list));
/* add port_list to chain */
portlist->next = NULL;
portlistpointer = &ep_portlist;
while(*portlistpointer)
portlistpointer = &((*portlistpointer)->next);
*portlistpointer = portlist;
/* link to call or port */
portlist->port_id = port_id;
portlist->port_type = port_type;
return(portlist);
}
/* free portlist relation
*/
void Endpoint::free_portlist(struct port_list *portlist)
{
struct port_list *temp, **tempp;
temp = ep_portlist;
tempp = &ep_portlist;
while(temp)
{
if (temp == portlist)
break;
tempp = &temp->next;
temp = temp->next;
}
if (temp == 0)
{
PERROR("port_list not in endpoint's list, exitting.\n");
exit(-1);
}
/* detach */
*tempp=portlist->next;
/* free */
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removed port_list from endpoint\n", ep_serial);
memset(portlist, 0, sizeof(struct port_list));
free(portlist);
ememuse--;
}
/* handler for endpoint
*/
int Endpoint::handler(void)
{
if (ep_use <= 0)
{
delete this;
return(-1);
}
/* call application handler */
if (ep_app)
return(ep_app->handler());
return(0);
}

53
endpoint.h Normal file
View File

@ -0,0 +1,53 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** Endpoint header file **
** **
\*****************************************************************************/
/* structure of port_list */
struct port_list {
struct port_list *next;
unsigned long port_id;
int port_type;
};
/* structure of an Enpoint */
class Endpoint
{
public:
Endpoint(int port_id, int call_id);
~Endpoint();
class Endpoint *next; /* next in list */
unsigned long ep_serial; /* a unique serial to identify */
int handler(void);
/* applocaton relation */
class EndpointApp *ep_app; /* link to application class */
/* port relation */
struct port_list *ep_portlist; /* link to list of ports */
struct port_list *portlist_new(unsigned long port_id, int port_type);
void free_portlist(struct port_list *portlist);
/* call relation */
unsigned long ep_call_id; /* link to call */
/* if still used by threads */
int ep_use;
/* application indipendant states */
int ep_park; /* indicates that the epoint is parked */
unsigned char ep_park_callid[8];
int ep_park_len;
};
extern class Endpoint *epoint_first;
class Endpoint *find_epoint_id(unsigned long epoint_id);

49
endpointapp.cpp Normal file
View File

@ -0,0 +1,49 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** The EndpointApp represents the application for the Endpoint. **
** **
\*****************************************************************************/
#include <stdio.h>
#include "main.h"
/*
* EndpointApp constructor
*/
EndpointApp::EndpointApp(class Endpoint *epoint)
{
ea_endpoint = epoint;
classuse++;
}
/*
* endpoint destructor
*/
EndpointApp::~EndpointApp(void)
{
classuse--;
}
int EndpointApp::handler(void)
{
return(0);
}
/* mini application for test purpose only */
void EndpointApp::ea_message_port(unsigned long port_id, int message_type, union parameter *param)
{
PDEBUG(DEBUG_EPOINT, "%s: Spare function.\n", __FUNCTION__);
}
void EndpointApp::ea_message_call(unsigned long port_id, int message_type, union parameter *param)
{
PDEBUG(DEBUG_EPOINT, "%s: Spare function.\n", __FUNCTION__);
}

25
endpointapp.h Normal file
View File

@ -0,0 +1,25 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** EndpointApp header file **
** **
\*****************************************************************************/
/* structure of an EndpointApp */
class EndpointApp
{
public:
EndpointApp(class Endpoint *epoint);
virtual ~EndpointApp();
class Endpoint *ea_endpoint;
virtual int handler(void);
virtual void ea_message_port(unsigned long port_id, int message, union parameter *param);
virtual void ea_message_call(unsigned long call_id, int message, union parameter *param);
};

2070
extension.c Normal file

File diff suppressed because it is too large Load Diff

187
extension.h Normal file
View File

@ -0,0 +1,187 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** extension header file **
** **
\*****************************************************************************/
/* display of callerid on internal numbers */
enum {
DISPLAY_CID_ASIS, /* with type as defined */
DISPLAY_CID_NUMBER, /* "5551212" */
DISPLAY_CID_ABBREVIATION, /* "05" */
DISPLAY_CID_NAME, /* "Axel" */
DISPLAY_CID_NAME_NUMBER, /* "Axel 5551212" */
DISPLAY_CID_NUMBER_NAME, /* "5551212 Axel" */
DISPLAY_CID_ABBREV_NUMBER, /* "05 5551212" */
DISPLAY_CID_ABBREV_NAME, /* "05 Axel" */
DISPLAY_CID_ABBREV_NUMBER_NAME, /* "05 5551212 Axel" */
DISPLAY_CID_ABBREV_NAME_NUMBER, /* "05 Axel 5551212" */
};
enum {
DISPLAY_CID_INTERNAL_OFF, /* "20" */
DISPLAY_CID_INTERNAL_ON, /* "Intern 20" */
};
/* display of clear causes using display messages */
enum {
DISPLAY_CAUSE_NONE,
DISPLAY_CAUSE_ENGLISH, /* "34 - no channel" */
DISPLAY_CAUSE_GERMAN, /* "34 - kein Kanal" */
DISPLAY_LOCATION_ENGLISH, /* "34 - Network (Remote)" */
DISPLAY_LOCATION_GERMAN, /* "34 - Vermittlung (Gegenstelle)" */
DISPLAY_CAUSE_NUMBER, /* "Cause 34" */
};
/* clip */
enum {
CLIP_ASIS, /* use colp as presented by caller */
CLIP_HIDE, /* use extension's caller id */
};
/* colp */
enum {
COLP_ASIS, /* use colp as presented by called */
COLP_HIDE, /* use extension's caller id */
COLP_FORCE, /* use colp even if called dosn't provide or allow */
};
/* codec to use */
enum {
CODEC_OFF, /* record wave off */
CODEC_MONO, /* record wave mono */
CODEC_STEREO, /* record wave stereo */
CODEC_8BIT, /* record wave mono 8bit */
CODEC_LAW, /* record LAW */
};
/* VBOX mode */
enum {
VBOX_MODE_NORMAL, /* normal mode: send announcement, then record */
VBOX_MODE_PARALLEL, /* parallel mode: send announcement and record during announcement */
VBOX_MODE_ANNOUNCEMENT, /* announcement mode: send announcement and disconnect */
};
/* VBOX display */
enum {
VBOX_DISPLAY_BRIEF, /* parallel mode: send announcement and record during announcement */
VBOX_DISPLAY_DETAILED, /* announcement mode: send announcement and disconnect */
VBOX_DISPLAY_OFF, /* normal mode: send announcement, then record */
};
/* VBOX language */
enum {
VBOX_LANGUAGE_ENGLISH, /* display and announcements are in english */
VBOX_LANGUAGE_GERMAN, /* display and announcements are in german */
};
/* dsptones */
enum {
DSP_NONE,
DSP_AMERICAN,
DSP_GERMAN,
DSP_OLDGERMAN,
};
/* extensions
*
* extensions are settings saved at <extensions_dir>/<extension>/settings
* they carry all information and permissions about an extension
* they will be loaded when needed and saved when changed
*/
struct extension {
char name[16];
char prefix[32];
char next[32]; /* next number to dial when pickup (temp prefix) */
char alarm[32];
char cfb[256];
char cfu[256];
char cfnr[256];
int cfnr_delay;
int change_forward;
char cfp[256];
char interfaces[128];
char callerid[32];
int callerid_type;
int callerid_present;
char id_next_call[32];
int id_next_call_type;
int id_next_call_present;
int change_callerid;
int clip; /* how to present caller id on forwarded calls */
int colp; /* how to present called line id on forwarded calls */
char clip_prefix[32]; /* prefix for screening incomming clip */
int keypad; /* support keypad for call control */
int centrex; /* present name of caller/called on internal extension */
int anon_ignore; /* ignore anonymouse calls */
int rights;
int delete_ext; /* delete function for external dialing */
int noknocking; /* deny knocking of incoming call */
char last_out[MAX_REMEMBER][64]; /* numbers to redail */
char last_in[MAX_REMEMBER][64]; /* numbers to reply */
int txvol;
int rxvol;
int display_cause; /* clear cause using display message */
int display_ext; /* display external caller ids */
int display_int; /* display internal caller ids */
int display_voip; /* display h323 caller ids */
int display_fake; /* display fake caller ids */
int display_anon; /* display anonymouse caller ids */
int display_menu; /* display menu */
int display_dialing; /* display interpreted digits while dialing */
int display_name; /* display caller's name if available (CNIP) */
char tones_dir[64]; /* directory of all tones/patterns */
int record; /* SEE RECORD_* */
char password[64]; /* callback / login password */
int vbox_mode; /* see VBOX_MODE_* */
int vbox_codec; /* see CODEC_* */
int vbox_time; /* time to recorde, 0=infinite */
int vbox_display; /* see VBOX_DISPLAY_* */
int vbox_language; /* see VBOX_LANGUAGE_* */
char vbox_email[128]; /* send mail if given */
int vbox_email_file; /* set, if also the audio fille will be attached */
int vbox_free; /* if vbox shall connect after announcment */
int tout_setup;
int tout_dialing;
int tout_proceeding;
int tout_alerting;
int tout_disconnect;
// int tout_hold;
// int tout_park;
int own_setup;
int own_proceeding;
int own_alerting;
int own_cause;
int facility; /* must be set to forward facility to terminal */
int datacall; /* data calls are handled as voice calls */
int no_seconds; /* don't include seconds in the connect message */
};
int read_extension(struct extension *ext, char *number);
int write_extension(struct extension *ext, char *number);
int write_log(char *number, char *callerid, char *calledid, time_t start, time_t stop, int aoce, int cause, int location);
int parse_phonebook(char *number, char **abbrev_pointer, char **phone_pointer, char **name_pointer);
int parse_secrets(char *number, char *remote_id, char **auth_pointer, char **crypt_pointer, char **key_pointer);
char *parse_directory(char *number, int type);
int parse_callbackauth(char *number, struct caller_info *callerinfo);
void append_callbackauth(char *number, struct caller_info *callerinfo);

148
genext.c Normal file
View File

@ -0,0 +1,148 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** generate extension **
** **
\*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include "main.h"
int memuse = 0;
int mmemuse = 0;
int cmemuse = 0;
int ememuse = 0;
int pmemuse = 0;
int classuse = 0;
int fduse = 0;
int fhuse = 0;
struct isdn_cause isdn_cause[128];
struct isdn_location isdn_location[16];
void _printdebug(const char *function, int line, unsigned long mask, const char *fmt, ...)
{
}
void _printerror(const char *function, int line, const char *fmt, ...)
{
char buffer[4096];
va_list args;
va_start(args,fmt);
VUNPRINT(buffer,sizeof(buffer)-1,fmt,args);
buffer[sizeof(buffer)-1]=0;
va_end(args);
fprintf(stderr, "%s", buffer);
}
int main(int argc, char *argv[])
{
struct extension ext;
char pathname[256];
FILE *fp;
if (!read_options())
{
PERROR("Failed to read options.conf\n");
return(-1);
}
if (argc != 4)
{
printf("Usage: %s <extension> <interfaces> <callerid>\n\n", argv[0]);
printf("extension: any number for the extension (e.g 200)\n");
printf("interfaces: internal interface(es) to reach extension (seperated by commas. e.g Int1,Int2)\n");
printf("callerid: normal undefined called is (use what your telco assigned you)\n");
return(0);
}
SPRINT(pathname, "%s/%s/%s", INSTALL_DATA, options.extensions_dir, argv[1]);
if (mkdir(pathname, 0755) < 0)
{
if (errno == EEXIST)
PERROR("Extension's directory already exists. Nothing done!\n");
else PERROR("Cannot open extension's directory '%s'.\n", pathname);
return(-1);
}
memset(&ext, 0, sizeof(ext));
ext.rights = 4;
ext.tout_setup = 120;
ext.tout_dialing = 120;
ext.tout_proceeding = 120;
ext.tout_alerting = 120;
ext.tout_disconnect = 120;
// ext.tout_hold = 900;
// ext.tout_park = 900;
ext.cfnr_delay = 20;
ext.vbox_codec = CODEC_MONO;
UCPY(ext.interfaces, argv[2]);
UCPY(ext.callerid, argv[3]);
ext.callerid_present = INFO_PRESENT_ALLOWED;
ext.callerid_type = INFO_NTYPE_UNKNOWN;
ext.change_forward = 1;
ext.facility = 1;
write_extension(&ext, argv[1]);
SPRINT(pathname, "%s/%s/%s/phonebook", INSTALL_DATA, options.extensions_dir, argv[1]);
if (!(fp = fopen(pathname, "w")))
{
PERROR("Failed to write phonebook example '%s'.\n", pathname);
return(-1);
} else
{
fprintf(fp, "# fromat: <shortcut> <phone number> [<Name>]\n");
fprintf(fp, "# The shotcut may have any number of digits. \n");
fprintf(fp, "# The phone number must include the dialing code for external, internal or\n");
fprintf(fp, "# other type of dialing. \n");
fprintf(fp, "# The name must not be in quotes. All 2 or 3 attributes must be seperated by\n");
fprintf(fp, "# white space(s) and/or tab(s)\n");
fprintf(fp, "# Empty lines and lines starting with '#' will be ignored.\n");
fprintf(fp, "\n");
fprintf(fp, "0 008003301000 German Telekom Service\n");
fprintf(fp, "10 011880 Directory Service Telegate\n");
fprintf(fp, "11 011833 Directory Service DTAG\n");
fprintf(fp, "12 011811 Directory Service Fred\n");
fclose(fp);
}
SPRINT(pathname, "%s/%s/%s/secrets", INSTALL_DATA, options.extensions_dir, argv[1]);
if (!(fp = fopen(pathname, "w")))
{
PERROR("Failed to write secrets example '%s'.\n", pathname);
return(-1);
} else
{
fprintf(fp, "# Format: <remote number> <key exchange> <cypher> [<key>]\n");
fprintf(fp, "# The remote number must match the dialed number for outgoing calls.\n");
fprintf(fp, "# The remote number must match the caller id for incoming calls.\n");
fprintf(fp, "# The caller id must include the prefix digits as received.\n");
fprintf(fp, "# The key exchange method must be given: e.g 'manual'\n");
fprintf(fp, "# The cypher method must be given: e.g 'blowfish'\n");
fprintf(fp, "# The key must be a string of characters (ASCII) or 0xXXXXXX...\n");
fprintf(fp, "# All 2 or 3 attributes must be seperated by white space(s) and/or tab(s)\n");
fprintf(fp, "# Empty lines and lines starting with '#' will be ignored.\n\n");
fprintf(fp, "###############################################################################\n");
fprintf(fp, "## REFER TO THE DOCUMENTATION FOR DETAILS ON ENCRYPTION AND KEYS! ##\n");
fprintf(fp, "###############################################################################\n");
fprintf(fp, "\n");
fprintf(fp, "# This examples explains the format, NEVER USE IT, it would be dumb!\n");
fprintf(fp, "021250993 manual blowfish 0x012345678\n");
fclose(fp);
}
printf("Extension %s created at %s/%s/%s/.\n", argv[1], INSTALL_DATA, options.extensions_dir, argv[1]);
return(0);
}

268
genrc.c Normal file
View File

@ -0,0 +1,268 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** generate start/stop script **
** **
\*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "save.h"
char mode[256];
int type[256];
int ptp[256];
int port[256];
char name[256];
int coredebug=0, carddebug=0, l1debug=0, l2debug=0, l3debug=0, dspdebug=0;
int lawopt=0;
static struct cards {
char *card;
char *module;
int ntmode;
int isac;
int ports;
} cards[] = {
{ "AVM Fritz PCI (PNP)", "avmfritz", 0, 1, 1},
{ "HFC PCI (Cologne Chip)", "hfcpci", 1, 0, 1},
{ "HFC-4S 4 S/T Ports (Cologne Chip)", "hfcmulti", 1, 0, 4},
{ "HFC-8S 8 S/T Ports (Cologne Chip)", "hfcmulti", 1, 0, 8},
{ "HFC-E1 1 E1 Port (Cologne Chip)", "hfcmulti", 1, 0, 1},
{ "HFC-S USB (Cologne Chip)", "hfcsusb", 1, 0, 1},
{ "HFC-S MINI (Cologne Chip)", "hfcsmini", 1, 0, 1},
{ "XHFC (Cologne Chip)", "xhfc", 1, 0, 1},
{ "Sedlbaur FAX", "sedlfax", 0, 1, 1},
{ "Winbond 6692 PCI", "w6692pci", 0, 0, 1},
{ NULL, NULL, 0, 0},
};
int main(void)
{
FILE *fp;
int i = 0, j, jj, n, anyte = 0, remove_isac;
char input[256];
char protocol[1024], layermask[1024], types[256];
printf("\n\nThis program generates a script, which is used to start/stop/restart mISDN\n");
printf("driver. All configuration of cards is done for using with the PBX.\n");
while(i < (int)sizeof(mode)) /* number of cards */
{
moreports:
do
{
printf("\nEnter mode of isdn port #%d. Should it run in NT-mode (for internal\nphones), or in TE-mode (for external lines)? If you do not like to add more\ncards, say 'done'.\n[nt | te | done]: ", i+1); fflush(stdout);
scanf("%s", input);
} while (input[0]!='t' && input[0]!='n' && input[0]!='d');
mode[i] = input[0];
if (mode[i] == 'd')
break;
ptp[i] = 0;
do
{
printf("\nIs your port #%d connected to point-to-multipoint line/phone, which supports multiple\ntelephones (Mehrgeräteanschluss) OR is it a point-to-point link which is used\nfor PBX and supports extension dialing (Anlagenanschluss)?\n[ptp | ptm]: ", i+1); fflush(stdout);
scanf("%s", input);
} while (!!strcmp(input,"ptp") && !!strcmp(input,"ptm"));
ptp[i] = (input[2]=='p')?1:0;
anyte = 1;
if (!i)
{
askcard:
do
{
printf("\nSelect driver of ISDN port #%d.\n\n", i+1);
jj = 0;
while(cards[jj].card)
{
if (cards[jj].ntmode || mode[i]!='n')
printf(" (%d) %s\n", jj+1, cards[jj].card);
jj++;
}
printf("\n%sSelect card number[1-n]: ", (mode[i]=='n')?"Your card will run in NT-mode. The shown cards are capable of providing\nhardware layer for NT-mode.\n":""); fflush(stdout);
scanf("%s", input);
} while (atoi(input) <= 0);
type[i] = atoi(input);
port[i] = 1;
j = 0;
while(j < jj)
{
if (j+1==type[i] && (cards[j].ntmode || mode[i]!='n'))
break;
j++;
}
if (j == jj)
{
printf("\n\nWrong selection, please try again.\n");
goto askcard;
}
} else
if (cards[type[i-1]-1].ports == port[i-1])
goto askcard;
else {
type[i] = type[i-1];
port[i] = port[i-1]+1;
printf("\nUsing port %d of card '%s'.", port[i], cards[type[i]-1].card);
}
printf("\n\n\nSummary: Port #%d of type %s will run in %s-mode and %s-mode.\n", i+1, cards[type[i]-1].card, (mode[i]=='n')?"NT":"TE", (ptp[i])?"point-to-point":"point-to-multipoint");
i++;
}
if (!i)
{
printf("\nNo ports/cards defined!\n");
return(-1);
}
if (cards[type[i-1]-1].ports > port[i-1])
{
printf("\nNot all ports for the last card are defined. Please do that even if they will be not\nused! Select 'NT-mode' for these unused ports.\n");
goto moreports;
}
printf("\nEnter LAW audio mode. For a-LAW (default), just enter 0. For u-LAW enter 1.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
lawopt = strtoul(input, NULL, 0);
printf("\nEnter debugging flags of mISDN core. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
coredebug = strtoul(input, NULL, 0);
printf("\nEnter debugging flags of cards. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
carddebug = strtoul(input, NULL, 0);
printf("\nEnter l1 debugging flags of driver. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
l1debug = strtoul(input, NULL, 0);
printf("\nEnter l2 debugging flags of driver. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
l2debug = strtoul(input, NULL, 0);
printf("\nEnter l3 debugging flags of driver. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
l3debug = strtoul(input, NULL, 0);
printf("\nEnter dsp debugging flags of driver. For no debug, just enter 0.\n[0..n | 0xn]: "); fflush(stdout);
scanf("%s", input);
dspdebug = strtoul(input, NULL, 0);
n = i;
printf("\nWhere do you like to load the modules from, enter 0 for default, 1 for\n'/usr/local/pbx/modules/' or the full path.\n[0 | 1 | <path>]: "); fflush(stdout);
scanf("%s", input);
if (!strcmp(input, "0"))
SCPY(input, "");
if (!strcmp(input, "1"))
SCPY(input, "/usr/local/pbx/modules");
if (input[0]) if (input[strlen(input)-1] != '/')
SCAT(input, "/");
printf("\n\nFinally tell me where to write the mISDN rc file.\Enter the name 'mISDN' for current directory.\nYou may want to say '/usr/local/pbx/mISDN' or '/etc/rc.d/mISDN'\n: "); fflush(stdout);
scanf("%s", name);
if (!(fp=fopen(name, "w")))
{
fprintf(stderr, "\nError: Failed to open '%s', try again.\n", name);
exit(-1);
}
fprintf(fp, "# rc script for mISDN driver\n\n");
fprintf(fp, "case \"$1\" in\n");
fprintf(fp, "\tstart|--start)\n");
fprintf(fp, "\t\t%s %smISDN_core%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", coredebug);
if (anyte)
{
fprintf(fp, "\t\t%s %smISDN_l1%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", l1debug);
fprintf(fp, "\t\t%s %smISDN_l2%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", l2debug);
fprintf(fp, "\t\t%s %sl3udss1%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", l3debug);
}
fprintf(fp, "\t\t%s %smISDN_dsp%s debug=0x%x options=0x%x\n", input[0]?"insmod -f":"modprobe", input, input[0]?".ko":"", dspdebug, lawopt);
j = 0;
while(cards[j].card)
{
protocol[0] = layermask[0] = types[0] = '\0';
i = 0;
while(i < n)
{
if (j+1 == type[i])
{
if (!strcmp(cards[j].module, "hfcmulti") && port[i]==1)
UPRINT(strchr(types,'\0'), "0x%x,", cards[j].ports+((lawopt)?0x100:0)+0x200);
UPRINT(strchr(protocol,'\0'), "0x%x,", ((mode[i]=='n')?0x12:0x2) + (ptp[i]?0x20:0x0));
UPRINT(strchr(layermask,'\0'), "0x%x,", (mode[i]=='n')?0x3:0x0f);
}
i++;
}
if (protocol[0])
{
protocol[strlen(protocol)-1] = '\0';
layermask[strlen(layermask)-1] = '\0';
if (types[0])
{
types[strlen(types)-1] = '\0';
fprintf(fp, "\t\t%s %s%s%s type=%s protocol=%s layermask=%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, cards[j].module, input[0]?".ko":"", types, protocol, layermask, carddebug);
} else
fprintf(fp, "\t\t%s %s%s%s protocol=%s layermask=%s debug=0x%x\n", input[0]?"insmod -f":"modprobe", input, cards[j].module, input[0]?".ko":"", protocol, layermask, carddebug);
}
j++;
}
fprintf(fp, "\t\tsleep 1\n");
fprintf(fp, "\t\t;;\n\n");
fprintf(fp, "\tstop|--stop)\n");
remove_isac = 0;
j = 0;
while(cards[j].card)
{
protocol[0] = 0;
i = 0;
while(i < n)
{
if (j+1 == type[i])
{
protocol[0] = 1;
}
i++;
}
if (protocol[0])
{
fprintf(fp, "\t\trmmod %s\n", cards[j].module);
if (cards[j].isac)
remove_isac = 1;
}
j++;
}
if (remove_isac)
{
fprintf(fp, "\t\trmmod mISDN_isac\n");
}
fprintf(fp, "\t\trmmod mISDN_dsp\n");
if (anyte)
{
fprintf(fp, "\t\trmmod l3udss1\n");
fprintf(fp, "\t\trmmod mISDN_l2\n");
fprintf(fp, "\t\trmmod mISDN_l1\n");
}
fprintf(fp, "\t\trmmod mISDN_core\n");
fprintf(fp, "\t\t;;\n\n");
fprintf(fp, "\trestart|--restart)\n");
fprintf(fp, "\t\tsh $0 stop\n");
fprintf(fp, "\t\tsleep 2 # some phones will release tei when layer 1 is down\n");
fprintf(fp, "\t\tsh $0 start\n");
fprintf(fp, "\t\t;;\n\n");
fprintf(fp, "\thelp|--help)\n");
fprintf(fp, "\t\techo \"Usage: $0 {start|stop|restart|help}\"\n");
fprintf(fp, "\t\texit 0\n");
fprintf(fp, "\t\t;;\n\n");
fprintf(fp, "\t*)\n");
fprintf(fp, "\t\techo \"Usage: $0 {start|stop|restart|help}\"\n");
fprintf(fp, "\t\texit 2\n");
fprintf(fp, "\t\t;;\n\n");
fprintf(fp, "esac\n");
fclose(fp);
printf("\nFile '%s' is written to the current directory.\n", name);
}

379
gentones.c Normal file
View File

@ -0,0 +1,379 @@
/* isdn tone generation
by jolly
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
/* ulaw -> signed 16-bit */
static short isdn_audio_ulaw_to_s16[] =
{
0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
};
/* alaw -> signed 16-bit */
static short isdn_audio_alaw_to_s16[] =
{
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
};
unsigned char encode_isdn(short sample, char law)
{
int best=-1;
int i,diff;
int best_diff;
i=0;
while(i<256)
{
diff = (law=='u')?isdn_audio_ulaw_to_s16[i]:isdn_audio_alaw_to_s16[i]-sample;
//printf("s16=%d sample%d diff=%d\n",isdn_audio_to_s16[i],sample,diff);
if (diff<0)
diff=0-diff;
//printf("diff=%d\n",diff);
if (diff<best_diff || best<0)
{
//printf("better %d\n",i);
best_diff=diff;
best=i;
}
i++;
}
return(best);
}
void write_tone(FILE *fp,double t1,double t2,int length,int fade_in,int fade_out, char law)
{
double x,s,t,fade;
int i;
i=0;
while(i<length)
{
if (i < fade_in)
fade=(double)i / (double)fade_in;
else fade=1.0;
if (length-1-i < fade_out)
fade=((double)length-1.0-(double)i) / (double)fade_out;
s = (double)i / 8000.0 * (double)t1 * 3.1415927F * 2.0;
t = (double)i / 8000.0 * (double)t2 * 3.1415927F * 2.0;
x = sin(s)+sin(t);
//printf("%e,%e,%e\n",s,t,x);
fputc(encode_isdn((short)(x * 6000.0 * fade), law),fp);
i++;
}
}
struct fmt {
unsigned short stereo; /* 1 = pcm, 2 = adpcm */
unsigned short channels; /* number of channels */
unsigned long sample_rate; /* sample rate */
unsigned long data_rate; /* data rate */
unsigned short bytes_sample; /* bytes per sample (all channels) */
unsigned short bits_sample; /* bits per sample (one channel) */
};
void write_wav(FILE *fp, char *wav, char law)
{
unsigned char buffer[256];
struct fmt *fmt;
FILE *wfp;
signed long i;
int channels, bytes;
short sample, sample2;
signed long size, chunk;
int gotfmt = 0, gotdata = 0;
if ((wfp=fopen(wav,"r")))
{
fread(buffer,8,1,wfp);
size=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
if (!!strncmp((char *)buffer, "RIFF", 4))
{
fclose(wfp);
fprintf(stderr, "Error: %s is no riff file!\n", wav);
return;
}
printf("%c%c%c%c size=%ld\n",buffer[0],buffer[1],buffer[2],buffer[3],size);
fread(buffer,4,1,wfp);
size -= 4;
if (!!strncmp((char *)buffer, "WAVE", 4))
{
fclose(wfp);
fprintf(stderr, "Error: %s is no wave file!\n", wav);
return;
}
while(size > 0)
{
if (size>0 && size<8)
{
fclose(wfp);
fprintf(stderr, "Error: Remaining file size %ld not large enough for next chunk.\n",size);
return;
}
fread(buffer,8,1,wfp);
chunk=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
//printf("DEBUG: size(%ld) - (8+chunk(%ld) = size(%ld)\n", size, chunk, size-chunk-8);
size -= (8+chunk);
if (size < 0)
{
fclose(wfp);
fprintf(stderr, "Error: Chunk '%c%c%c%c' is larger than remainig file size (length=%ld)\n",buffer[0],buffer[1],buffer[2],buffer[3], chunk);
return;
}
// printf("%c%c%c%c lenght=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],chunk);
if (!strncmp((char *)buffer, "fmt ", 4))
{
if (chunk != 16)
{
fclose(wfp);
fprintf(stderr, "Error: Fmt chunk illegal size.\n");
return;
}
fread(buffer, chunk, 1, wfp);
fmt = (struct fmt *)buffer;
if (fmt->channels<1 || fmt->channels>2)
{
fclose(wfp);
fprintf(stderr, "Error: Only support one or two channels file.\n");
return;
}
channels = fmt->channels;
printf("Channels: %d\n", channels);
if (fmt->sample_rate != 8000)
{
fprintf(stderr, "Warning: File has sample rate of %ld.\n", fmt->sample_rate);
}
printf("Sample Rate: %ld\n", fmt->sample_rate);
if (fmt->bits_sample!=8 && fmt->bits_sample!=16)
{
fclose(wfp);
fprintf(stderr, "Error: File has neigher 8 nor 16 bit samples.\n");
return;
}
bytes = (fmt->bits_sample==16)?2:1;
printf("Bit-Resolution: %d\n", bytes*16-16);
gotfmt = 1;
} else
if (!strncmp((char *)buffer, "data", 4))
{
if (!gotfmt)
{
fclose(wfp);
fprintf(stderr, "Error: No fmt chunk fount in file.\n");
return;
}
printf("Length: %ld samples (%ld.%03ld seconds)\n", chunk/bytes/channels, chunk/bytes/channels/8000, ((chunk/bytes/channels)%8000)*1000/8000);
i=0;
if (bytes==2 && channels==1)
{
while(i<chunk)
{
fread(buffer, 2, 1, wfp);
sample=(buffer[1]<<8) + (buffer[0]);
fputc(encode_isdn(sample, law),fp);
i+=2;
}
}
if (bytes==2 && channels==2)
{
while(i<chunk)
{
fread(buffer, 4, 1, wfp);
sample=(buffer[1]<<8) + (buffer[0]);
sample2=(buffer[3]<<8) + (buffer[2]);
sample = (sample/2) + (sample2/2);
fputc(encode_isdn(sample, law),fp);
i+=4;
}
}
if (bytes==1 && channels==1)
{
while(i<chunk)
{
fread(buffer, 1, 1, wfp);
sample=(buffer[0]<<8);
fputc(encode_isdn(sample, law),fp);
i+=1;
}
}
if (bytes==1 && channels==2)
{
while(i<chunk)
{
fread(buffer, 2, 1, wfp);
sample=(buffer[0]<<8);
sample2=(buffer[1]<<8);
sample = (sample/2) + (sample2/2);
fputc(encode_isdn(sample, law),fp);
i+=2;
}
}
gotdata = 1;
} else
{
printf("Ignoring chunk '%c%c%c%c' (length=%ld)\n",buffer[0],buffer[1],buffer[2],buffer[3], chunk);
while(chunk > (signed long)sizeof(buffer))
{
fread(buffer, sizeof(buffer), 1, wfp);
chunk -= sizeof(buffer);
}
if (chunk)
fread(buffer, chunk, 1, wfp);
}
}
fclose(wfp);
if (!gotdata)
{
fprintf(stderr, "Error: No data chunk fount in file.\n");
return;
}
}
}
int main(int argc, char *argv[])
{
FILE *fp;
if (argc <= 1)
{
usage:
printf("Usage:\n");
printf("%s wave2alaw <wav file> <alaw file>\n", argv[0]);
printf("%s wave2ulaw <wav file> <ulaw file>\n", argv[0]);
printf("%s tone2alaw <frq1> <frq2> <length> <fade in> <fade out> <alaw file>\n", argv[0]);
printf("%s tone2ulaw <frq1> <frq2> <length> <fade in> <fade out> <ulaw file>\n", argv[0]);
printf("Length and fade lengths must be given in samples (8000 samples are one second).\n");
printf("Tones will append to existing files, wav files don't.\n");
printf("Frequencies may be given as floating point values.\n");
return(0);
}
if (!strcmp(argv[1], "wave2alaw"))
{
if (argc <= 3)
goto usage;
if ((fp=fopen(argv[3],"w")))
{
write_wav(fp,argv[2],'a');
fclose(fp);
} else
{
printf("Cannot open isdn file %s\n",argv[3]);
}
} else
if (!strcmp(argv[1], "wave2ulaw"))
{
if (argc <= 3)
goto usage;
if ((fp=fopen(argv[3],"w")))
{
write_wav(fp,argv[2],'u');
fclose(fp);
} else
{
printf("Cannot open isdn file %s\n",argv[3]);
}
} else
if (!strcmp(argv[1], "tone2alaw"))
{
if (argc <= 7)
goto usage;
if ((fp=fopen(argv[7],"a")))
{
write_tone(fp,strtod(argv[2],NULL),strtod(argv[3],NULL),atoi(argv[4]),atoi(argv[5]),atoi(argv[6]),'a');
fclose(fp);
} else
{
printf("Cannot open isdn file %s\n",argv[7]);
}
} else
if (!strcmp(argv[1], "tone2ulaw"))
{
if (argc <= 7)
goto usage;
if ((fp=fopen(argv[7],"a")))
{
write_tone(fp,atoi(argv[2]),atoi(argv[3]),atoi(argv[4]),atoi(argv[5]),atoi(argv[6]),'u');
fclose(fp);
} else
{
printf("Cannot open isdn file %s\n",argv[7]);
}
} else
goto usage;
return(0);
}

197
genwave.c Normal file
View File

@ -0,0 +1,197 @@
/* isdn 2 wave
by jolly
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
/* ulaw -> signed 16-bit */
static short isdn_audio_ulaw_to_s16[] =
{
0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84,
0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84,
0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84,
0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84,
0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804,
0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004,
0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444,
0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844,
0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64,
0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64,
0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74,
0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74,
0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc,
0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c,
0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0,
0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000,
0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c,
0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c,
0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c,
0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c,
0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc,
0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc,
0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc,
0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc,
0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c,
0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c,
0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c,
0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c,
0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104,
0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084,
0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040,
0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
};
/* alaw -> signed 16-bit */
static short isdn_audio_alaw_to_s16[] =
{
0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4,
0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74,
0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4,
0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64,
0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4,
0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4,
0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4,
0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4,
0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64,
0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34,
0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844,
0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24,
0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64,
0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4,
0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964,
0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4,
0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24,
0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94,
0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924,
0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94,
0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24,
0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14,
0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24,
0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14,
0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4,
0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54,
0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4,
0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64,
0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4,
0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4,
0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4,
0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4
};
struct fmt {
unsigned short stereo; /* 1 = pcm, 2 = adpcm */
unsigned short channels; /* number of channels */
unsigned long sample_rate; /* sample rate */
unsigned long data_rate; /* data rate */
unsigned short bytes_sample; /* bytes per sample (all channels) */
unsigned short bits_sample; /* bits per sample (one channel) */
};
void write_law(FILE *fp, char *name, char law)
{
unsigned char buffer[256];
struct fmt fmt;
FILE *lfp;
unsigned long i;
short sample;
unsigned long size, wsize;
if ((lfp=fopen(name,"r")))
{
/* get size */
fseek(lfp, 0, SEEK_END);
size = ftell(lfp);
printf("samples: %ld\n", size);
size += size;
fseek(lfp, 0, SEEK_SET);
wsize = 4+8+sizeof(fmt)+8+size+8+4+8+4;
/* RIFF */
fprintf(fp, "RIFF%c%c%c%c", (char)(wsize&0xff), (char)((wsize>>8)&0xff), (char)((wsize>>16)&0xff), (char)(wsize>>24));
/* WAVE */
fprintf(fp, "WAVE");
/* fmt */
fprintf(fp, "fmt %c%c%c%c", sizeof(fmt), 0, 0, 0);
fmt.stereo = 1;
fmt.channels = 1;
fmt.sample_rate = 8000;
fmt.data_rate = 16000;
fmt.bytes_sample = 2;
fmt.bits_sample = 16;
fwrite(&fmt, sizeof(fmt), 1, fp);
/* data */
fprintf(fp, "data%c%c%c%c", (char)(size&0xff), (char)((size>>8)&0xff), (char)((size>>16)&0xff), (char)(size>>24));
i = 0;
while(i < size)
{
fread(buffer, 1, 1, lfp);
if (law == 'a')
sample = isdn_audio_alaw_to_s16[*buffer];
else
sample = isdn_audio_ulaw_to_s16[*buffer];
fwrite(&sample, 2, 1, fp);
i+=2;
}
/* cue */
fprintf(fp, "cue %c%c%c%c%c%c%c%c", 4, 0, 0, 0, 0,0,0,0);
/* LIST */
fprintf(fp, "LIST%c%c%c%cadtl", 4, 0, 0, 0);
fclose(lfp);
}
}
int main(int argc, char *argv[])
{
FILE *fp;
if (argc <= 1)
{
usage:
printf("Usage:\n");
printf("%s ulaw2wave <alaw file> <wav file>\n", argv[0]);
printf("%s alaw2wave <alaw file> <wav file>\n", argv[0]);
return(0);
}
if (!strcmp(argv[1], "alaw2wave"))
{
if (argc <= 3)
goto usage;
if ((fp=fopen(argv[3],"w")))
{
write_law(fp,argv[2],'a');
fclose(fp);
} else
{
printf("Cannot open wave file %s\n",argv[3]);
}
} else
if (!strcmp(argv[1], "ulaw2wave"))
{
if (argc <= 3)
goto usage;
if ((fp=fopen(argv[3],"w")))
{
write_law(fp,argv[2],'u');
fclose(fp);
} else
{
printf("Cannot open wave file %s\n",argv[3]);
}
} else
goto usage;
return(0);
}

343
h323.cpp Normal file
View File

@ -0,0 +1,343 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** h323 port **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "main.h"
/*
* initialize h323 port
*/
H323Port::H323Port(int type, char *portname, struct port_settings *settings) : Port(type, portname, settings)
{
p_h323_channel_in = p_h323_channel_out = NULL;
p_h323_connect = NULL;
/* configure device */
switch (type)
{
case PORT_TYPE_H323_IN:
break;
case PORT_TYPE_H323_OUT:
SPRINT(p_name, "H323_outgoing_port_#%lu", p_serial);
break;
}
if (options.law == 'u')
{
}
}
/*
* destructor
*/
H323Port::~H323Port()
{
}
/*
* endpoint sends messages to the interface
*/
int H323Port::message_epoint(unsigned long epoint_id, int message_id, union parameter *param)
{
H323Connection *connection;
H323Connection::CallEndReason h323_cause;
char name[sizeof(p_name)];
if (Port::message_epoint(epoint_id, message_id, param))
return(1);
switch(message_id)
{
case MESSAGE_mISDNSIGNAL: /* isdn command */
PDEBUG(DEBUG_H323, "H323Port(%s) mISDN signal not supported.\n", p_name);
break;
case MESSAGE_INFORMATION: /* additional digits from endpoint */
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received more digit information: '%s'\n", p_name, p_callerinfo.id, param->information.number);
/* queue to be done */
if (p_state != PORT_STATE_OUT_OVERLAP)
{
PERROR("H323Port(%s) additinal digits are only possible in outgoing overlap state.\n", p_name);
break;
}
if (strlen(param->information.number)>30)
{
PERROR("H323Port(%s) information string too long.\n", p_name);
break;
}
SCAT((char *)p_dialinginfo.number, param->information.number);
break;
case MESSAGE_PROCEEDING: /* call of endpoint is proceeding */
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received proceeding\n", p_name, p_callerinfo.id);
if (p_state != PORT_STATE_IN_OVERLAP)
{
PERROR("H323Port(%s) proceeding command only possible in setup state.\n", p_name);
break;
}
p_state = PORT_STATE_IN_PROCEEDING;
break;
case MESSAGE_ALERTING: /* call of endpoint is ringing */
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received alerting\n", p_name, p_callerinfo.id);
if (p_state != PORT_STATE_IN_OVERLAP
&& p_state != PORT_STATE_IN_PROCEEDING)
{
PERROR("H323Port(%s) alerting command only possible in setup or proceeding state.\n", p_name);
break;
}
p_state = PORT_STATE_IN_ALERTING;
UCPY(name, p_name);
mutex_h323.Signal();
connection = h323_ep->FindConnectionWithLock(name);
if (connection)
{
if (options.h323_ringconnect && !p_callerinfo.intern[0])
{
connection->AnsweringCall(H323Connection::AnswerCallNow);
p_state = PORT_STATE_CONNECT;
} else
connection->AnsweringCall(H323Connection::AnswerCallPending);
connection->Unlock();
}
mutex_h323.Wait();
break;
case MESSAGE_CONNECT: /* call of endpoint is connected */
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received connect\n", p_name, p_callerinfo.id);
if (p_state != PORT_STATE_IN_OVERLAP
&& p_state != PORT_STATE_IN_PROCEEDING
&& p_state != PORT_STATE_IN_ALERTING)
{
PDEBUG(DEBUG_H323, "H323Port(%s) connect command only possible in setup, proceeding or alerting state.\n", p_name);
break;
}
new_state(PORT_STATE_CONNECT);
/* copy connected information */
memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
p_connectinfo.itype = INFO_ITYPE_H323;
UCPY(name, p_name);
mutex_h323.Signal();
connection = h323_ep->FindConnectionWithLock(name);
if (connection)
{
int type, present, screen;
PString connect_number;
/* modify connectinfo (COLP) */
if (p_connectinfo.present!=INFO_PRESENT_NULL)
{
connect_number = p_connectinfo.id;
switch(p_connectinfo.ntype)
{
case INFO_NTYPE_SUBSCRIBER:
type = Q931::SubscriberType;
break;
case INFO_NTYPE_NATIONAL:
type = Q931::NationalType;
break;
case INFO_NTYPE_INTERNATIONAL:
type = Q931::InternationalType;
break;
default: /* INFO_TYPE_UNKNOWN */
type = Q931::UnknownType;
}
switch(p_connectinfo.present)
{
case INFO_PRESENT_RESTRICTED:
present = 1;
break;
case INFO_PRESENT_NOTAVAIL:
present = 2;
break;
default: /* INFO_PRESENT_ALLOWED */
present = 0;
}
switch(p_connectinfo.screen)
{
case INFO_SCREEN_USER:
screen = 0;
break;
default: /* INFO_SCREEN_NETWORK */
screen = 3;
}
#if 0
if (p_h323_connect)
{
//PDEBUG(DEBUG_H323, "DDDEBUG: number %s, type=%d, present %d, screen %d\n", p_connectinfo.id, type, present, screen);
((Q931 *)p_h323_connect)->SetConnectedNumber(connect_number, Q931::ISDNPlan, type, present, screen);
}
else
PERROR("missing p_h323_connect\n");
#endif
}
connection->AnsweringCall(H323Connection::AnswerCallNow);
connection->Unlock();
}
mutex_h323.Wait();
break;
case MESSAGE_DISCONNECT: /* call has been disconnected */
#if 0
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
/* we just play what we hear from the remote site */
if (p_state == PORT_STATE_IN_OVERLAP
|| p_state == PORT_STATE_IN_PROCEEDING)
{
/* copy connected information */
memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
UCPY(name, p_name);
mutex_h323.Signal();
connection = h323_ep->FindConnectionWithLock(name);
if (connection)
{
connection->AnsweringCall(H323Connection::AnswerCallNow);
connection->Unlock();
}
mutex_h323.Wait();
}
new_state(PORT_STATE_DISCONNECT);
break;
#endif
case MESSAGE_RELEASE: /* release h323 port */
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received disconnect cause=%d\n", p_name, p_callerinfo.id, param->disconnectinfo.cause);
if (p_state != PORT_STATE_IN_OVERLAP
&& p_state != PORT_STATE_IN_PROCEEDING
&& p_state != PORT_STATE_IN_ALERTING
&& p_state != PORT_STATE_OUT_SETUP
&& p_state != PORT_STATE_OUT_OVERLAP
&& p_state != PORT_STATE_OUT_PROCEEDING
&& p_state != PORT_STATE_OUT_ALERTING
&& p_state != PORT_STATE_CONNECT)
{
PERROR("H323Port(%s) disconnect command only possible in setup, proceeding, alerting or connect state.\n", p_name);
break;
}
switch(param->disconnectinfo.cause)
{
case 1:
h323_cause = H323Connection::EndedByNoUser;
break;
case 2:
case 3:
case 5:
h323_cause = H323Connection::EndedByUnreachable;
break;
case 17:
h323_cause = H323Connection::EndedByRemoteBusy;
break;
case 18:
h323_cause = H323Connection::EndedByNoEndPoint;
break;
case 19:
h323_cause = H323Connection::EndedByNoAnswer;
break;
case 21:
h323_cause = H323Connection::EndedByRefusal;
break;
case 27:
h323_cause = H323Connection::EndedByHostOffline;
break;
case 47:
h323_cause = H323Connection::EndedByConnectFail;
break;
case 65:
h323_cause = H323Connection::EndedByCapabilityExchange;
break;
case 42:
h323_cause = H323Connection::EndedByRemoteCongestion;
break;
case 41:
h323_cause = H323Connection::EndedByTemporaryFailure;
break;
default:
h323_cause = H323Connection::EndedByRemoteUser;
break;
}
UCPY(name, p_name);
mutex_h323.Signal();
h323_ep->ClearCall(name, h323_cause);
mutex_h323.Wait();
delete this;
break;
case MESSAGE_SETUP: /* dial-out command received from epoint */
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port received setup from '%s' to '%s'\n", p_name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
if (p_type!=PORT_TYPE_H323_OUT)
{
PERROR("H323Port(%s) cannot dial because h323 port not of outgoing type.\n", p_name);
break;
}
if (p_state != PORT_STATE_IDLE)
{
PERROR("H323Port(%s) error: dialing command only possible in idle state.\n", p_name);
break;
}
/* link relation */
if (p_epointlist)
{
PERROR("H323Port(%s) software error: epoint pointer is set in idle state, how bad!! exitting.\n", p_name);
exit(-1);
}
if (!(epointlist_new(epoint_id)))
{
PERROR("no memory for epointlist\n");
exit(-1);
}
/* copy setup infos to port */
memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
p_state = PORT_STATE_OUT_SETUP;
UCPY(name, p_name);
mutex_h323.Signal();
h323_ep->Call(name, param->setup.callerinfo.id, param->setup.dialinginfo.number);
mutex_h323.Wait();
break;
default:
PDEBUG(DEBUG_H323, "H323Port(%s) h323 port with (caller id %s) received an unsupported message: %d\n", p_name, p_callerinfo.id, message_id);
}
return(1);
}

27
h323.h Normal file
View File

@ -0,0 +1,27 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** h323-port header file **
** **
\*****************************************************************************/
/* h323 port class */
class H323_chan;
class H323Port : public Port
{
public:
H323Port(int type, char *portname, struct port_settings *settings);
~H323Port();
int message_epoint(unsigned long epoint_id, int message, union parameter *param);
H323_chan *p_h323_channel_in; /* channels of port */
H323_chan *p_h323_channel_out;
void *p_h323_connect; /* q931 object of connect PDU */
};

189
h323_chan.cpp Normal file
View File

@ -0,0 +1,189 @@
///////////////////////////////////////////////////////////////////////////////
// //
// PBX4Linux //
// //
//---------------------------------------------------------------------------//
// Copyright: Andreas Eversberg //
// //
// H323_chan class //
// //
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include "main.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
//
// constructor
//
H323_chan::H323_chan(const PString &token, BOOL isEncoding) : PIndirectChannel()
{
d_token = token;
// d_isEncoding = isEncoding;
PDEBUG(DEBUG_H323, "H323 channel constuctor of channel (%scoding)\n", (isEncoding)?"en":"de");
transfering = FALSE;
}
//
// destructor
//
H323_chan::~H323_chan(void)
{
PDEBUG(DEBUG_H323, "H323 channel destuctor\n");
}
//
// Closes the
//
BOOL H323_chan::Close(void)
{
PDEBUG(DEBUG_H323, "H323 channel Close\n");
return TRUE;
}
//
// IsOpen
//
BOOL H323_chan::IsOpen(void) const
{
PDEBUG(DEBUG_H323, "H323 channel IsOpen\n");
return TRUE;
}
//
// Read
//
BOOL H323_chan::Read(void *buf, PINDEX len)
{
int nr_words;
class H323Port *port;
const unsigned char *token_string = d_token;
PTime Now;
PTimeInterval diff;
nr_words = len/2;
// cout << "H323 channel Read " << nr_words << " words" << endl;
mutex_h323.Wait();
if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("H323 channel Read() cannot find port with token %s\n", token_string);
mutex_h323.Signal();
lastReadCount = 0;
return FALSE;
}
nr_words = port->read_audio((unsigned char *)buf, nr_words, 0);
mutex_h323.Signal();
// delay
if (!transfering)
{
PDEBUG(DEBUG_H323, "H323 channel Read(%s) sending to h323 the first time\n", token_string);
start = Now;
transfering = TRUE;
elapsed = 0;
}
diff = Now-start;
elapsed += nr_words*125;
if (elapsed > (diff.GetMilliSeconds()*1000))
usleep(elapsed - (diff.GetMilliSeconds()*1000));
lastReadCount = 2 * nr_words;
return TRUE;
}
//
// Write
//
BOOL H323_chan::Write(const void *buf, PINDEX len)
{
int nr_words;
class H323Port *port;
const unsigned char *token_string = d_token;
PTime Now;
PTimeInterval diff;
unsigned char *data_temp;
unsigned long length_temp;
struct message *message;
nr_words = len / 2;
// cout << "H323 channel Write " << nr_words << " words" << endl;
mutex_h323.Wait();
if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("H323 channel Write() cannot find port with token %s\n", token_string);
mutex_h323.Signal();
lastReadCount = 0;
return FALSE;
}
// send data message
length_temp = len;
data_temp = (unsigned char *)buf;
while(length_temp)
{
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_DATA);
message->param.data.len = (length_temp>sizeof(message->param.data.data))?sizeof(message->param.data.data):length_temp;
memcpy(message->param.data.data, data_temp, message->param.data.len);
message->param.data.compressed = 0;
/* { // testin with law data
int i=0;
while (i<message->param.data.len)
{
((unsigned char *)message->param.data.data)[i] = audio_s16_to_law[((signed short*)data_temp)[i] & 0xffff];
i++;
}
}
message->param.data.len = message->param.data.len/2;
message->param.data.compressed = 1;
*/
message->param.data.port_type = port->p_type;
message->param.data.port_id = port->p_serial;
message_put(message);
if (length_temp <= sizeof(message->param.data.data))
break;
data_temp += sizeof(message->param.data.data);
length_temp -= sizeof(message->param.data.data);
}
mutex_h323.Signal();
// delay
if (!transfering)
{
PDEBUG(DEBUG_H323, "H323 channel Write(%s) receiving from h323 the first time\n", token_string);
start = Now;
transfering = TRUE;
elapsed = 0;
}
diff = Now-start;
elapsed += nr_words*125;
if (elapsed > (diff.GetMilliSeconds()*1000))
usleep(elapsed - (diff.GetMilliSeconds()*1000));
lastWriteCount = 2 * nr_words;
return TRUE;
}

34
h323_chan.h Normal file
View File

@ -0,0 +1,34 @@
///////////////////////////////////////////////////////////////////////////////
// //
// PBX4Linux //
// //
//---------------------------------------------------------------------------//
// Copyright: Andreas Eversberg //
// //
// h323_chan header file //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef H323_CHAN_HEADER
#define H323_CHAN_HEADER
class H323_chan : public PIndirectChannel
{
public:
H323_chan(const PString &token, BOOL isEncoding);
~H323_chan(void);
BOOL Close(void);
BOOL IsOpen(void) const;
BOOL Read(void *buf, PINDEX len);
BOOL Write(const void *buf, PINDEX len);
private:
PString d_token;
PTime start;
BOOL transfering;
PInt64 elapsed;
};
#endif

648
h323_con.cpp Normal file
View File

@ -0,0 +1,648 @@
///////////////////////////////////////////////////////////////////////////////
// //
// PBX4Linux //
// //
//---------------------------------------------------------------------------//
// Copyright: Andreas Eversberg //
// //
// h323_con connection class //
// //
///////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include "main.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
//
// constructor
//
H323_con::H323_con(H323_ep &endpoint, unsigned callReference) : H323Connection(endpoint, callReference)
{
PDEBUG(DEBUG_H323, "H323 connection constuctor\n");
SetAudioJitterDelay(0, 0);
}
//
// destructor
//
H323_con::~H323_con()
{
class H323Port *port;
const unsigned char *token_string = callToken;
struct message *message;
mutex_h323.Wait();
// get ioport
port = (class H323Port *)find_port_with_token((char *)token_string);
if (!port)
{
PERROR("no port with token '%s'\n", token_string);
} else
{
/* sending release (if not already) */
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 16;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
}
mutex_h323.Signal();
PDEBUG(DEBUG_H323, "H323 connection destuctor\n");
}
//
// AnswerCallResponse (incoming call)
//
H323Connection::AnswerCallResponse H323_con::OnAnswerCall(const PString &, const H323SignalPDU &setupPDU, H323SignalPDU &connectPDU)
{
class H323Port *port;
const char *calleraddress;
char callerip[32], *extension;
const char *dialing = NULL;
const H225_Setup_UUIE &setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
const H225_ArrayOf_AliasAddress &adr = setup.m_destinationAddress;
PINDEX i;
const unsigned char *token_string = callToken;
struct message *message;
class Endpoint *epoint;
const Q931 setup_q931 = setupPDU.GetQ931();
PString calling_number;
PString redir_number;
unsigned type, plan, present, screen, reason;
struct caller_info *callerinfo;
struct dialing_info *dialinginfo;
struct capa_info *capainfo;
struct redir_info *redirinfo;
char option[64] = "";
PDEBUG(DEBUG_H323, "H323 connection incoming call\n");
mutex_h323.Wait();
// alloc new h323 port structure
if (!(port = new H323Port(PORT_TYPE_H323_IN, (char *)token_string, NULL)))
{
mutex_h323.Signal();
return AnswerCallDenied;
}
callerinfo = &port->p_callerinfo;
redirinfo = &port->p_redirinfo;
capainfo = &port->p_capainfo;
dialinginfo = &port->p_dialinginfo;
memset(callerinfo, 0, sizeof(struct caller_info));
memset(redirinfo, 0, sizeof(struct redir_info));
memset(capainfo, 0, sizeof(struct capa_info));
memset(dialinginfo, 0, sizeof(struct dialing_info));
callerinfo->itype = INFO_ITYPE_H323;
// get calling party information
if (setup_q931.GetCallingPartyNumber(calling_number, &plan, &type, &present, &screen))
{
SCPY(callerinfo->id, calling_number.GetPointer());
switch (present)
{
case 1:
callerinfo->present = INFO_PRESENT_RESTRICTED;
break;
case 2:
callerinfo->present = INFO_PRESENT_NOTAVAIL;
break;
default:
callerinfo->present = INFO_PRESENT_ALLOWED;
break;
}
switch (type)
{
case Q931::InternationalType:
callerinfo->ntype = INFO_NTYPE_INTERNATIONAL;
break;
case Q931::NationalType:
callerinfo->ntype = INFO_NTYPE_NATIONAL;
break;
case Q931::SubscriberType:
callerinfo->ntype = INFO_NTYPE_SUBSCRIBER;
break;
default:
callerinfo->ntype = INFO_NTYPE_UNKNOWN;
break;
}
switch (screen)
{
case 0:
callerinfo->screen = INFO_SCREEN_USER;
break;
default:
callerinfo->screen = INFO_SCREEN_NETWORK;
break;
}
}
redirinfo->itype = INFO_ITYPE_H323;
// get redirecting number information
if (setup_q931.GetRedirectingNumber(redir_number, &plan, &type, &present, &screen, &reason))
{
SCPY(redirinfo->id, redir_number.GetPointer());
switch (present)
{
case 1:
redirinfo->present = INFO_PRESENT_RESTRICTED;
break;
case 2:
redirinfo->present = INFO_PRESENT_NOTAVAIL;
break;
default:
redirinfo->present = INFO_PRESENT_ALLOWED;
break;
}
switch (type)
{
case Q931::InternationalType:
redirinfo->ntype = INFO_NTYPE_INTERNATIONAL;
break;
case Q931::NationalType:
redirinfo->ntype = INFO_NTYPE_NATIONAL;
break;
case Q931::SubscriberType:
redirinfo->ntype = INFO_NTYPE_SUBSCRIBER;
break;
default:
redirinfo->ntype = INFO_NTYPE_UNKNOWN;
break;
}
switch (screen)
{
case 0:
redirinfo->screen = INFO_SCREEN_USER;
break;
default:
redirinfo->screen = INFO_SCREEN_NETWORK;
break;
}
switch (reason)
{
case 1:
redirinfo->reason = INFO_REDIR_BUSY;
break;
case 2:
redirinfo->reason = INFO_REDIR_NORESPONSE;
break;
case 15:
redirinfo->reason = INFO_REDIR_UNCONDITIONAL;
break;
case 10:
redirinfo->reason = INFO_REDIR_CALLDEFLECT;
break;
case 9:
redirinfo->reason = INFO_REDIR_OUTOFORDER;
break;
default:
redirinfo->reason = INFO_REDIR_UNKNOWN;
break;
}
}
// get remote party h323-address information
calleraddress = GetRemotePartyAddress();
callerip[0] = '\0';
if (calleraddress)
{
if (strstr(calleraddress, "ip$"))
{
SCPY(callerip, strstr(calleraddress, "ip$")+3);
if (strchr(callerip, ':'))
*strchr(callerip, ':') = '\0';
memmove(strstr(calleraddress, "ip$"), strstr(calleraddress, "ip$")+3, strlen(strstr(calleraddress, "ip$")+3)+1);
}
if (strchr(calleraddress, ':'))
*strchr(calleraddress, ':') = '\0';
}
// get dialing information
for(i=0; i<adr.GetSize(); i++)
if (adr[i].GetTag() == H225_AliasAddress::e_dialedDigits)
dialing = H323GetAliasAddressString(adr[i]);
if (!dialing)
dialing = "";
// fill port's information
if (calleraddress)
SCPY(callerinfo->voip, (char *)calleraddress);
capainfo->bearer_mode = INFO_BMODE_CIRCUIT;
capainfo->bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
capainfo->bearer_capa = INFO_BC_SPEECH;
// change to incoming setup state
port->new_state(PORT_STATE_IN_OVERLAP);
// allocate new endpoint
if (!(epoint = new Endpoint(port->p_serial, 0)))
{
// error allocating endpoint
PDEBUG(DEBUG_H323, "h323-connection(%s) rejecting call because cannot create epoint for '%s'\n", port->p_name, callerinfo->id);
delete port;
port = NULL;
mutex_h323.Signal();
return AnswerCallDenied;
}
if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint)))
{
PERROR("no memory for application\n");
exit(-1);
}
if (!(port->epointlist_new(epoint->ep_serial)))
{
PERROR("no memory for epointlist\n");
exit(-1);
}
port->set_tone(NULL, "");
// send setup message to endpoint
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
message->param.setup.port_type = port->p_type;
// before we start, we may check for h323_gateway entry
if (callerip[0])
{
extension = parse_h323gateway(callerip, option, sizeof(option));
if (extension)
{
PDEBUG(DEBUG_H323, "h323-connection(%s) gateway '%s' is mapped to extension '%s' (option= '%s')\n", port->p_name, callerip, extension, option);
SCPY(callerinfo->id, extension);
SCPY(callerinfo->intern, extension);
callerinfo->itype = INFO_ITYPE_INTERN;
callerinfo->screen = INFO_SCREEN_NETWORK;
} else
{
PDEBUG(DEBUG_H323, "h323-connection(%s) gateway '%s' is not mapped to any extension. (port_type=0x%x)\n", port->p_name, callerip, port->p_type);
// get the default dialing external dialing string
}
}
// default dialing for extenal calls
if (!callerinfo->intern[0] && !dialing[0])
dialing = options.h323_icall_prefix;
// dialing information
if (callerip[0] || dialing[0])
{
SCPY(dialinginfo->number, (char *)dialing);
dialinginfo->ntype = INFO_NTYPE_UNKNOWN;
}
memcpy(&message->param.setup.callerinfo, callerinfo, sizeof(struct caller_info));
memcpy(&message->param.setup.dialinginfo, dialinginfo, sizeof(struct dialing_info));
memcpy(&message->param.setup.redirinfo, redirinfo, sizeof(struct redir_info));
memcpy(&message->param.setup.capainfo, capainfo, sizeof(struct capa_info));
message->param.setup.dtmf = 1;
message_put(message);
port->p_h323_connect = &(connectPDU.GetQ931());
mutex_h323.Signal();
if (!strcasecmp(option, "connect") || !strcasecmp(option, "dtmf"))
{
port->new_state(PORT_STATE_CONNECT);
return AnswerCallNow;
} else
{
return AnswerCallDeferred;
}
}
//
// OnOutgoingCall (outgoing call)
//
BOOL H323_con::OnOutgoingCall(const H323SignalPDU &connectPDU)
{
class H323Port *port;
const char *calleraddress;
char callerip[32];
const unsigned char *token_string = callToken;
struct message *message;
// H225_Connect_UUIE &connect_uuie = connectPDU.m_h323_uu_pdu.m_h323_message_body;
const Q931 connect_q931 = connectPDU.GetQ931();
PString connect_number;
unsigned type = 0, plan = 0, present = 0, screen = 0;
struct connect_info *connectinfo;
PDEBUG(DEBUG_H323, "H323 connection outgoing call is connected.\n");
mutex_h323.Wait();
if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR(" cannot find port with token '%s'\n", token_string);
mutex_h323.Signal();
return FALSE;
}
connectinfo = &port->p_connectinfo;
if (port->p_type == PORT_TYPE_H323_IN)
{
PDEBUG(DEBUG_H323, "H323 endpoint OnConnectionEstablished() incoming port\n");
}
if (port->p_type == PORT_TYPE_H323_OUT)
{
PDEBUG(DEBUG_H323, "H323 endpoint OnConnectionEstablished() outgoing port\n");
if (port->p_state==PORT_STATE_OUT_SETUP
|| port->p_state==PORT_STATE_OUT_OVERLAP
|| port->p_state==PORT_STATE_OUT_PROCEEDING
|| port->p_state==PORT_STATE_OUT_ALERTING)
{
// get remote party h323-address information
calleraddress = GetRemotePartyAddress();
callerip[0] = '\0';
if (calleraddress)
{
if (strchr(calleraddress, '$'))
{
SCPY(callerip, strchr(calleraddress, '$'));
callerip[sizeof(callerip)-1] = '\0';
if (strchr(callerip, ':'))
*strchr(callerip, ':') = '\0';
}
SCPY(connectinfo->voip, (char *)calleraddress);
}
// get COLP
memset(connectinfo, 0, sizeof(struct connect_info));
connectinfo->itype = INFO_ITYPE_H323;
if (connect_q931.GetConnectedNumber(connect_number, &plan, &type, &present, &screen))
{
SCPY(connectinfo->id, connect_number.GetPointer());
switch (present)
{
case 1:
connectinfo->present = INFO_PRESENT_RESTRICTED;
break;
case 2:
connectinfo->present = INFO_PRESENT_NOTAVAIL;
break;
default:
connectinfo->present = INFO_PRESENT_ALLOWED;
}
switch (type)
{
case Q931::InternationalType:
connectinfo->ntype = INFO_NTYPE_INTERNATIONAL;
break;
case Q931::NationalType:
connectinfo->ntype = INFO_NTYPE_NATIONAL;
break;
case Q931::SubscriberType:
connectinfo->ntype = INFO_NTYPE_SUBSCRIBER;
break;
default:
connectinfo->ntype = INFO_NTYPE_UNKNOWN;
}
switch (screen)
{
case 0:
connectinfo->screen = INFO_SCREEN_USER;
break;
default:
connectinfo->screen = INFO_SCREEN_NETWORK;
}
}
port->new_state(PORT_STATE_CONNECT);
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
memcpy(&message->param.connectinfo, connectinfo, sizeof(struct connect_info));
message_put(message);
}
}
mutex_h323.Signal();
return H323Connection::OnOutgoingCall(connectPDU);
}
//
// send setup information to the called h323 user
//
BOOL H323_con::OnSendSignalSetup(H323SignalPDU &setupPDU)
{
H225_Setup_UUIE &setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
H225_ArrayOf_AliasAddress &adr = setup.m_sourceAddress;
H225_AliasAddress new_alias;
PString calling_number;
PString calling_alias;
PString dialing_number;
PString redir_number;
int type, present, screen, reason;
class H323Port *port;
const unsigned char *token_string = callToken;
struct caller_info *callerinfo;
struct dialing_info *dialinginfo;
struct capa_info *capainfo;
struct redir_info *redirinfo;
mutex_h323.Wait();
if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR(" no port with token '%s'\n", token_string);
mutex_h323.Signal();
return FALSE;
}
callerinfo = &port->p_callerinfo;
redirinfo = &port->p_redirinfo;
capainfo = &port->p_capainfo;
dialinginfo = &port->p_dialinginfo;
PDEBUG(DEBUG_H323, "H323-connection sending modified setup signal '%s'->'%s'\n", callerinfo->id, dialinginfo->number);
if (callerinfo->present!=INFO_PRESENT_NULL)
{
calling_alias = numberrize_callerinfo(callerinfo->id, callerinfo->ntype);
H323SetAliasAddress(calling_alias, new_alias);
adr.SetSize(adr.GetSize()+1);
adr[adr.GetSize()-1] = new_alias;
calling_number = callerinfo->id;
switch(callerinfo->ntype)
{
case INFO_NTYPE_SUBSCRIBER:
type = Q931::SubscriberType;
break;
case INFO_NTYPE_NATIONAL:
type = Q931::NationalType;
break;
case INFO_NTYPE_INTERNATIONAL:
type = Q931::InternationalType;
break;
default: /* INFO_NTYPE_UNKNOWN */
type = Q931::UnknownType;
}
switch(callerinfo->present)
{
case INFO_PRESENT_RESTRICTED:
present = 1;
break;
case INFO_PRESENT_NOTAVAIL:
present = 2;
break;
default: /* INFO_PRESENT_ALLOWED */
present = 0;
}
switch(callerinfo->screen)
{
case INFO_SCREEN_USER:
screen = 0;
break;
default: /* INFO_SCREEN_NETWORK */
screen = 3;
}
Q931 &new_q931 = setupPDU.GetQ931();
new_q931.SetCallingPartyNumber(calling_number, Q931::ISDNPlan, type, present, screen);
}
if (redirinfo->present!=INFO_PRESENT_NULL)
{
if (redirinfo->present==INFO_PRESENT_ALLOWED)
{
redir_number = callerinfo->id;
} else
redir_number = "";
switch(redirinfo->ntype)
{
case INFO_NTYPE_SUBSCRIBER:
type = Q931::SubscriberType;
break;
case INFO_NTYPE_NATIONAL:
type = Q931::NationalType;
break;
case INFO_NTYPE_INTERNATIONAL:
type = Q931::InternationalType;
break;
default: /* INFO_TYPE_UNKNOWN */
type = Q931::UnknownType;
}
switch(redirinfo->present)
{
case INFO_PRESENT_RESTRICTED:
present = 1;
break;
case INFO_PRESENT_NOTAVAIL:
present = 2;
break;
default: /* INFO_PRESENT_ALLOWED */
present = 0;
}
switch(redirinfo->reason)
{
case INFO_REDIR_BUSY:
reason = 1;
break;
case INFO_REDIR_NORESPONSE:
reason = 2;
break;
case INFO_REDIR_UNCONDITIONAL:
reason = 15;
break;
case INFO_REDIR_OUTOFORDER:
reason = 9;
break;
case INFO_REDIR_CALLDEFLECT:
reason = 10;
break;
default: /* INFO_REDIR_UNKNOWN */
reason = 0;
}
Q931 &new_q931 = setupPDU.GetQ931();
new_q931.SetRedirectingNumber(redir_number, Q931::ISDNPlan, type, present, screen, reason);
}
if (dialinginfo->number[0])
{
dialing_number = dialinginfo->number;
Q931 &new_q931 = setupPDU.GetQ931();
new_q931.SetCalledPartyNumber(dialing_number);
}
mutex_h323.Signal();
return H323Connection::OnSendSignalSetup(setupPDU);
}
//
// callback for start of channel
//
BOOL H323_con::OnStartLogicalChannel(H323Channel &channel)
{
if (!H323Connection::OnStartLogicalChannel(channel))
{
PERROR("starting logical channel failed!\n");
return FALSE;
}
PDEBUG(DEBUG_H323, "H323 connection starting logical channel using \"%s\" codec %s :%s\n",
channel.GetCapability().GetFormatName().GetPointer(),
(channel.GetDirection()==H323Channel::IsTransmitter)?"transmit":"receive",
callToken.GetPointer());
return H323Connection::OnStartLogicalChannel(channel);
}
//
// user input received
//
void H323_con::OnUserInputString (const PString &value)
{
class H323Port *port;
const unsigned char *token_string = callToken;
const unsigned char *value_string = value;
struct message *message;
PDEBUG(DEBUG_H323, "H323-connection received user input'%s'\n", value_string);
mutex_h323.Wait();
if (!(port = (class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("no port with token '%s'\n", token_string);
} else
{
while(*value_string)
{
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_DTMF);
message->param.dtmf = *value_string++;
message_put(message);
}
#if 0
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
SCPY(message->param.information.number, (char *)value_string);
message_put(message);
#endif
}
mutex_h323.Signal();
}

35
h323_con.h Normal file
View File

@ -0,0 +1,35 @@
///////////////////////////////////////////////////////////////////////////////
// //
// PBX4Linux //
// //
//---------------------------------------------------------------------------//
// Copyright: Andreas Eversberg //
// //
// h323_con connection header file //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef H323_CON_HEADER
#define H323_CON_HEADER
class H323_chan;
class H323_con : public H323Connection
{
public:
H323_con(H323_ep &endpoint, unsigned callReference);
~H323_con();
AnswerCallResponse OnAnswerCall(const PString &, const H323SignalPDU &, H323SignalPDU &);
BOOL OnOutgoingCall(const H323SignalPDU &connectPDU);
BOOL OnSendSignalSetup(H323SignalPDU &);
BOOL OnStartLogicalChannel(H323Channel &channel);
void OnUserInputString (const PString &value);
H323SignalPDU *GetConnectPDU(void);
private:
};
#endif // H323_CON_HEADER

503
h323_ep.cpp Normal file
View File

@ -0,0 +1,503 @@
///////////////////////////////////////////////////////////////////////////////
// //
// PBX4Linux //
// //
//---------------------------------------------------------------------------//
// Copyright: Andreas Eversberg //
// //
// h323_ep class //
// //
///////////////////////////////////////////////////////////////////////////////
/*
NOTE:
The code was inspired by the isdn2h323 gateway my marco bode.
Thanx to marco budde for lerarning to program h323 and c++ from your code.
His homepage is www.telos.de, there you'll find the isdn2h323 gateway.
Also thanx to others who write documents and applications for OpenH323.
Andreas Eversberg
*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include "main.h"
//#include <gsmcodec.h>
//#include <g7231codec.h>
//#include <g729codec.h>
//#include "g726codec.h"
//#include <speexcodec.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
//
// constructor
//
H323_ep::H323_ep(void)
{
terminalType = e_GatewayOnly;
PDEBUG(DEBUG_H323, "H323 endpoint constuctor\n");
}
//
// destructor
//
H323_ep::~H323_ep()
{
// clear all calls to remote endpoints
ClearAllCalls();
PDEBUG(DEBUG_H323, "H323 endpoint destuctor\n");
}
//
// create connection
//
H323Connection *H323_ep::CreateConnection(unsigned callReference)
{
PDEBUG(DEBUG_H323, "H323 endpoint create connection\n");
return new H323_con(*this, callReference);
}
//
// on establishment of conneciton
//
void H323_ep::OnConnectionEstablished(H323Connection &connection, const PString &token)
{
const unsigned char *token_string = token;
PDEBUG(DEBUG_H323, "H323 endpoint connection established to: %s\n", token_string);
H323EndPoint::OnConnectionEstablished(connection, token);
}
//
// on remote alerting
//
BOOL H323_ep::OnAlerting(H323Connection &connection, const H323SignalPDU &alertingPDU, const PString &user)
{
class H323Port *port;
const unsigned char *token_string = connection.GetCallToken();
const unsigned char *user_string = user;
struct message *message;
PDEBUG(DEBUG_H323, "H323 endpoint alerting at: %s\n", user_string);
mutex_h323.Wait();
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("cannot find port with token '%s'\n", token_string);
mutex_h323.Signal();
return FALSE;
}
if (port->p_state==PORT_STATE_OUT_SETUP
|| port->p_state==PORT_STATE_OUT_OVERLAP
|| port->p_state==PORT_STATE_OUT_PROCEEDING)
{
port->new_state(PORT_STATE_OUT_ALERTING);
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
message_put(message);
}
mutex_h323.Signal();
return TRUE;
}
//
// on clearing of connection
//
void H323_ep::OnConnectionCleared(H323Connection &connection, const PString &token)
{
int cause;
class H323Port *port;
const unsigned char *token_string = token;
struct message *message;
PDEBUG(DEBUG_H323, "H323 endpoint connection cleared.\n");
mutex_h323.Wait();
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("cannot find port with token '%s'\n", token_string);
mutex_h323.Signal();
return;
}
switch(connection.GetCallEndReason())
{
case H323Connection::EndedByRemoteUser:
case H323Connection::EndedByCallerAbort:
case H323Connection::EndedByGatekeeper:
case H323Connection::EndedByCallForwarded:
cause = 16; // normal call clearing
break;
case H323Connection::EndedByRefusal:
case H323Connection::EndedBySecurityDenial:
cause = 21; // call rejected
break;
case H323Connection::EndedByNoAnswer:
cause = 19; // no answer from user
break;
case H323Connection::EndedByTransportFail:
cause = 47; // resource unavaiable, unspecified
break;
case H323Connection::EndedByNoBandwidth:
cause = 49; // quality of service not available
break;
case H323Connection::EndedByNoUser:
cause = 1; // unallocated number
break;
case H323Connection::EndedByCapabilityExchange:
cause = 65; // bearer capability not implemented
break;
case H323Connection::EndedByRemoteBusy:
cause = 17; // user busy
break;
case H323Connection::EndedByRemoteCongestion:
cause = 42; // switching equipment congestion
break;
case H323Connection::EndedByUnreachable:
cause = 2; // no route ...
break;
case H323Connection::EndedByNoEndPoint:
case H323Connection::EndedByConnectFail:
cause = 18; // no user responding
break;
case H323Connection::EndedByHostOffline:
cause = 27; // destination out of order
break;
case H323Connection::EndedByTemporaryFailure:
cause = 41; // temporary failure
break;
default:
cause = 31; // normal, unspecified
break;
}
// delete channels
if (port->p_h323_channel_in)
delete port->p_h323_channel_in;
port->p_h323_channel_in = NULL;
if (port->p_h323_channel_out)
delete port->p_h323_channel_out;
port->p_h323_channel_out = NULL;
/* release endpoint */
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = cause;
message->param.disconnectinfo.location = LOCATION_BEYOND;
message_put(message);
/* delete port */
delete port;
mutex_h323.Signal();
}
//
// open audio channel
//
BOOL H323_ep::OpenAudioChannel(H323Connection &connection, BOOL isEncoding, unsigned bufferSize, H323AudioCodec &codec)
{
H323_chan *channel;
class H323Port *port;
const unsigned char *token_string = connection.GetCallToken();
PDEBUG(DEBUG_H323, "H323 endpoint audio channel open (isEndcoding=%d).\n", isEncoding);
// disable the silence detection
codec.SetSilenceDetectionMode (H323AudioCodec::NoSilenceDetection);
// create channels
if (isEncoding)
{
channel = new H323_chan(connection.GetCallToken(), TRUE);
} else
{
channel = new H323_chan(connection.GetCallToken(), FALSE);
}
if (!channel)
{
PERROR("channel for token '%s' not set", token_string);
return FALSE;
}
// return the channel object
mutex_h323.Wait();
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("cannot find port with token '%s'\n", token_string);
mutex_h323.Signal();
return FALSE;
}
// set channels
if (isEncoding)
{
port->p_h323_channel_out = channel;
} else
{
port->p_h323_channel_in = channel;
}
mutex_h323.Signal();
return codec.AttachChannel(channel, FALSE);
}
//
// open video channel
//
BOOL H323_ep::OpenVideoChannel(H323Connection &connection, BOOL isEncoding, H323VideoCodec &codec)
{
PDEBUG(DEBUG_H323, "H323 endpoint video channel open (isEndcoding=%d).\n", isEncoding);
return FALSE;
}
//
// initialize H323 endpoint
//
BOOL H323_ep::Init(void)
{
H323ListenerTCP *listener;
int pri;
PDEBUG(DEBUG_H323, "H323 endpoint initialize\n");
// add keypad capability
H323_UserInputCapability::AddAllCapabilities(capabilities, 0, P_MAX_INDEX);
/* will add codec in order of priority 1 = highest, 0 = don't use */
pri = 1;
while (pri < 256)
{
#warning codecs are temporarily disabled due to api change
#if 0
if (options.h323_gsm_pri == pri)
{
H323_GSM0610Capability * gsm_cap;
MicrosoftGSMAudioCapability * msgsm_cap;
SetCapability(0, 0, gsm_cap = new H323_GSM0610Capability);
gsm_cap->SetTxFramesInPacket(options.h323_gsm_opt);
SetCapability(0, 0, msgsm_cap = new MicrosoftGSMAudioCapability);
msgsm_cap->SetTxFramesInPacket(options.h323_gsm_opt);
}
if (options.h323_g726_pri == pri)
{
if (options.h323_g726_opt > 4)
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_40k));
if (options.h323_g726_opt > 3)
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_32k));
if (options.h323_g726_opt > 2)
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_24k));
SetCapability(0, 0, new H323_G726_Capability(*this, H323_G726_Capability::e_16k));
}
if (options.h323_g7231_pri == pri)
{
#if 0
SetCapability(0, 0, new H323_G7231Capability(FALSE));
#endif
}
if (options.h323_g729a_pri == pri)
{
#if 0
SetCapability(0, 0, new H323_G729Capability());
#endif
}
if (options.h323_lpc10_pri == pri)
{
SetCapability(0, 0, new H323_LPC10Capability(*this));
}
if (options.h323_speex_pri == pri)
{
if (options.h323_speex_opt > 5)
SetCapability(0, 0, new SpeexNarrow6AudioCapability());
if (options.h323_speex_opt > 4)
SetCapability(0, 0, new SpeexNarrow5AudioCapability());
if (options.h323_speex_opt > 3)
SetCapability(0, 0, new SpeexNarrow4AudioCapability());
if (options.h323_speex_opt > 2)
SetCapability(0, 0, new SpeexNarrow3AudioCapability());
SetCapability(0, 0, new SpeexNarrow2AudioCapability());
}
if (options.h323_xspeex_pri == pri)
{
if (options.h323_xspeex_opt > 5)
SetCapability(0, 0, new XiphSpeexNarrow6AudioCapability());
if (options.h323_xspeex_opt > 4)
SetCapability(0, 0, new XiphSpeexNarrow5AudioCapability());
if (options.h323_xspeex_opt > 3)
SetCapability(0, 0, new XiphSpeexNarrow4AudioCapability());
if (options.h323_xspeex_opt > 2)
SetCapability(0, 0, new XiphSpeexNarrow3AudioCapability());
SetCapability(0, 0, new XiphSpeexNarrow2AudioCapability());
}
#endif
if (options.h323_law_pri == pri)
{
H323_G711Capability * g711uCap;
H323_G711Capability * g711aCap;
SetCapability(0, 0, g711uCap = new H323_G711Capability (H323_G711Capability::ALaw/*, H323_G711Capability::At64k*/));
#warning H323_law frame size is disabled due to bug in OpenH323
// g711uCap->SetTxFramesInPacket(options.h323_law_opt);
SetCapability(0, 0, g711aCap = new H323_G711Capability (H323_G711Capability::muLaw/*, H323_G711Capability::At64k*/));
// g711aCap->SetTxFramesInPacket(options.h323_law_opt);
}
pri++;
}
// h323 user is the hostname or given by h323_name
if (options.h323_name[0] == '\0')
{
if (getenv("HOSTNAME") == NULL)
{
cout << "OpenH323: Environment variable HOSTNAME not set. Please specify 'h323_name' in options.conf" << endl;
return FALSE;
}
}
SetLocalUserName((options.h323_name[0])?options.h323_name:getenv("HOSTNAME"));
// create listener
if (options.h323_icall)
{
PIPSocket::Address interfaceAddress(INADDR_ANY);
listener = new H323ListenerTCP(*this, interfaceAddress, options.h323_port);
if (!StartListener(listener))
{
cout << "OpenH323: Could not open H323 port " << listener->GetListenerPort() << endl;
return FALSE;
}
cout << "OpenH323: Waiting for incoming H323 connections on port " << listener->GetListenerPort() << endl;
}
// register with gatekeeper
if (options.h323_gatekeeper)
{
if (options.h323_gatekeeper_host[0] == '\0')
{
if (DiscoverGatekeeper(new H323TransportUDP(*this)))
{
cout << "OpenH323: Registering with gatekeeper " << gatekeeper->GetIdentifier() << " (automatically)" << endl;
} else
{
cout << "OpenH323: Gatekeeper not found." << endl;
sleep(2);
}
} else
{
if (SetGatekeeper(options.h323_gatekeeper_host) == TRUE)
{
cout << "OpenH323: Registering with gatekeeper " << gatekeeper->GetIdentifier() << " (automatically)" << endl;
} else
{
cout << "OpenH323: Gatekeeper at " << gatekeeper->GetIdentifier() << " not found." << endl;
sleep(2);
}
}
}
return TRUE;
}
//
// make an outgoing h323 call
//
BOOL H323_ep::Call(char *token_string, char *caller, char *host)
{
PString address;
PString token = "";
BOOL failed = FALSE;
class H323Port *port;
struct message *message;
char *newtoken_string;
PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
address = host;
if (!MakeCall(address, token))
{
PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
failed = TRUE;
}
// set new token
mutex_h323.Wait();
if (!(port=(class H323Port *)find_port_with_token((char *)token_string)))
{
PERROR("cannot find port with token '%s'\n", token_string);
mutex_h323.Signal();
return FALSE;
}
if (failed == TRUE)
{
PDEBUG(DEBUG_H323, "call of port '%s' failed.\n", token_string);
message = message_create(port->p_serial, ACTIVE_EPOINT(port->p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
message->param.disconnectinfo.cause = 31;
message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
message_put(message);
} else
{
PDEBUG(DEBUG_H323, "changing port name from '%s' to token '%s'\n", token_string, token.GetPointer());
newtoken_string = token.GetPointer();
SCPY(port->p_name, newtoken_string);
}
mutex_h323.Signal();
PDEBUG(DEBUG_H323, "H323 endpoint call to host '%s'\n", host);
if (failed == TRUE)
return FALSE;
return TRUE;
}
void H323_ep::SetEndpointTypeInfo(H225_EndpointType &info) const
{
// H225_VoiceCaps voicecaps;
PDEBUG(DEBUG_H323, "H323 endpoint set endpoint type info *TBD*\n");
H323EndPoint::SetEndpointTypeInfo(info);
// protocols.SetTag(H225_SupportedProtocols::e_voice);
// (H225_VoiceCaps&)protocols = voicecaps;
// a_protocols.SetSize(1);
// a_protocols[0] = protocols;
// gateway.IncludeOptionalField(H225_GatewayInfo::e_protocol);
// gateway.m_protocol = a_protocols;
// info.m_gateway = gateway;
}

37
h323_ep.h Normal file
View File

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// //
// PBX4Linux //
// //
//---------------------------------------------------------------------------//
// Copyright: Andreas Eversberg //
// //
// h323_ep endpoint header file //
// //
///////////////////////////////////////////////////////////////////////////////
#ifndef H323_EP_HEADER
#define H323_EP_HEADER
class H323_con;
class H323_ep : public H323EndPoint
{
public:
H323_ep(void);
~H323_ep();
H323Connection *CreateConnection(unsigned callReference);
void OnConnectionEstablished(H323Connection &connection, const PString &token);
BOOL OnAlerting(H323Connection &connection, const H323SignalPDU &alertingPDU, const PString &user);
void OnConnectionCleared(H323Connection &connection, const PString &token);
BOOL OpenAudioChannel(H323Connection &connection, BOOL isEncoding, unsigned bufferSize, H323AudioCodec &codec);
BOOL OpenVideoChannel(H323Connection &connection, BOOL isEncoding, H323VideoCodec &codec);
BOOL Init(void);
void SetEndpointTypeInfo (H225_EndpointType & info) const;
BOOL Call(char *token_string, char *caller, char *host);
private:
};
#endif // H323_EP_HEADER

137
h323conf.c Normal file
View File

@ -0,0 +1,137 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** parse h323 gateway config file **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "main.h"
/* parse h323_gateway.conf
*
* searches for the given ip and returns the extension or NULL if not found
*/
char *parse_h323gateway(char *ip, char *opt, int opt_size)
{
FILE *fp=NULL;
char filename[256];
char *p;
unsigned int line,i;
char buffer[256];
static char host_ip[32], extension[32], option[64];
int found = 0;
SPRINT(filename, "%s/h323_gateway.conf", INSTALL_DATA);
if (!(fp = fopen(filename, "r")))
{
PERROR("Cannot open h323 gateway map: \"%s\"\n", filename);
return(0);
}
line=0;
while((fgets(buffer, sizeof(buffer), fp)))
{
line++;
buffer[sizeof(buffer)-1] = '\0';
if (buffer[0]) buffer[strlen(buffer)-1] = '\0';
p = buffer;
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
if (*p==0 || *p=='#') /* ignore comments and empty line */
continue;
host_ip[0]=0;
extension[0]=0;
option[0]=0;
i=0; /* read host ip */
while(*p > 32)
{
if (i+1 >= sizeof(host_ip))
{
PERROR_RUNTIME("Error in %s (line %d): ip too long.\n",filename,line);
break;
}
host_ip[i+1] = '\0';
host_ip[i++] = *p++;
}
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
if (*p!=0 && *p!='#') /* extension */
{
i=0; /* read extension */
while(*p > 32)
{
if (i+1 >= sizeof(extension))
{
PERROR_RUNTIME("Error in %s (line %d): extension too long.\n",filename,line);
break;
}
extension[i+1] = '\0';
extension[i++] = *p++;
}
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
}
if (*p!=0 && *p!='#') /* option */
{
i=0; /* read option */
while(*p > 32)
{
if (i+1 >= sizeof(option))
{
PERROR_RUNTIME("Error in %s (line %d): option too long.\n",filename,line);
break;
}
option[i+1] = '\0';
option[i++] = *p++;
}
// ignoring more
}
if (!!strcasecmp(ip, host_ip))
continue;
if (extension[0] == '\0')
continue;
found = 1;
break; /* found entry */
}
if (fp) fclose(fp);
if (found)
{
UNCPY(opt, option, opt_size-1);
opt[opt_size-1] = '\0';
return(extension);
}
return(0);
}

14
h323conf.h Normal file
View File

@ -0,0 +1,14 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** h323gw header file **
** **
\*****************************************************************************/
char *parse_h323gateway(char *ip, char *opt, int opt_size);

1543
ie.cpp Normal file

File diff suppressed because it is too large Load Diff

1055
interface.c Normal file

File diff suppressed because it is too large Load Diff

113
interface.h Normal file
View File

@ -0,0 +1,113 @@
/*****************************************************************************\
** **
** LCR **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** interface header file **
** **
\*****************************************************************************/
#define FLAG_PORT_USE 1
#define FLAG_PORT_PTP (1<<1)
enum { /* interface type */
IF_TYPE_DIRECT,
IF_TYPE_EXTENSION,
};
/* channel selection -1 is reserved for "no ie" */
#define CHANNEL_NO -2
#define CHANNEL_ANY -3
#define CHANNEL_FREE -100
/* port selection */
enum { HUNT_LINEAR = 0,
HUNT_ROUNDROBIN,
};
/* filters */
enum { FILTER_GAIN,
FILTER_CANCEL,
FILTER_BLOWFISH,
};
enum { IS_DEFAULT = 0,
IS_YES,
IS_NO,
};
struct select_channel {
struct select_channel *next;
int channel;
};
struct interface_port {
struct interface_port *next;
struct interface *interface; /* link to interface */
struct mISDNport *mISDNport; /* link to port */
int portnum; /* port number */
int ptp; /* load stack in PTP mode */
int channel_force; /* forces channel by protocol */
struct select_channel *out_select; /* list of channels to select */
struct select_channel *in_select; /* the same for incoming channels */
// int open; /* set if port is opened */
int block; /* set if interface is blocked */
};
struct interface_msn {
struct interface_msn *next;
char msn[64]; /* msn */
};
struct interface_screen {
struct interface_screen *next;
char match[64]; /* what caller id to match */
int match_type; /* number type */
int match_present; /* presentation type */
char result[64]; /* what caller id to change to */
int result_type; /* number type */
int result_present; /* presentation type */
};
struct interface_filter {
struct interface_filter *next;
int filter; /* filter to use */
char parameter[256]; /* filter parameter */
};
struct interface {
struct interface *next;
char name[64]; /* name of interface */
int extension; /* calls are handled as extension */
int is_tones; /* generate tones */
int is_earlyb; /* bridge tones during call setup */
int hunt; /* select algorithm */
int hunt_next; /* ifport index to start hunt */
struct interface_port *ifport; /* link to interface port list */
struct interface_msn *ifmsn; /* link to interface msn list */
struct interface_screen *ifscreen_in; /* link to screening list */
struct interface_screen *ifscreen_out; /* link to screening list */
struct interface_filter *iffilter; /* link to filter list */
};
struct interface_param {
char *name;
/* return value (pointer of function)(args ...) */
int (*func)(struct interface *, char *, int, char *, char*);
char *usage;
char *help;
};
extern struct interface *interface_first;
extern struct interface *interface_newlist;
extern char interface_error[256];
struct interface *read_interfaces(void);
void free_interfaces(struct interface *interface_start);
void relink_interfaces(void);
void doc_interface(void);

2071
mISDN.cpp Normal file

File diff suppressed because it is too large Load Diff

142
mISDN.h Normal file
View File

@ -0,0 +1,142 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** mISDN-port header file **
** **
\*****************************************************************************/
#define B_STATE_IDLE 0
#define B_STATE_ACTIVATING 1
#define B_STATE_ACTIVE 2
#define B_STATE_DEACTIVATING 3
extern int entity;
extern int mISDNdevice;
/* mISDN port structure list */
struct mISDNport {
net_stack_t nst; /* MUST be the first entry, so &nst equals &mISDNlist */
manager_t mgr;
struct mISDNport *next;
struct interface_port *ifport; /* link to interface_port */
// int iftype; /* IF_* */
// int multilink; /* if set, this port will not support callwaiting */
int portnum; /* port number */
int ptp; /* if ptp is set, we keep track of l2link */
int l1link; /* if l1 is available (only works with nt-mode) */
int l2link; /* if l2 is available (at PTP we take this serious) */
// time_t l1timeout; /* timout when establishing link */
time_t l2establish; /* time until establishing after link failure */
int use; /* counts the number of port that uses this port */
int ntmode; /* is TRUE if port is nt mode */
int pri; /* is TRUE if port is a primary rate interface */
int upper_id; /* id to transfer data down */
int lower_id; /* id to transfer data up */
int d_stid;
int b_num; /* number of bchannels */
int b_reserved; /* number of bchannels reserved or in use */
class PmISDN *b_port[128]; /* maximum number of ports shall be 128 due to S0 / E1 / special E1 */
int b_stid[128];
int b_addr[128];
int b_state[128]; /* state 0 = IDLE */
int procids[128]; /* keep track of free ids */
msg_queue_t downqueue; /* l4->l3 */
};
extern mISDNport *mISDNport_first;
/*
notes on bchannels:
if a b-channel is in use, the b_port[channel] is linked to the port using it.
also each used b-channel counts b_inuse.
to assign a bchannel, that is not jet defined due to remote channel assignment,
the b_inuse is also increased to reserve channel
'use' is the number of port instances using this mISDNport. this counts also
calls with no bchannel (call waiting, call on hold).
*/
/* mISDN none-object functions */
void mISDN_port_info(void);
struct mISDNport *mISDNport_open(int port, int ptp);
void mISDNport_close_all(void);
void mISDNport_close(struct mISDNport *mISDNport);
void mISDN_port_reorder(void);
int mISDN_handler(void);
void enc_ie_cause_standalone(unsigned char **ntmode, msg_t *msg, int location, int cause);
void ph_control(unsigned long b_addr, int c1, int c2);
void ph_control_block(unsigned long b_addr, int c1, void *c2, int c2_len);
msg_t *create_l2msg(int prim, int dinfo, int size);
void setup_queue(struct mISDNport *mISDNport, int link);
int stack2manager_nt(void *dat, void *arg);
int stack2manager_te(struct mISDNport *mISDNport, msg_t *msg);
/* mISDN port classes */
class PmISDN : public Port
{
public:
PmISDN(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel);
~PmISDN();
void bchannel_receive(iframe_t *frm);
int handler(void);
int message_epoint(unsigned long epoint_id, int message, union parameter *param);
void message_mISDNsignal(unsigned long epoint_id, int message_id, union parameter *param);
void message_crypt(unsigned long epoint_id, int message_id, union parameter *param);
struct mISDNport *p_m_mISDNport; /* pointer to port */
int p_m_delay; /* use delay instead of dejitter */
int p_m_txvol, p_m_rxvol; /* volume shift (0 = no change) */
int p_m_echo, p_m_conf; /* remote echo, conference number */
int p_m_tone; /* current kernel space tone */
int p_m_rxoff; /* rx from driver is disabled */
int p_m_nodata; /* all parties within a conf are isdn ports, so pure bridging is possible */
int p_m_txmix; /* mix tx with conference */
int p_m_txmix_on; /* delay for turning back on after sending a binary message, must be signed */
int p_m_dtmf; /* dtmf decoding is enabled */
int p_m_crypt; /* encryption is enabled */
int p_m_crypt_msg_loops; /* sending a message */
int p_m_crypt_msg_len;
unsigned char p_m_crypt_msg[1100];
int p_m_crypt_msg_current;
unsigned char p_m_crypt_key[128];
int p_m_crypt_key_len;
int p_m_crypt_listen;
int p_m_crypt_listen_state;
int p_m_crypt_listen_len;
unsigned char p_m_crypt_listen_msg[1100];
unsigned long p_m_crypt_listen_crc;
void cryptman_listen_bch(unsigned char *p, int l);
void set_tone(char *dir, char *name);
void set_echotest(int echotest);
int p_m_portnum; /* used port number (1...n) */
int p_m_b_index; /* index 0,1 0..29 */
int p_m_b_channel; /* number 1,2 1..15,17... */
int p_m_b_exclusive; /* if bchannel is exclusive */
// int p_m_b_reserved; /* set if channel is reserved */
int p_m_b_stid; /* current stack id */
int p_m_b_addr; /* current layer address */
long long p_m_jittercheck; /* time of audio data */
long long p_m_jitterdropped; /* number of bytes dropped */
int p_m_delete; /* true if obj. must del. */
int p_m_hold; /* if port is on hold */
unsigned long p_m_timeout; /* timeout of timers */
time_t p_m_timer; /* start of timer */
int alloc_bchannel(int channel, int exclusive);
void free_bchannel(void);
};
extern unsigned char mISDN_rand[256]; /* noisy randomizer */

221
mail.c Normal file
View File

@ -0,0 +1,221 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** use mailer to send mail about message **
** **
\*****************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
//#include <poll.h>
#include "main.h"
static char *months[] = {
"January", "February", "March", "April", "Mai", "June", "July",
"August", "September", "October", "November", "December"
};
/*
* create mail with or without sample
* the process creates forks to keep pbx running
*/
struct mail_args {
char email[128];
char filename[256];
int year;
int mon;
int mday;
int hour;
int min;
char callerid[64];
char callerintern[32];
char callername[64];
char terminal[32];
};
static void *mail_child(void *arg)
{
struct mail_args *args = (struct mail_args *)arg;
char *email = args->email;
char *filename = args->filename;
int year = args->year;
int mon = args->mon;
int mday = args->mday;
int hour = args->hour;
int min = args->min;
char *callerid = args->callerid;
char *callerintern = args->callerintern;
char *callername = args->callername;
char *terminal = args->terminal;
char command[128];
char buffer[256];
char rbuf[54];
FILE *ph;
int fh;
unsigned char e1, e2, e3;
int i, n, cnt;
unsigned char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
struct sched_param schedp;
int ret;
PDEBUG(DEBUG_EPOINT, "child process started for sending a mail\n");
/* lower priority to keep pbx running fluently */
if (options.schedule > 0)
{
memset(&schedp, 0, sizeof(schedp));
schedp.sched_priority = 0;
ret = sched_setscheduler(0, SCHED_OTHER, &schedp);
if (ret < 0)
{
PERROR("Scheduling to normal priority failed (errno = %d).\nExitting child process...\n", errno);
goto done;
}
}
/* open process */
SPRINT(command, "%s -f%s %s", SENDMAIL, options.email, email);
if ((ph = popen(command, "w")) < 0)
{
PERROR("Cannot send mail using command '%s'\n", command);
goto done;
}
/* send header */
fprintf(ph, "MIME-Version: 1.0\n");
fprintf(ph, "Content-Type: multipart/mixed;\n\tboundary=\"next_part\"\n");
fprintf(ph, "From: %s <%s>\n", NAME, options.email);
fprintf(ph, "To: %s\n", email);
fprintf(ph, "Subject: Message from '%s' recorded.\n\n", callerid);
/* send message */
fprintf(ph, "This is a MIME-encapsulated message\n--next_part\n");
fprintf(ph, "Content-Type: text/plain; charset=us-ascii\nContent-Transfer-Encoding: 7bit\n\n");
fprintf(ph, "\nThe voice box of %s has recorded a message:\n\n * extension: %s\n * from: %s", NAME, terminal, callerid);
if (callerintern[0])
fprintf(ph, " (intern %s)", callerintern);
if (callername[0])
fprintf(ph, " %s", callername);
fprintf(ph, "\n * date: %s %d %d %d:%02d\n\n", months[mon], mday, year+1900, hour, min);
/* attach audio file */
if (filename[0])
if ((fh = open(filename, O_RDONLY)))
{
while(strchr(filename, '/'))
filename = strchr(filename, '/')+1;
fprintf(ph, "--next_part\n");
if (strlen(filename) >= 4)
if (!strcasecmp(filename+strlen(filename)-4, ".wav"))
fprintf(ph, "Content-Type: audio/x-wav;\n\tname=\"%s\"\n", filename);
fprintf(ph, "Content-Transfer-Encoding: base64\nContent-Disposition: inline;\n\tfilename=\"%s\"\n\n", filename);
/* stream from disk and encode */
while(42)
{
/* read exactly one line */
cnt = read(fh, rbuf, 54);
if (cnt <= 0)
break;
/* encode */
n = cnt;
while (n%3)
{
rbuf[n] = 0;
n++;
}
n = n/3;
i = 0;
while(i<n)
{
e1 = rbuf[i+i+i];
e2 = rbuf[i+i+i+1];
e3 = rbuf[i+i+i+2];
buffer[(i<<2)+3] = base64[e3 & 0x3f];
buffer[(i<<2)+2] = base64[((e3>>6)+(e2<<2)) & 0x3f];
buffer[(i<<2)+1] = base64[((e2>>4)+(e1<<4)) & 0x3f];
buffer[i<<2] = base64[e1 >> 2];
i++;
}
if ((cnt%3) > 0)
buffer[(i<<2)-1] = '=';
if ((cnt%3) == 1)
buffer[(i<<2)-2] = '=';
buffer[(i<<2)] = '\n';
buffer[(i<<2)+1] = '\0';
/* write */
fprintf(ph, "%s", buffer);
}
fprintf(ph, "\n\n");
close(fh);
} else
{
SPRINT(buffer, "-Error- Failed to read audio file: '%s'.\n\n", filename);
fprintf(ph, "%s", buffer);
PERROR("%s", buffer);
}
/* finish mail */
fprintf(ph, ".\n");
/* wait for mail to be sent and close process */
pclose(ph);
done:
PDEBUG(DEBUG_EPOINT, "child process done for sending a mail\n");
/* exit process */
memset(args, 0, sizeof(struct mail_args));
free(args);
amemuse--;
return(NULL);
}
void send_mail(char *filename, char *callerid, char *callerintern, char *callername, char *vbox_email, int vbox_year, int vbox_mon, int vbox_mday, int vbox_hour, int vbox_min, char *terminal)
{
struct mail_args *arg;
pthread_t tid;
arg = (struct mail_args *)calloc(1, sizeof(struct mail_args));
if (!arg)
{
PERROR("failed to alloc memory.\n");
return;
}
amemuse++;
SCPY(arg->email, vbox_email);
SCPY(arg->filename, filename);
arg->year = vbox_year;
arg->mon = vbox_mon;
arg->mday = vbox_mday;
arg->hour = vbox_hour;
arg->min = vbox_min;
SCPY(arg->callerid, callerid);
SCPY(arg->callerintern, callerintern);
SCPY(arg->callername, callername);
SCPY(arg->terminal, terminal);
if ((pthread_create(&tid, NULL, mail_child, arg)<0))
{
PERROR("failed to create mail-thread.\n");
return;
}
PDEBUG(DEBUG_EPOINT, "EPOINT '%s' send mail: child process created for sending a mail\n", terminal);
}

1037
main.c Normal file

File diff suppressed because it is too large Load Diff

202
main.h Normal file
View File

@ -0,0 +1,202 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** Header file for defining fixed values for the current version **
** **
\*****************************************************************************/
#define NAME "PBX4Linux"
#define DEFAULT_ENDPOINT_APP EndpointAppPBX
#define VERSION_STRING "3.6 (Januar 2006)"
extern int memuse;
extern int mmemuse;
extern int cmemuse;
extern int ememuse;
extern int pmemuse;
extern int amemuse;
extern int rmemuse;
extern int classuse;
extern int fduse;
extern int fhuse;
#define PDEBUG(mask, fmt, arg...) _printdebug(__FUNCTION__, __LINE__, mask, fmt, ## arg)
#define PERROR(fmt, arg...) _printerror(__FUNCTION__, __LINE__, fmt, ## arg)
#define PDEBUG_RUNTIME(mask, fmt, arg...) _printdebug(NULL, 0, mask, fmt, ## arg)
#define PERROR_RUNTIME(fmt, arg...) _printerror(NULL, 0, fmt, ## arg)
void _printdebug(const char *function, int line, unsigned long mask, const char *fmt, ...);
void printlog(const char *fmt, ...);
void _printerror(const char *function, int line, const char *fmt, ...);
#define DEBUG_CONFIG 0x0001
#define DEBUG_MSG 0x0002
#define DEBUG_STACK 0x0004
#define DEBUG_BCHANNEL 0x0008
#define DEBUG_PORT 0x0100
#define DEBUG_ISDN 0x0110
#define DEBUG_OPAL 0x0120
#define DEBUG_H323 0x0130
//#define DEBUG_KNOCK 0x0140
#define DEBUG_VBOX 0x0180
#define DEBUG_EPOINT 0x0200
#define DEBUG_CALL 0x0400
#define DEBUG_VERSATEL 0x0800
#define DEBUG_CRYPT 0x1000
#define DEBUG_ROUTE 0x2000
#define DEBUG_IDLETIME 0x4000
#define DEBUG_LOG 0x7fff
// check any faulty malloc
#define MALLOC_CHECK_ 1
/*
* one of the bits must be enabled in order to write log files
*/
#define DEBUG_LOG 0x7fff
/* audio buffer for mixer and recording.
* all partys within a call (most time two endpoints) write audio data to the buffer. this is used because
* the buffer experience jitter. if the buffer is too small, jitter will cause drops and gaps.
* if the buffer is too large, the delay is large. 768 is a good value to start with.
*/
#ifdef VOIP
#warning to be removed soon
#endif
#define PORT_BUFFER 768
/* keep this 0 for minimum delay */
#ifdef VOIP
#warning to be removed soon
#endif
#define ISDN_PRELOAD 0
/* the jitterlimit specifies the number of samples received too fast, before
* it recognizes a stalling process.
* but should NOT be less 256.
*/
#ifdef VOIP
#warning to be removed soon
#endif
#define ISDN_JITTERLIMIT 512 /* maximum samples received before dropping */
/* give sendmail program. if not inside $PATH, give absolute path here (e.g. "/usr/sbin/sendmail")
*/
#define SENDMAIL "sendmail"
/* maximum number of redial/powerdial and reply numbers to remember
*/
#define MAX_REMEMBER 50
/* leave it above 1024, because lower values can be unsafe, higher valuse cause
* data larger than 512 bytes of hex strings.
*/
#define RSA_BITS 1536
/* 'goto' or 'menu' actions may cause infinite loops. they will be prevented by this limit.
* Also other recursions, like redialing the 'redial' action must be prevented.
* increase it ONLY IF you have a deeper tree of rule sets, than the value given here.
*/
#define RULE_NESTING 10
/* special debugging for buffer overflow bugs
* note: whenever a buffer gets strange values, the budetect function must
* be modified to detect the change of these values. whenever it is detected,
* an error message is given at budetect function.
*/
//#define BUDETECT_DEF
#ifdef BUDETECT_DEF
#define BUDETECT budetect(__FILE__, __LINE__, __FUNCTION__);
void budetect(const char *file, int line, char *function);
#else
#define BUDETECT ;
#endif
#ifdef H323
#define VOIP
#ifdef OPAL
#error It is not allowed to use H323 and OPAL. Please disable H323, because it is included in OPAL.
#endif
#endif
#ifdef OPAL
#define VOIP
#endif
#ifdef H323INCLUDE
#define NO_VIDEO_CAPTURE
//#include <vector>
//#include <string>
#include <ptlib.h>
#include <h225.h>
#include <h323.h>
#include <h323pdu.h>
#include <h323caps.h>
#include <q931.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
//#include <asm/bitops.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <isdn_net.h>
#include <net_l3.h>
#ifdef __cplusplus
}
#endif
#include "save.h"
#include "options.h"
#include "interface.h"
#include "h323conf.h"
#include "extension.h"
#include "message.h"
#include "endpoint.h"
#include "endpointapp.h"
#include "apppbx.h"
#include "route.h"
#include "port.h"
#include "mISDN.h"
#include "dss1.h"
#ifdef H323
#include "h323.h"
#endif
#ifdef OPAL
#include "opal.h"
#endif
#include "vbox.h"
#include "call.h"
#include "callpbx.h"
#include "callchan.h"
#include "cause.h"
#include "alawulaw.h"
#include "tones.h"
#include "crypt.h"
#include "admin_server.h"
extern double now_d;
extern time_t now;
extern struct tm *now_tm;
extern struct timeval now_tv;
extern struct timezone now_tz;
#ifdef H323INCLUDE
#include "h323_ep.h"
#include "h323_con.h"
#include "h323_chan.h"
extern PMutex mutex_h323; // mutual exclude for synchroniszing threads
extern H323_ep *h323_ep;
#endif

128
message.c Normal file
View File

@ -0,0 +1,128 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** message handling **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "main.h"
MESSAGES
struct message *message_first = NULL;
struct message **messagepointer_end = &message_first;
//#ifdef H323
//PMutex mutex_message;
//#endif
/* creates a new message with the given attributes. the message must be filled then. after filling, the message_put must be called */
struct message *message_create(int id_from, int id_to, int flow, int type)
{
struct message *message;
int i = 0;
while(i < 10)
{
message = (struct message *)calloc(1, sizeof(struct message));
if (message)
break;
if (!i)
PERROR("no mem for message, retrying...\n");
i++;
usleep(300000);
}
if (!message)
{
PERROR("***Fatal error: no mem for message!!! exitting.\n");
exit(-1);
}
mmemuse++;
memset(message, 0, sizeof(struct message));
message->id_from = id_from;
message->id_to = id_to;
message->flow = flow;
message->type = type;
return(message);
}
/* attaches a message to the end of the message chain */
void message_put(struct message *message)
{
/* the mutex prevents from creating two messages at a time (h323 thread and main thread). */
//#ifdef H323
// mutex_message.Wait();
//#endif
if (message->id_to == 0)
{
PDEBUG(DEBUG_MSG, "message %s not written, because destination is 0.\n", messages_txt[message->type]);
message_free(message);
return;
}
if ((options.deb&DEBUG_MSG) && message->type != MESSAGE_DATA)
PDEBUG(DEBUG_MSG, "message %s written from %ld to %ld (memory %x)\n", messages_txt[message->type], message->id_from, message->id_to, message);
*messagepointer_end = message;
messagepointer_end = &(message->next);
//#ifdef H323
// mutex_message.Signal();
//#endif
}
/* detaches the first messages from the message chain */
struct message *message_get(void)
{
struct message *message;
/* the mutex prevents from getting a message while creating a messages at a time (h323 thread and main thread). */
//#ifdef H323
// mutex_message.Wait();
//#endif
if (!message_first)
{
//#ifdef H323
// mutex_message.Signal();
//#endif
return(0);
}
message = message_first;
message_first = message->next;
if (!message_first)
messagepointer_end = &message_first;
//#ifdef H323
// mutex_message.Signal();
//#endif
if ((options.deb&DEBUG_MSG) && message->type != MESSAGE_DATA)
PDEBUG(DEBUG_MSG, "message %s reading from %ld to %ld (memory %x)\n", messages_txt[message->type], message->id_from, message->id_to, message);
return(message);
}
/* free a message */
void message_free(struct message *message)
{
memset(message, 0, sizeof(struct message));
free(message);
mmemuse--;
}

398
message.h Normal file
View File

@ -0,0 +1,398 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** message types and parameters **
** **
\*****************************************************************************/
enum { /* interface types */
INFO_ITYPE_ISDN,
INFO_ITYPE_ISDN_EXTENSION, /* call from internal extension */
INFO_ITYPE_CHAN,
INFO_ITYPE_VBOX,
};
enum { /* number types */
INFO_NTYPE_UNKNOWN,
INFO_NTYPE_SUBSCRIBER,
INFO_NTYPE_NATIONAL,
INFO_NTYPE_INTERNATIONAL,
};
enum { /* number presentation */
INFO_PRESENT_NULL,
INFO_PRESENT_ALLOWED,
INFO_PRESENT_RESTRICTED,
INFO_PRESENT_NOTAVAIL,
};
enum { /* number presentation */
INFO_SCREEN_USER, /* user provided */
INFO_SCREEN_NETWORK, /* network provided */
};
enum { /* redirection reason */
INFO_REDIR_UNKNOWN,
INFO_REDIR_BUSY,
INFO_REDIR_NORESPONSE,
INFO_REDIR_UNCONDITIONAL,
INFO_REDIR_OUTOFORDER,
INFO_REDIR_CALLDEFLECT,
};
#define INFO_NOTIFY_NONE 0x00
#define INFO_NOTIFY_USER_SUSPENDED 0x80
#define INFO_NOTIFY_USER_RESUMED 0x81
#define INFO_NOTIFY_BEARER_SERVICE_CHANGED 0x82
#define INFO_NOTIFY_CALL_COMPLETION_DELAY 0x83
#define INFO_NOTIFY_CONFERENCE_ESTABLISHED 0xc2
#define INFO_NOTIFY_CONFERENCE_DISCONNECTED 0xc3
#define INFO_NOTIFY_OTHER_PARTY_ADDED 0xc4
#define INFO_NOTIFY_ISOLATED 0xc5
#define INFO_NOTIFY_REATTACHED 0xc6
#define INFO_NOTIFY_OTHER_PARTY_ISOLATED 0xc7
#define INFO_NOTIFY_OTHER_PARTY_REATTACHED 0xc8
#define INFO_NOTIFY_OTHER_PARTY_SPLIT 0xc9
#define INFO_NOTIFY_OTHER_PARTY_DISCONNECTED 0xca
#define INFO_NOTIFY_CONFERENCE_FLOATING 0xcb
#define INFO_NOTIFY_CONFERENCE_DISCONNECTED_P 0xcc /* preemted */
#define INFO_NOTIFY_CONFERENCE_FLOATING_S_U_P 0xcf /* served user preemted */
#define INFO_NOTIFY_CALL_IS_A_WAITING_CALL 0xe0
#define INFO_NOTIFY_DIVERSION_ACTIVATED 0xe8
#define INFO_NOTIFY_RESERVED_CT_1 0xe9
#define INFO_NOTIFY_RESERVED_CT_2 0xea
#define INFO_NOTIFY_REVERSE_CHARGING 0xee
#define INFO_NOTIFY_REMOTE_HOLD 0xf9
#define INFO_NOTIFY_REMOTE_RETRIEVAL 0xfa
#define INFO_NOTIFY_CALL_IS_DIVERTING 0xfb
enum { /* diversion types */
INFO_DIVERSION_CFU,
INFO_DIVERSION_CFNR,
INFO_DIVERSION_CFB,
INFO_DIVERSION_CFP,
};
/* bearer capabilities */
#define INFO_BC_SPEECH 0x00
#define INFO_BC_DATAUNRESTRICTED 0x08
#define INFO_BC_DATARESTRICTED 0x09
#define INFO_BC_AUDIO 0x10
#define INFO_BC_DATAUNRESTRICTED_TONES 0x11
#define INFO_BC_VIDEO 0x18
/* bearer mode */
#define INFO_BMODE_CIRCUIT 0
#define INFO_BMODE_PACKET 2
/* bearer user l1 */
#define INFO_INFO1_NONE 0x00
#define INFO_INFO1_V110 0x81
#define INFO_INFO1_ULAW 0x82
#define INFO_INFO1_ALAW 0x83
#define INFO_INFO1_G721 0x84
#define INFO_INFO1_H221H242 0x85
#define INFO_INFO1_NONCCITT 0x87
#define INFO_INFO1_V120 0x88
#define INFO_INFO1_X31HDLC 0x89
/* hlc */
#define INFO_HLC_NONE 0x00
#define INFO_HLC_TELEPHONY 0x81
#define INFO_HLC_FAXG2G3 0x84
#define INFO_HLC_FAXG4 0xa1
#define INFO_HLC_TELETEX1 0xa4
#define INFO_HLC_TELETEX2 0xa8
#define INFO_HLC_TELETEX3 0xb1
#define INFO_HLC_VIDEOTEX1 0xb2
#define INFO_HLC_VIDEOTEX2 0xb3
#define INFO_HLC_TELEX 0xb5
#define INFO_HLC_MHS 0xb8
#define INFO_HLC_OSI 0xc1
#define INFO_HLC_MAINTENANCE 0xde
#define INFO_HLC_MANAGEMENT 0xdf
#define INFO_HLC_AUDIOVISUAL 0xe0
enum { /* isdnsignal */
mISDNSIGNAL_VOLUME,
mISDNSIGNAL_CONF,
mISDNSIGNAL_NODATA, /* no data required */
mISDNSIGNAL_ECHO,
};
/* call-info structure CALLER */
struct caller_info {
char id[32]; /* id of caller (user number) */
char voip[64]; /* URI of voip (or gateway) */
char intern[32]; /* internal id */
char name[16];
int isdn_port; /* internal/external port (if call is isdn) */
char interface[32]; /* interface name the call was from */
int itype; /* type of interface */
int ntype; /* type of number */
int present; /* presentation */
int screen; /* who provided the number */
char display[84]; /* display information */
};
/* call-info structure DIALING */
struct dialing_info {
char number[256]; /* number dialing (so far) */
char interfaces[128]; /* interfaces for extenal calls */
int itype; /* type of interface */
int ntype; /* type of number */
int sending_complete; /* end of dialing */
};
/* call-info structure CONNECT */
struct connect_info {
char id[32]; /* id of caller (user number) */
char voip[64]; /* URI of voip (or gateway) */
char intern[32]; /* internal id */
char name[16];
int isdn_port; /* internal/external port (if call is isdn) */
char interfaces[128]; /* interfaces for extenal calls */
int itype; /* type of interface */
int ntype; /* type of number */
int present; /* presentation */
int screen; /* who provided the number */
char display[84]; /* display information */
};
/* call-info structure DISCONNECT */
struct disconnect_info {
int cause; /* reason for disconnect */
int location; /* disconnect location */
char display[84]; /* optional display information */
};
/* call-info structure REDIR */
struct redir_info {
char id[32]; /* id of caller (user number) */
char voip[64]; /* host of voip (or gateway) */
char intern[32]; /* internal id */
int isdn_port; /* internal/external port (if call is isdn) */
int itype; /* type of interface */
int ntype; /* type of number */
int present; /* presentation */
int screen; /* who provided the number */
int reason; /* reason for redirecing */
};
/* call-info structure capability */
struct capa_info {
int bearer_capa; /* capability */
int bearer_mode; /* circuit/packet */
int bearer_info1; /* alaw,ulaw,... */
int hlc; /* hlc capability */
int exthlc; /* extendet hlc */
};
/* call-info structure NOTIFY */
struct notify_info {
int notify; /* notifications (see INFO_NOTIFY_*) */
char id[32]; /* redirection id (user number) */
char voip[64]; /* host of voip (or gateway) */
char intern[32]; /* internal id */
int isdn_port; /* internal/external port (if call is isdn) */
int itype; /* type of interface */
int ntype; /* type of number */
int present; /* redirection presentation */
char display[84]; /* display information */
int local; /* if set, endpoints gets information about audio channel (open/close) */
};
/* call-info structure FACILITY */
struct facility_info {
char data[256]; /* data info about facility */
int len; /* length of facility content */
};
/* call-info structure USERUSER */
struct useruser_info {
int protocol;
int len;
unsigned char data[128]; /* user-user info (not a sting!)*/
};
/* call-info structure SETUP */
struct message_setup {
int isdn_port; /* card number 1...n (only on calls from internal isdn port) */
int port_type; /* type of port (only required if message is port -> epoint) */
int dtmf; /* used to enabled dtmf dialing at setup state */
int partyline; /* if set, call will be a conference room */
struct caller_info callerinfo; /* information about the caller */
struct dialing_info dialinginfo; /* information about dialing */
struct redir_info redirinfo; /* info on redirection (to the calling user) */
struct capa_info capainfo; /* info on l2,l3 capability */
struct useruser_info useruser; /* user-user */
};
/* call-info structure PARK */
struct park_info {
char callid[8];
int len;
};
/* DATA */
struct param_data {
unsigned char data[512]; /* audio/hdlc data */
int len; /* audio/hdlc data */
int compressed; /* 0 for law-data, 1 for 16-bit data */
unsigned long port_id; /* to identify the source of this data */
int port_type; /* type of the source's port */
};
struct param_play {
char file[512]; /* file name */
int offset; /* offset to start file at (in seconds) */
};
struct param_tone {
char dir[128]; /* directory */
char name[128]; /* file name */
};
struct param_counter {
int current; /* current counter in seconds */
int max; /* total size of file (0=no info) */
};
struct param_mISDNsignal {
int message;
int rxvol;
int txvol;
int conf;
int nodata;
int tone;
int echo;
};
/* encryption control structure CRYPT */
struct param_crypt {
int type; /* see messages in crypt.h */
int len;
unsigned char data[512+32]; /* a block of 512 byte + some overhead */
};
/* structure of message parameter */
union parameter {
struct param_tone tone; /* MESSAGE_TONE */
char dtmf; /* MESSAGE_DTMF */
struct message_setup setup; /* MESSAGE_SETUP */
struct dialing_info information; /* MESSAGE_INFO */
struct connect_info connectinfo; /* CONNECT INFO */
struct disconnect_info disconnectinfo; /* DISCONNECT INFO */
struct notify_info notifyinfo; /* some notifications */
struct facility_info facilityinfo; /* some notifications */
struct park_info parkinfo; /* MESSAGE_SUSPEND, MESSAGE_RESUME */
int state; /* MESSAGE_TIMEOUT */
int knock; /* MESSAGE_KNOCK 0=off !0=on */
int channel; /* MESSAGE_CHANNEL see RELATION_CHANNEL_* (call.h) */
struct param_data data; /* MESSAGE_DATA */
struct param_play play; /* MESSAGE_VBOX_PLAY */
int speed; /* MESSAGE_VBOX_PLAY_SPEED */
struct param_counter counter; /* MESSAGE_TONE_COUNTER */
struct param_mISDNsignal mISDNsignal; /* MESSAGE_mISDNSIGNAL */
struct extension ext; /* tell port about extension information */
struct param_crypt crypt; /* MESSAGE_CRYPT */
};
enum { /* message flow */
PORT_TO_EPOINT,
EPOINT_TO_CALL,
CALL_TO_EPOINT,
EPOINT_TO_PORT,
};
/* message structure */
struct message {
struct message *next;
int type; /* type of message */
int flow; /* from where to where */
unsigned long id_from; /* in case of flow==PORT_TO_EPOINT: id_from is the port's serial, id_to is the epoint's serial */
unsigned long id_to;
union parameter param;
};
enum { /* messages between entities */
MESSAGE_NONE, /* no message */
MESSAGE_TONE, /* set information tone (to isdn port) */
MESSAGE_DTMF, /* dtmf digit (from isdn port) */
MESSAGE_mISDNSIGNAL, /* special mixer command (down to isdn port) */
MESSAGE_SETUP, /* setup message */
MESSAGE_INFORMATION, /* additional digit information */
MESSAGE_OVERLAP, /* call accepted, send more information */
MESSAGE_PROCEEDING, /* proceeding */
MESSAGE_ALERTING, /* ringing */
MESSAGE_CONNECT, /* connect */
MESSAGE_DISCONNECT, /* disconnect with cause */
MESSAGE_RELEASE, /* release with cause */
MESSAGE_TIMEOUT, /* protocol state has timed out (port->epoint) */
MESSAGE_NOTIFY, /* used to send progress and notify infos */
MESSAGE_FACILITY, /* used to facility infos, like aocd */
MESSAGE_SUSPEND, /* suspend port */
MESSAGE_RESUME, /* resume port */
MESSAGE_CHANNEL, /* set status of audio path to endpoint (to call, audio is also set) */
MESSAGE_REMOTE_AUDIO, /* tell remote to set audio status */
MESSAGE_PATTERN, /* pattern information tones available */
MESSAGE_NOPATTERN, /* pattern information tones unavailable */
MESSAGE_CRYPT, /* encryption message */
MESSAGE_DATA, /* audio/hdlc data */
MESSAGE_VBOX_PLAY, /* play recorded file */
MESSAGE_VBOX_PLAY_SPEED,/* change speed of file */
MESSAGE_VBOX_TONE, /* set answering VBOX tone */
MESSAGE_TONE_COUNTER, /* tone counter (for VBOX tone use) */
MESSAGE_TONE_EOF, /* tone is end of file */
MESSAGE_VBOX_RECORD, /* tell endpoint to start recording */
};
#define MESSAGES static const char *messages_txt[] = { \
"MESSAGE_NONE", \
"MESSAGE_TONE", \
"MESSAGE_DTMF", \
"MESSAGE_mISDNSIGNAL", \
"MESSAGE_SETUP", \
"MESSAGE_INFORMATION", \
"MESSAGE_OVERLAP", \
"MESSAGE_PROCEEDING", \
"MESSAGE_ALERTING", \
"MESSAGE_CONNECT", \
"MESSAGE_DISCONNECT", \
"MESSAGE_RELEASE", \
"MESSAGE_TIMEOUT", \
"MESSAGE_NOTIFY", \
"MESSAGE_FACILITY", \
"MESSAGE_SUSPEND", \
"MESSAGE_RESUME", \
"MESSAGE_CHANNEL", \
"MESSAGE_REMOTE_AUDIO", \
"MESSAGE_PATTERN", \
"MESSAGE_NOPATTERN", \
"MESSAGE_CRYPT", \
"MESSAGE_DATA", \
"MESSAGE_VBOX_PLAY", \
"MESSAGE_VBOX_PLAY_SPEED", \
"MESSAGE_VBOX_TONE", \
"MESSAGE_TONE_COUNTER", \
"MESSAGE_TONE_EOF", \
"MESSAGE_VBOX_RECORD", \
};
struct message *message_create(int id_from, int id_to, int flow, int type);
void message_put(struct message *message);
struct message *message_get(void);
void message_free(struct message *message);

161
message.txt Normal file
View File

@ -0,0 +1,161 @@
call state messages between epoint and port, call and endpoint objects:
-----------------------------------------------------------------------
MESSAGE_SETUP
- a new call is set up
MESSAGE_MORE
- more digits are needed
MESSAGE_PROCEEDING
- call proceeds, no more digits needed
MESSAGE_ALERTING
- call alerts, no more digits needed
MESSAGE_CONNECT
- call connects
MESSAGE_DISCONNECT
- call disconnects, but not yet released
MESSAGE_RELEASE
- call has been released
* other messages like dialing information, notifications and others
are processed by the objects and can cause other internal states to change
but will not change any call state. objects may analyze the given information
and process call state message. (e.g MESSAGE_DISCONNECT when dialing a wrong
number)
states of port object:
----------------------
PORT_STATE_IDLE
- port is just created, no setup yet
PORT_STATE_IN_SETUP
- a setup was received from isdn stack
PORT_STATE_OUT_SETUP
- a setup was sent to isdn stack
PORT_STATE_IN_MORE
- the endpoint object requires more digits to complete the call
PORT_STATE_OUT_MORE
- the port object requires more digits to complete the call
PORT_STATE_IN_PROCEEDING
- the incoming call proceeds, no more digits needed
PORT_STATE_OUT_PROCEEDING
- the outgoing call proceeds, no more digits needed
PORT_STATE_IN_ALERTING
- the incoming call alerts, no more digits needed
PORT_STATE_OUT_ALERTING
- the outgoing call alerts, no more digits needed
PORT_STATE_CONNECT
- the call is active
PORT_STATE_IN_DISCONNECT
- the call is disconnected from the incoming side
PORT_STATE_OUT_DISCONNECT
- the call is disconnected from the outgoing side
PORT_STATE_RELEASE
- the call is released, the port object waits for the l3-process to terminate
states of endpoint object:
--------------------------
EPOINT_STATE_IDLE
- endpoint is just created, no setup yet
EPOINT_STATE_OUT_SETUP
- a setup was received from call object
EPOINT_STATE_IN_MORE
- the port object requires more digits to complete the call
EPOINT_STATE_OUT_MORE
- the call object requires more digits to complete the call
EPOINT_STATE_IN_PROCEEDING
- the incoming call proceeds, no more digits needed
EPOINT_STATE_OUT_PROCEEDING
- the outgoing call proceeds, no more digits needed
EPOINT_STATE_IN_ALERTING
- the incoming call alerts, no more digits needed
EPOINT_STATE_OUT_ALERTING
- the outgoing call alerts, no more digits needed
EPOINT_STATE_CONNECT
- the call is active
EPOINT_STATE_IN_DISCONNECT
- the incoming call is disconnected
EPOINT_STATE_OUT_DISCONNECT
- the outgoing call is disconnected
states of call:
---------------
there are no call states.
procedure of messages between port and endpoint objects:
--------------------------------------------------------
INCOMING CALL (port->endpoint)
- the endpoint object is created by the port object.
- a MESSAGE_SETUP is sent as the first message port->endpoint.
the port goes into PORT_STATE_IN_SETUP state.
the endpoint goes into EPOINT_STATE_IN_MORE state or any other state after
processing the given dialing information.
- the endpoint MUST now respond with MESSAGE_MORE, MESSAGE_PROCEEDING,
MESSAGE_ALERTING, MESSAGE_CONNECT, MESSAGE_DISCONNECT.
the endpoint goes into the appropiate EPOINT_STATE_IN_* state.
the port goes into the appropiate PORT_STATE_IN_* state.
OUTGOING CALL (endpoint->port)
- the port object is created by the endpoint object.
- a MESSAGE_SETUP is sent as the first message endpoint->port.
the endpoint goes into EPOINT_STATE_OUT_SETUP state.
the port goes into PORT_STATE_OUT_SETUP state.
- the port may now respond with MESSAGE_MORE, MESSAGE_PROCEEDING,
MESSAGE_ALERTING, MESSAGE_CONNECT, MESSAGE_DISCONNECT.
the port goes into the appropiate PORT_STATE_OUT_* state.
the endpoint goes into the appropiate EPOINT_STATE_OUT_* state.
DISCONNECTING CALL (endpoint->port)
- the endpoint may disconnect the call at any state, except IDLE.
it sends MESSAGE_DISCONNECT.
the endpoint goes into EPOINT_STATE_OUT_DISCONNECT state.
the port goes into PORT_STATE_OUT_DISCONNECT state.
DISCONNECTING CALL (port->endpoint)
- the port may disconnect the call at any state, except IDLE.
it sends MESSAGE_DISCONNECT.
the port goes into PORT_STATE_IN_DISCONNECT state.
the endpoint goes into EPOINT_STATE_IN_DISCONNECT state.
RELEASING CALL (port->endpoint, endpoint->port)
- at any state, this message is possible
the object sends MESSAGE_RELEASE, the port will terminate soon.
the receiving object will unlink the relation to the sending object.
procedure of messages between endpoint and call objects:
CALL PROCEEDING (endpoint->call, call->endpoint)
- any message will be sent to the call and transfered to the other end
- any message will be received from the endpoint coming from the other end
- if more than two endpoints are connected in one call, the messages are
blocked.
- if only one endpoint exists after creation, the call will create another
endpoint and delivers the MESSAGE_SETUP
CALL RELEASE (endpoint->call, call->endpoint)
- the endpoint sends MESSAGE_RELEASE in order to be removed from the call.
the endpoint will soon terminate.
the call will remove the endpoint and if there is only one endpoint left,
it will send a MESSAGE_RELEASE to the endpoint and will release itself.
DISCONNECT and RELEASE
----------------------
the endpoint may receive MESSAGE_RELEASE from a call but may NOT send it
to the port. the port MUST get a MESSAGE_DISCONNECT instead.

497
options.c Normal file
View File

@ -0,0 +1,497 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** reading options.conf and filling structure **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "main.h"
struct options options = {
"/usr/local/pbx/log", /* log file */
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
0x0000, /* debug mode */
'a', /* a-law */
"0", /* national prefix */
"00", /* international prefix */
"tones_american", /* directory of tones */
"", /* directories of tones to fetch */
"extensions", /* directory of extensions */
"", /* h323 endpoint name */
0, /* h323 ringconnect */
0,4, 0,2, 0, 0, 0, 0,4, 0,4, 0,64, /* h323 codecs to use */
0,"",1720, /* allow incoming h323 calls */
0,"", /* register with h323 gatekeeper */
5060, 5, /* SIP port, maxqueue */
0, /* dtmf detection on */
"", /* dummy caller id */
0, /* inband patterns on external calls */
0, /* use tones by dsp.o */
0, /* by default use priority 0 */
"pbx@jolly.de" /* source mail adress */
};
/* read options
*
* read options from options.conf
*/
int read_options(void)
{
FILE *fp=NULL;
char filename[128];
char *p;
char option[32];
char param[256];
unsigned int line,i;
char buffer[256];
#ifdef H323
int codecpri = 0;
#endif
SPRINT(filename, "%s/options.conf", INSTALL_DATA);
if (!(fp=fopen(filename,"r")))
{
PERROR("Cannot open %s\n",filename);
return(-1);
}
line=0;
while((fgets(buffer,sizeof(buffer),fp)))
{
line++;
buffer[sizeof(buffer)-1]=0;
if (buffer[0]) buffer[strlen(buffer)-1]=0;
p=buffer;
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
if (*p==0 || *p=='#') /* ignore comments and empty line */
continue;
option[0]=0;
i=0; /* read option */
while(*p > 32)
{
if (i+1 >= sizeof(option))
{
PERROR_RUNTIME("Error in %s (line %d): option too long.\n",filename,line);
goto error;
}
option[i+1] = '\0';
option[i++] = *p++;
}
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
param[0]=0;
if (*p!=0 && *p!='#') /* param */
{
i=0; /* read param */
while(*p > 31)
{
if (i+1 >= sizeof(param))
{
PERROR_RUNTIME("Error in %s (line %d): param too long.\n",filename,line);
goto error;
}
param[i+1] = '\0';
param[i++] = *p++;
}
}
/* at this point we have option and param */
/* check option */
if (!strcmp(option,"nt_if") || !strcmp(option,"te_if"))
{
PERROR_RUNTIME("Error in %s (line %d): obsolete option %s. Use multiple 'port' options to define ports to use.\n",filename,line,option);
goto error;
} else
if (!strcmp(option,"debug"))
{
if (param[0]==0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
goto error;
}
options.deb = strtol(param, NULL, 0);
PDEBUG(DEBUG_CONFIG, "debugging: 0x%x\n", options.deb);
} else
if (!strcmp(option,"log"))
{
if (param[0]==0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(options.log, param);
PDEBUG(DEBUG_CONFIG, "log file: %s\n", options.log);
} else
if (!strcmp(option,"port"))
{
i = strtol(param, NULL, 0);
if (i < 1 || i > sizeof(options.ports))
{
PERROR_RUNTIME("Error in %s (line %d): port number %s out of range.\n", filename, line, option);
goto error;
}
options.ports[i] |= FLAG_PORT_USE;
PDEBUG(DEBUG_CONFIG, "adding interface: %d (param=%s)\n", i, param);
if (strstr(param, "ptp"))
{
options.ports[i] |= FLAG_PORT_PTP;
PDEBUG(DEBUG_CONFIG, " -> interface shall be ptp\n");
}
} else
#if 0
if (!strcmp(option,"ptp"))
{
options.ptp = 1;
PDEBUG(DEBUG_CONFIG, "ptp layer-2 watch and keep established.\n");
} else
#endif
if (!strcmp(option,"alaw"))
{
options.law = 'a';
PDEBUG(DEBUG_CONFIG, "isdn audio type: alaw\n");
} else
if (!strcmp(option,"ulaw"))
{
options.law = 'u';
PDEBUG(DEBUG_CONFIG, "isdn audio type: ulaw\n");
} else
if (!strcmp(option,"h323_name"))
{
#ifdef H323
SCPY(options.h323_name, param);
PDEBUG(DEBUG_CONFIG, "H323 endpoint name: '%s'\n", param);
#endif
} else
if (!strcmp(option,"h323_ringconnect"))
{
#ifdef H323
options.h323_ringconnect = 1;
PDEBUG(DEBUG_CONFIG, "H323 ringconnect: enabled\n");
#endif
} else
if (!strcmp(option,"h323_gsm"))
{
#ifdef H323
codecpri ++;
options.h323_gsm_pri = codecpri;
options.h323_gsm_opt = atoi(param);
if (atoi(param)<1 && atoi(param)>7)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be in range 1..7.\n",filename,line,option);
goto error;
}
PDEBUG(DEBUG_CONFIG, "H323 codec to use: GSM, MicrosoftGSM priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_g726"))
{
#ifdef H323
codecpri ++;
options.h323_g726_pri = codecpri;
options.h323_g726_opt = atoi(param);
if (atoi(param)<2 && atoi(param)>5)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be in range 2..5.\n",filename,line,option);
goto error;
}
PDEBUG(DEBUG_CONFIG, "H323 codec to use: G726 priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_g7231"))
{
#ifdef H323
codecpri ++;
options.h323_g7231_pri = codecpri;
PDEBUG(DEBUG_CONFIG, "H323 codec to use: G7231 priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_g729a"))
{
#ifdef H323
codecpri ++;
options.h323_g729a_pri = codecpri;
PDEBUG(DEBUG_CONFIG, "H323 codec to use: G729A priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_lpc10"))
{
#ifdef H323
codecpri ++;
options.h323_lpc10_pri = codecpri;
PDEBUG(DEBUG_CONFIG, "H323 codec to use: LPC-10 priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_speex"))
{
#ifdef H323
codecpri ++;
options.h323_speex_pri = codecpri;
options.h323_speex_opt = atoi(param);
if (atoi(param)<2 && atoi(param)>6)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be in range 2..6.\n",filename,line,option);
goto error;
}
PDEBUG(DEBUG_CONFIG, "H323 codec to use: Speex priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_xspeex"))
{
#ifdef H323
codecpri ++;
options.h323_xspeex_pri = codecpri;
options.h323_xspeex_opt = atoi(param);
if (atoi(param)<2 && atoi(param)>6)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be in range 2..6.\n",filename,line,option);
goto error;
}
PDEBUG(DEBUG_CONFIG, "H323 codec to use: XiphSpeex priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_law"))
{
#ifdef H323
codecpri ++;
options.h323_law_pri = codecpri;
options.h323_law_opt = atoi(param);
if (atoi(param)<10 && atoi(param)>240)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be in range 10..240.\n",filename,line,option);
goto error;
}
PDEBUG(DEBUG_CONFIG, "H323 codec to use: Alaw, muLaw priority %d\n", codecpri);
#endif
} else
if (!strcmp(option,"h323_icall"))
{
#ifdef H323
options.h323_icall = 1;
SCPY(options.h323_icall_prefix, param);
PDEBUG(DEBUG_CONFIG, "process incoming H323 call with prefix '%s'\n", param);
#endif
} else
if (!strcmp(option,"h323_port"))
{
#ifdef H323
options.h323_port = atoi(param);
PDEBUG(DEBUG_CONFIG, "use port for incoming H323 calls: %d\n", atoi(param));
#endif
} else
if (!strcmp(option,"sip_port"))
{
#ifdef SIP
options.sip_port = atoi(param);
PDEBUG(DEBUG_CONFIG, "use port for incoming SIP calls: %d\n", atoi(param));
#endif
} else
if (!strcmp(option,"sip_maxqueue"))
{
#ifdef SIP
options.sip_maxqueue = atoi(param);
PDEBUG(DEBUG_CONFIG, "number of simultanious incoming sockets for SIP calls: %d\n", atoi(param));
#endif
} else
if (!strcmp(option,"h323_gatekeeper"))
{
#ifdef H323
options.h323_gatekeeper = 1;
if (param[0])
{
SCPY(options.h323_gatekeeper_host, param);
}
PDEBUG(DEBUG_CONFIG, "register with H323 gatekeeper (%s)\n", (param[0])?param:"automatically");
#endif
} else
if (!strcmp(option,"tones_dir"))
{
if (param[0]==0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
goto error;
}
if (param[strlen(param)-1] == '/')
param[strlen(param)-1]=0;
SCPY(options.tones_dir, param);
PDEBUG(DEBUG_CONFIG, "directory of tones: %s\n",param);
} else
if (!strcmp(option,"fetch_tones"))
{
if (param[0]==0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
goto error;
}
if (param[strlen(param)-1] == '/')
param[strlen(param)-1]=0;
SCPY(options.fetch_tones, param);
PDEBUG(DEBUG_CONFIG, "directories of tones to fetch: %s\n",param);
} else
if (!strcmp(option,"extensions_dir"))
{
if (param[0]==0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
goto error;
}
if (param[strlen(param)-1] == '/')
param[strlen(param)-1]=0;
SCPY(options.extensions_dir, param);
PDEBUG(DEBUG_CONFIG, "directory of extensions: %s\n",param);
} else
if (!strcmp(option,"national"))
{
SCPY(options.national, param);
PDEBUG(DEBUG_CONFIG, "national dial prefix: %s\n", param);
} else
if (!strcmp(option,"international"))
{
SCPY(options.international, param);
PDEBUG(DEBUG_CONFIG, "inernational dial prefix: %s\n", param);
} else
if (!strcmp(option,"nodtmf"))
{
options.nodtmf = 1;
PDEBUG(DEBUG_CONFIG, "disable dtmf detection\n");
} else
if (!strcmp(option,"dummyid"))
{
SCPY(options.dummyid, param);
PDEBUG(DEBUG_CONFIG, "dummy caller id\n", param);
} else
if (!strcmp(option,"inbandpattern"))
{
if (!strcasecmp(param, "yes"))
options.inbandpattern = 1;
PDEBUG(DEBUG_CONFIG, "inband pattern = %s\n", (options.inbandpattern)?"yes":"no");
} else
if (!strcmp(option,"dsptones"))
{
if (!strcasecmp(param, "american"))
options.dsptones = DSP_AMERICAN;
else if (!strcasecmp(param, "german"))
options.dsptones = DSP_GERMAN;
else if (!strcasecmp(param, "oldgerman"))
options.dsptones = DSP_OLDGERMAN;
else if (!strcasecmp(param, "none"))
options.dsptones = DSP_NONE;
else {
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
goto error;
}
PDEBUG(DEBUG_CONFIG, "dsp tones = %d\n", options.dsptones);
} else
if (!strcmp(option,"schedule"))
{
options.schedule = atoi(param);
if (options.schedule < 0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be at least '0'.\n", filename,line,option);
goto error;
}
if (options.schedule > 99)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s must be '99' or less.\n", filename,line,option);
goto error;
}
if (atoi(param))
PDEBUG(DEBUG_CONFIG, "use real time scheduler priority: %d\n", atoi(param));
else
PDEBUG(DEBUG_CONFIG, "don't use real time scheduler\n");
} else
if (!strcmp(option,"email"))
{
if (param[0]==0)
{
PERROR_RUNTIME("Error in %s (line %d): parameter for option %s missing.\n", filename,line,option);
goto error;
}
SCPY(options.email, param);
PDEBUG(DEBUG_CONFIG, "source mail address of pbx: %s\n", param);
} else
{
PERROR_RUNTIME("Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
goto error;
}
}
#if 0
if (!options.dsptones)
{
PERROR_RUNTIME("Error in %s (line %d): option 'dsptones' missing.\n", filename);
goto error;
}
#endif
if (!options.tones_dir[0])
{
PERROR_RUNTIME("Error in %s (line %d): option 'tones_dir' with parameter missing.\n", filename);
goto error;
}
if (fp) fclose(fp);
return(1);
error:
if (fp) fclose(fp);
return(0);
}

59
options.h Normal file
View File

@ -0,0 +1,59 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** options header file **
** **
\*****************************************************************************/
struct options {
char log[128]; /* location of log file */
char ports[256]; /* use of ports */
// int ptp; /* if layer 2 should be watched */
int deb; /* debugging */
char law; /* 'a' or 'u' law */
char national[10]; /* prefix for national calls */
char international[10]; /* prefix for international calls */
char tones_dir[64]; /* directory of all tones/patterns */
char fetch_tones[256]; /* directories of tones to fetch */
char extensions_dir[64]; /* directory of extensions */
char h323_name[128]; /* the name of h323 endpoint */
int h323_ringconnect; /* connected when ringing */
int h323_gsm_pri; /* priority to use of GSM codec (0 == don't use) */
int h323_gsm_opt;
int h323_g726_pri; /* priority to use of G726 codec (0 == don't use) */
int h323_g726_opt;
int h323_g7231_pri; /* priority to use of G7231 codec (0 == don't use) */
int h323_g729a_pri; /* priority to use of G729a codec (0 == don't use) */
int h323_lpc10_pri; /* priority to use of lpc-10 codec (0 == don't use) */
int h323_speex_pri; /* priority to use of speex codec (0 == don't use) */
int h323_speex_opt;
int h323_xspeex_pri; /* priority to use of xspeex codec (0 == don't use) */
int h323_xspeex_opt;
int h323_law_pri; /* priority to use of law codec (0 == don't use) */
int h323_law_opt;
int h323_icall; /* allow incoming h323 calls */
char h323_icall_prefix[32]; /* the prefix */
int h323_port; /* port for incoming calls */
int h323_gatekeeper; /* register with h323 gatekeeper */
char h323_gatekeeper_host[128];/* the gatekeeper host */
int sip_port;
int sip_maxqueue;
int nodtmf; /* use dtmf detection */
char dummyid[32]; /* caller id for external calls if not available */
int inbandpattern; /* inband patterns on external calls */
int dsptones; /* tones will be generated via dsp.o 1=american 2=ger */
int schedule; /* run process in realtime @ given priority */
char email[128]; /* source email address */
};
extern struct options options;
int read_options(void);

2116
port.cpp Normal file

File diff suppressed because it is too large Load Diff

238
port.h Normal file
View File

@ -0,0 +1,238 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** port header file **
** **
\*****************************************************************************/
#ifndef PORT_HEADER
#define PORT_HEADER
/* type of port */
#define PORT_TYPE_NULL 0x0000
#define PORT_CLASS_mISDN 0x0100
#define PORT_CLASS_MASK 0xff00
#define PORT_CLASS_mISDN_DSS1 0x0110
#define PORT_CLASS_mISDN_MASK 0xfff0
/* nt-mode */
#define PORT_TYPE_DSS1_NT_IN 0x0111
#define PORT_TYPE_DSS1_NT_OUT 0x0112
/* te-mode */
#define PORT_TYPE_DSS1_TE_IN 0x0113
#define PORT_TYPE_DSS1_TE_OUT 0x0114
/* sip */
#define PORT_TYPE_SIP_IN 0x0121
#define PORT_TYPE_SIP_OUT 0x0122
/* h323 */
#define PORT_TYPE_H323_IN 0x0211
#define PORT_TYPE_H323_OUT 0x0212
/* answering machine */
#define PORT_TYPE_VBOX_OUT 0x0311
enum { /* states of call */
PORT_STATE_IDLE, /* no call */
PORT_STATE_IN_SETUP, /* incoming connection */
PORT_STATE_OUT_SETUP, /* outgoing connection */
PORT_STATE_IN_OVERLAP, /* more informatiopn needed */
PORT_STATE_OUT_OVERLAP, /* more informatiopn needed */
PORT_STATE_IN_PROCEEDING,/* call is proceeding */
PORT_STATE_OUT_PROCEEDING,/* call is proceeding */
PORT_STATE_IN_ALERTING, /* call is ringing */
PORT_STATE_OUT_ALERTING,/* call is ringing */
PORT_STATE_CONNECT_WAITING,/* connect is sent to the network, waiting for acknowledge */
PORT_STATE_CONNECT, /* call is connected and transmission is enabled */
PORT_STATE_IN_DISCONNECT,/* incoming disconnected */
PORT_STATE_OUT_DISCONNECT,/* outgoing disconnected */
PORT_STATE_RELEASE, /* call released */
};
#define PORT_STATE_NAMES \
static char *state_name[] = { \
"PORT_STATE_IDLE", \
"PORT_STATE_IN_SETUP", \
"PORT_STATE_OUT_SETUP", \
"PORT_STATE_IN_OVERLAP", \
"PORT_STATE_OUT_OVERLAP", \
"PORT_STATE_IN_PROCEEDING", \
"PORT_STATE_OUT_PROCEEDING", \
"PORT_STATE_IN_ALERTING", \
"PORT_STATE_OUT_ALERTING", \
"PORT_STATE_CONNECT_WAITING", \
"PORT_STATE_CONNECT", \
"PORT_STATE_IN_DISCONNECT", \
"PORT_STATE_OUT_DISCONNECT", \
"PORT_STATE_RELEASE", \
};
enum { /* event list from listening to tty */
TTYI_EVENT_nodata, /* no data was received nor processed */
TTYI_EVENT_NONE, /* nothing happens */
TTYI_EVENT_CONNECT, /* a connection is made */
TTYI_EVENT_RING, /* incoming call */
TTYI_EVENT_CALLER, /* caller id information */
TTYI_EVENT_INFO, /* dialing information */
TTYI_EVENT_OVERLAP, /* setup complete, awaiting more dialing info */
TTYI_EVENT_PROC, /* proceeding */
TTYI_EVENT_ALRT, /* alerting */
TTYI_EVENT_CONN, /* connect */
TTYI_EVENT_DISC, /* disconnect */
TTYI_EVENT_RELE, /* release signal */
TTYI_EVENT_BUSY, /* channel unavailable */
};
/* structure of epoint_list */
struct epoint_list {
struct epoint_list *next;
unsigned long epoint_id;
int active;
};
inline unsigned long ACTIVE_EPOINT(struct epoint_list *epointlist)
{
while(epointlist)
{
if (epointlist->active)
return(epointlist->epoint_id);
epointlist = epointlist->next;
}
return(0);
}
inline unsigned long INACTIVE_EPOINT(struct epoint_list *epointlist)
{
while(epointlist)
{
if (!epointlist->active)
return(epointlist->epoint_id);
epointlist = epointlist->next;
}
return(0);
}
/* a linked list of soft-mixer relations */
struct mixer_relation {
struct mixer_relation *next; /* next in list */
unsigned long port_id; /* port related to */
int mixer_writep; /* write pointer in buffer */
};
/* structure of port settings */
struct port_settings {
char tones_dir[256]; /* directory of current tone */
int tout_setup;
int tout_dialing;
int tout_proceeding;
int tout_alerting;
int tout_disconnect;
// int tout_hold;
// int tout_park;
int no_seconds; /* don't send seconds with time information element */
};
/* generic port class */
class Port
{
public:
/* methods */
Port(int type, char *portname, struct port_settings *settings);
virtual ~Port();
class Port *next; /* next port in list */
int p_type; /* type of port */
virtual int handler(void);
virtual int message_epoint(unsigned long epoint_id, int message, union parameter *param);
virtual void set_echotest(int echotest);
virtual void set_tone(char *dir, char *name);
virtual int read_audio(unsigned char *buffer, int length, int compressed);
struct port_settings p_settings;
/* tone */
int p_debug_nothingtosend; /* used for debugging the, if we have currently nothing to send (used for ISDN) */
char p_tone_dir[256]; /* name of current directory */
char p_tone_name[256]; /* name of current tone */
char p_tone_fh; /* file descriptor of current tone or -1 if not open */
void *p_tone_fetched; /* pointer to fetched data */
int p_tone_codec; /* codec that the tone is made of */
long p_tone_size, p_tone_left; /* size of tone in bytes (not samples), bytes left */
long p_tone_eof; /* flag that makes the use of eof message */
long p_tone_counter; /* flag that makes the use of counter message */
long p_tone_speed; /* speed of current tone, 1=normal, may also be negative */
// char p_knock_fh; /* file descriptor of knocking tone or -1 if not open */
// void *p_knock_fetched; /* pointer to fetched data */
// int p_knock_codec;
// long p_knock_size, p_knock_left;
void set_vbox_tone(char *dir, char *name);/* tone of answering machine */
void set_vbox_play(char *name, int offset); /* sample of answ. */
void set_vbox_speed(int speed); /* speed of answ. */
/* user space mixer buffer */
signed long p_mixer_buffer[PORT_BUFFER]; /* mixer buffer */
signed long p_record_buffer[PORT_BUFFER]; /* record buffer */
signed long p_stereo_buffer[PORT_BUFFER]; /* record buffer for stereo (user only) */
struct mixer_relation *p_mixer_rel; /* list of mixer relations */
int p_mixer_readp; /* read pointer in buffer */
/* methods */
void mixer(union parameter *param);
/* identification */
unsigned long p_serial; /* serial unique id of port */
char p_name[128]; /* name of port or token (h323) */
/* endpoint relation */
struct epoint_list *p_epointlist; /* endpoint relation */
/* state */
int p_state; /* state of port */
void new_state(int state); /* set new state */
struct caller_info p_callerinfo; /* information about the caller */
struct dialing_info p_dialinginfo; /* information about dialing */
struct connect_info p_connectinfo; /* information about connected line */
struct redir_info p_redirinfo; /* info on redirection (to the calling user) */
struct capa_info p_capainfo; /* info on l2,l3 capacity */
int p_echotest; /* set to echo audio data FROM port back to port's mixer */
/* recording */
int open_record(int type, int mode, int skip, char *terminal, int anon_ignore, char *vbox_email, int vbox_email_file);
void close_record(int beep);
FILE *p_record; /* recording fp: if not NULL, recording is enabled */
int p_record_type; /* codec to use: RECORD_MONO, RECORD_STEREO, ... */
int p_record_skip; /* skip bytes before writing the sample */
unsigned long p_record_length; /* size of what's written so far */
char p_record_filename[256]; /* record filename */
int p_record_vbox; /* 0= normal recording, 1= announcement, 2= record to vbox dir */
int p_record_vbox_year; /* time when vbox recording started */
int p_record_vbox_mon;
int p_record_vbox_mday;
int p_record_vbox_hour;
int p_record_vbox_min;
char p_record_extension[32]; /* current name (digits) of extension */
int p_record_anon_ignore;
char p_record_vbox_email[128];
int p_record_vbox_email_file;
virtual void printisdn(char *fmt, ...);
void free_epointlist(struct epoint_list *epointlist);
void free_epointid(unsigned long epoint_id);
struct epoint_list *epointlist_new(unsigned long epoint_id);
};
extern Port *port_first;
extern unsigned long port_serial;
class Port *find_port_with_token(char *name);
class Port *find_port_id(unsigned long port_id);
#endif // PORT_HEADER

90
q931.h Normal file
View File

@ -0,0 +1,90 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** information elements support header **
** **
\*****************************************************************************/
#define MT_ALERTING 0x01
#define MT_CALL_PROCEEDING 0x02
#define MT_CONNECT 0x07
#define MT_CONNECT_ACKNOWLEDGE 0x0f
#define MT_PROGRESS 0x03
#define MT_SETUP 0x05
#define MT_SETUP_ACKNOWLEDGE 0x0d
#define MT_RESUME 0x26
#define MT_RESUME_ACKNOWLEDGE 0x2e
#define MT_RESUME_REJECT 0x22
#define MT_SUSPEND 0x25
#define MT_SUSPEND_ACKNOWLEDGE 0x2d
#define MT_SUSPEND_REJECT 0x21
#define MT_USER_INFORMATION 0x20
#define MT_DISCONNECT 0x45
#define MT_RELEASE 0x4d
#define MT_RELEASE_COMPLETE 0x5a
#define MT_RESTART 0x46
#define MT_RESTART_ACKNOWLEDGE 0x4e
#define MT_SEGMENT 0x60
#define MT_CONGESTION_CONTROL 0x79
#define MT_INFORMATION 0x7b
#define MT_FACILITY 0x62
#define MT_NOTIFY 0x6e
#define MT_STATUS 0x7d
#define MT_STATUS_ENQUIRY 0x75
#define MT_HOLD 0x24
#define MT_HOLD_ACKNOWLEDGE 0x28
#define MT_HOLD_REJECT 0x30
#define MT_RETRIEVE 0x31
#define MT_RETRIEVE_ACKNOWLEDGE 0x33
#define MT_RETRIEVE_REJECT 0x37
#define IE_SEGMENT 0x00
#define IE_BEARER 0x04
#define IE_CAUSE 0x08
#define IE_CALL_ID 0x10
#define IE_CALL_STATE 0x14
#define IE_CHANNEL_ID 0x18
#define IE_FACILITY 0x1c
#define IE_PROGRESS 0x1e
#define IE_NET_FAC 0x20
#define IE_NOTIFY 0x27
#define IE_DISPLAY 0x28
#define IE_DATE 0x29
#define IE_KEYPAD 0x2c
#define IE_SIGNAL 0x34
#define IE_INFORATE 0x40
#define IE_E2E_TDELAY 0x42
#define IE_TDELAY_SEL 0x43
#define IE_PACK_BINPARA 0x44
#define IE_PACK_WINSIZE 0x45
#define IE_PACK_SIZE 0x46
#define IE_CUG 0x47
#define IE_REV_CHARGE 0x4a
#define IE_CONNECT_PN 0x4c
#define IE_CONNECT_SUB 0x4d
#define IE_CALLING_PN 0x6c
#define IE_CALLING_SUB 0x6d
#define IE_CALLED_PN 0x70
#define IE_CALLED_SUB 0x71
#define IE_REDIR_NR 0x74
#define IE_REDIR_DN 0x76
#define IE_TRANS_SEL 0x78
#define IE_RESTART_IND 0x79
#define IE_LLC 0x7c
#define IE_HLC 0x7d
#define IE_USER_USER 0x7e
#define IE_ESCAPE 0x7f
#define IE_CNIP 0x80 /* siemens centrex extension */
#define IE_SHIFT 0x90
#define IE_MORE_DATA 0xa0
#define IE_COMPLETE 0xa1
#define IE_CONGESTION 0xb0
#define IE_REPEAT 0xd0
#define CENTREX_FAC 0x88
#define CENTREX_ID 0xa1

2524
route.c Normal file

File diff suppressed because it is too large Load Diff

282
route.h Normal file
View File

@ -0,0 +1,282 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** match header file **
** **
\*****************************************************************************/
/* memory structure of rulesets */
enum { /* value types */
VALUE_TYPE_NULL,
VALUE_TYPE_INTEGER,
VALUE_TYPE_INTEGER_RANGE,
VALUE_TYPE_STRING,
VALUE_TYPE_STRING_RANGE,
};
enum { /* how to parse text file during startup */
COND_TYPE_NULL,
COND_TYPE_INTEGER,
COND_TYPE_TIME,
COND_TYPE_MDAY,
COND_TYPE_MONTH,
COND_TYPE_WDAY,
COND_TYPE_YEAR,
COND_TYPE_STRING,
COND_TYPE_IP,
COND_TYPE_CAPABILITY,
COND_TYPE_BMODE,
COND_TYPE_IFATTR,
};
enum { /* what to check during runtime */
#ifdef PBX
MATCH_EXTERN,
MATCH_INTERN,
#endif
MATCH_H323,
// MATCH_IP,
MATCH_PORT,
MATCH_INTERFACE,
MATCH_CALLERID,
MATCH_EXTENSION,
MATCH_DIALING,
MATCH_ENBLOCK,
MATCH_OVERLAP,
MATCH_ANONYMOUS,
MATCH_VISIBLE,
MATCH_UNKNOWN,
MATCH_AVAILABLE,
MATCH_FAKE,
MATCH_REAL,
MATCH_REDIRECTED,
MATCH_DIRECT,
MATCH_REDIRID,
MATCH_TIME,
MATCH_MDAY,
MATCH_MONTH,
MATCH_YEAR,
MATCH_WDAY,
MATCH_CAPABILITY,
MATCH_INFOLAYER1,
MATCH_HLC,
MATCH_FILE,
MATCH_EXECUTE,
MATCH_DEFAULT,
MATCH_TIMEOUT,
MATCH_FREE,
MATCH_NOTFREE,
MATCH_DOWN,
MATCH_UP,
MATCH_BUSY,
MATCH_IDLE,
};
enum { /* how to parse text file during startup */
PARAM_TYPE_NULL,
PARAM_TYPE_INTEGER,
PARAM_TYPE_STRING,
PARAM_TYPE_YESNO,
PARAM_TYPE_CAPABILITY,
PARAM_TYPE_BMODE,
PARAM_TYPE_DIVERSION,
PARAM_TYPE_DESTIN,
PARAM_TYPE_PORTS,
PARAM_TYPE_TYPE,
PARAM_TYPE_CALLERIDTYPE,
};
/* parameter ID bits */
#define PARAM_PROCEEDING 1LL
#define PARAM_ALERTING (1LL<<1)
#define PARAM_CONNECT (1LL<<2)
#ifdef PBX
#define PARAM_EXTENSION (1LL<<3)
#define PARAM_EXTENSIONS (1LL<<4)
#endif
#define PARAM_PREFIX (1LL<<5)
#define PARAM_CAPA (1LL<<6)
#define PARAM_BMODE (1LL<<7)
#define PARAM_INFO1 (1LL<<8)
#define PARAM_HLC (1LL<<9)
#define PARAM_EXTHLC (1LL<<10)
#define PARAM_PRESENT (1LL<<11)
#define PARAM_DIVERSION (1LL<<12)
#define PARAM_DEST (1LL<<13)
#define PARAM_SELECT (1LL<<14)
#define PARAM_DELAY (1LL<<15)
#define PARAM_LIMIT (1LL<<16)
#define PARAM_HOST (1LL<<17)
#define PARAM_PORT (1LL<<18)
#define PARAM_INTERFACES (1LL<<19)
#define PARAM_ADDRESS (1LL<<20)
#define PARAM_SAMPLE (1LL<<21)
#ifdef PBX
#define PARAM_ANNOUNCEMENT (1LL<<22)
#endif
#define PARAM_RULESET (1LL<<23)
#define PARAM_CAUSE (1LL<<24)
#define PARAM_LOCATION (1LL<<25)
#define PARAM_DISPLAY (1LL<<26)
#define PARAM_PORTS (1LL<<27)
#define PARAM_TPRESET (1LL<<28)
#define PARAM_FILE (1LL<<29)
#define PARAM_CONTENT (1LL<<30)
#define PARAM_APPEND (1LL<<31)
#define PARAM_EXECUTE (1LL<<32)
#define PARAM_PARAM (1LL<<33)
#define PARAM_TYPE (1LL<<34)
#define PARAM_COMPLETE (1LL<<35)
#define PARAM_CALLERID (1LL<<36)
#define PARAM_CALLERIDTYPE (1LL<<37)
#define PARAM_CALLTO (1LL<<38)
#define PARAM_ROOM (1LL<<39)
#define PARAM_TIMEOUT (1LL<<40)
#ifdef PBX
#define PARAM_NOPASSWORD (1LL<<41)
#endif
/* action index
* NOTE: The given index is the actual entry number of action_defs[], so add/remove both lists!!!
*/
#define ACTION_EXTERNAL 0
#define ACTION_INTERNAL 1
#define ACTION_OUTDIAL 2
#define ACTION_H323 3
#define ACTION_CHAN 4
#define ACTION_VBOX_RECORD 5
#define ACTION_PARTYLINE 6
#define ACTION_LOGIN 7
#define ACTION_CALLERID 8
#define ACTION_CALLERIDNEXT 9
#define ACTION_FORWARD 10
#define ACTION_REDIAL 11
#define ACTION_REPLY 12
#define ACTION_POWERDIAL 13
#define ACTION_CALLBACK 14
#define ACTION_ABBREV 15
#define ACTION_TEST 16
#define ACTION_PLAY 17
#define ACTION_VBOX_PLAY 18
#define ACTION_CALCULATOR 19
#define ACTION_TIMER 20
#define ACTION_GOTO 21
#define ACTION_MENU 22
#define ACTION_DISCONNECT 23
#define ACTION_HELP 24
#define ACTION_DEFLECT 25
#define ACTION_SETFORWARD 26
#define ACTION_EXECUTE 27
#define ACTION_FILE 28
#define ACTION_PICK 29
#define ACTION_PASSWORD 30
#define ACTION_PASSWORD_WRITE 31
#define ACTION_NOTHING 32
#define ACTION_EFI 33
struct route_cond { /* an item */
struct route_cond *next; /* next entry */
int index; /* index of cond_defs */
int match; /* what is matching (MATCH_*) */
int value_type; /* type of value (VALUE_TYPE_*) */
int value_extension; /* will it be extended? */
int integer_value; /* first integer */
int integer_value_to; /* second integer */
char *string_value; /* first string */
char *string_value_to; /* second string */
int comp_string; /* compare value of strings */
};
struct route_param { /* a parameter */
struct route_param *next; /* next item */
int index; /* index of param_defs */
unsigned long long id; /* what is it (PARAM_*) */
int value_type; /* type of value (VALUE_TYPE_*) */
int value_extension; /* will it be extended? */
int integer_value; /* integer value */
char *string_value; /* string value */
};
struct route_action { /* an action has a list of parameters */
struct route_action *next; /* next item */
struct route_param *param_first; /* link to parameter list */
int index; /* index of action_defs */
int timeout; /* timeout value for action (0 = no timeout) */
int line; /* line parsed from */
};
struct route_rule { /* a rule has a list of items and actions */
struct route_rule *next; /* next item */
char file[128]; /* filename */
int line; /* line parsed from */
struct route_cond *cond_first; /* link to condition list */
struct route_action *action_first; /* link to action list */
};
struct route_ruleset { /* the ruleset is a list of rules */
struct route_ruleset *next; /* next item */
char file[128]; /* filename */
int line; /* line parsed from */
char name[64]; /* name of rule */
struct route_rule *rule_first; /* linke to rule list */
};
struct cond_defs { /* defintion of all conditions */
char *name; /* item's name */
int match; /* what to check */
int type; /* type of value (COND_TYPE) */
char *doc; /* syntax */
char *help; /* short help */
};
struct param_defs { /* definition of all options */
unsigned long long id; /* ID of parameter (just for checking) */
char *name; /* name of parameter */
int type; /* type of value (PARAM_TYPE_*) */
char *doc; /* syntax */
char *help; /* quick help */
};
struct action_defs { /* definition of all actions */
int id; /* ID of parameter (just for checking) */
char *name;
void (EndpointAppPBX::*init_func)(void);
void (EndpointAppPBX::*dialing_func)(void);
void (EndpointAppPBX::*hangup_func)(void);
unsigned long long params;
char *help;
};
extern struct cond_defs cond_defs[];
extern struct param_defs param_defs[];
extern struct action_defs action_defs[];
extern struct route_ruleset *ruleset_first;
extern struct route_ruleset *ruleset_main;
extern struct route_action action_external;
extern struct route_action action_internal;
extern struct route_action action_h323;
extern struct route_action action_chan;
extern struct route_action action_vbox;
extern struct route_action action_partyline;
extern struct route_action action_password;
extern struct route_action action_password_write;
extern struct route_action action_disconnect;
/* functions */
void doc_rules(const char *action);
void ruleset_free(struct route_ruleset *ruleset_start);
void ruleset_debug(struct route_ruleset *ruleset_start);
extern char ruleset_error[256];
struct route_ruleset *ruleset_parse(void);
struct route_ruleset *getrulesetbyname(char *name);

64
save.h Normal file
View File

@ -0,0 +1,64 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** Macros to do save string operations to avoid buffer overflows. **
** **
\*****************************************************************************/
/* save strcpy/strncpy */
#define SCPY(dst, src) scpy(dst, src, sizeof(dst))
extern __inline__ void scpy(char *dst, char *src, unsigned int siz)
{
strncpy(dst, src, siz);
dst[siz-1] = '\0';
}
/* save strcat/strncat */
#define SCAT(dst, src) scat(dst, src, sizeof(dst))
extern __inline__ void scat(char *dst, char *src, unsigned int siz)
{
strncat(dst, src, siz);
dst[siz-1] = '\0';
}
/* save concat of a byte */
#define SCCAT(dst, src) sccat(dst, src, sizeof(dst))
extern __inline__ void sccat(char *dst, char chr, unsigned int siz)
{
if (strlen(dst) < siz-1)
{
dst[strlen(dst)+1] = '\0';
dst[strlen(dst)] = chr;
}
}
/* save sprintf/snprintf */
#define SPRINT(dst, fmt, arg...) sprint(dst, sizeof(dst), fmt, ## arg)
extern __inline__ void sprint(char *dst, unsigned int siz, char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vsnprintf(dst, siz, fmt, args);
dst[siz-1] = '\0';
va_end(args);
}
/* unsave */
#define UCPY strcpy
#define UNCPY strncpy
#define UCAT strcat
#define UNCAT strncat
#define UPRINT sprintf
#define UNPRINT snprintf
#define VUNPRINT vsnprintf

37
todo.txt Normal file
View File

@ -0,0 +1,37 @@
make asterisk call implementation
interface.conf neu
mixer abspecken
call recording
call zu mehreren extensions
old stuff....
NOTE: check CENTREX
durchstellen mit disconnect
durchstellen mit keypad
ruf bei CFP gibt besetzt, wenn teilnehmer intern besetzt ist.
short ring
sleep relaxed
auto pick
alarm clock (timer)
sonderwahlton
facility: diversion, 3pty, ...

669
tones.c Normal file
View File

@ -0,0 +1,669 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** opening and reading tone **
** **
\*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include "main.h"
/*
notes about codecs:
CODEC_OFF is a none accepted value
CODEC_LAW is 8 bit (1 byte) data 8khz
other codecs are 16 bit (2 bytes) data 8khz
the read_tone() will return law or 16bit mono. the read_tone will convert all other formats to 16bit mono.
*/
/*
* open the tone (don't increase fhuse, since it is done after calling this function)
* NOTE: length and left will be set to the number of samples, NOT bytes
*/
struct fmt {
unsigned short stereo; /* 1 = pcm, 2 = adpcm */
unsigned short channels; /* number of channels */
unsigned long sample_rate; /* sample rate */
unsigned long data_rate; /* data rate */
unsigned short bytes_sample; /* bytes per sample (all channels) */
unsigned short bits_sample; /* bits per sample (one channel) */
};
int open_tone(char *file, int *codec, signed long *length, signed long *left)
{
int fh;
char filename[256];
char linkname[256];
unsigned char buffer[256];
struct fmt *fmt;
int channels, bytes;
unsigned long size, chunk;
int gotfmt = 0;
struct stat _stat;
int linksize;
int l;
char *p;
/* try to open the law file */
SPRINT(filename, "%s.isdn", file);
if ((fh = open(filename, O_RDONLY)) >= 0)
{
/* stat tone */
l = 0;
while(42)
{
if (l >= 10)
{
close(fh);
PERROR("Link chain too deep: '%s'\n", filename);
return(-1);
}
if (lstat(filename, &_stat) == -1)
{
close(fh);
PERROR("Cannot stat file: '%s'\n", filename);
return(-1);
}
if (!S_ISLNK(_stat.st_mode))
{
break;
}
if ((linksize=readlink(filename, linkname, sizeof(linkname))) > 0)
{
linkname[linksize] = '\0';
} else
{
close(fh);
PERROR("Cannot read link information: '%s'\n", filename);
return(-1);
}
if (linkname[0] == '/') /* absolute link */
{
SCPY(filename, linkname);
} else /* relative link */
{
/* remove filename */
p = filename;
while(strchr(p, '/'))
{
p = strchr(p, '/')+1;
}
*p = 0;
/* concat the link */
SCAT(filename, linkname);
}
//printf("follow link: %s\n", filename);
l++;
}
if (length)
*length = _stat.st_size;
if (left)
*left = _stat.st_size;
if (codec)
*codec = CODEC_LAW;
return(fh);
}
/* try to open the wave file */
SPRINT(filename, "%s.wav", file);
if ((fh = open(filename, O_RDONLY)) >= 0)
{
/* get wave header */
read(fh, buffer, 8);
size=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
if (!!strncmp((char *)buffer, "RIFF", 4))
{
close(fh);
errno = 0;
PERROR("%s is no riff file!\n", filename);
return(-1);
}
// printf("%c%c%c%c size=%ld\n",buffer[0],buffer[1],buffer[2],buffer[3],size);
read(fh, buffer, 4);
size -= 4;
if (!!strncmp((char *)buffer, "WAVE", 4))
{
close(fh);
errno = 0;
PERROR("%s is no wave file!\n", filename);
return(-1);
}
while(size)
{
if (size>0 && size<8)
{
close(fh);
errno = 0;
PERROR("Remaining file size %ld not large enough for next chunk.\n",size);
return(-1);
}
read(fh, buffer, 8);
chunk=(buffer[4]) + (buffer[5]<<8) + (buffer[6]<<16) + (buffer[7]<<24);
size -= (8+chunk);
// printf("%c%c%c%c lenght=%d\n",buffer[0],buffer[1],buffer[2],buffer[3],chunk);
if (size < 0)
{
close(fh);
errno = 0;
PERROR("Chunk '%c%c%c%c' is larger than remainig file size (length=%ld)\n",buffer[0],buffer[1],buffer[2],buffer[3], chunk);
return(-1);
}
if (!strncmp((char *)buffer, "fmt ", 4))
{
if (chunk != 16)
{
close(fh);
errno = 0;
PERROR("File %s Fmt chunk illegal size.\n", filename);
return(-1);
}
read(fh, buffer, chunk);
fmt = (struct fmt *)buffer;
if (fmt->channels<1 || fmt->channels>2)
{
close(fh);
errno = 0;
PERROR("File %s Only support one or two channels file.\n", filename);
return(-1);
}
channels = fmt->channels;
// printf("Channels: %d\n", channels);
if (fmt->sample_rate != 8000)
{
PERROR("Warning: File %s has sample rate of %ld.\n", filename, fmt->sample_rate);
}
// printf("Sample Rate: %ld\n", fmt->sample_rate);
if (fmt->bits_sample!=8 && fmt->bits_sample!=16)
{
close(fh);
errno = 0;
PERROR("File %s has neigher 8 nor 16 bit samples.\n", filename);
return(-1);
}
bytes = (fmt->bits_sample==16)?2:1;
// printf("Bit-Resolution: %d\n", bytes*16-16);
gotfmt = 1;
} else
if (!strncmp((char *)buffer, "data", 4))
{
if (!gotfmt)
{
close(fh);
errno = 0;
PERROR("File %s No fmt chunk found before data chunk.\n", filename);
return(-1);
}
// printf("Length: %ld samples (%ld.%03ld seconds)\n", chunk/bytes/channels, chunk/bytes/channels/8000, ((chunk/bytes/channels)%8000)*1000/8000);
if (bytes==2 && channels==1)
{
if (codec)
*codec = CODEC_MONO;
if (length)
*length = ((signed long)chunk)>>1;
if (left)
*left = ((signed long)chunk)>>1;
} else
if (bytes==2 && channels==2)
{
if (codec)
*codec = CODEC_STEREO;
if (length)
*length = ((signed long)chunk)>>2;
if (left)
*left = ((signed long)chunk)>>2;
} else
if (bytes==1 && channels==1)
{
if (codec)
*codec = CODEC_8BIT;
if (length)
*length = (signed long)chunk;
if (left)
*left = (signed long)chunk;
} else
{
close(fh);
errno = 0;
PERROR("File %s Is not MONO8, MONO16 nor STEREO16.\n", filename);
return(-1);
}
return(fh);
} else
{
// PDEBUG(DEBUG_PORT, "Unknown chunk '%c%c%c%c'\n",buffer[0],buffer[1],buffer[2],buffer[3]);
while(chunk > sizeof(buffer))
{
read(fh, buffer, sizeof(buffer));
chunk -= sizeof(buffer);
}
if (chunk)
read(fh, buffer, chunk);
}
}
if (!gotfmt)
{
close(fh);
errno = 0;
PERROR("File %s No fmt chunk found in file.\n", filename);
return(-1);
}
close(fh);
errno = 0;
PERROR("File %s No data chunk found in file.\n", filename);
return(-1);
}
return(-1);
}
/*
* read from tone, check size
* the len must be the number of samples, NOT for the bytes to read!!
*/
int read_tone(int fh, void *buffer, int codec, int len, signed long size, signed long *left, int speed)
{
int l;
int offset;
//printf("left=%ld\n",*left);
/* if no *left is given (law has unknown length) */
if (!left)
goto unknown_length;
if (speed!=1)
{
offset = ((len&(~4)) * (speed-1));
lseek(fh, offset, SEEK_CUR); /* step fowards, backwards (len must be round to 4 bytes, to be sure, that 16bit stereo will not drift out of sync)*/
*left -= offset; /* correct the current bytes left */
if (*left < 0)
{
/* eof */
*left = 0;
return(0);
}
if (*left >= size)
{
/* eof */
*left = size;
return(0);
}
}
if (*left == 0)
return(0);
if (*left < len)
len = *left;
unknown_length:
switch(codec)
{
case CODEC_LAW:
l = read(fh, buffer, len); /* as is */
break;
case CODEC_MONO:
l = read(fh, buffer, len<<1); /* as is */
if (l>0)
l = l>>1;
break;
case CODEC_STEREO:
{
signed short buffer32[len<<1], *buf32 = buffer32;
signed short *buf16 = (signed short *)buffer;
signed long sample;
int i = 0;
l = read(fh, buf32, len<<2);
if (l>0)
{
l = l>>2;
while(i < l)
{
sample = (*buf32++) + (*buf32++);
if (sample < -32767)
sample = -32767;
if (sample > 32767)
sample = 32767;
*buf16++ = sample;
i++;
}
}
}
break;
case CODEC_8BIT:
{
unsigned char buffer8[len], *buf8 = buffer8;
signed short *buf16 = (signed short *)buffer;
int i = 0;
l = read(fh, buf8, len);
if (l>0)
{
while(i < l)
{
*buf16++ = (((*buf8++) << 8) - 0x8000) & 0xffff;
i++;
}
}
}
break;
default:
PERROR("codec %d is not specified or supported, exitting...\n", codec);
exit(-1);
}
if (l>0 && left)
*left -= l;
return(l);
}
struct toneset *toneset_first = NULL;
/*
* free fetched tones
*/
void free_tones(void)
{
struct toneset *toneset_temp;
struct tonesettone *tonesettone_temp;
void *temp;
toneset_temp = toneset_first;
while(toneset_temp)
{
tonesettone_temp = toneset_temp->first;
while(tonesettone_temp)
{
temp = tonesettone_temp;
tonesettone_temp = tonesettone_temp->next;
free(temp);
memuse--;
}
temp = toneset_temp;
toneset_temp = toneset_temp->next;
free(temp);
memuse--;
}
toneset_first = NULL;
}
/*
* fetch tones as specified in options.conf
*/
int fetch_tones(void)
{
DIR *dir;
struct dirent *dirent;
struct toneset **toneset_nextpointer;
struct tonesettone **tonesettone_nextpointer;
char *p, *p_next;
char path[256];
char filename[256], name[256];
int fh;
int tone_codec;
signed long tone_size, tone_left, real_size;
unsigned long memory = 0;
int samples = 0;
/* if disabled */
if (!options.fetch_tones)
return(1);
toneset_nextpointer = &toneset_first;
p = options.fetch_tones;
if (*p == '\0')
return(1);
while (*p)
{
p_next = p;
while(*p_next)
{
if (*p_next == ',')
{
*p_next = '\0';
p_next++;
break;
}
p_next++;
}
/* remove trailing / */
if (*p) if (p[strlen(p)-1] == '/')
p[strlen(p)-1] = '\0';
printf("PBX: Fetching tones '%s'\n", p);
PDEBUG(DEBUG_PORT, "fetching tones directory '%s'\n", p);
*toneset_nextpointer = (struct toneset *)calloc(1, sizeof(struct toneset));
if (*toneset_nextpointer == NULL)
{
PERROR("No memory for tone set: '%s'\n",p);
return(0);
}
memuse++;
memory += sizeof(struct toneset);
memset(*toneset_nextpointer, 0 , sizeof(struct toneset));
SCPY((*toneset_nextpointer)->directory, p);
tonesettone_nextpointer = &(*toneset_nextpointer)->first;
SPRINT(path, "%s/%s", INSTALL_DATA, p);
dir = opendir(path);
if (dir == NULL)
{
PERROR("Tone set not found: '%s'\n", path);
return(0);
}
while((dirent=readdir(dir)))
{
SPRINT(name, "%s", dirent->d_name);
/* remove .isdn and .wave */
if (strlen(name) >= 4)
{
if (!strcmp(name+strlen(name)-4, ".wav"))
name[strlen(name)-4] = '\0';
}
if (strlen(name) >= 5)
{
if (!strcmp(name+strlen(name)-5, ".isdn"))
name[strlen(name)-5] = '\0';
}
SPRINT(filename, "%s/%s", path, name);
/* skip . / .. */
if (!strcmp(dirent->d_name, "."))
continue;
if (!strcmp(dirent->d_name, ".."))
continue;
/* open file */
fh = open_tone(filename, &tone_codec, &tone_size, &tone_left);
if (fh < 0)
{
PERROR("Cannot open file: '%s'\n", filename);
continue;
}
fduse++;
if (tone_size < 0)
{
PERROR("File has 0-length: '%s'\n", filename);
close(fh);
fduse--;
continue;
}
/* real size */
switch(tone_codec)
{
case CODEC_LAW:
real_size = tone_size;
break;
case CODEC_MONO:
real_size = tone_size << 1;
break;
case CODEC_STEREO:
real_size = tone_size << 1;
break;
case CODEC_8BIT:
real_size = tone_size << 1;
break;
default:
PERROR("codec %d is not specified or supported, exitting...\n", tone_codec);
exit(-1);
}
/* allocate tone */
*tonesettone_nextpointer = (struct tonesettone *)calloc(1, sizeof(struct tonesettone)+real_size);
if (*toneset_nextpointer == NULL)
{
PERROR("No memory for tone set: '%s'\n",p);
close(fh);
fduse--;
return(0);
}
memuse++;
//printf("tone:%s, %ld bytes\n", name, tone_size);
memset(*tonesettone_nextpointer, 0 , sizeof(struct tonesettone)+real_size);
memory += sizeof(struct tonesettone)+real_size;
samples ++;
/* load tone */
read_tone(fh, (*tonesettone_nextpointer)->data, tone_codec, tone_size, tone_size, &tone_left, 1);
(*tonesettone_nextpointer)->size = tone_size;
(*tonesettone_nextpointer)->codec = (tone_codec==CODEC_LAW)?CODEC_LAW:CODEC_MONO;
SCPY((*tonesettone_nextpointer)->name, name);
close(fh);
fduse--;
tonesettone_nextpointer = &((*tonesettone_nextpointer)->next);
}
toneset_nextpointer = &((*toneset_nextpointer)->next);
p = p_next;
}
printf("PBX: Memory used for tones: %ld bytes (%d samples)\n", memory, samples);
PDEBUG(DEBUG_PORT, "Memory used for tones: %ld bytes (%d samples)\n", memory, samples);
return(1);
}
/*
* opens the fetched tone (if available)
*/
void *open_tone_fetched(char *dir, char *file, int *codec, signed long *length, signed long *left)
{
struct toneset *toneset;
struct tonesettone *tonesettone;
/* if anything fetched */
if (!toneset_first)
return(NULL);
/* find set */
toneset = toneset_first;
while(toneset)
{
//printf("1. comparing '%s' with '%s'\n", toneset->directory, dir);
if (!strcmp(toneset->directory, dir))
break;
toneset = toneset->next;
}
if (!toneset)
return(NULL);
/* find tone */
tonesettone = toneset->first;
while(tonesettone)
{
//printf("2. comparing '%s' with '%s'\n", tonesettone->name, file);
if (!strcmp(tonesettone->name, file))
break;
tonesettone = tonesettone->next;
}
if (!tonesettone)
return(NULL);
/* return information */
if (length)
*length = tonesettone->size;
if (left)
*left = tonesettone->size;
if (codec)
*codec = tonesettone->codec;
//printf("size=%ld, data=%08x\n", tonesettone->size, tonesettone->data);
return(tonesettone->data);
}
/*
* read from fetched tone, check size
* the len must be the number of samples, NOT for the bytes to read!!
*/
int read_tone_fetched(void **fetched, void *buffer, int codec, int len, signed long size, signed long *left, int speed)
{
int l;
//printf("left=%ld\n",*left);
/* if no *left is given (law has unknown length) */
if (!left)
return(0);
if (*left == 0)
return(0);
if (*left < len)
len = *left;
switch(codec)
{
case CODEC_LAW:
memcpy(buffer, *fetched, len);
*((char **)fetched) += len;
l = len;
break;
case CODEC_MONO:
memcpy(buffer, *fetched, len<<1);
*((char **)fetched) += len<<1;
l = len;
break;
default:
PERROR("codec %d is not specified or supported, exitting...\n", codec);
exit(-1);
}
if (l>0 && left)
*left -= l;
return(l);
}

36
tones.h Normal file
View File

@ -0,0 +1,36 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** tones header file **
** **
\*****************************************************************************/
int open_tone(char *file, int *codec, signed long *length, signed long *left);
int read_tone(int fh, void *buffer, int codec, int len, signed long size, signed long *left, int speed);
int fetch_tones(void);
void free_tones(void);
void *open_tone_fetched(char *dir, char *file, int *codec, signed long *length, signed long *left);
int read_tone_fetched(void **fetched, void *buffer, int codec, int len, signed long size, signed long *left, int speed);
/* tone sets */
struct tonesettone {
struct tonesettone *next;
char name[128];
int codec;
int size;
unsigned char data[0];
};
struct toneset {
struct toneset *next;
char directory[128];
struct tonesettone *first;
};
extern struct toneset *toneset_first;

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

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