aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/mate/AUTHORS3
-rw-r--r--plugins/mate/COPYING340
-rw-r--r--plugins/mate/INSTALL0
-rw-r--r--plugins/mate/Makefile.am44
-rw-r--r--plugins/mate/Makefile.nmake30
-rw-r--r--plugins/mate/NEWS0
-rw-r--r--plugins/mate/examples/call.thing4
-rw-r--r--plugins/mate/examples/cmplx_call.thing78
-rw-r--r--plugins/mate/examples/ftp.thing38
-rw-r--r--plugins/mate/examples/mgw.thing261
-rw-r--r--plugins/mate/examples/mgw2.thing18
-rw-r--r--plugins/mate/examples/mgw_mi.thing248
-rw-r--r--plugins/mate/examples/newcall.mate22
-rw-r--r--plugins/mate/examples/nrg_sms.thing20
-rw-r--r--plugins/mate/examples/rad.thing11
-rw-r--r--plugins/mate/mate.h295
-rw-r--r--plugins/mate/mate_plugin.c62
-rw-r--r--plugins/mate/mate_runtime.c742
-rw-r--r--plugins/mate/mate_setup.c1417
-rw-r--r--plugins/mate/mate_util.c1861
-rw-r--r--plugins/mate/mate_util.h284
-rw-r--r--plugins/mate/matelib/dns.mate19
-rw-r--r--plugins/mate/matelib/h225_ras.mate7
-rw-r--r--plugins/mate/matelib/isup.mate6
-rw-r--r--plugins/mate/matelib/megaco.mate6
-rw-r--r--plugins/mate/matelib/q931.mate6
-rw-r--r--plugins/mate/matelib/radius.mate7
-rw-r--r--plugins/mate/matelib/rtsp.mate5
-rw-r--r--plugins/mate/matelib/sip.mate6
-rw-r--r--plugins/mate/moduleinfo.h16
-rw-r--r--plugins/mate/packet-mate.c321
-rw-r--r--plugins/mate/presentation.txt91
32 files changed, 6268 insertions, 0 deletions
diff --git a/plugins/mate/AUTHORS b/plugins/mate/AUTHORS
new file mode 100644
index 0000000000..e37df0dd7d
--- /dev/null
+++ b/plugins/mate/AUTHORS
@@ -0,0 +1,3 @@
+Author:
+Luis E. Garcia Ontanon <luis.ontanon [AT] gmail.com>
+
diff --git a/plugins/mate/COPYING b/plugins/mate/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/plugins/mate/COPYING
@@ -0,0 +1,340 @@
+ 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.
diff --git a/plugins/mate/INSTALL b/plugins/mate/INSTALL
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/plugins/mate/INSTALL
diff --git a/plugins/mate/Makefile.am b/plugins/mate/Makefile.am
new file mode 100644
index 0000000000..2b6fd02673
--- /dev/null
+++ b/plugins/mate/Makefile.am
@@ -0,0 +1,44 @@
+# Makefile.am
+# Automake file for MATE Ethereal plugin
+#
+# $Id$
+#
+# Ethereal - Network traffic analyzer
+# By Gerald Combs <gerald@ethereal.com>
+# Copyright 1998 Gerald Combs
+#
+# 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.
+#
+
+INCLUDES = -I$(top_srcdir)
+
+plugindir = @plugindir@
+
+plugin_LTLIBRARIES = mate.la
+mate_la_SOURCES = moduleinfo.h mate.h mate_util.h packet-mate.c mate_runtime.c mate_setup.c mate_util.c mate_plugin.c
+mate_la_LDFLAGS = -module -avoid-version
+mate_la_LIBADD = @PLUGIN_LIBS@
+
+# Libs must be cleared, or else libtool won't create a shared module.
+# If your module needs to be linked against any particular libraries,
+# add them here.
+LIBS =
+
+CLEANFILES = \
+ mate \
+ *~
+
+EXTRA_DIST = \
+ Makefile.nmake
diff --git a/plugins/mate/Makefile.nmake b/plugins/mate/Makefile.nmake
new file mode 100644
index 0000000000..e627b24a5b
--- /dev/null
+++ b/plugins/mate/Makefile.nmake
@@ -0,0 +1,30 @@
+#
+# $Id$
+#
+
+include ..\..\config.nmake
+
+############### no need to modify below this line #########
+
+CFLAGS=/DHAVE_CONFIG_H /I../.. /I../../wiretap $(GLIB_CFLAGS) \
+ /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
+
+LDFLAGS = /NOLOGO /INCREMENTAL:no /MACHINE:I386 $(LOCAL_LDFLAGS)
+
+!IFDEF LINK_PLUGINS_WITH_LIBETHEREAL
+LINK_PLUGIN_WITH=..\..\epan\libethereal.lib
+CFLAGS=/DHAVE_WIN32_LIBETHEREAL_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS)
+!ELSE
+LINK_PLUGIN_WITH=..\plugin_api.obj
+!ENDIF
+
+OBJECTS=packet-mate.obj mate_setup.obj mate_runtime.obj mate_util.obj mate_plugin.obj
+
+mate.dll mate.exp mate.lib : $(OBJECTS) $(LINK_PLUGIN_WITH)
+ link -dll /out:mate.dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \
+ $(GLIB_LIBS)
+
+clean:
+ rm -f $(OBJECTS) mate.dll mate.exp mate.lib *.pdb
+
+distclean: clean
diff --git a/plugins/mate/NEWS b/plugins/mate/NEWS
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/plugins/mate/NEWS
diff --git a/plugins/mate/examples/call.thing b/plugins/mate/examples/call.thing
new file mode 100644
index 0000000000..46fc1e2f9d
--- /dev/null
+++ b/plugins/mate/examples/call.thing
@@ -0,0 +1,4 @@
+# call.thing
+
+Action=Include; Filename=/Users/lego/things/call.mate;
+
diff --git a/plugins/mate/examples/cmplx_call.thing b/plugins/mate/examples/cmplx_call.thing
new file mode 100644
index 0000000000..c2befd91fb
--- /dev/null
+++ b/plugins/mate/examples/cmplx_call.thing
@@ -0,0 +1,78 @@
+# call_tracing.thing
+#
+# This config works with most of the ViG's call scenarios
+#
+# To work well with the Vig needs the following:
+# a user to calling mapping to map emails to calling numbers (this only if calls begin towards an e-mail not a number)
+# a opc:cic to term mapping to represent the MGw config (if you want to see megaco)
+#
+
+Action=PDU; Proto=sip; Transport=ip; addr=ip.addr; sip_method=sip.Method; sip_callid=sip.Call-ID; calling=sdp.owner.username;
+Action=LegKey; On=sip; sip_callid; addr; addr;
+Action=LegStart; On=sip; sip_method=INVITE;
+Action=LegStop; On=sip; sip_method=BYE;
+
+#Action=Include; Filename=users.thing;
+# will contain:
+Action=Transform; On=sip; Method=Every; calling=merlia;
+Action=Transform; On=sip; Method=Insert; calling=1793900802;
+
+Action=PDU; Proto=q931; Transport=ip; addr=ip.addr; call_ref=q931.call_ref; q931_msg=q931.message_type; guid=h225.guid; called=q931.called_party_number.digits; calling=q931.calling_party_number.digits; q931_cause=q931.cause_value; h225_cause=h225.ReleaseCompleteReason;
+Action=LegKey; On=q931; call_ref; addr; addr;
+Action=LegStart; On=q931; q931_msg=5;
+Action=LegStop; On=q931; q931_msg=90;
+
+Action=PDU; Proto=isup; Transport=mtp3; mtp3pc=mtp3.dpc; mtp3pc=mtp3.opc; cic=isup.cic; isup_msg=isup.message_type; called=isup.called; calling=isup.calling; isup_cause=isup.cause_indicator;
+Action=LegKey; On=isup; cic; mtp3pc; mtp3pc;
+Action=LegStart; On=isup; isup_msg=1;
+Action=LegStop; On=isup; isup_msg=16;
+
+Action=PDU; Proto=h225.RasMessage; Transport=ip; ras_msg=h225.RasMessage; addr=ip.addr; guid=h225.guid; seqnum=h225.RequestSeqNum;
+Action=LegKey; On=h225.RasMessage; addr; addr; seqnum;
+Action=LegStart; On=h225.RasMessage; ras_msg|0|3|6|9|12|15|18|21|26|30;
+Action=LegStop; On=h225.RasMessage; ras_msg|1|2|4|5|7|8|10|11|13|14|16|17|19|20|22|24|27|28|29|31;
+
+Action=PDU; Proto=megaco; Transport=ip; addr=ip.addr; megaco_ctx=megaco.context; megaco_trx=megaco.transid; megaco_msg=megaco.transaction; term=megaco.termid;
+Action=LegKey; On=megaco; addr; addr; megaco_trx;
+Action=LegStart; On=megaco; megaco_msg|Request|Notify;
+Action=LegStop; On=megaco; megaco_msg=Reply;
+
+#Action=Include; Filename=mgw.thing;
+# will contain the whole list of dpc:cic -> ds1_term mappings like the following
+Action=Transform; On=isup; Method=Every; mtp3pc=1921; cic=1;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=1921; cic=2;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=1921; cic=14;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/14;
+
+
+Action=PDU; Proto=rtsp; Transport=ip; isup_msg=isup.message_type; calling=X_Vig_Msisdn; rtsp_method=rtsp.method; rtsp_ses=rtsp.session; addr=ip.addr; rtsp_url=rtsp.url;
+Action=LegKey; On=rtsp; rtsp_ses;
+Action=LegStart; On=rtsp; rtsp_method=SETUP;
+Action=LegStop; On=rtsp; rtsp_method=TEARDOWN;
+
+Action=PDU; Proto=radius; Transport=ip; radius_id=radius.id; radius_code=radius.code; class=radius.class; addr=ip.addr; calling=radius.calling; rad_sesid=radius.acct.sessionid;
+Action=LegKey; On=radius; addr; addr; radius_id;
+Action=LegStart; On=radius; radius_code|1|4;
+Action=LegStop; On=radius; radius_code|2|3|5;
+
+Action=LegExtra; On=radius; calling; rad_sesid;
+
+Action=LegExtra; On=sip; calling!-;
+Action=LegExtra; On=q931; called; calling; guid; q931_cause; h225_cause;
+Action=LegExtra; On=h225.RasMessage; guid;
+Action=LegExtra; On=isup; called; calling; isup_cause; term;
+Action=LegExtra; On=megaco; term^DS1; megaco_ctx!Choose one;
+Action=LegExtra; On=rtsp; rtsp_url; calling;
+Action=LegExtra; On=radius; calling;
+
+Action=SesKey; Name=call; On=sip; calling; sip_callid;
+Action=SesKey; Name=call; On=isup; calling;
+Action=SesKey; Name=call; On=q931; calling;
+Action=SesKey; Name=call; On=megaco; term^DS1;
+Action=SesKey; Name=call; On=megaco; megaco_ctx;
+Action=SesKey; Name=call; On=rtsp; calling;
+Action=SesKey; Name=call; On=h225.RasMessage; guid;
+
+Action=SesExtra; On=call; called; term^DS1; megaco_ctx; guid; q931_cause; h225_cause; isup_cause; rtsp_url;
diff --git a/plugins/mate/examples/ftp.thing b/plugins/mate/examples/ftp.thing
new file mode 100644
index 0000000000..8cafd66a3a
--- /dev/null
+++ b/plugins/mate/examples/ftp.thing
@@ -0,0 +1,38 @@
+# ftp.thing
+Action=Settings; Debug_PDU=9;
+# at every packet mate will try match the PDUS in order
+# if Proto exists for the current frame a mate's PDU will be created.
+# for attributes to be imported from the tree they must be inside
+# either in the span of the the Proto
+# or in that of any of the protocols in the Transport stack
+#
+# The PDU's AVPL will contain all the remaining attributes
+Action=PDU; Name=FTP; Proto=ftp; Transport=tcp/ip; ftp_addr=ip.addr; tcp_port=tcp.port; addr=ftp.passive.ip; port=ftp.passive.port; ftp_cmd=ftp.request.command;
+Action=PDU; Name=TCP; Proto=tcp; Transport=ip; addr=ip.addr; port=tcp.port; tcp_start=tcp.flags.syn; tcp_stop=tcp.flags.reset; tcp_stop=tcp.flags.fin;
+
+# once all PDUs for a packet have being created
+# they will be matched against their relative LegKeys
+# the attribute On specifies for which type of PDU the leg will be created
+# the remaining of the AVPL will be used to create the key of the leg
+# the matched attributes will become attributes of the leg
+Action=LegKey; On=FTP; ftp_addr; ftp_addr; tcp_port; tcp_port;
+Action=LegKey; On=TCP; addr; addr; port; port;
+
+# LegExtra is used to copy into the leg any other attributes from the PDU
+# that may be usefull later in the analysis
+Action=LegExtra; On=FTP; addr; port;
+Action=LegExtra; On=TCP; tcp_start; tcp_stop;
+
+
+# Legs are created when a PDU that belongs to them matches the LegStart AVPL
+Action=LegStart; On=FTP; ftp_cmd=USER;
+Action=LegStart; On=TCP; tcp_start=1;
+
+# and stopped when the PDU matches the LegStop AVPL
+Action=LegStop; On=FTP; ftp_cmd=QUIT;
+Action=LegStop; On=TCP; tcp_stop=1;
+
+Action=SesKey; Name=ftp_session; On=FTP; ftp_addr; ftp_addr; ftp_port; ftp_port;
+Action=SesKey; Name=ftp_session; On=TCP; addr; port;
+
+Action=SesExtra; On=ftp_session; addr; port;
diff --git a/plugins/mate/examples/mgw.thing b/plugins/mate/examples/mgw.thing
new file mode 100644
index 0000000000..6535664807
--- /dev/null
+++ b/plugins/mate/examples/mgw.thing
@@ -0,0 +1,261 @@
+# the transformations example file
+
+# the match (Method=extact|Method=loose|Method=Every)
+# must precede the replace (Method=replace|Method=Insert)
+
+# the list is going to be applied in order
+
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=1;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=2;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=3;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=4;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=5;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=6;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=7;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=8;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=9;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=10;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=11;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=12;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=13;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=14;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=15;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=16;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=17;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=18;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=19;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=20;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=21;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=22;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=23;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=24;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=25;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=26;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=27;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=28;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=29;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=30;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/30;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=31;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/31;
+
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=32;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/0;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=33;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=34;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=35;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=36;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=37;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=38;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=39;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=40;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=41;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=42;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=43;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=44;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=45;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=46;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=47;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=48;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=49;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=50;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=51;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=52;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=53;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=54;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=55;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=56;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=57;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=58;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=59;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=60;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=61;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=62;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/30;
+
+
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=1;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=2;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=3;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=4;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=5;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=6;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=7;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=8;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=9;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=10;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=11;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=12;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=13;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=14;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=15;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=16;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=17;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=18;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=19;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=20;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=21;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=22;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=23;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=24;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=25;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=26;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=27;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=28;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=29;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=30;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/30;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=31;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/31;
+
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=32;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/0;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=33;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=34;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=35;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=36;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=37;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=38;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=39;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=40;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=41;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=42;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=43;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=44;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=45;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=46;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=47;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=48;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=49;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=50;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=51;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=52;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=53;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=54;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=55;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=56;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=57;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=58;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=59;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=60;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=61;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=62;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/30;
+
+
diff --git a/plugins/mate/examples/mgw2.thing b/plugins/mate/examples/mgw2.thing
new file mode 100644
index 0000000000..b07f53d370
--- /dev/null
+++ b/plugins/mate/examples/mgw2.thing
@@ -0,0 +1,18 @@
+# the transformations example file
+
+# the match (Method=extact|Method=loose|Method=Every)
+# must precede the replace (Method=replace|Method=Insert)
+
+# the list is going to be applied in order
+
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=49;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/2/1;
+
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=61;
+Action=Transform; On=isup; Method=Insert; term=DS1/2/2/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=61;
+Action=Transform; On=isup; Method=Insert; term=DS1/2/2/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=63;
+Action=Transform; On=isup; Method=Insert; term=DS1/2/2/31;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=109;
+Action=Transform; On=isup; Method=Insert; term=DS1/2/3/13;
diff --git a/plugins/mate/examples/mgw_mi.thing b/plugins/mate/examples/mgw_mi.thing
new file mode 100644
index 0000000000..d76851b484
--- /dev/null
+++ b/plugins/mate/examples/mgw_mi.thing
@@ -0,0 +1,248 @@
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=1;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=2;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=3;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=4;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=5;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=6;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=7;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=8;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=9;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=10;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=11;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=12;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=13;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=14;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=15;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=16;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=17;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=18;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=19;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=20;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=21;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=22;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=23;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=24;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=25;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=26;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=27;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=28;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=29;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=30;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/30;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=31;
+Action=Transform; On=isup; Method=Insert; term=DS1/0/1/31;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=33;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=34;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=35;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=36;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=37;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=38;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=39;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=40;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=41;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=42;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=43;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=44;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=45;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=46;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=47;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=48;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=49;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=50;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=51;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=52;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=53;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=54;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=55;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=56;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=57;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=58;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=59;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=60;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=61;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=62;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/30;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=63;
+Action=Transform; On=isup; Method=Insert; term=DS1/3/1/31;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=33;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=34;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=35;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=36;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=37;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=38;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=39;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=40;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=41;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=42;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=43;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=44;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=45;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=46;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=47;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=48;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=49;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=50;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=51;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=52;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=53;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=54;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=55;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=56;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=57;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=58;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=59;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=60;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=61;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=62;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/30;
+Action=Transform; On=isup; Method=Every; mtp3pc=5378; cic=63;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/1/31;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=1;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/1;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=2;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/2;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=3;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/3;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=4;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/4;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=5;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/5;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=6;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/6;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=7;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/7;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=8;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/8;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=9;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/9;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=10;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/10;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=11;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/11;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=12;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/12;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=13;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/13;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=14;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/14;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=15;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/15;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=16;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/16;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=17;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/17;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=18;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/18;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=19;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/19;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=20;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/20;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=21;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/21;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=22;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/22;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=23;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/23;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=24;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/24;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=25;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/25;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=26;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/26;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=27;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/27;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=28;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/28;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=29;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/29;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=30;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/30;
+Action=Transform; On=isup; Method=Every; mtp3pc=11522; cic=31;
+Action=Transform; On=isup; Method=Insert; term=DS1/1/2/31;
diff --git a/plugins/mate/examples/newcall.mate b/plugins/mate/examples/newcall.mate
new file mode 100644
index 0000000000..4158c0b9a9
--- /dev/null
+++ b/plugins/mate/examples/newcall.mate
@@ -0,0 +1,22 @@
+Action=Settings; Debug_Cfg=1; Debug_Leg=5;
+#Debug_PDU=9;
+
+Action=PDU; Name=Q931; Proto=q931; Transport=ip; addr=ip.addr; call_ref=q931.call_ref; q931_msg=q931.message_type; guid=h225.guid; called=q931.called_party_number.digits; calling=q931.calling_party_number.digits; q931_cause=q931.cause_value; h225_cause=h225.ReleaseCompleteReason;
+Action=PDU; Name=ISUP; Proto=isup; Transport=mtp3; mtp3pc=mtp3.dpc; mtp3pc=mtp3.opc; cic=isup.cic; isup_msg=isup.message_type; called=isup.called; calling=isup.calling; isup_cause=isup.cause_indicator;
+Action=PDU; Name=RAS; Proto=h225; Transport=ip; udp_port=udp.port; ras_msg=h225.RasMessage; addr=ip.addr; guid=h225.guid; seqnum=h225.RequestSeqNum;
+
+Action=Grp; Grp=isup; On=ISUP; cic; mtp3pc; mtp3pc;
+Action=GrpStart; Grp=isup; isup_msg=1;
+Action=GrpStop; Grp=isup; isup_msg=16;
+Action=GrpExtra; Grp=isup; called; calling; isup_cause;
+
+Action=GrpKey; Name=q931; On=Q931; call_ref; addr; addr;
+Action=GrpStart; Grp=q931; q931_msg=5;
+Action=GrpStop; Grp=q931; q931_msg=90;
+Action=GrpExtra; Grp=q931; guid; called; calling; q931_cause; h225_cause;
+
+Action=GrpKey; Name=ras; On=RAS; seqnum; addr; addr;
+Action=GrpStart; Grp=ras; ras_msg|0|3|6|9|12|15|18|21|26|30;
+Action=GrpStop; Grp=ras; ras_msg|1|2|4|5|7|8|10|11|13|14|16|17|19|20|22|24|27|28|29|31;
+Action=GrpExtra; Grp=ras; guid;
+
diff --git a/plugins/mate/examples/nrg_sms.thing b/plugins/mate/examples/nrg_sms.thing
new file mode 100644
index 0000000000..038deed5a2
--- /dev/null
+++ b/plugins/mate/examples/nrg_sms.thing
@@ -0,0 +1,20 @@
+# nrg_sms.thing
+# (c) 2004, Luis E. Garcia Ontanon
+# Distributed under GPL see http://www.gno.org/gpl.html for licencing info
+
+#Action=Settings; DiscardPduData=TRUE; Debug_Leak=3; Filename=/Users/lego/Desktop/call_thing.log;
+
+Action=PDU; Proto=ucp; Transport=ip; addr=ip.addr; ucp_trn=ucp.hdr.TRN; ucp_ot=ucp.hdr.OT; ucp_type=ucp.hdr.O_R; e164=ucp.parm.AdC;
+Action=LegKey; On=ucp; ucp_trn; addr; addr;
+Action=LegStart; On=ucp; ucp_type=79;
+Action=LegStop; On=ucp; ucp_type=82;
+
+Action=LegExtra; On=ucp; e164; ucp_ot;
+
+Action=PDU; Proto=giop; Transport=ip; addr=ip.addr; giop_id=giop.request_id; giop_op=giop.request_op; giop_type=giop.type;
+Action=LegKey; On=giop; giop_id; addr; addr;
+Action=LegStart; On=giop; giop_type=0;
+Action=LegStop; On=giop; giop_type=1;
+
+Action=LegExtra; On=giop; giop_op;
+
diff --git a/plugins/mate/examples/rad.thing b/plugins/mate/examples/rad.thing
new file mode 100644
index 0000000000..55b7801d44
--- /dev/null
+++ b/plugins/mate/examples/rad.thing
@@ -0,0 +1,11 @@
+Action=Settings; SessionExpire=300;
+
+Action=PDU; Proto=radius; Transport=ip; radius_id=radius.id; radius_code=radius.code; class=radius.class; addr=ip.addr; calling=radius.calling; rad_sesid=radius.acct.sessionid;
+Action=LegKey; On=radius; addr; addr; radius_id;
+Action=LegStart; On=radius; radius_code|1|4;
+Action=LegStop; On=radius; radius_code|2|3|5;
+
+Action=LegExtra; On=radius; calling; class; rad_sesid;
+
+Action=SesExtra; On=radses; calling; class;
+Action=SesKey; Name=radses; On=radius; rad_sesid;
diff --git a/plugins/mate/mate.h b/plugins/mate/mate.h
new file mode 100644
index 0000000000..9b6de5f71b
--- /dev/null
+++ b/plugins/mate/mate.h
@@ -0,0 +1,295 @@
+/* mate.h
+* MATE -- Meta Analysis and Tracing Engine
+*
+* Copyright 2004, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id$
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* 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.
+*/
+
+
+#ifndef __MATE_H_
+#define __MATE_H_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "plugins/plugin_api.h"
+#include "moduleinfo.h"
+
+#include <gmodule.h>
+#include <epan/packet.h>
+#include <epan/strutil.h>
+#include <epan/prefs.h>
+#include <stdio.h>
+#include <string.h>
+#include <epan/proto.h>
+#include <epan/epan_dissect.h>
+#include <epan/tap.h>
+
+#include "mate_util.h"
+#include "plugins/plugin_api_defs.h"
+
+
+/* defaults */
+
+#define DEFAULT_MAX_MATE_ITEMS 0
+#define DEFAULT_GOG_EXPIRATION 2.0
+
+#ifdef WIN32
+#define DIR_SEP '\\'
+#else
+#define DIR_SEP '/'
+#endif
+
+#define DEFAULT_MATE_LIB_PATH "matelib"
+
+#define MATE_ITEM_ID_SIZE 24
+
+/* Config AVP Names */
+#define KEYWORD_ACTION "Action"
+#define KEYWORD_SETTINGS "Settings"
+#define KEYWORD_INCLUDE "Include"
+#define KEYWORD_TRANSFORM "Transform"
+#define KEYWORD_PDU "PduDef"
+#define KEYWORD_PDUCRITERIA "PduCriteria"
+#define KEYWORD_PDUEXTRA "PduExtra"
+#define KEYWORD_PDUTRANSFORM "PduTransform"
+#define KEYWORD_GOP "GopDef"
+#define KEYWORD_GOPSTART "GopStart"
+#define KEYWORD_GOPSTOP "GopStop"
+#define KEYWORD_GOPEXTRA "GopExtra"
+#define KEYWORD_GOPTRANSFORM "GopTransform"
+#define KEYWORD_GOGDEF "GogDef"
+#define KEYWORD_GOGKEY "GogKey"
+#define KEYWORD_GOGEXTRA "GogExtra"
+#define KEYWORD_GOGTRANSFORM "GogTransform"
+#define KEYWORD_NAME "Name"
+#define KEYWORD_ON "On"
+#define KEYWORD_FOR "For"
+#define KEYWORD_FROM "From"
+#define KEYWORD_TO "To"
+#define KEYWORD_MATCH "Match"
+#define KEYWORD_MODE "Mode"
+#define KEYWORD_FILENAME "Filename"
+#define KEYWORD_PROTO "Proto"
+#define KEYWORD_METHOD "Method"
+#define KEYWORD_TRANSPORT "Transport"
+#define KEYWORD_STRICT "Strict"
+#define KEYWORD_LOOSE "Loose"
+#define KEYWORD_EVERY "Every"
+#define KEYWORD_REPLACE "Replace"
+#define KEYWORD_INSERT "Insert"
+#define KEYWORD_MAP "Map"
+#define KEYWORD_GOGEXPIRE "GogExpiration"
+#define KEYWORD_DISCARDPDU "DiscardPduData"
+#define KEYWORD_LIBPATH "ThingLibPath"
+#define KEYWORD_SHOWPDUTREE "ShowPduTree"
+#define KEYWORD_SHOWGOPTIMES "ShowGopTimes"
+#define KEYWORD_STOP "Stop"
+#define KEYWORD_DROPGOP "DiscardUnassignedGop"
+#define KEYWORD_DROPPDU "DiscardUnassignedPdu"
+
+#define KEYWORD_DEBUGFILENAME "Debug_File"
+#define KEYWORD_DBG_GENERAL "Debug_General"
+#define KEYWORD_DBG_CFG "Debug_Cfg"
+#define KEYWORD_DBG_PDU "Debug_PDU"
+#define KEYWORD_DBG_GOP "Debug_Gop"
+#define KEYWORD_DBG_GOG "Debug_Gog"
+#ifdef _AVP_DEBUGGING
+#define KEYWORD_DBG_AVPLIB "Debug_AVP_Lib"
+#define KEYWORD_DBG_AVP "Debug_AVP"
+#define KEYWORD_DBG_AVP_OP "Debug_AVP_Op"
+#define KEYWORD_DBG_AVPL "Debug_AVPL"
+#define KEYWORD_DBG_AVPL_OP "Debug_AVPL_Op"
+#endif
+
+#define VALUE_TOO ((void*)1)
+
+typedef enum _mate_item_type {
+ MATE_UNK_TYPE,
+ MATE_PDU_TYPE,
+ MATE_GOP_TYPE,
+ MATE_GOG_TYPE
+} mate_item_type;
+
+typedef struct _mate_cfg_item mate_cfg_pdu;
+typedef struct _mate_cfg_item mate_cfg_gop;
+typedef struct _mate_cfg_item mate_cfg_gog;
+
+typedef struct _mate_item mate_item;
+typedef struct _mate_item mate_pdu;
+typedef struct _mate_item mate_gop;
+typedef struct _mate_item mate_gog;
+
+typedef struct _mate_cfg_item {
+ guint8* name;
+ mate_item_type type;
+ GPtrArray* transforms; /* transformations to be applied */
+ AVPL* extra; /* attributes to be added */
+ guint last_id; /* keeps the last id given to an item of this kind */
+ int hfid;
+ GHashTable* my_hfids; /* for creating register info */
+
+ /* pdu */
+ gboolean discard_pdu_attributes;
+ gboolean last_to_be_created;
+ int hfid_proto;
+ GPtrArray* hfid_ranges; /* hfids of candidate ranges from which to extract attributes */
+ GHashTable* hfids_attr; /* k=hfid v=avp_name */
+ gboolean drop_pdu;
+ avpl_match_mode criterium_match_mode;
+ AVPL* criterium; /* must match to be created */
+ int hfid_pdu_rel_time;
+
+ /* gop */
+ AVPL* start; /* start candidate avpl */
+ AVPL* stop; /* stop candidate avpl */
+ AVPL* key; /* key candidate avpl */
+ gboolean show_pdu_tree;
+ gboolean show_gop_times;
+ gboolean drop_gop;
+ int hfid_gop_pdu;
+ int hfid_gop_start_time;
+ int hfid_gop_stop_time;
+ int hfid_gop_last_time;
+ int hfid_gop_num_pdus;
+
+ /* gog */
+ LoAL* keys;
+ float expiration;
+ int hfid_gog_num_of_gops;
+ int hfid_gog_gop;
+
+} mate_cfg_item;
+
+typedef struct _mate_config {
+ /* current defaults */
+ float gog_expiration; /* default expirations for gogs if undefined in gog */
+ gboolean discard_pdu_attributes; /* destroy the pdu's avpl once analyzed */
+ gboolean drop_pdu; /* destroy the pdu if not assign to a gop */
+ gboolean drop_gop; /* destroy the gop if not assign to a gog */
+ guint8* mate_lib_path; /* where to look for "Include" files first */
+ gboolean show_pdu_tree;
+ gboolean show_gop_times;
+ gboolean last_to_be_created;
+ avpl_match_mode match_mode;
+ avpl_replace_mode replace_mode;
+
+ /* what to dbgprint */
+ int dbg_lvl;
+ int dbg_cfg_lvl;
+ int dbg_pdu_lvl;
+ int dbg_gop_lvl;
+ int dbg_gog_lvl;
+
+ guint8* mate_config_file; /* name of the config file */
+ GString* mate_attrs_filter; /* "ip.addr || dns.id || ... " for the tap */
+ GString* mate_protos_filter; /* "dns || ftp || ..." for the tap */
+ FILE* dbg_facility; /* where to dump dbgprint output g_message if null */
+ guint8* tap_filter;
+
+ GHashTable* pducfgs; /* k=pducfg->name v=pducfg */
+ GHashTable* gopcfgs; /* k=gopcfg->name v=gopcfg */
+ GHashTable* gogcfgs; /* k=gogcfg->name v=gogcfg */
+ GHashTable* transfs; /* k=transform->name v=transform */
+
+ GPtrArray* pducfglist; /* pducfgs in order of "execution" */
+ GHashTable* gops_by_pduname; /* k=pducfg->name v=gopcfg */
+ GHashTable* gogs_by_gopname; /* k=gopname v=loal where avpl->name == matchedgop->name */
+
+ GArray* hfrs;
+} mate_config;
+
+typedef struct _mate_runtime_data {
+ guint current_items; /* a count of items */
+ GMemChunk* mate_items;
+ float now;
+ guint highest_analyzed_frame;
+
+ GHashTable* frames; /* k=frame.num v=pdus */
+ GHashTable* items; /* k=item->id v=item */
+ GHashTable* gops; /* k=gop_key_match v=gop */
+ GHashTable* gogs; /* k=gog_key_match v=gog */
+
+} mate_runtime_data;
+
+/* these are used to contain information regarding pdus, gops and gogs */
+struct _mate_item {
+ /* all three of them */
+ guint8 id[MATE_ITEM_ID_SIZE]; /* 1:1 -> saving a g_malloc */
+ mate_cfg_item* cfg; /* the type of this item */
+
+ AVPL* avpl; /* the attributes of the pdu/gop/gog */
+
+ /* these two have different uses in pdu and gop/gog */
+ gint start; /* start of the pdu in the tvb / framenum of the start of a gop */
+ gint end; /* end of the pdu in the tvb / framenum of the stop of a gop */
+
+ mate_item* next; /* in pdu: next in gop; in gop: next in gog; in gog this doesn't make any sense yet */
+
+ /* union _payload { */
+ /* struct _pdu { */
+ guint32 frame; /* wich frame I belog to? */
+ mate_gop* gop; /* the gop the pdu belongs to (if any) */
+ gboolean first; /* is this the first pdu in this frame? */
+ gboolean is_start; /* this is the start pdu for this gop */
+ gboolean is_stop; /* this is the stop pdu for this gop */
+ gboolean after_release; /* this pdu comes after the stop */
+ float rel_time; /* time since gop start if in gop or start of capture if unassigned */
+ mate_pdu* next_in_frame; /* points to the next pdu in this frame */
+ /* } pdu; */
+
+ /* struct _gop { */
+ mate_gog* gog; /* the gog of a gop */
+ mate_pdu* pdus; /* pdus that belong to a gop (NULL in gog) */
+ float expiration; /* when will it expire once released? */
+ gboolean released; /* has this gop been released? */
+ int num_of_pdus; /* how many gops a gog has? */
+ int num_of_after_release_pdus; /* how many pdus have arrived since it's been released */
+ float start_time; /* time of start */
+ float release_time; /* when this gop was released */
+ float last_time; /* the rel time at which the last pdu/gop has been added */
+ guint8* gop_key; /* used by gop */
+ mate_pdu* last_pdu; /* last pdu in pdu's list */
+ /* } gop; */
+
+ /* struct _gog { */
+ mate_gop* gops; /* gops that belong to a gog (NULL in gop) */
+ int num_of_gops; /* how many gops a gog has? */
+ int num_of_released_gops; /* how many of them have already been released */
+ guint last_n; /* the number of attributes the avpl had the last time we checked */
+ GPtrArray* gog_keys; /* the keys under which this gog is stored in the gogs hash */
+ mate_gop* last_gop; /* last gop in gop's list */
+ /* } gog; */
+ /* } o; */
+};
+
+/* from mate_runtime.c */
+extern void init_mate_runtime_data(void);
+extern mate_pdu* mate_get_pdus(guint32 framenum);
+extern int mate_packet(void *prs _U_, packet_info *pinfo, epan_dissect_t *edt, void *dummy _U_);
+
+/* from mate_setup.c */
+extern mate_config* mate_make_config(guint8* filename);
+extern mate_config* mate_cfg();
+
+#endif
diff --git a/plugins/mate/mate_plugin.c b/plugins/mate/mate_plugin.c
new file mode 100644
index 0000000000..bbdfce6583
--- /dev/null
+++ b/plugins/mate/mate_plugin.c
@@ -0,0 +1,62 @@
+/* mate_plugin.c
+* MATE -- Meta Analysis Tracing Engine
+*
+* Copyright 2004, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id$
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* 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.
+*/
+
+/* this file is used temporarily to buid it as a plugin */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugins/plugin_api.h"
+#include "moduleinfo.h"
+#include <gmodule.h>
+#include "plugins/plugin_api_defs.h"
+
+
+/* these two are in packet-mate.c */
+void proto_register_mate(void);
+void proto_reg_handoff_mate(void);
+static gboolean initialized = FALSE;
+
+#ifndef ENABLE_STATIC
+G_MODULE_EXPORT const gchar version[] = VERSION;
+
+G_MODULE_EXPORT void plugin_init(plugin_address_table_t *pat _U_ ) {
+ /* initialise the table of pointers needed in Win32 DLLs */
+ plugin_address_table_init(pat);
+
+ /* register the new protocol, protocol fields, and subtrees */
+ if (! initialized ) { /* execute protocol initialization only once */
+ proto_register_mate();
+ initialized = 1;
+ }
+}
+
+G_MODULE_EXPORT void plugin_reg_handoff(void)
+{
+ proto_reg_handoff_mate();
+}
+#endif
diff --git a/plugins/mate/mate_runtime.c b/plugins/mate/mate_runtime.c
new file mode 100644
index 0000000000..1b753a8354
--- /dev/null
+++ b/plugins/mate/mate_runtime.c
@@ -0,0 +1,742 @@
+/* mate_runtime.c
+* MATE -- Meta Analysis Tracing Engine
+*
+* Copyright 2004, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id$
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* 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.
+*/
+
+/* TODO:
+ + fix debug_print levels
+ - timers
+ - on gops
+ - on gogs?
+ - on pdu?
+ + transformations
+ + maps
+*/
+
+#include "mate.h"
+
+typedef struct _mate_range mate_range;
+
+struct _mate_range {
+ guint start;
+ guint end;
+};
+
+typedef struct _tmp_pdu_data {
+ GPtrArray* ranges;
+ GHashTable* interesting;
+ mate_pdu* pdu;
+} tmp_pdu_data;
+
+
+mate_runtime_data* rd = NULL;
+static mate_config* mc = NULL;
+
+static int zero = 0;
+
+static int* dbg = &zero;
+static int* dbg_pdu = &zero;
+static int* dbg_gop = &zero;
+static int* dbg_gog = &zero;
+static FILE* dbg_facility = NULL;
+
+
+static gboolean destroy_mate_items(gpointer k _U_, gpointer v, gpointer p _U_) {
+ mate_item* mi = (mate_item*) v;
+
+ if (mi->gop_key) g_free(mi->gop_key);
+ if (mi->gog_keys) g_ptr_array_free (mi->gog_keys,TRUE);
+ delete_avpl(mi->avpl,TRUE);
+
+ return TRUE;
+}
+
+static void delete_mate_runtime_data(mate_runtime_data* rdat) {
+ g_hash_table_destroy(rdat->gops);
+ g_hash_table_destroy(rdat->frames);
+ g_hash_table_destroy(rdat->gogs);
+
+ g_hash_table_foreach_remove(rdat->items,destroy_mate_items,FALSE);
+ g_hash_table_destroy(rdat->items);
+
+ g_mem_chunk_destroy (rdat->mate_items);
+
+ g_free(rdat);
+}
+
+
+extern void init_mate_runtime_data(void) {
+
+ if (rd) {
+ delete_mate_runtime_data(rd);
+ }
+
+ rd = g_malloc(sizeof(mate_runtime_data));
+
+ mc = mate_cfg();
+
+ rd->current_items = 0;
+ rd->now = -1.0;
+ rd->frames = g_hash_table_new(g_direct_hash,g_direct_equal);
+ rd->items = g_hash_table_new(g_str_hash,g_str_equal);
+ rd->gops = g_hash_table_new(g_str_hash,g_str_equal);
+ rd->gogs = g_hash_table_new(g_str_hash,g_str_equal);
+ rd->mate_items = g_mem_chunk_new("mate_items",sizeof(mate_item),1024,G_ALLOC_AND_FREE);
+}
+
+/* creates a mate_item*/
+static mate_item* new_mate_item(mate_cfg_item* cfg) {
+ mate_item* it = g_mem_chunk_alloc(rd->mate_items);
+
+ it->cfg = cfg;
+ cfg->last_id++;
+
+ g_snprintf(it->id,MATE_ITEM_ID_SIZE,"%s:%i",cfg->name,cfg->last_id);
+
+ it->avpl = NULL ;
+ it->start = 0 ;
+ it->end = 0 ;
+ it->frame = 0 ;
+ it->next = NULL ;
+ it->released = FALSE ;
+ it->expiration = 0.0;
+
+ rd->current_items++;
+
+ return it;
+}
+
+/* a new gop */
+static mate_gop* new_gop(mate_cfg_gop* cfg, mate_pdu* pdu, guint8* key) {
+ mate_gop* gop = new_mate_item(cfg);
+
+ dbg_print (dbg_gop,1,dbg_facility,"new_gop: %s: ``%s''",gop->id,key);
+
+ gop->avpl = new_avpl("attributes");
+
+ gop->gog = NULL;
+ gop->pdus = pdu;
+ gop->last_pdu = pdu;
+ gop->gop_key = key;
+ gop->next = NULL;
+ gop->start_time = pdu->rel_time;
+ gop->release_time = 0.0;
+ gop->last_time = 0.0;
+
+ pdu->gop = gop;
+ pdu->next = NULL;
+ pdu->is_start = TRUE;
+ pdu->rel_time = 0.0;
+
+ return gop;
+}
+
+
+static void adopt_gop(mate_gog* gog, mate_gop* gop) {
+ dbg_print (dbg_gog,5,dbg_facility,"adopt_gop: gog=%X gop=%X",gog,gop);
+
+ gop->gog = gog;
+ gop->next = NULL;
+
+ gog->num_of_gops++;
+
+ if (gog->last_gop) {
+ gog->last_gop->next = gop;
+ }
+
+ gog->last_gop = gop;
+
+ if (! gog->gops ) {
+ gog->gops = gop;
+ }
+
+}
+
+/* a new gog */
+static mate_gog* new_gog(mate_cfg_gog* cfg, mate_gop* gop) {
+ mate_gog* gog = new_mate_item(cfg);
+
+ dbg_print (dbg_gog,1,dbg_facility,"new_gog: %s for %s",gog->id,gop->id);
+
+ gog->cfg = cfg;
+ gog->avpl = new_avpl("");
+ gog->gops = NULL;
+ gog->last_n = 0;
+ gog->gog_keys = g_ptr_array_new();
+ gog->last_gop = NULL;
+
+ gog->start_time = gop->rel_time;
+
+ adopt_gop(gog,gop);
+
+ return gog;
+}
+
+
+static void apply_transforms(mate_item* item) {
+ AVPL_Transf* transform = NULL;
+ guint i;
+
+ for (i = 0; i < item->cfg->transforms->len; i++) {
+ transform = g_ptr_array_index(item->cfg->transforms,i);
+ avpl_transform(item->avpl, transform);
+ }
+}
+
+
+/* applies the extras for which type to what avpl */
+static void apply_extras(AVPL* from, AVPL* to, mate_cfg_item* cfg) {
+ AVPL* our_extras = NULL;
+
+ if (cfg->extra) {
+ dbg_print (dbg,3,dbg_facility,"apply_extras: entering: from='%s' to='%s' for='%s'\n",from->name,to->name,cfg->name);
+
+ our_extras = new_avpl_loose_match("",from, cfg->extra, FALSE) ;
+
+ if (our_extras) {
+ merge_avpl(to,our_extras,TRUE);
+ delete_avpl(our_extras,FALSE);
+ }
+ }
+}
+
+static void gog_remove_keys (mate_gog* gog) {
+ guint8* k;
+
+ while (gog->gog_keys->len) {
+ k = (guint8*) g_ptr_array_remove_index_fast(gog->gog_keys,0);
+ g_hash_table_remove(rd->gogs,k);
+ g_free(k);
+ }
+}
+
+static void reanalyze_gop(mate_gop* gop) {
+ LoAL* gog_keys = NULL;
+ AVPL* curr_gogkey = NULL;
+ void* cookie = NULL;
+ AVPL* gogkey_match = NULL;
+ mate_gog* gog = gop->gog;
+ guint8* key;
+
+ if ( ! gog ) return;
+
+ dbg_print (dbg_gog,1,dbg_facility,"reanalize_gop: gop=%s gog=%s\n",gop->id,gog->id);
+
+ apply_extras(gop->avpl,gog->avpl,gog->cfg);
+
+ if (gog->last_n != gog->avpl->len) {
+
+ dbg_print (dbg_gog,2,dbg_facility,"analize_gop: gog has new attributes let's look for new keys\n");
+
+ gog_keys = gog->cfg->keys;
+
+ while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) {
+ if (( gogkey_match = new_avpl_exact_match("",gog->avpl,curr_gogkey,FALSE) )) {
+ key = avpl_to_str(gogkey_match);
+ if ( g_hash_table_lookup(rd->gogs,key) ) {
+ g_free(key);
+ } else {
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: new key for gog=%s : %s\n",gog->id,key);
+ g_hash_table_insert(rd->gogs,key,gog);
+ g_ptr_array_add(gog->gog_keys,key);
+ }
+ delete_avpl(gogkey_match,FALSE);
+ }
+ }
+ gog->last_n = gog->avpl->len;
+ }
+
+ if (gog->num_of_released_gops == gog->num_of_gops) {
+ gog->released = TRUE;
+ gog->expiration = gog->cfg->expiration + rd->now;
+ } else {
+ gog->released = FALSE;
+ }
+}
+
+static void analize_gop(mate_gop* gop) {
+ mate_cfg_gog* cfg = NULL;
+ LoAL* gog_keys = NULL;
+ AVPL* curr_gogkey = NULL;
+ void* cookie = NULL;
+ AVPL* gogkey_match = NULL;
+ mate_gog* gog = NULL;
+ guint8* key = NULL;
+
+ if ( ! ( gog = gop->gog ) ) {
+ /* no gog, let's either find one or create it if due */
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: no gog\n");
+
+ gog_keys = g_hash_table_lookup(mc->gogs_by_gopname,gop->cfg->name);
+
+ if ( ! gog_keys ) {
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: no gog_keys for this gop\n");
+ return;
+ }
+
+ /* We'll look for any matching gogkeys */
+
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: got gog_keys\n");
+
+ while (( curr_gogkey = get_next_avpl(gog_keys,&cookie) )) {
+
+ dbg_print (dbg_gog,2,dbg_facility,"analize_gop: about to match\n");
+
+ if (( gogkey_match = new_avpl_exact_match(curr_gogkey->name,gop->avpl,curr_gogkey,TRUE) )) {
+
+ key = avpl_to_str(gogkey_match);
+
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: got gogkey_match: %s\n",key);
+
+ if (( gog = g_hash_table_lookup(rd->gogs,key) )) {
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: got already a matching gog\n");
+
+ if (gog->num_of_gops == gog->num_of_released_gops && gog->expiration < rd->now) {
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: this is a new gog, not the old one, let's create it\n");
+
+ gog_remove_keys(gog);
+
+ gog = new_gog(gog->cfg,gop);
+ gog->num_of_gops = 1;
+
+ break;
+ } else {
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: this is our gog\n");
+
+ g_free(key);
+
+ if (! gop->gog ) adopt_gop(gog,gop);
+
+ break;
+ }
+ } else {
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: no such gog in hash, let's create a new one\n");
+
+ cfg = g_hash_table_lookup(mc->gogcfgs,curr_gogkey->name);
+
+ gog = new_gog(cfg,gop);
+ gog->num_of_gops = 1;
+ }
+
+ delete_avpl(gogkey_match,TRUE);
+ gogkey_match = NULL;
+ }
+ dbg_print (dbg_gog,1,dbg_facility,"analize_gop: no gogkey_match: %s\n",key);
+ }
+
+ if (gogkey_match) delete_avpl(gogkey_match,TRUE);
+
+ reanalyze_gop(gop);
+ }
+}
+
+
+
+static void analize_pdu(mate_pdu* pdu) {
+ /* TODO:
+ return a g_boolean to tell we've destroyed the pdu when the pdu is unnassigned
+ destroy the unassigned pdu
+ */
+ mate_cfg_gop* cfg = NULL;
+ mate_gop* gop = NULL;
+ guint8* gop_key;
+ guint8* orig_gop_key = NULL;
+ AVPL* candidate_gop_key_match = NULL;
+ AVPL* candidate_start = NULL;
+ AVPL* candidate_stop = NULL;
+ AVPL* our_extras = NULL;
+ AVPL* is_start = NULL;
+ AVPL* is_stop = NULL;
+ AVPL* gopkey_match = NULL;
+ guint8* avpl_str = NULL;
+
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: %s\n",pdu->cfg->name);
+
+ apply_transforms(pdu);
+
+ cfg = g_hash_table_lookup(mc->gops_by_pduname,pdu->cfg->name);
+
+ if (!cfg) return;
+
+
+
+ candidate_gop_key_match = cfg->key;
+
+ if (! candidate_gop_key_match) return;
+ avpl_str = avpl_to_str(candidate_gop_key_match);
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: got candidate key: %s\n",avpl_str);
+ g_free(avpl_str);
+
+ gopkey_match = new_avpl_exact_match("",pdu->avpl,candidate_gop_key_match, TRUE);
+
+ if (gopkey_match) {
+ gop_key = avpl_to_str(gopkey_match);
+
+ candidate_start = cfg->start;
+
+ if (candidate_start) {
+ avpl_str = avpl_to_str(candidate_start);
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: got candidate start: %s\n",avpl_str);
+ g_free(avpl_str);
+ is_start = new_avpl_exact_match("",pdu->avpl, candidate_start, FALSE);
+ }
+
+ if (is_start) {
+ avpl_str = avpl_to_str(is_start);
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: got start match: %s\n",avpl_str);
+ g_free(avpl_str);
+ delete_avpl(is_start,FALSE);
+ }
+
+ g_hash_table_lookup_extended(rd->gops,gop_key,(gpointer*)&orig_gop_key,(gpointer*)&gop);
+
+ if ( gop ) {
+ g_free(gop_key);
+
+ gop_key = orig_gop_key;
+
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: got gop: %s\n",gop_key);
+
+ if (is_start) {
+ if ( gop->released ) {
+
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: new gop on released key before key expiration\n");
+
+ g_hash_table_remove(rd->gops,gop_key);
+ gop = new_gop(cfg,pdu,gop_key);
+ g_hash_table_insert(rd->gops,gop_key,gop);
+ }
+
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: duplicate start on gop\n");
+
+ }
+
+ pdu->gop = gop;
+
+ if (gop->last_pdu) gop->last_pdu->next = pdu;
+ gop->last_pdu = pdu;
+ pdu->next = NULL;
+ pdu->rel_time -= gop->start_time;
+ if (gop->released) pdu->after_release = TRUE;
+
+ } else {
+
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: no gop\n");
+
+ if (is_start) {
+ gop = new_gop(cfg,pdu,gop_key);
+
+ g_hash_table_insert(rd->gops,gop_key,gop);
+ } else {
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: an unassigned pdu\n");
+
+ pdu->gop = NULL;
+ pdu->next = NULL;
+
+ return;
+ }
+ }
+
+ if ( gop ) gop->num_of_pdus++;
+
+ dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: merge with key\n");
+
+ merge_avpl(gop->avpl,gopkey_match,TRUE);
+ delete_avpl(gopkey_match,TRUE);
+
+ dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: apply extras\n");
+
+ apply_extras(pdu->avpl,gop->avpl,gop->cfg);
+
+ avpl_str = avpl_to_str(gop->avpl);
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: Gop Attributes: %s\n",avpl_str);
+ g_free(avpl_str);
+
+ gop->last_time = pdu->rel_time;
+
+ if ( ! gop->released) {
+ candidate_stop = cfg->stop;
+ if (candidate_stop) {
+ dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: got candidate stop\n");
+ is_stop = new_avpl_exact_match("",pdu->avpl, candidate_stop,FALSE);
+ }
+
+ if(is_stop) {
+ avpl_str = avpl_to_str(is_stop);
+ dbg_print (dbg_gop,1,dbg_facility,"analize_pdu: is_stop: %s\n",avpl_str);
+ g_free(avpl_str);
+ delete_avpl(is_stop,FALSE);
+
+ if (! gop->released) {
+ gop->released = TRUE;
+ gop->release_time = pdu->rel_time;
+ if (gop->gog) gop->gog->num_of_released_gops++;
+ }
+
+ pdu->is_stop = TRUE;
+ } else {
+ dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: is not a stop\n");
+ }
+ }
+
+ if (gop->last_n != gop->avpl->len) apply_transforms(gop);
+
+ gop->last_n = gop->avpl->len;
+
+ if (gop->gog) {
+ reanalyze_gop(gop);
+ } else {
+ analize_gop(gop);
+ }
+
+ } else {
+ dbg_print (dbg_gop,4,dbg_facility,"analize_pdu: no gop_key\n");
+
+ pdu->gop = NULL;
+ }
+}
+
+static void get_pdu_fields(gpointer k, gpointer v, gpointer p) {
+ int hfid = *((int*) k);
+ guint8* name = (guint8*) v;
+ tmp_pdu_data* data = (tmp_pdu_data*) p;
+ GPtrArray* fis;
+ field_info* fi;
+ guint i,j;
+ mate_range* curr_range;
+ guint start;
+ guint end;
+ AVP* avp;
+ guint8* s;
+
+ /* no warning */
+ k = p;
+
+ fis = (GPtrArray*) g_hash_table_lookup(data->interesting,(gpointer) hfid);
+
+ if (fis) {
+ for (i = 0; i < fis->len; i++) {
+ fi = (field_info*) g_ptr_array_index(fis,i);
+
+
+ start = fi->start;
+ end = fi->start + fi->length;
+
+ dbg_print(dbg_pdu,6,dbg_facility,"get_pdu_fields: found field %i-%i\n",start,end);
+
+ for (j = 0; j < data->ranges->len; j++) {
+
+ curr_range = (mate_range*) g_ptr_array_index(data->ranges,j);
+
+ dbg_print(dbg_pdu,6,dbg_facility,"get_pdu_fields: check if in range %i-%i\n",curr_range->start,curr_range->end);
+
+ if (curr_range->end >= end && curr_range->start <= start) {
+ avp = new_avp_from_finfo(name, fi);
+
+ s = avp_to_str(avp);
+ dbg_print(dbg_pdu,5,dbg_facility,"get_pdu_fields: got %s\n",s);
+ g_free(s);
+
+ if (! insert_avp(data->pdu->avpl,avp) ) {
+ delete_avp(avp);
+ }
+
+ }
+ }
+ }
+ }
+}
+
+static mate_pdu* new_pdu(mate_cfg_pdu* cfg, guint32 framenum, field_info* proto, GHashTable* interesting) {
+ mate_pdu* pdu = new_mate_item(cfg);
+ field_info* cfi;
+ GPtrArray* ptrs;
+ mate_range* range;
+ mate_range* proto_range;
+ tmp_pdu_data data;
+ guint i,j;
+ gint min_dist;
+ field_info* range_fi;
+ gint32 last_start;
+ int hfid;
+
+ dbg_print (dbg_pdu,2,dbg_facility,"new_pdu: type=%s framenum=%i\n",cfg->name,framenum);
+
+ pdu->avpl = new_avpl(pdu->id);
+ pdu->cfg = cfg;
+ pdu->gop = NULL;
+ pdu->next_in_frame = NULL;
+ pdu->next = NULL;
+ pdu->first = FALSE;
+ pdu->is_start = FALSE;
+ pdu->is_stop = FALSE;
+ pdu->after_release = FALSE;
+ pdu->start = proto->start;
+ pdu->end = pdu->start + proto->length;
+ pdu->frame = framenum;
+ pdu->rel_time = rd->now;
+
+ data.ranges = g_ptr_array_new();
+ data.pdu = pdu;
+ data.interesting = interesting;
+
+ /* first we create the proto range */
+ proto_range = g_malloc(sizeof(mate_range));
+ proto_range->start = pdu->start;
+ proto_range->end = pdu->end;
+ g_ptr_array_add(data.ranges,proto_range);
+
+ dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: proto range %u-%u\n",proto_range->start,proto_range->end);
+
+ last_start = proto_range->start;
+
+ for (i = 0; i < cfg->hfid_ranges->len; i++) {
+ hfid = *((int*)g_ptr_array_index(cfg->hfid_ranges,i));
+ ptrs = (GPtrArray*) g_hash_table_lookup(interesting,GINT_TO_POINTER(hfid));
+ min_dist = 99999;
+ range_fi = NULL;
+
+ if (ptrs) {
+ for (j=0; j < ptrs->len; j++) {
+ cfi = (field_info*) g_ptr_array_index(ptrs,j);
+ if (cfi->start < last_start && min_dist >= (last_start - cfi->start) ) {
+ range_fi = cfi;
+ min_dist = last_start - cfi->start;
+ }
+ }
+
+ if ( range_fi ) {
+ range = g_malloc(sizeof(range));
+ range->start = range_fi->start;
+ range->end = range_fi->start + range_fi->length;
+ g_ptr_array_add(data.ranges,range);
+
+ last_start = range_fi->start;
+
+ dbg_print(dbg_pdu,3,dbg_facility,"new_pdu: transport(%i) range %i-%i\n",hfid,range->start,range->end);
+ } else {
+
+ /* what do I do if I miss a range? */
+ }
+
+ }
+ }
+
+ g_hash_table_foreach(cfg->hfids_attr,get_pdu_fields,&data);
+
+ g_ptr_array_free(data.ranges,TRUE);
+
+ return pdu;
+}
+
+extern int mate_packet(void *prs _U_, packet_info *pinfo, epan_dissect_t *edt, void *dummy _U_) {
+ mate_pdu* pdu = NULL;
+ mate_pdu* last = NULL;
+ proto_tree* tree = edt->tree;
+ mate_cfg_pdu* cfg;
+ GPtrArray* protos;
+ field_info* proto;
+ guint i,j;
+
+ rd->now = (((float)pinfo->fd->rel_secs) + (((float)pinfo->fd->rel_usecs) / 1000000) );
+
+ dbg_print (dbg,3,dbg_facility,"mate_packet: got frame number: %i at %d\n",pinfo->fd->num,rd->now);
+
+ if ( tree->tree_data && tree->tree_data->interesting_hfids ) {
+ for ( i = 0; i < mc->pducfglist->len; i++ ) {
+
+ cfg = g_ptr_array_index(mc->pducfglist,i);
+
+ dbg_print (dbg_pdu,4,dbg_facility,"mate_packet: tryning to extract: %s\n",cfg->name);
+ protos = (GPtrArray*) g_hash_table_lookup(tree->tree_data->interesting_hfids,(gpointer) cfg->hfid_proto);
+
+ if (protos) {
+ pdu = NULL;
+
+ for (j = 0; j < protos->len; j++) {
+
+ dbg_print (dbg_pdu,3,dbg_facility,"mate_packet: found matching proto, extracting: %s\n",cfg->name);
+
+ proto = (field_info*) g_ptr_array_index(protos,j);
+ pdu = new_pdu(cfg, pinfo->fd->num, proto, tree->tree_data->interesting_hfids);
+
+ if (!last) {
+ g_hash_table_insert(rd->frames,(gpointer) pinfo->fd->num,pdu);
+ last = pdu;
+ } else {
+ last->next_in_frame = pdu;
+ last = pdu;
+ }
+
+ analize_pdu(pdu);
+
+ if ( cfg->discard_pdu_attributes ) {
+ delete_avpl(pdu->avpl,TRUE);
+ pdu->avpl = NULL;
+ }
+
+ }
+
+ if ( pdu && cfg->last_to_be_created ) break;
+ }
+ }
+
+
+ }
+
+
+ rd->highest_analyzed_frame = pinfo->fd->num;
+
+ dbg_print (dbg,6,dbg_facility,"do_mate: make_pdus done\n");
+
+ return 0;
+}
+
+extern mate_pdu* mate_get_pdus(guint32 framenum) {
+
+ if (rd) {
+ return (mate_pdu*) g_hash_table_lookup(rd->frames,GUINT_TO_POINTER(framenum));
+ } else {
+ return NULL;
+ }
+}
+
+/* this will be called when the mate's dissector is initialized */
+extern void initialize_mate(guint8* configuration_filename) {
+ dbg_print (dbg,5,dbg_facility,"initialize_mate: entering");
+
+ if (( mc = mate_cfg() )) {
+
+ dbg_pdu = &(mc->dbg_pdu_lvl);
+ dbg_gop = &(mc->dbg_gop_lvl);
+ dbg_gog = &(mc->dbg_gog_lvl);
+
+ } else {
+ return;
+ }
+
+ return;
+}
+
+
diff --git a/plugins/mate/mate_setup.c b/plugins/mate/mate_setup.c
new file mode 100644
index 0000000000..93def5120f
--- /dev/null
+++ b/plugins/mate/mate_setup.c
@@ -0,0 +1,1417 @@
+/* mate_setup.c
+* MATE -- Meta Analysis Tracing Engine
+*
+* Copyright 2004, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id$
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* 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.
+*/
+
+#include "mate.h"
+
+/* FIXME: config names should be at most 8 chars! */
+
+static int* dbg;
+
+static int dbg_cfg_lvl = 1;
+static int* dbg_cfg = &dbg_cfg_lvl;
+
+FILE* dbg_facility;
+
+typedef gboolean config_action(AVPL* avpl);
+
+/* the current mate_config */
+static mate_config* matecfg = NULL;
+
+/* key: the name of the action
+value: a pointer to an config_action */
+static GHashTable* actions = NULL;
+
+/* aestetics: I like keywords separated from user attributes */
+static AVPL* all_keywords = NULL;
+
+/* use as: setting = extract_named_xxx(avpl,keyword,default_value); */
+static int extract_named_int(AVPL* avpl, guint8* keyword, int value) {
+ AVP* avp = NULL;
+
+ if(( avp = extract_avp_by_name(avpl,keyword) )) {
+ value = strtol(avp->v,NULL,10);
+ }
+
+ return value;
+}
+
+static float extract_named_float(AVPL* avpl, guint8* keyword, float value) {
+ AVP* avp = NULL;
+
+ if(( avp = extract_avp_by_name(avpl,keyword) )) {
+ value = (float) strtod(avp->v,NULL);
+ }
+
+ return value;
+}
+
+static gboolean extract_named_bool(AVPL* avpl, guint8* keyword, gboolean value) {
+ AVP* avp = NULL;
+ if(( avp = extract_avp_by_name(avpl,keyword) )) {
+ value = ((g_strcasecmp(avp->v,"TRUE") == 0) ? TRUE : FALSE);
+ }
+
+ return value;
+}
+
+static guint8* extract_named_str(AVPL* avpl, guint8* keyword, guint8* value) {
+ AVP* avp = NULL;
+
+ if(( avp = extract_avp_by_name(avpl,keyword) )) {
+ value = avp->v;
+ }
+
+ return value;
+}
+
+/* lookups for the string value of the given named attribute from a given hash */
+static gpointer lookup_using_index_avp(AVPL* avpl, guint8* keyword, GHashTable* table, guint8** avp_value) {
+ AVP* avp = extract_avp_by_name(avpl,keyword);
+
+ if (avp) {
+ *avp_value = avp->v;
+ return g_hash_table_lookup(table,avp->v);
+ } else {
+ *avp_value = NULL;
+ return NULL;
+ }
+}
+
+
+/* creates and initializes a mate_cfg_item */
+static mate_cfg_item* new_mate_cfg_item(guint8* name) {
+ mate_cfg_pdu* new = g_malloc(sizeof(mate_cfg_item));
+
+ new->name = g_strdup(name);
+ new->type = MATE_UNK_TYPE;
+ new->transforms = g_ptr_array_new();
+ new->extra = new_avpl(name);
+ new->hfid_proto = -1;
+ new->discard_pdu_attributes = matecfg->discard_pdu_attributes;
+ new->last_to_be_created = matecfg->last_to_be_created;
+ new->drop_pdu = matecfg->drop_pdu;
+ new->drop_gop = matecfg->drop_gop;
+ new->expiration = matecfg->gog_expiration;
+ new->show_pdu_tree = matecfg->show_pdu_tree;
+ new->show_gop_times = matecfg->show_gop_times;
+ new->last_id = 0;
+ new->hfid_ranges = NULL;
+ new->hfids_attr = NULL;
+ new->criterium = NULL;
+ new->start = NULL;
+ new->stop = NULL;
+ new->key = NULL;
+ new->keys = NULL;
+
+ new->hfid = -1;
+ new->hfid_pdu_rel_time = -1;
+ new->my_hfids = g_hash_table_new(g_str_hash,g_str_equal);
+
+ new->hfid_gop_pdu = -1;
+ new->hfid_gop_start_time = -1;
+ new->hfid_gop_stop_time = -1;
+ new->hfid_gop_last_time = -1;
+ new->hfid_gop_num_pdus = -1;
+
+ new->hfid_gog_num_of_gops = -1;
+ new->hfid_gog_gop = -1;
+
+ return new;
+}
+
+/* for cleaning hashes */
+static gboolean free_both(gpointer k, gpointer v, gpointer p) {
+ g_free(k);
+ if (p) g_free(v);
+ return TRUE;
+}
+
+static void delete_mate_cfg_item(mate_cfg_item* cfg, gboolean avp_items_too) {
+
+ g_free(cfg->name);
+
+ if (avp_items_too) {
+ if (cfg->extra) delete_avpl(cfg->extra,TRUE);
+ if (cfg->start) delete_avpl(cfg->start,TRUE);
+ if (cfg->stop) delete_avpl(cfg->stop,TRUE);
+ if (cfg->key) delete_avpl(cfg->key,TRUE);
+ if (cfg->criterium) delete_avpl(cfg->criterium,TRUE);
+ if (cfg->keys) delete_loal(cfg->keys,TRUE,TRUE);
+ }
+
+ if (cfg->transforms) g_ptr_array_free(cfg->transforms,TRUE);
+
+ if (cfg->hfid_ranges)
+ g_ptr_array_free(cfg->hfid_ranges,TRUE);
+
+ if (cfg->hfids_attr)
+ g_hash_table_foreach_remove(cfg->hfids_attr,free_both, VALUE_TOO );
+
+}
+
+static mate_cfg_pdu* new_pducfg(guint8* name) {
+ mate_cfg_pdu* new = new_mate_cfg_item(name);
+
+ new->type = MATE_PDU_TYPE;
+ new->hfid_ranges = g_ptr_array_new();
+ new->hfids_attr = g_hash_table_new(g_int_hash,g_int_equal);
+
+ g_ptr_array_add(matecfg->pducfglist,(gpointer) new);
+
+ g_hash_table_insert(matecfg->pducfgs,(gpointer) new->name,(gpointer) new);
+
+ return new;
+}
+
+static mate_cfg_gop* new_gopcfg(guint8* name) {
+ mate_cfg_gop* new = new_mate_cfg_item(name);
+ new->type = MATE_GOP_TYPE;
+
+ g_hash_table_insert(matecfg->gopcfgs,(gpointer) new->name, (gpointer) new);
+
+ return new;
+}
+
+static mate_cfg_gog* new_gogcfg(guint8* name) {
+ mate_cfg_gog* new = new_mate_cfg_item(name);
+ new->type = MATE_GOG_TYPE;
+
+ new->keys = new_loal(name);
+ new->expiration = matecfg->gog_expiration;
+
+ g_hash_table_insert(matecfg->gogcfgs,new->name,new);
+
+ return new;
+}
+
+static gboolean free_cfgs(gpointer k _U_, gpointer v, gpointer p) {
+ delete_mate_cfg_item((mate_cfg_item*)v,(gboolean) p);
+ return TRUE;
+}
+
+extern void destroy_mate_config(mate_config* mc , gboolean avplib_too) {
+ if (mc->dbg_facility) fclose(mc->dbg_facility);
+ if (mc->mate_lib_path) g_free(mc->mate_lib_path);
+ if (mc->mate_config_file) g_free(mc->mate_config_file);
+ if (mc->mate_attrs_filter) g_string_free(mc->mate_attrs_filter,TRUE);
+ if (mc->mate_protos_filter) g_string_free(mc->mate_protos_filter,TRUE);
+ if (mc->pducfglist) g_ptr_array_free(mc->pducfglist,FALSE);
+
+ if (mc->gogs_by_gopname) {
+ g_hash_table_destroy(mc->gogs_by_gopname);
+ }
+
+ if (mc->pducfgs) {
+ g_hash_table_foreach_remove(mc->pducfgs,free_cfgs,(gpointer) avplib_too);
+ g_hash_table_destroy(mc->pducfgs);
+ }
+
+ if (mc->gopcfgs) {
+ g_hash_table_foreach_remove(mc->gopcfgs,free_cfgs,(gpointer) avplib_too);
+ g_hash_table_destroy(mc->gopcfgs);
+ }
+
+ if (mc->gogcfgs) {
+ g_hash_table_foreach_remove(mc->gogcfgs,free_cfgs,(gpointer) avplib_too);
+ g_hash_table_destroy(mc->gogcfgs);
+ }
+
+ if (mc->tap_filter) g_free(mc->tap_filter);
+
+ if (mc->hfrs) g_array_free(mc->hfrs,TRUE);
+ g_free(mc);
+
+}
+
+
+/* a configuration error */
+static void mate_config_error(LoAL* loal _U_ ,guint8* line _U_ , guint8* fmt, ...) {
+ va_list list;
+ guint8* desc;
+
+ va_start( list, fmt );
+ desc = g_strdup_vprintf(fmt, list);
+ va_end( list );
+
+ dbg_print (dbg,0,dbg_facility,"mate_config_error: %s",desc);
+
+ g_warning(desc);
+ g_free(desc);
+
+}
+
+
+static gboolean mate_load_config(guint8* filename) {
+ LoAL* loal = loal_from_file(filename);
+ AVPL* avpl;
+ guint8* line = NULL;
+ config_action* action;
+ guint8* name;
+
+ if (loal) {
+ while(( avpl = extract_first_avpl(loal) )) {
+ line = avpl_to_str(avpl);
+
+ dbg_print (dbg_cfg,3,dbg_facility,"mate_make_config: current line: %s",line);
+
+ action = lookup_using_index_avp(avpl, KEYWORD_ACTION, actions,&name);
+
+ if (action) {
+ if ( ! action(avpl) ) {
+ mate_config_error(loal,line,"mate: Error on AVPL: '%s'",name);
+ return FALSE;
+ }
+ } else {
+ mate_config_error(loal,line,"mate: Error: action '%s' unknown",name);
+ return FALSE;
+ }
+
+ g_free(line);
+ }
+
+ return TRUE;
+ } else {
+ g_warning("mate: could not load '%s'",filename);
+ return FALSE;
+ }
+}
+
+static gboolean add_hfid(guint8* what, guint8* how, GHashTable* where) {
+ header_field_info* hfi = NULL;
+ header_field_info* first_hfi = NULL;
+ gboolean exists = FALSE;
+ guint8* as;
+ guint8* h;
+ int* ip;
+
+ hfi = proto_registrar_get_byname(what);
+
+ while(hfi) {
+ first_hfi = hfi;
+ hfi = hfi->same_name_prev;
+ }
+
+ hfi = first_hfi;
+
+ while (hfi) {
+ exists = TRUE;
+ ip = g_malloc(sizeof(int));
+
+ *ip = hfi->id;
+
+ if (( as = g_hash_table_lookup(where,ip) )) {
+ g_free(ip);
+ if (! g_str_equal(as,how)) {
+ g_warning("Error: add_hfid: attempt to add %s(%i) as %s"
+ " failed: hfid already added as '%s'",what,hfi->id,how,as);
+ return FALSE;
+ }
+ } else {
+ h = g_strdup(how);
+ g_hash_table_insert(where,ip,h);
+
+
+ dbg_print (dbg,5,dbg_facility,"add_hfid: added hfid %s(%i) as %s",what,*ip,how);
+ }
+
+ hfi = hfi->same_name_next;
+
+ }
+
+ if (! exists) {
+ g_warning("Error: add_hfid(%s): cannot find",what);
+ }
+
+ return exists;
+}
+
+static gboolean config_pdu(AVPL* avpl) {
+ guint8* name = NULL;
+ guint8* transport = extract_named_str(avpl,KEYWORD_TRANSPORT,NULL);
+ guint8* proto = extract_named_str(avpl,KEYWORD_PROTO,"no_protocol");
+ mate_cfg_pdu* cfg = lookup_using_index_avp(avpl,KEYWORD_NAME,matecfg->pducfgs,&name);
+ header_field_info* hfi;
+ int* hfidp;
+ gchar** transports;
+ guint i;
+ AVP* attr_avp;
+
+ if (! cfg) {
+ cfg = new_pducfg(name);
+ } else {
+ g_warning("MATE: PDU Config error: No such PDU: %s",cfg->name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ cfg->last_to_be_created = extract_named_bool(avpl,KEYWORD_STOP,matecfg->last_to_be_created);
+ cfg->discard_pdu_attributes = extract_named_bool(avpl,KEYWORD_DISCARDPDU,matecfg->discard_pdu_attributes);
+ cfg->drop_pdu = extract_named_bool(avpl,KEYWORD_DROPPDU,matecfg->drop_pdu);
+
+ hfi = proto_registrar_get_byname(proto);
+
+ if (hfi) {
+ cfg->hfid_proto = hfi->id;
+ } else {
+ g_warning("mate: PDU Config error: no such proto: %s",proto);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ g_string_sprintfa(matecfg->mate_protos_filter,"||%s",proto);
+
+ if ( transport ) {
+
+ transports = g_strsplit(transport,"/",0);
+
+ if (transports) {
+ for (i=0; transports[i]; i++) {
+ hfi = proto_registrar_get_byname(transports[i]);
+ if (hfi) {
+ hfidp = g_malloc(sizeof(int));
+ *hfidp = hfi->id;
+ g_ptr_array_add(cfg->hfid_ranges,(gpointer)hfidp);
+ g_string_sprintfa(matecfg->mate_attrs_filter, "||%s",transports[i]);
+ } else {
+ g_warning("mate: PDU Config error: no such proto: %s for Transport",proto);
+ g_strfreev(transports);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+ }
+
+ g_strfreev(transports);
+ }
+ } else {
+ g_warning("mate: PDU Config error: no Transport for %s",cfg->name);
+ return FALSE;
+ }
+
+ while (( attr_avp = extract_first_avp(avpl) )) {
+ if ( ! add_hfid(attr_avp->v,attr_avp->n,cfg->hfids_attr) ) {
+ g_warning("mate: PDU Config error: failed to set PDU attribute '%s'",attr_avp->n);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+ g_string_sprintfa(matecfg->mate_attrs_filter, "||%s",attr_avp->v);
+ }
+
+ delete_avpl(avpl,TRUE);
+ return TRUE;
+}
+
+static gboolean config_pduextra(AVPL* avpl) {
+ guint8* name;
+ AVP* attr_avp;
+ mate_cfg_pdu* cfg = lookup_using_index_avp(avpl,KEYWORD_FOR,matecfg->pducfgs,&name);
+
+ if (! cfg) {
+ g_warning("mate: PduExtra Config error: no such Pdu %s",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ cfg->last_to_be_created = extract_named_bool(avpl,KEYWORD_STOP,cfg->last_to_be_created);
+ cfg->discard_pdu_attributes = extract_named_bool(avpl,KEYWORD_DISCARDPDU,cfg->discard_pdu_attributes);
+ cfg->drop_pdu = extract_named_bool(avpl,KEYWORD_DROPPDU,cfg->drop_pdu);
+
+ while (( attr_avp = extract_first_avp(avpl) )) {
+ if ( ! add_hfid(attr_avp->v,attr_avp->n,cfg->hfids_attr) ) {
+ g_warning("mate: PDU Config error: failed to set attr %s",attr_avp->n);
+ delete_avp(attr_avp);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+ g_string_sprintfa(matecfg->mate_attrs_filter, "||%s",attr_avp->v);
+ }
+
+ delete_avpl(avpl,TRUE);
+ return TRUE;
+
+}
+
+
+
+static gboolean config_include(AVPL* avpl) {
+ guint8* filename = extract_named_str(avpl,KEYWORD_FILENAME,NULL);
+
+ /* TODO: use library path */
+ if( ! filename ) {
+ mate_config_error(NULL,NULL,"mate: Include file error: no filename");
+ return FALSE;
+ }
+
+ /* FIXME: stop recursion */
+ if ( ! mate_load_config(filename) ) {
+ mate_config_error(NULL,NULL,"mate: Error Loading '%s'",filename);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static gboolean config_settings(AVPL*avpl) {
+ AVP* avp;
+
+#ifdef _AVP_DEBUGGING
+ int debug_avp = 0;
+ int dbg_avp = 0;
+ int dbg_avp_op = 0;
+ int dbg_avpl = 0;
+ int dbg_avpl_op = 0;
+#endif
+
+
+ matecfg->gog_expiration = extract_named_bool(avpl, KEYWORD_GOGEXPIRE,matecfg->gog_expiration);
+ matecfg->discard_pdu_attributes = extract_named_bool(avpl, KEYWORD_DISCARDPDU,matecfg->discard_pdu_attributes);
+ matecfg->drop_pdu = extract_named_bool(avpl, KEYWORD_DROPPDU,matecfg->drop_pdu);
+ matecfg->drop_gop = extract_named_bool(avpl, KEYWORD_DROPGOP,matecfg->drop_gop);
+ matecfg->show_pdu_tree = extract_named_bool(avpl, KEYWORD_SHOWPDUTREE,matecfg->show_pdu_tree);
+ matecfg->show_gop_times = extract_named_bool(avpl, KEYWORD_SHOWGOPTIMES,matecfg->show_gop_times);
+
+ if(( avp = extract_avp_by_name(avpl,KEYWORD_DEBUGFILENAME) )) {
+ matecfg->dbg_facility = dbg_facility = fopen(avp->v,"w");
+ delete_avp(avp);
+ avp = NULL;
+ }
+
+ matecfg->dbg_lvl = extract_named_int(avpl, KEYWORD_DBG_GENERAL,0);
+ matecfg->dbg_cfg_lvl = extract_named_int(avpl, KEYWORD_DBG_CFG,0);
+ matecfg->dbg_gop_lvl = extract_named_int(avpl, KEYWORD_DBG_PDU,0);
+ matecfg->dbg_gop_lvl = extract_named_int(avpl, KEYWORD_DBG_GOP,0);
+ matecfg->dbg_gog_lvl = extract_named_int(avpl, KEYWORD_DBG_GOG,0);
+
+#ifdef _AVP_DEBUGGING
+ setup_avp_debug(dbg_facility,
+ extract_named_int(avpl, KEYWORD_DBG_AVPLIB,0),
+ extract_named_int(avpl, KEYWORD_DBG_AVP,0),
+ extract_named_int(avpl, KEYWORD_DBG_AVP_OP,0),
+ extract_named_int(avpl, KEYWORD_DBG_AVPL,0),
+ extract_named_int(avpl, KEYWORD_DBG_AVPL_OP,0));
+#endif
+
+ dbg_cfg_lvl = matecfg->dbg_cfg_lvl;
+
+ return TRUE;
+}
+
+static gboolean config_transform(AVPL* avpl) {
+ guint8* name = extract_named_str(avpl, KEYWORD_NAME, NULL);
+ guint8* match = extract_named_str(avpl, KEYWORD_MATCH, NULL);
+ guint8* mode = extract_named_str(avpl, KEYWORD_MODE, NULL);
+ avpl_match_mode match_mode;
+ avpl_replace_mode replace_mode;
+ AVPL_Transf* t;
+ AVPL_Transf* last;
+
+ if ( match ) {
+ if ( g_strcasecmp(match,KEYWORD_LOOSE) == 0 ) {
+ match_mode = AVPL_LOOSE;
+ } else if ( g_strcasecmp(match,KEYWORD_EVERY) == 0 ) {
+ match_mode = AVPL_EVERY;
+ } else if ( g_strcasecmp(match,KEYWORD_STRICT) == 0 ) {
+ match_mode = AVPL_STRICT;
+ } else {
+ g_warning("mate: Transform Config error: no such match mode: %s",match);
+ return FALSE;
+ }
+ } else {
+ match_mode = matecfg->match_mode;
+ }
+
+ if ( mode ) {
+ if ( g_strcasecmp(mode,KEYWORD_INSERT) == 0 ) {
+ replace_mode = AVPL_INSERT;
+ } else if ( g_strcasecmp(mode,KEYWORD_REPLACE) == 0 ) {
+ replace_mode = AVPL_REPLACE;
+ } else {
+ g_warning("mate: Transform Config error: no such replace mode: %s",mode);
+ return FALSE;
+ }
+
+ } else {
+ replace_mode = matecfg->replace_mode;
+ }
+
+ if (! name) {
+ g_warning("mate: Transform Config error: no Name");
+ return FALSE;
+ }
+
+ t = new_avpl_transform(name,avpl, match_mode, replace_mode);
+
+ if (( last = g_hash_table_lookup(matecfg->transfs,name) )) {
+ while (last->next) last = last->next;
+ last->next = t;
+ } else {
+ g_hash_table_insert(matecfg->transfs,t->name,t);
+ }
+
+ return TRUE;
+}
+
+static gboolean config_xxx_transform(AVPL* avpl, GHashTable* hash, guint8* keyword) {
+ guint8* pdu_name;
+ guint8* name;
+ AVPL_Transf* transf = lookup_using_index_avp(avpl,KEYWORD_NAME,matecfg->transfs,&name);
+ mate_cfg_pdu* cfg = lookup_using_index_avp(avpl,KEYWORD_FOR,hash,&pdu_name);;
+
+ if (! name ) {
+ g_warning("mate: %s Config error: No Name",keyword);
+ return FALSE;
+ }
+
+ if (! pdu_name ) {
+ g_warning("mate: %s Config error: No For",keyword);
+ return FALSE;
+ }
+
+ if (! cfg ) {
+ g_warning("mate: %s Config error: %s doesn't exist",keyword,pdu_name);
+ return FALSE;
+ }
+
+ if (!transf) {
+ g_warning("mate: %s Config error: Transform %s doesn't exist",keyword,name);
+ return FALSE;
+ }
+
+ g_ptr_array_add(cfg->transforms,transf);
+
+ return TRUE;
+}
+
+static gboolean config_pdu_transform(AVPL* avpl) {
+ return config_xxx_transform(avpl, matecfg->pducfgs, KEYWORD_PDUTRANSFORM);
+}
+
+static gboolean config_gop_transform(AVPL* avpl) {
+ return config_xxx_transform(avpl, matecfg->gopcfgs, KEYWORD_GOPTRANSFORM);
+}
+
+static gboolean config_gog_transform(AVPL* avpl) {
+ return config_xxx_transform(avpl, matecfg->gogcfgs, KEYWORD_GOPTRANSFORM);
+}
+
+static gboolean config_gop(AVPL* avpl) {
+ guint8* name = NULL;
+ mate_cfg_gop* cfg = lookup_using_index_avp(avpl, KEYWORD_NAME,matecfg->gopcfgs,&name);
+ guint8* on = extract_named_str(avpl,KEYWORD_ON,NULL);
+
+ if (!cfg) {
+ cfg = new_gopcfg(name);
+ } else {
+ g_warning("mate: GopDef Config error: Gop '%s' exists already",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ if (! on ) {
+ g_warning("mate: GopDef Config error: No 'On' AVP");
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ if (g_hash_table_lookup(matecfg->gops_by_pduname,on) ) {
+ g_warning("mate: GopDef Config error: Gop for Pdu '%s' exists already",on);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ } else {
+ g_hash_table_insert(matecfg->gops_by_pduname,on,cfg);
+ }
+
+ cfg->drop_gop = extract_named_bool(avpl, KEYWORD_DROPGOP,matecfg->drop_gop);
+ cfg->show_pdu_tree = extract_named_bool(avpl, KEYWORD_SHOWPDUTREE, matecfg->show_pdu_tree);
+ cfg->show_gop_times = extract_named_bool(avpl, KEYWORD_SHOWGOPTIMES,matecfg->show_gop_times);
+
+ cfg->key = avpl;
+
+ return TRUE;
+}
+
+static gboolean config_start(AVPL* avpl) {
+ guint8* name;
+ mate_cfg_gop* cfg = lookup_using_index_avp(avpl, KEYWORD_FOR,matecfg->gopcfgs,&name);;
+
+ if (!cfg) {
+ g_warning("mate: GopStart Config error: Gop %s does not exist",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ if (cfg->start) {
+ /* FEATURE: more start conditions */
+ g_warning("mate: GopStart Config error: GopStart alredy exists for %s",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ cfg->start = avpl;
+
+ return TRUE;
+}
+
+static gboolean config_stop(AVPL* avpl) {
+ guint8* name;
+ mate_cfg_gop* cfg = lookup_using_index_avp(avpl, KEYWORD_FOR,matecfg->gopcfgs,&name);;
+
+ if (!cfg) {
+ g_warning("mate: GopStop Config error: Gop %s does not exist",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ if (cfg->stop) {
+ /* FEATURE: more GopStop conditions */
+ g_warning("mate: GopStart Config error: GopStop alredy exists for %s",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ cfg->stop = avpl;
+
+ return TRUE;
+}
+
+static gboolean config_gopextra(AVPL* avpl) {
+ guint8* name;
+ mate_cfg_gop* cfg = lookup_using_index_avp(avpl, KEYWORD_FOR,matecfg->gopcfgs,&name);;
+
+ if (!cfg) {
+ g_warning("mate: GopExtra Config error: Gop %s does not exist",name);
+ delete_avpl(avpl,TRUE);
+ return FALSE;
+ }
+
+ cfg->drop_gop = extract_named_bool(avpl, KEYWORD_DROPGOP,cfg->drop_gop);
+ cfg->show_pdu_tree = extract_named_bool(avpl, KEYWORD_SHOWPDUTREE, cfg->show_pdu_tree);
+ cfg->show_gop_times = extract_named_bool(avpl, KEYWORD_SHOWGOPTIMES,cfg->show_gop_times);
+
+ merge_avpl(cfg->extra,avpl,TRUE);
+
+ delete_avpl(avpl,TRUE);
+ return TRUE;
+}
+
+static gboolean config_gog(AVPL* avpl) {
+ guint8* name = extract_named_str(avpl, KEYWORD_NAME,NULL);
+ mate_cfg_gog* cfg = NULL;
+
+ if (!name) {
+ g_warning("mate: GogDef Config error: no Name");
+ return FALSE;
+ }
+
+ if ( g_hash_table_lookup(matecfg->gogcfgs,name) ) {
+ g_warning("mate: GogDef Config error: Gog %s exists already", name);
+ return FALSE;
+ }
+
+ cfg = new_gogcfg(name);
+
+ cfg->expiration = extract_named_float(avpl, KEYWORD_GOGEXPIRE,matecfg->gog_expiration);
+
+ return TRUE;
+}
+
+static gboolean config_gogkey(AVPL* avpl) {
+ guint8* name;
+ mate_cfg_gog* cfg = lookup_using_index_avp(avpl, KEYWORD_FOR,matecfg->gogcfgs,&name);
+ AVPL* reverse_avpl;
+ LoAL* gogkeys;
+ guint8* on = extract_named_str(avpl,KEYWORD_ON,NULL);
+
+ if ( ! name || ! cfg ) {
+ if ( ! name )
+ g_warning("mate: GogKey Config error: no Name");
+ else
+ g_warning("mate: GogKey Config error: no such Gop %s",name);
+
+ return FALSE;
+ }
+
+ if (! on ) {
+ g_warning("mate: GogKey Config error: no " KEYWORD_ON);
+ return FALSE;
+ }
+
+ rename_avpl(avpl,name);
+
+ gogkeys = (LoAL*) g_hash_table_lookup(matecfg->gogs_by_gopname,on);
+
+ if (! gogkeys) {
+ gogkeys = new_loal("straight");
+ g_hash_table_insert(matecfg->gogs_by_gopname,g_strdup(on),gogkeys);
+ }
+
+ loal_append(gogkeys,avpl);
+
+ reverse_avpl = new_avpl_from_avpl(on,avpl,TRUE);
+
+ loal_append(cfg->keys,reverse_avpl);
+
+ return TRUE;
+}
+
+static gboolean config_gogextra(AVPL* avpl) {
+ guint8* name;
+ mate_cfg_gop* cfg = lookup_using_index_avp(avpl, KEYWORD_FOR,matecfg->gogcfgs,&name);
+
+ if ( ! name || ! cfg ) {
+ if ( ! name )
+ g_warning("mate: GogExtra Config error: no Name");
+ else
+ g_warning("mate: GogExtra Config error: no such Gop %s",name);
+
+ return FALSE;
+ }
+
+ cfg->expiration = extract_named_float(avpl, KEYWORD_GOGEXPIRE,cfg->expiration);
+
+ merge_avpl(cfg->extra,avpl,TRUE);
+
+ delete_avpl(avpl,TRUE);
+ return TRUE;
+}
+
+
+static void print_xxx_transforms(mate_cfg_item* cfg) {
+ guint8* tr_name;
+ guint8* cfg_name;
+ guint i;
+
+ switch (cfg->type) {
+ case MATE_PDU_TYPE:
+ cfg_name = "PduTransform";
+ break;
+ case MATE_GOP_TYPE:
+ cfg_name = "GopTransform";
+ break;
+ case MATE_GOG_TYPE:
+ cfg_name = "GogTransform";
+ break;
+ default:
+ cfg_name = "UnknownTransform";
+ break;
+ }
+
+ for (i=0; i < cfg->transforms->len; i++) {
+ tr_name = ((AVPL_Transf*) g_ptr_array_index(cfg->transforms,i))->name;
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=%s; For=%s; Name=%s;\n",cfg_name,cfg->name,tr_name);
+ }
+
+}
+
+static void print_gog_config(gpointer k _U_, gpointer v, gpointer p _U_) {
+ mate_cfg_gop* cfg = (mate_cfg_gop*) v;
+ guint8* avplstr = NULL;
+ void* cookie = NULL;
+ AVPL* avpl;
+
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=GogDef; Name=%s; Expiration=%f;\n",cfg->name,cfg->expiration);
+
+ if (cfg->keys) {
+ while (( avpl = get_next_avpl(cfg->keys,&cookie) )) {
+ avplstr = avpl_to_str(avpl);
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=GogKey; For=%s; On=%s; %s\n",cfg->name,avpl->name,avplstr);
+ g_free(avplstr);
+ }
+ }
+
+ if (cfg->extra) {
+ avplstr = avpl_to_str(cfg->extra);
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=GogExtra; For=%s; %s\n",cfg->name,avplstr);
+ g_free(avplstr);
+ }
+
+ print_xxx_transforms(cfg);
+
+}
+
+
+
+static void print_gop_config(gpointer k _U_ , gpointer v, gpointer p _U_) {
+ mate_cfg_gop* cfg = (mate_cfg_gop*) v;
+ guint8* avplstr = NULL;
+ guint8* show_pdu_tree;
+ GString* gopdef;
+
+ gopdef = g_string_new("Action=GopDef; ");
+
+ show_pdu_tree = cfg->show_pdu_tree ? "TRUE" : "FALSE";
+ g_string_sprintfa(gopdef,"Name=%s; ShowPduTree=%s;",cfg->name,show_pdu_tree);
+
+ if (cfg->key) {
+ avplstr = avpl_to_str(cfg->key);
+ g_string_sprintfa(gopdef," %s",avplstr);
+ g_free(avplstr);
+ }
+
+ dbg_print (dbg_cfg,0,dbg_facility,"%s\n",gopdef->str);
+
+
+ if (cfg->start) {
+ avplstr = avpl_to_str(cfg->start);
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=GopStart; For=%s; %s\n",cfg->name,avplstr);
+ g_free(avplstr);
+ }
+
+ if (cfg->stop) {
+ avplstr = avpl_to_str(cfg->stop);
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=GopStop; For=%s; %s\n",cfg->name,avplstr);
+ g_free(avplstr);
+ }
+
+ if (cfg->extra) {
+ avplstr = avpl_to_str(cfg->extra);
+ dbg_print (dbg_cfg,0,dbg_facility,"Action=GopExtra; For=%s; %s\n",cfg->name,avplstr);
+ g_free(avplstr);
+ }
+
+ print_xxx_transforms(cfg);
+
+ g_string_free(gopdef,TRUE);
+
+}
+
+static guint8* my_protoname(int proto_id) {
+ if (proto_id) {
+ return proto_registrar_get_abbrev(proto_id);
+ } else {
+ return "*";
+ }
+}
+
+static void print_hfid_hash(gpointer k, gpointer v, gpointer p _U_) {
+ g_string_sprintfa((GString*)p," %s=%s;",(guint8*)v,my_protoname(*(int*)k));
+}
+
+
+static void print_transforms(gpointer k, gpointer v, gpointer p _U_) {
+ AVPL_Transf* t = NULL;
+ guint8* match;
+ guint8* mode;
+ guint8* match_s;
+ guint8* replace_s;
+
+ for (t = v; t; t = t->next) {
+ match_s = avpl_to_str(t->match);
+ replace_s = avpl_to_dotstr(t->replace);
+
+ switch (t->match_mode) {
+ case AVPL_STRICT:
+ match = "Strict";
+ break;
+ case AVPL_LOOSE:
+ match = "Loose";
+ break;
+ case AVPL_EVERY:
+ match = "Every";
+ break;
+ default:
+ match = "None";
+ break;
+ }
+
+ switch (t->replace_mode) {
+ case AVPL_INSERT:
+ mode = "Insert";
+ break;
+ case AVPL_REPLACE:
+ mode = "Replace";
+ break;
+ default:
+ mode = "None";
+ break;
+ }
+
+ dbg_print (dbg,0,dbg_facility,"\tAction=Transform; Name=%s; Match=%s; Mode=%s; %s %s\n",(guint8*) k,match,mode,match_s,replace_s);
+
+ g_free(match_s);
+ g_free(replace_s);
+ }
+}
+
+static void print_pdu_config(mate_cfg_pdu* cfg) {
+ guint i;
+ int hfid;
+ guint8* discard;
+ guint8* stop;
+ GString* s = g_string_new("Action=PduDef; ");
+
+ discard = cfg->discard_pdu_attributes ? "TRUE": "FALSE";
+ stop = cfg->last_to_be_created ? "TRUE" : "FALSE";
+
+ g_string_sprintfa(s, "Name=%s; Proto=%s; DiscartAttribs=%s; Stop=%s; Transport=",
+ cfg->name,my_protoname(cfg->hfid_proto),discard,stop);
+
+ for (i = 0; i < cfg->hfid_ranges->len; i++) {
+ hfid = *((int*) g_ptr_array_index(cfg->hfid_ranges,i));
+ g_string_sprintfa(s,"%s/",my_protoname(hfid));
+ }
+
+ *(s->str + s->len - 1) = ';';
+
+ g_hash_table_foreach(cfg->hfids_attr,print_hfid_hash,s);
+
+ dbg_print(dbg_cfg,0,dbg_facility,"%s",s->str);
+
+ print_xxx_transforms(cfg);
+
+ g_string_free(s,TRUE);
+}
+
+
+
+static void print_gogs_by_gopname(gpointer k, gpointer v, gpointer p _U_) {
+ void* cookie = NULL;
+ guint8* str = NULL;
+ AVPL* avpl;
+
+ while(( avpl = get_next_avpl((LoAL*)v,&cookie) )) {
+ str = avpl_to_str(avpl);
+ dbg_print(dbg_cfg,0,dbg_facility,"Gop=%s; Gog=%s; --> %s\n",(guint8*)k,avpl->name,str);
+ g_free(str);
+ }
+
+}
+
+static void print_gops_by_pduname(gpointer k, gpointer v, gpointer p _U_) {
+ dbg_print(dbg_cfg,0,dbg_facility,
+ "PduName=%s; GopName=%s;\n", (guint8*)k,((mate_cfg_gop*)v)->name);
+}
+
+static void print_config() {
+ guint i;
+
+ /* FIXME: print the settings */
+
+ dbg_print(dbg_cfg,0,dbg_facility,"###########################"
+ " CURRENT CONFIGURATION " "###########################");
+
+ g_hash_table_foreach(matecfg->transfs,print_transforms,NULL);
+
+ for (i=0; i<matecfg->pducfglist->len; i++) {
+ print_pdu_config((mate_cfg_pdu*) g_ptr_array_index(matecfg->pducfglist,i));
+ }
+
+ g_hash_table_foreach(matecfg->gopcfgs,print_gop_config,NULL);
+ g_hash_table_foreach(matecfg->gogcfgs,print_gog_config,NULL);
+
+ dbg_print(dbg_cfg,0,dbg_facility,"###########################"
+ " END OF CURRENT CONFIGURATION " "###########################");
+
+ if (*dbg_cfg > 1) {
+ dbg_print(dbg_cfg,0,dbg_facility,"******* Config Hashes");
+ dbg_print(dbg_cfg,0,dbg_facility,"*** Gops by PduName");
+ g_hash_table_foreach(matecfg->gops_by_pduname,print_gops_by_pduname,NULL);
+ dbg_print(dbg_cfg,0,dbg_facility,"*** GogKeys by GopName");
+ g_hash_table_foreach(matecfg->gogs_by_gopname,print_gogs_by_gopname,NULL);
+ }
+}
+
+
+static void new_attr_hfri(mate_cfg_item* cfg, guint8* name) {
+ int* p_id = g_malloc(sizeof(int));
+
+ hf_register_info hfri = {
+ p_id,
+ {
+ g_strdup_printf("%s",name),
+ g_strdup_printf("mate.%s.%s",cfg->name,name),
+ FT_STRING,BASE_NONE,NULL,0,
+ g_strdup_printf("%s attribute of %s",name,cfg->name),HFILL
+ }};
+
+ *p_id = -1;
+ g_hash_table_insert(cfg->my_hfids,name,p_id);
+ g_array_append_val(matecfg->hfrs,hfri);
+
+}
+
+static void analyze_pdu_hfids(gpointer k, gpointer v, gpointer p) {
+ new_attr_hfri((mate_cfg_pdu*) p,(guint8*) v);
+}
+
+static void analyze_transform_hfrs(mate_cfg_item* cfg) {
+ guint i;
+ void* cookie = NULL;
+ AVPL_Transf* t;
+ AVP* avp;
+
+ for (i=0; i < cfg->transforms->len;i++) {
+ for (t = g_ptr_array_index(cfg->transforms,i); t; t=t->next ) {
+ cookie = NULL;
+ while(( avp = get_next_avp(t->replace,&cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+ }
+ }
+}
+
+static void analyze_pdu_config(mate_cfg_pdu* cfg) {
+ hf_register_info hfri = { NULL, {NULL, NULL, FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}};
+
+ hfri.p_id = &(cfg->hfid);
+ hfri.hfinfo.name = g_strdup_printf("%s",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("PDU of type %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_pdu_rel_time);
+ hfri.hfinfo.name = g_strdup_printf("%s time",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.RelativeTime",cfg->name);
+ hfri.hfinfo.type = FT_FLOAT;
+ hfri.hfinfo.display = BASE_DEC;
+ hfri.hfinfo.blurb = "Seconds passed since the start of the GOP or capture if the PDU is unnassigned";
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ g_hash_table_foreach(cfg->hfids_attr,analyze_pdu_hfids,cfg);
+
+ analyze_transform_hfrs(cfg);
+}
+
+static void analyze_gop_config(gpointer k _U_, gpointer v, gpointer p _U_) {
+ mate_cfg_gop* cfg = v;
+ void* cookie = NULL;
+ AVP* avp;
+ hf_register_info hfri = { NULL, {NULL, NULL, FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}};
+
+ hfri.p_id = &(cfg->hfid);
+ hfri.hfinfo.name = g_strdup_printf("%s",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("GOP of type %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gop_start_time);
+ hfri.hfinfo.name = g_strdup_printf("%s start time",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.StartTime",cfg->name);
+ hfri.hfinfo.type = FT_FLOAT;
+ hfri.hfinfo.display = BASE_DEC;
+ hfri.hfinfo.blurb = g_strdup_printf("Seconds passed since the begining of caputre to the start of this %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gop_stop_time);
+ hfri.hfinfo.name = g_strdup_printf("%s hold time",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.Time",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("Duration in seconds from start to stop of this %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gop_last_time);
+ hfri.hfinfo.name = g_strdup_printf("%s current time",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.Duration",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("Time passed between the start of this %s and the last pdu assigned to it",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gop_num_pdus);
+ hfri.hfinfo.name = g_strdup_printf("%s number of PDUs",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.NumOfPdus",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("Number of PDUs assigned to this %s",cfg->name);
+ hfri.hfinfo.type = FT_UINT32;
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gop_pdu);
+ hfri.hfinfo.name = g_strdup_printf("A PDU of %s",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.Pdu",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("A PDU assigned to this %s",cfg->name);
+ hfri.hfinfo.type = FT_FRAMENUM;
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ while(( avp = get_next_avp(cfg->key,&cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+
+ cookie = NULL;
+ while(( avp = get_next_avp(cfg->start,&cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+
+ cookie = NULL;
+ while(( avp = get_next_avp(cfg->stop,&cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+
+ cookie = NULL;
+ while(( avp = get_next_avp(cfg->extra,&cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+
+ analyze_transform_hfrs(cfg);
+}
+
+
+static void analyze_gog_config(gpointer k _U_, gpointer v, gpointer p _U_) {
+ mate_cfg_gop* cfg = v;
+ void* avp_cookie;
+ void* avpl_cookie;
+ AVP* avp;
+ AVPL* avpl;
+ hf_register_info hfri = { NULL, {NULL, NULL, FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL}};
+
+ hfri.p_id = &(cfg->hfid);
+ hfri.hfinfo.name = g_strdup_printf("%s",cfg->name);
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s",cfg->name);
+ hfri.hfinfo.blurb = g_strdup_printf("GOG of type %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gog_num_of_gops);
+ hfri.hfinfo.name = "number of GOPs";
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.NumOfGops",cfg->name);
+ hfri.hfinfo.type = FT_UINT32;
+ hfri.hfinfo.display = BASE_DEC;
+ hfri.hfinfo.blurb = g_strdup_printf("Number of GOPs assigned to this %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ hfri.p_id = &(cfg->hfid_gog_gop);
+ hfri.hfinfo.name = "a GOP";
+ hfri.hfinfo.abbrev = g_strdup_printf("mate.%s.Gop",cfg->name);
+ hfri.hfinfo.type = FT_STRING;
+ hfri.hfinfo.display = BASE_DEC;
+ hfri.hfinfo.blurb = g_strdup_printf("a GOPs assigned to this %s",cfg->name);
+
+ g_array_append_val(matecfg->hfrs,hfri);
+
+ avpl_cookie = NULL;
+ while (( avpl = get_next_avpl(cfg->keys,&avpl_cookie) )) {
+ avp_cookie = NULL;
+ while (( avp = get_next_avp(avpl,&avp_cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+ }
+
+ avp_cookie = NULL;
+ while (( avp = get_next_avp(cfg->extra,&avp_cookie) )) {
+ if (! g_hash_table_lookup(cfg->my_hfids,avp->n)) {
+ new_attr_hfri(cfg,avp->n);
+ }
+ }
+
+ analyze_transform_hfrs(cfg);
+}
+
+static size_t analyze_config() {
+ guint i;
+
+ for (i=0; i<matecfg->pducfglist->len; i++) {
+ analyze_pdu_config((mate_cfg_pdu*) g_ptr_array_index(matecfg->pducfglist,i));
+ }
+
+ g_hash_table_foreach(matecfg->gopcfgs,analyze_gop_config,matecfg);
+ g_hash_table_foreach(matecfg->gogcfgs,analyze_gog_config,matecfg);
+
+}
+
+static void new_action(guint8* name, config_action* action) {
+ g_hash_table_insert(actions,name,action);
+
+}
+
+static void init_actions() {
+
+ all_keywords = new_avpl("all_keywords");
+ insert_avp(all_keywords,new_avp(KEYWORD_ACTION,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_SETTINGS,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_INCLUDE,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_TRANSFORM,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_PDU,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_PDUCRITERIA,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_PDUEXTRA,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_PDUTRANSFORM,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOPSTART,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOPSTOP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOPEXTRA,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOPTRANSFORM,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOGDEF,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOGKEY,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOGEXTRA,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOGTRANSFORM,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_NAME,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_ON,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_FOR,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_FROM,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_TO,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_MATCH,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_MODE,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_FILENAME,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_PROTO,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_METHOD,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_TRANSPORT,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_METHOD,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_STRICT,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_LOOSE,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_EVERY,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_REPLACE,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_INSERT,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_MAP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_GOGEXPIRE,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DISCARDPDU,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_LIBPATH,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_SHOWPDUTREE,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_SHOWGOPTIMES,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_STOP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DROPPDU,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DROPGOP,"",'='));
+
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_GENERAL,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_CFG,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_PDU,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_GOP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_GOG,"",'='));
+
+#ifdef _AVP_DEBUGGING
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_AVPLIB,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_AVP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_AVP_OP,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_AVPL,"",'='));
+ insert_avp(all_keywords,new_avp(KEYWORD_DBG_AVPL_OP,"",'='));
+#endif
+
+ if (actions) {
+ g_hash_table_destroy(actions);
+ }
+
+ actions = g_hash_table_new(g_str_hash,g_str_equal);
+
+ new_action(KEYWORD_SETTINGS,config_settings);
+ new_action(KEYWORD_PDU,config_pdu);
+ new_action(KEYWORD_PDUEXTRA,config_pduextra);
+ /* new_action(KEYWORD_PDUCRITERIA,config_pdu); */
+ new_action(KEYWORD_GOP,config_gop);
+ new_action(KEYWORD_GOGDEF,config_gog);
+ new_action(KEYWORD_GOGKEY,config_gogkey);
+ new_action(KEYWORD_GOPSTART,config_start);
+ new_action(KEYWORD_GOPSTOP,config_stop);
+ new_action(KEYWORD_GOPEXTRA,config_gopextra);
+ new_action(KEYWORD_GOGEXTRA,config_gogextra);
+ new_action(KEYWORD_INCLUDE,config_include);
+ new_action(KEYWORD_TRANSFORM,config_transform);
+ new_action(KEYWORD_PDUTRANSFORM,config_pdu_transform);
+ new_action(KEYWORD_GOPTRANSFORM,config_gop_transform);
+ new_action(KEYWORD_GOGTRANSFORM,config_gog_transform);
+
+}
+
+void reset_cfg(gpointer k _U_, gpointer v, gpointer p _U_) {
+ mate_cfg_item* c = v;
+ c->last_id = 0;
+}
+
+extern mate_config* mate_cfg() {
+
+ g_hash_table_foreach(matecfg->pducfgs,reset_cfg,NULL);
+ g_hash_table_foreach(matecfg->gopcfgs,reset_cfg,NULL);
+ g_hash_table_foreach(matecfg->gogcfgs,reset_cfg,NULL);
+
+ return matecfg;
+}
+
+extern mate_config* mate_make_config(guint8* filename) {
+
+ avp_init();
+ init_actions();
+
+ matecfg = g_malloc(sizeof(mate_config));
+
+ matecfg->gog_expiration = DEFAULT_GOG_EXPIRATION;
+ matecfg->discard_pdu_attributes = FALSE;
+ matecfg->drop_pdu = FALSE;
+ matecfg->drop_gop = FALSE;
+ matecfg->show_pdu_tree = TRUE;
+ matecfg->show_gop_times = TRUE;
+ matecfg->last_to_be_created = FALSE;
+ matecfg->match_mode = AVPL_STRICT;
+ matecfg->replace_mode = AVPL_INSERT;
+ matecfg->mate_lib_path = g_strdup_printf("%s%c%s",get_datafile_dir(),DIR_SEP,DEFAULT_MATE_LIB_PATH);
+ matecfg->mate_config_file = g_strdup(filename);
+ matecfg->mate_attrs_filter = g_string_new("");
+ matecfg->mate_protos_filter = g_string_new("");
+ matecfg->dbg_facility = NULL;
+ matecfg->dbg_lvl = 0;
+ matecfg->dbg_cfg_lvl = 0;
+ matecfg->dbg_pdu_lvl = 0;
+ matecfg->dbg_gop_lvl = 0;
+ matecfg->dbg_gog_lvl = 0;
+ matecfg->pducfglist = g_ptr_array_new();
+ matecfg->pducfgs = g_hash_table_new(g_str_hash,g_str_equal);
+ matecfg->gopcfgs = g_hash_table_new(g_str_hash,g_str_equal);
+ matecfg->gogcfgs = g_hash_table_new(g_str_hash,g_str_equal);
+ matecfg->transfs = g_hash_table_new(g_str_hash,g_str_equal);
+ matecfg->gops_by_pduname = g_hash_table_new(g_str_hash,g_str_equal);
+ matecfg->gogs_by_gopname = g_hash_table_new(g_str_hash,g_str_equal);
+
+ matecfg->hfrs = g_array_new(FALSE,TRUE,sizeof(hf_register_info));
+
+ dbg = &matecfg->dbg_lvl;
+
+ if ( mate_load_config(filename) ) {
+ analyze_config();
+ dbg_print (dbg_cfg,3,dbg_facility,"mate_make_config: OK");
+ if (dbg_cfg_lvl > 0) print_config();
+ } else {
+ if (matecfg) destroy_mate_config(matecfg,FALSE);
+ matecfg = NULL;
+ return NULL;
+ }
+
+ if (matecfg->mate_attrs_filter->len > 1) {
+ g_string_erase(matecfg->mate_attrs_filter,0,2);
+ g_string_erase(matecfg->mate_protos_filter,0,2);
+ } else {
+ mate_config_error(NULL,NULL,"mate: Failed: nothing left to tap on");
+ if (matecfg) destroy_mate_config(matecfg,FALSE);
+ matecfg = NULL;
+ return NULL;
+ }
+
+ matecfg->tap_filter = g_strdup_printf("(%s) && (%s)",matecfg->mate_protos_filter->str,matecfg->mate_attrs_filter->str);
+
+ return matecfg;
+}
+
diff --git a/plugins/mate/mate_util.c b/plugins/mate/mate_util.c
new file mode 100644
index 0000000000..953f3fbc9a
--- /dev/null
+++ b/plugins/mate/mate_util.c
@@ -0,0 +1,1861 @@
+/* mate_util.c
+* MATE -- Meta Analysis Tracing Engine
+* Utility Library: Single Copy Strings and Attribute Value Pairs
+*
+* Copyright 2004, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id$
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* 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.
+*/
+
+#include "config.h"
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include "mate.h"
+#include "mate_util.h"
+
+/* TODO:
++ fix debug_print levels
++ chunks for scs_strings (do I realy need em??)
+ + checking bounds in (almost) every operator
+- operators
+ + rethink '&' operator
+ - bounds check on op_match()
+ ? change &{} into []
+ ? add {xxx} to get avps named xxxx from the src avpl
+ ? add (yyy) to do aaa+31 or and similar stuff
+ - add perlre operator?
+ - transform
+ + map (N->M hash)
+*/
+
+
+/***************************************************************************
+* dbg_print
+***************************************************************************
+* This is the debug facility of the thing.
+***************************************************************************/
+
+/* dbg_print:
+ * which: a pointer to the current level of debugging for a feature
+ * how: the level over which this message should be printed out
+ * where: the file on which to print (g_message if null)
+ * fmt, ...: what to print
+ */
+
+void dbg_print(const guint* which, guint how, FILE* where, guint8* fmt, ... ) {
+ static guint8 debug_buffer[DEBUG_BUFFER_SIZE];
+ va_list list;
+
+ if ( ! which || *which < how ) return;
+
+ va_start( list, fmt );
+ g_vsnprintf(debug_buffer,DEBUG_BUFFER_SIZE,fmt,list);
+ va_end( list );
+
+ if (! where) {
+ g_message(debug_buffer);
+ } else {
+ fputs(debug_buffer,where);
+ }
+
+}
+
+
+/***************************************************************************
+ * single copy strings
+ ***************************************************************************
+ * In order to save memory and since strings repeat more often than don't,
+ * we'll keep only one copy of each as key to a hash with a count of
+ * subscribers as value.
+ ***************************************************************************/
+/* FIXME: use hash fom glib 1.X not 2.X */
+
+/**
+ * scs_init:
+ * @collection: the scs hash
+ *
+ * Initializes the scs hash.
+ **/
+
+void scs_init(GHashTable** hash) {
+ /* key: a string
+ value: guint number of subscribers */
+
+ if (*hash) g_hash_table_destroy(*hash);
+
+ *hash = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
+
+}
+
+
+/**
+ * subscribe:
+ * @collection: the scs hash
+ * @s: a string
+ *
+ * Checks if the given string exists already and if so it increases the count of
+ * subsscribers and returns a pointer to the stored string. If not It will copy
+ * the given string store it in the hash and return the pointer to the copy.
+ * Remember, containment is handled internally, take care of your own strings.
+ *
+ * Return value: a pointer to the subscribed string.
+ **/
+guint8* scs_subscribe(GHashTable* collection, guint8* s) {
+ guint8* ok = NULL;
+ guint* ip = NULL;
+
+ g_hash_table_lookup_extended(collection,s,(gpointer*)&ok,(gpointer*)&ip);
+
+ if (ip) {
+ (*ip)++;
+ s = ok;
+ } else {
+ ip = g_malloc(sizeof(int));
+ *ip = 0;
+ s = g_strdup(s);
+ g_hash_table_insert(collection,s,ip);
+ }
+
+ return s;
+}
+
+/**
+ * unsubscribe:
+ * @collection: the scs hash
+ * @s: a string.
+ *
+ * decreases the count of subscribers, if zero frees the internal copy of
+ * the string.
+ **/
+void scs_unsubscribe(GHashTable* collection, guint8* s) {
+ guint8* ok = NULL;
+ guint* ip = NULL;
+
+ g_hash_table_lookup_extended(collection,s,(gpointer*)&ok,(gpointer*)&ip);
+
+ if (ip) {
+ if (*ip == 0) g_hash_table_remove(collection,ok);
+ else (*ip)--;
+ } else {
+ g_warning("unsusbcribe: already deleted: '%s'?",s);
+ }
+}
+
+/**
+ * scs_subscribe_printf:
+ * @fmt: a format string ...
+ *
+ * Formats the input and subscribes it.
+ *
+ * Return value: the stored copy of the formated string.
+ *
+ **/
+extern guint8* scs_subscribe_printf(GHashTable* collection, guint8* fmt, ...) {
+ va_list list;
+ guint8* ok = NULL;
+ guint8* s = NULL;
+ guint* ip = NULL;
+
+ va_start( list, fmt );
+ s = g_strdup_vprintf(fmt, list);
+ va_end( list );
+
+ g_hash_table_lookup_extended(collection,s,(gpointer*)&ok,(gpointer*)&ip);
+
+ if (ip) {
+ (*ip)++;
+ g_free(s);
+ s = ok;
+ } else {
+ ip = g_malloc0(sizeof(int));
+ *ip = 0;
+ g_hash_table_insert(collection,s,ip);
+ }
+
+ return s;
+}
+
+
+/***************************************************************************
+* AVPs & Co.
+***************************************************************************
+* The Thing operates mainly on avps, avpls and loals
+* - attribute value pairs (two strings: the name and the value and an opeartor)
+* - avp lists a somehow sorted list of avps
+* - loal (list of avp lists) an arbitrarily sorted list of avpls
+*
+*
+***************************************************************************/
+
+
+typedef union _any_avp_type {
+ AVP avp;
+ AVPN avpn;
+ AVPL avpl;
+ LoAL loal;
+ LoALnode loaln;
+} any_avp_type;
+
+
+static GMemChunk* avp_chunk = NULL;
+static GHashTable* avp_strings = NULL;
+
+#ifdef _AVP_DEBUGGING
+static FILE* dbg_fp = NULL;
+
+static int dbg_level = 0;
+static int* dbg = &dbg_level;
+
+static int dbg_avp_level = 0;
+static int* dbg_avp = &dbg_avp_level;
+
+static int dbg_avp_op_level = 0;
+static int* dbg_avp_op = &dbg_avp_op_level;
+
+static int dbg_avpl_level = 0;
+static int* dbg_avpl = &dbg_avpl_level;
+
+static int dbg_avpl_op_level = 0;
+static int* dbg_avpl_op = &dbg_avpl_op_level;
+
+/**
+ * setup_avp_debug:
+ * @fp: the file in which to send debugging output.
+ * @general: a pointer to the level of debugging of facility "general"
+ * @avp: a pointer to the level of debugging of facility "avp"
+ * @avp_op: a pointer to the level of debugging of facility "avp_op"
+ * @avpl: a pointer to the level of debugging of facility "avpl"
+ * @avpl_op: a pointer to the level of debugging of facility "avpl_op"
+ *
+ * (If enabled set's up the debug facilities for the avp library.
+ *
+ **/
+extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op) {
+ dbg_fp = fp;
+ dbg = general;
+ dbg_avp = avp;
+ dbg_avp_op = avp_op;
+ dbg_avpl = avpl;
+ dbg_avpl_op = avpl_op;
+}
+
+#endif /* _AVP_DEBUGGING */
+
+/**
+ * avp_init:
+ * @chunk_size: the initial chunk's size.
+ *
+ * (Re)Initializes the avp library.
+ *
+ **/
+extern void avp_init(void) {
+
+ scs_init(&avp_strings);
+
+
+ if ( avp_chunk ) {
+ g_mem_chunk_destroy(avp_chunk);
+ }
+
+ avp_chunk = g_mem_chunk_new("avp_chunk", sizeof(any_avp_type),
+ AVP_CHUNK_SIZE, G_ALLOC_AND_FREE);
+
+}
+
+
+/**
+ * new_avp_from_finfo:
+ * @name: the name the avp will have.
+ * @finfo: the field_info from which to fetch the data.
+ *
+ * Creates an avp from a field_info record.
+ *
+ * Return value: a pointer to the newly created avp.
+ *
+ **/
+extern AVP* new_avp_from_finfo(guint8* name, field_info* finfo) {
+ AVP* new = g_mem_chunk_alloc(avp_chunk);
+ guint8* value;
+ guint8* str;
+ new->n = scs_subscribe(avp_strings, name);
+
+ if (finfo->value.ftype->get_value_integer) {
+ value = scs_subscribe_printf(avp_strings, "%i",fvalue_get_integer(&finfo->value));
+#ifdef _AVP_DEBUGGING
+ dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from integer: %s",value);
+#endif
+ } else if (finfo->value.ftype->val_to_string_repr) {
+ str = fvalue_to_string_repr(&finfo->value,FTREPR_DISPLAY,NULL);
+ value = scs_subscribe(avp_strings, str);
+#ifdef _AVP_DEBUGGING
+ dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from string: %s",value);
+#endif
+ } else if (finfo->value.ftype->get_value_floating) {
+ value = scs_subscribe_printf(avp_strings, "%f",fvalue_get_floating(&finfo->value));
+#ifdef _AVP_DEBUGGING
+ dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: from float: %s",value);
+#endif
+ } else {
+#ifdef _AVP_DEBUGGING
+ dbg_print (dbg_avp,2,dbg_fp,"new_avp_from_finfo: a proto: %s",finfo->hfinfo->abbrev);
+#endif
+ value = scs_subscribe(avp_strings, finfo->hfinfo->abbrev);
+ }
+
+ new->v = value;
+
+ new->o = '=';
+
+#ifdef _AVP_DEBUGGING
+ dbg_print (dbg_avp,1,dbg_fp,"new_avp_from_finfo: %X %s%c%s;",(guint32) new,new->n,new->o,new->v);
+#endif
+
+ return new;
+}
+
+
+/**
+ * new_avp:
+ * @name: the name the avp will have.
+ * @value: the value the avp will have.
+ * @o: the operator of this avp.
+ *
+ * Creates an avp given every parameter.
+ *
+ * Return value: a pointer to the newly created avp.
+ *
+ **/
+extern AVP* new_avp(guint8* name, guint8* value, guint8 o) {
+ AVP* new = g_mem_chunk_alloc(avp_chunk);
+
+ new->n = scs_subscribe(avp_strings, name);
+ new->v = scs_subscribe(avp_strings, value);
+ new->o = o;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avp,1,dbg_fp,"new_avp: %X %s%c%s;",(guint32) new,new->n,new->o,new->v);
+#endif
+ return new;
+}
+
+
+/**
+* delete_avp:
+ * @avp: the avp to delete.
+ *
+ * Destroys an avp and releases the resources it uses.
+ *
+ **/
+extern void delete_avp(AVP* avp) {
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avp,1,dbg_fp,"delete_avp: %X %s%c%s;",(guint32) avp,avp->n,avp->o,avp->v);
+#endif
+
+ scs_unsubscribe(avp_strings, avp->n);
+ scs_unsubscribe(avp_strings, avp->v);
+ g_mem_chunk_free(avp_chunk,avp);
+}
+
+
+/**
+* avp_copy:
+ * @from: the avp to be copied.
+ *
+ * Creates an avp whose name op and value are copyes of the given one.
+ *
+ * Return value: a pointer to the newly created avp.
+ *
+ **/
+extern AVP* avp_copy(AVP* from) {
+ AVP* new = g_mem_chunk_alloc(avp_chunk);
+
+ new->n = scs_subscribe(avp_strings, from->n);
+ new->v = scs_subscribe(avp_strings, from->v);
+ new->o = from->o;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avp,1,dbg_fp,"copy_avp: %X %s%c%s;",(guint32) new,new->n,new->o,new->v);
+#endif
+
+ return new;
+}
+
+
+extern void rename_avp(AVP* avp, guint8* name) {
+ guint8* s = avp->n;
+ avp->n = scs_subscribe(avp_strings,name);
+ scs_unsubscribe(avp_strings,s);
+}
+
+/**
+ * new_avpl:
+ * @name: the name the avpl will have.
+ *
+ * Creates an empty avpl.
+ *
+ * Return value: a pointer to the newly created avpl.
+ *
+ **/
+extern AVPL* new_avpl(guint8* name) {
+ AVPL* new_avpl = g_mem_chunk_alloc(avp_chunk);
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpl: %X name=%s",new_avpl,name);
+#endif
+
+ new_avpl->name = scs_subscribe(avp_strings, name);
+ new_avpl->len = 0;
+ new_avpl->null.avp = NULL;
+ new_avpl->null.next = &new_avpl->null;
+ new_avpl->null.prev = &new_avpl->null;
+
+
+ return new_avpl;
+}
+
+extern void rename_avpl(AVPL* avpl, guint8* name) {
+ scs_unsubscribe(avp_strings,avpl->name);
+ avpl->name = scs_subscribe(avp_strings,name);
+}
+
+/**
+ * insert_avp:
+ * @avpl: the avpl in which to insert.
+ * @avp: the avp to be inserted.
+ *
+ * Inserts the given AVP into the given AVPL if an identical one isn't yet there.
+ *
+ * Return value: whether it was inserted or not.
+ *
+ * BEWARE: Check the return value, you might need to delete the avp if
+ * it is not inserted.
+ **/
+extern gboolean insert_avp(AVPL* avpl, AVP* avp) {
+ AVPN* new = g_mem_chunk_alloc(avp_chunk);
+ AVPN* c;
+
+ new->avp = avp;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,7,dbg_fp,"new_avpn: %X",new);
+ dbg_print(dbg_avpl_op,4,dbg_fp,"insert_avp: %X %X %s%c%s;",avpl,avp,avp->n,avp->o,avp->v);
+#endif
+
+ /* get to the insertion point */
+ for(c=avpl->null.next; c->avp; c = c->next) {
+
+ if ( avp->n == c->avp->n ) {
+
+ if (avp->v > c->avp->v) {
+ break;
+ }
+
+ if (avp->v == c->avp->v) {
+ if (avp->o == AVP_OP_EQUAL) {
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,7,dbg_fp,"delete_avpn: %X",new);
+#endif
+ g_mem_chunk_free(avp_chunk,new);
+ return FALSE;
+ }
+ }
+ }
+
+ if (avp->n > c->avp->n) {
+ break;
+ }
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl,5,dbg_fp,"insert_avp: inserting %X in %X before %X;",avp,avpl,c);
+#endif
+
+ new->next = c;
+ new->prev = c->prev;
+ c->prev->next = new;
+ c->prev = new;
+
+ avpl->len++;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
+#endif
+
+ return TRUE;
+}
+
+/**
+ * get_avp_by_name:
+ * @avpl: the avpl from which to try to get the avp.
+ * @name: the name of the avp we are looking for.
+ * @cookie: variable in which to store the state between calls.
+ *
+ * Gets pointer to the next avp whose name is given; uses cookie to store its
+ * state between calls.
+ *
+ * Return value: a pointer to the next matching avp if there's one, else NULL.
+ *
+ **/
+extern AVP* get_avp_by_name(AVPL* avpl, guint8* name, void** cookie) {
+ AVPN* curr;
+ AVPN* start = (AVPN*) *cookie;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,7,dbg_fp,"get_avp_by_name: entering: %X %s %X",avpl,name,*cookie);
+#endif
+
+ name = scs_subscribe(avp_strings, name);
+
+ if (!start) start = avpl->null.next;
+
+ for ( curr = start; curr->avp; curr = curr->next ) {
+ if ( curr->avp->n == name ) {
+ break;
+ }
+ }
+
+ *cookie = curr;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,5,dbg_fp,"get_avp_by_name: got avp: %X",curr);
+#endif
+
+ scs_unsubscribe(avp_strings, name);
+
+ return curr->avp;
+}
+
+/**
+ * extract_avp_by_name:
+ * @avpl: the avpl from which to try to extract the avp.
+ * @name: the name of the avp we are looking for.
+ *
+ * Extracts from the avpl the next avp whose name is given;
+ *
+ * Return value: a pointer to extracted avp if there's one, else NULL.
+ *
+ **/
+extern AVP* extract_avp_by_name(AVPL* avpl, guint8* name) {
+ AVPN* curr;
+ AVP* avp = NULL;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,7,dbg_fp,"extract_avp_by_name: entering: %X %s",avpl,name);
+#endif
+
+ name = scs_subscribe(avp_strings, name);
+
+ for ( curr = avpl->null.next; curr->avp; curr = curr->next ) {
+ if ( curr->avp->n == name ) {
+ break;
+ }
+ }
+
+ scs_unsubscribe(avp_strings, name);
+
+ if( ! curr->avp ) return NULL;
+
+ curr->next->prev = curr->prev;
+ curr->prev->next = curr->next;
+
+ avp = curr->avp;
+
+ g_mem_chunk_free(avp_chunk,curr);
+
+ (avpl->len)--;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
+#endif
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,5,dbg_fp,"extract_avp_by_name: got avp: %X",avp);
+#endif
+
+ return avp;
+}
+
+
+/**
+ * extract_first_avp:
+ * @avpl: the avpl from which to try to extract the avp.
+ *
+ * Extracts the fisrt avp from the avpl.
+ *
+ * Return value: a pointer to extracted avp if there's one, else NULL.
+ *
+ **/
+extern AVP* extract_first_avp(AVPL* avpl) {
+ AVP* avp;
+ AVPN* node;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,7,dbg_fp,"extract_first_avp: %X",avpl);
+#endif
+
+ node = avpl->null.next;
+
+ avpl->null.next->prev = &avpl->null;
+ avpl->null.next = node->next;
+
+ avp = node->avp;
+
+ if (avp) {
+ g_mem_chunk_free(avp_chunk,node);
+ (avpl->len)--;
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
+#endif
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,5,dbg_fp,"extract_first_avp: got avp: %X",avp);
+#endif
+
+ return avp;
+
+}
+
+
+/**
+ * extract_last_avp:
+ * @avpl: the avpl from which to try to extract the avp.
+ *
+ * Extracts the last avp from the avpl.
+ *
+ * Return value: a pointer to extracted avp if there's one, else NULL.
+ *
+ **/
+extern AVP* extract_last_avp(AVPL* avpl) {
+ AVP* avp;
+ AVPN* node;
+
+ node = avpl->null.prev;
+
+ avpl->null.prev->next = &avpl->null;
+ avpl->null.prev = node->prev;
+
+ avp = node->avp;
+
+ if (avp) {
+ g_mem_chunk_free(avp_chunk,node);
+ (avpl->len)--;
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl,4,dbg_fp,"avpl: %X new len: %i",avpl,avpl->len);
+#endif
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %X",avp);
+#endif
+
+ return avp;
+
+}
+
+
+/**
+ * delete_avpl:
+ * @avpl: the avpl from which to try to extract the avp.
+ * @avps_too: whether or not it should delete the avps as well.
+ *
+ * Destroys an avpl and releases the resources it uses. If told to do
+ * so releases the avps as well.
+ *
+ **/
+extern void delete_avpl(AVPL* avpl, gboolean avps_too) {
+ AVP* avp;
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl,3,dbg_fp,"delete_avpl: %X",avpl);
+#endif
+
+ while(( avp = extract_last_avp(avpl))) {
+ if (avps_too) {
+ delete_avp(avp);
+ }
+ }
+
+ scs_unsubscribe(avp_strings,avpl->name);
+ g_mem_chunk_free(avp_chunk,avpl);
+}
+
+
+
+/**
+ * get_next_avp:
+ * @avpl: the avpl from which to try to get the avps.
+ * @cookie: variable in which to store the state between calls.
+ *
+ * Iterates on an avpl to get its avps.
+ *
+ * Return value: a pointer to the next avp if there's one, else NULL.
+ *
+ **/
+extern AVP* get_next_avp(AVPL* avpl, void** cookie) {
+ AVPN* node;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,5,dbg_fp,"get_next_avp: avpl: %X avpn: %X",avpl,*cookie);
+#endif
+
+ if (*cookie) {
+ node = (AVPN*) *cookie;
+ } else {
+ node = avpl->null.next;
+ }
+
+ *cookie = node->next;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,5,dbg_fp,"extract_last_avp: got avp: %X",node->avp);
+#endif
+
+ return node->avp;
+}
+
+/**
+ * avpl_to_str:
+ * @avpl: the avpl to represent.
+ *
+ * Creates a newly allocated string containing a representation of an avpl.
+ *
+ * Return value: a pointer to the newly allocated string.
+ *
+ **/
+guint8* avpl_to_str(AVPL* avpl) {
+ AVPN* c;
+ GString* s = g_string_new("");
+ guint8* avp_s;
+ guint8* r;
+
+ for(c=avpl->null.next; c->avp; c = c->next) {
+ avp_s = avp_to_str(c->avp);
+ g_string_sprintfa(s," %s;",avp_s);
+ g_free(avp_s);
+ }
+
+ r = s->str;
+ g_string_free(s,FALSE);
+
+ /* g_strchug(r); ? */
+ return r;
+}
+
+extern guint8* avpl_to_dotstr(AVPL* avpl) {
+ AVPN* c;
+ GString* s = g_string_new("");
+ guint8* avp_s;
+ guint8* r;
+
+ for(c=avpl->null.next; c->avp; c = c->next) {
+ avp_s = avp_to_str(c->avp);
+ g_string_sprintfa(s," .%s;",avp_s);
+ g_free(avp_s);
+ }
+
+ r = s->str;
+ g_string_free(s,FALSE);
+
+ /* g_strchug(r); ? */
+ return r;
+}
+
+/**
+* merge_avpl:
+ * @dst: the avpl in which to merge the avps.
+ * @src: the avpl from which to get the avps.
+ * @copy: whether avps should be copied instead of referenced.
+ *
+ * Adds the avps of src that are not existent in dst into dst.
+ *
+ * Return value: a pointer to the newly allocated string.
+ *
+ **/
+extern void merge_avpl(AVPL* dst, AVPL* src, gboolean copy_avps) {
+ AVPN* cd = NULL;
+ AVPN* cs = NULL;
+ gint c;
+ AVP* copy;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"merge_avpl: %X %X",dst,src);
+#endif
+
+ cs = src->null.next;
+ cd = dst->null.next;
+
+ while(cs->avp) {
+
+ if(cd->avp) {
+ c = (guint) cd->avp->n - (guint) cs->avp->n;
+ } else {
+ c = -1;
+ }
+
+ if (c > 0) {
+ if (cd->avp) cd = cd->next;
+ } else if (c < 0) {
+ if (copy_avps) {
+ copy = avp_copy(cs->avp);
+ if ( ! insert_avp(dst,copy) ) {
+ delete_avp(copy);
+ }
+ } else {
+ insert_avp(dst,cs->avp);
+ }
+
+ cs = cs->next;
+ } else {
+ if ( ! cd->avp || ! (cd->avp->v == cs->avp->v) ) {
+ if (copy_avps) {
+ copy = avp_copy(cs->avp);
+ if ( ! insert_avp(dst,copy) ) {
+ delete_avp(copy);
+ }
+ } else {
+ insert_avp(dst,cs->avp);
+ }
+ }
+ cs = cs->next;
+ if (cd->avp) cd = cd->next;
+ }
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,8,dbg_fp,"merge_avpl: done");
+#endif
+
+ return;
+}
+
+
+/**
+ * merge_avpl:
+ * @name: the name of the new avpl.
+ * @avpl: the avpl from which to get the avps.
+ * @copy_avps: whether avps should be copied instead of referenced.
+ *
+ * Creates a new avpl containing the same avps as the given avpl
+ * It will either reference or copie the avps.
+ *
+ * Return value: a pointer to the newly allocated string.
+ *
+ **/
+extern AVPL* new_avpl_from_avpl(guint8* name, AVPL* avpl, gboolean copy_avps) {
+ AVPL* newavpl = new_avpl(name);
+ void* cookie = NULL;
+ AVP* avp;
+ AVP* copy;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_from_avpl: %X from=%X name='%s'",newavpl,avpl,name);
+#endif
+
+ while(( avp = get_next_avp(avpl,&cookie) )) {
+ if (copy_avps) {
+ copy = avp_copy(avp);
+ if ( ! insert_avp(newavpl,copy) ) {
+ delete_avp(copy);
+ }
+ } else {
+ insert_avp(newavpl,avp);
+ }
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,8,dbg_fp,"new_avpl_from_avpl: done");
+#endif
+
+ return newavpl;
+}
+
+
+#define TRANS_NUM '-': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0'
+
+/* BROKEN, makes no sense right now */
+/* FIXME: Use subscribe/unsubscribe */
+static AVP* avp_transform(AVP* src, AVP* op) {
+ unsigned int i;
+ guint8 c;
+
+ GString* replace_str = NULL;
+ GString* num_str = NULL;
+ GString* return_str = NULL;
+ guint8* v;
+ long num = 0;
+
+ enum _tranf_state {
+ START,
+ IN_NUM,
+ IN_REPLACE,
+ END
+ } state;
+
+ state = START;
+
+ for(i = 0; i < strlen(op->v); i++) {
+ c= op->v[i];
+
+ if (state == END) break;
+
+ switch(state) {
+ case START:
+ switch(c) {
+ case '{':
+ num_str = g_string_new("");
+ state = IN_NUM;
+ continue;
+ default:
+ continue;
+ };
+ case IN_NUM:
+ switch(c) {
+ case TRANS_NUM:
+ g_string_append_c(num_str,c);
+ continue;
+ case ':':
+ num = strtol(num_str->str,NULL,10);
+ g_string_free(num_str,TRUE);
+ replace_str = g_string_new("");
+ state = IN_REPLACE;
+ continue;
+ default:
+ /* will ignore any char that is not a number */
+ continue;
+ };
+ case IN_REPLACE:
+ switch(c) {
+ case '\\':
+ continue;
+ case '}':
+ state = END;
+ continue;
+ default :
+ g_string_append_c(replace_str,c);
+ continue;
+ }
+ case END:
+ /* it will never reach */
+ continue;
+ }
+
+ }
+
+ v = src->v;
+
+ if (num > 0) {
+ return_str = g_string_new(v);
+ g_string_erase(return_str,0,num);
+ g_string_prepend(return_str,replace_str->str);
+ } else if (num < 0) {
+ return_str = g_string_new(v);
+ g_string_truncate(return_str,return_str->len+num);
+ g_string_append(return_str,replace_str->str);
+
+ } else {
+ return_str = g_string_new(replace_str->str);
+ }
+
+ g_mem_chunk_free(avp_chunk,v);
+ g_string_free(replace_str,TRUE);
+
+ src->o = '=';
+ src->v = return_str->str;
+ g_string_free(return_str,FALSE);
+
+ return src;
+}
+
+
+
+/**
+* match_avp:
+ * @src: an src to be compared agains an "op" avp
+ * @op: the "op" avp that will be matched against the src avp
+ *
+ * Checks whether or not two avp's match.
+ *
+ * Return value: a pointer to the src avp if there's a match.
+ *
+ **/
+extern AVP* match_avp(AVP* src, AVP* op) {
+ gchar** splited;
+ int i;
+ gchar* p;
+ guint ls;
+ guint lo;
+ float fs = 0.0;
+ float fo = 0.0;
+ gboolean lower = FALSE;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"match_avp: %s%c%s; vs. %s%c%s;",src->n,src->o,src->v,op->n,op->o,op->v);
+#endif
+
+ if ( src->n != op->n ) {
+ return NULL;
+ }
+
+ switch (op->o) {
+ case AVP_OP_EXISTS:
+ return src;
+ case AVP_OP_EQUAL:
+ return src->v == op->v ? src : NULL;
+ case AVP_OP_NOTEQUAL:
+ return !( src->v == op->v) ? src : NULL;
+ case AVP_OP_STARTS:
+ return strncmp(src->v,op->v,strlen(op->v)) == 0 ? src : NULL;
+ case AVP_OP_ONEOFF:
+ splited = g_strsplit(op->v,"|",0);
+ if (splited) {
+ for (i=0;splited[i];i++) {
+ if(g_str_equal(splited[i],src->v)) {
+ g_strfreev(splited);
+ return src;
+ }
+ }
+ g_strfreev(splited);
+ }
+ return NULL;
+
+ case AVP_OP_LOWER:
+ lower = TRUE;
+ case AVP_OP_HIGHER:
+
+ fs = strtof(src->v, NULL);
+ fo = strtof(src->v, NULL);
+
+ if (lower) {
+ if (fs<fo) return src;
+ else return NULL;
+ } else {
+ if (fs>fo) return src;
+ else return NULL;
+ }
+ case AVP_OP_ENDS:
+ /* does this work? */
+ ls = strlen(src->v);
+ lo = strlen(op->v);
+
+ if ( ls < lo ) {
+ return NULL;
+ } else {
+ p = src->v + ( ls - lo );
+ return g_str_equal(p,op->v) ? src : NULL;
+ }
+
+ /* case AVP_OP_TRANSF: */
+ /* return do_transform(src,op); */
+ case AVP_OP_CONTAINS:
+ /* TODO */
+ return NULL;
+ }
+ /* will never get here */
+ return NULL;
+}
+
+
+
+/* TODO: rename me */
+/**
+ * new_avpl_loose_match:
+ * @name: the name of the resulting avpl
+ * @src: avpl to be matched agains an "op" avpl
+ * @op: the "op" avpl that will be matched against the src avpl
+ * @copy_avps: whether the avps in the resulting avpl should be copied
+ *
+ * creates an avp list containing any avps in src matching any avps in op
+ * it will eventually create an empty list in none match
+ *
+ * Return value: a pointer to the newly created avpl containing the
+ * matching avps.
+ **/
+extern AVPL* new_avpl_loose_match(guint8* name,
+ AVPL* src,
+ AVPL* op,
+ gboolean copy_avps) {
+
+ AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name));
+ AVPN* co = NULL;
+ AVPN* cs = NULL;
+ gint c;
+ AVP* m;
+ AVP* copy;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_loose_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
+#endif
+
+
+ cs = src->null.next;
+ co = op->null.next;
+ while(1) {
+
+ if (!co->avp) {
+ return newavpl;
+ }
+
+ if (!cs->avp) {
+ return newavpl;
+ }
+
+
+ c = (guint) co->avp->n - (guint) cs->avp->n;
+
+ if ( c > 0 ) {
+ if (co->avp) co = co->next;
+ } else if (c < 0) {
+ if (cs->avp) cs = cs->next;
+ } else {
+ m = match_avp(cs->avp,co->avp);
+ if(m) {
+
+ if (copy_avps) {
+ copy = avp_copy(m);
+ if ( ! insert_avp(newavpl,copy) ) {
+ delete_avp(copy);
+ }
+ } else {
+ insert_avp(newavpl,m);
+ }
+
+
+ }
+
+ if (cs->avp) cs = cs->next;
+
+ }
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,6,dbg_fp,"new_avpl_loose_match: done!");
+#endif
+
+ return NULL;
+}
+
+/* TODO: rename me */
+/**
+* new_avpl_every_match:
+ * @name: the name of the resulting avpl
+ * @src: avpl to be matched agains an "op" avpl
+ * @op: the "op" avpl that will be matched against the src avpl
+ * @copy_avps: whether the avps in the resulting avpl should be copied
+ *
+ * creates an avp list containing any avps in src matching every avp in op
+ * it will not create a list if there is not a match for every attribute in op
+ *
+ * Return value: a pointer to the newly created avpl containing the
+ * matching avps.
+ **/
+extern AVPL* new_avpl_every_match(guint8* name, AVPL* src, AVPL* op, gboolean copy_avps) {
+ AVPL* newavpl = new_avpl(scs_subscribe(avp_strings, name));
+ AVPN* co = NULL;
+ AVPN* cs = NULL;
+ gint c;
+ AVP* m;
+ AVP* copy;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_every_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
+#endif
+
+ gboolean matches = TRUE;
+
+ cs = src->null.next;
+ co = op->null.next;
+ while(1) {
+
+ if (!co->avp) {
+ break;
+ }
+
+ if (!cs->avp) {
+ break;
+ }
+
+ c = (guint) co->avp->n - (guint) cs->avp->n;
+
+ if ( c > 0 ) {
+ delete_avpl(newavpl,TRUE);
+ return NULL;
+ } else if (c < 0) {
+ cs = cs->next;
+ if (! cs->avp ) {
+ break;
+ }
+ } else {
+ m = match_avp(cs->avp,co->avp);
+
+ if(m) {
+ matches++;
+ cs = cs->next;
+ co = co->next;
+
+ if (copy_avps) {
+ copy = avp_copy(m);
+ if ( ! insert_avp(newavpl,copy) ) {
+ delete_avp(copy);
+ }
+ } else {
+ insert_avp(newavpl,m);
+ }
+
+ } else {
+ cs = cs->next;
+ }
+ }
+
+ }
+
+ if (matches) {
+ return newavpl;
+ } else {
+ delete_avpl(newavpl,TRUE);
+ return NULL;
+ }
+}
+
+
+/* TODO: rename me */
+/**
+ * new_avpl_exact_match:
+ * @name: the name of the resulting avpl
+ * @src: avpl to be matched agains an "op" avpl
+ * @op: the "op" avpl that will be matched against the src avpl
+ * @copy_avps: whether the avps in the resulting avpl should be copied
+ *
+ * creates an avp list containing every avp in src matching every avp in op
+ * it will not create a list unless every avp in op is matched only once
+ * to every avp in op.
+ *
+ * Return value: a pointer to the newly created avpl containing the
+ * matching avps.
+ **/
+extern AVPL* new_avpl_exact_match(guint8* name,AVPL* src, AVPL* op, gboolean copy_avps) {
+ AVPL* newavpl = new_avpl(name);
+ AVPN* co = NULL;
+ AVPN* cs = NULL;
+ gint c;
+ AVP* m;
+ AVP* copy;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"new_avpl_every_match: %X src=%X op=%X name='%s'",newavpl,src,op,name);
+#endif
+
+ cs = src->null.next;
+ co = op->null.next;
+ while(1) {
+
+ c = (guint) co->avp->n - (guint) cs->avp->n;
+
+ if ( c > 0 ) {
+ delete_avpl(newavpl,TRUE);
+ return NULL;
+ } else if (c < 0) {
+ cs = cs->next;
+ if (! cs->avp ) {
+ delete_avpl(newavpl,TRUE);
+ return NULL;
+ }
+ } else {
+ m = match_avp(cs->avp,co->avp);
+
+ if(m) {
+ cs = cs->next;
+ co = co->next;
+
+ if (copy_avps) {
+ copy = avp_copy(m);
+ if ( ! insert_avp(newavpl,copy) ) {
+ delete_avp(copy);
+ }
+ } else {
+ insert_avp(newavpl,m);
+ }
+
+
+ if (!co->avp) {
+ return newavpl;
+ }
+ if (!cs->avp) {
+ delete_avpl(newavpl,TRUE);
+ return NULL;
+ }
+ } else {
+ delete_avpl(newavpl,TRUE);
+ return NULL;
+ }
+ }
+
+ }
+
+ /* should never be reached */
+ return NULL;
+}
+
+
+/**
+ * new_avpl_transform:
+ *
+ * creates an empty avpl transformation
+ *
+ * Return value: a pointer to the newly created avpl transformation
+ **/
+extern AVPL_Transf* new_avpl_transform(guint8* name, AVPL* mixed, avpl_match_mode match_mode, avpl_replace_mode replace_mode) {
+ AVPL_Transf* t = g_malloc(sizeof(AVPL_Transf));
+ AVP* avp;
+
+ t->name = g_strdup(name);
+ t->match = new_avpl("match");
+ t->replace = new_avpl("replace");
+ t->match_mode = match_mode;
+ t->replace_mode = replace_mode;
+ t->next = NULL;
+ t->map = NULL;
+
+ while (( avp = extract_first_avp(mixed) )) {
+ if (*(avp->n) == '.') {
+ rename_avp(avp,(avp->n+1));
+ insert_avp(t->replace, avp);
+ } else {
+ insert_avp(t->match, avp);
+ }
+ }
+
+ return t;
+}
+
+
+/**
+ * delete_avpl_transform:
+ * @it: a pointer to the avpl transformation object
+ *
+ * Destroys an avpl transformation object and releases all the resources it
+ * uses.
+ *
+ **/
+extern void delete_avpl_transform(AVPL_Transf* op) {
+ AVPL_Transf* next;
+
+ for (; op ; op = next) {
+ next = op->next;
+
+ g_free(op->name);
+
+ if (op->match) {
+ delete_avpl(op->match,TRUE);
+ }
+
+ if (op->replace) {
+ delete_avpl(op->replace,TRUE);
+ }
+
+ g_free(op);
+ }
+
+}
+
+
+/**
+ * avpl_transform:
+ * @src: the source avpl for the transform operation.
+ * @op: a pointer to the avpl transformation object to apply.
+ *
+ * Applies the "op" transformation to an avpl, matches it and eventually
+ * replaces or inserts the transformed avps.
+ *
+ * Return value: whether the transformation was performed or not.
+ **/
+extern void avpl_transform(AVPL* src, AVPL_Transf* op) {
+ AVPL* avpl = NULL;
+ AVPN* cs;
+ AVPN* cm;
+ AVPN* n;
+ gboolean d;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"avpl_transform: src=%X op=%X",src,op);
+#endif
+
+ for ( ; op ; op = op->next) {
+ switch (op->match_mode) {
+ case AVPL_STRICT:
+ avpl = new_avpl_exact_match(src->name,src,op->match,TRUE);
+ break;
+ case AVPL_LOOSE:
+ avpl = new_avpl_loose_match(src->name,src,op->match,TRUE);
+ break;
+ case AVPL_EVERY:
+ avpl = new_avpl_every_match(src->name,src,op->match,TRUE);
+ break;
+ case AVPL_NO_MATCH:
+ avpl = new_avpl(src->name);
+ break;
+ }
+
+ if (avpl) {
+ switch (op->replace_mode) {
+ case AVPL_NO_REPLACE:
+ delete_avpl(avpl,TRUE);
+ return;
+ case AVPL_INSERT:
+ merge_avpl(src,op->replace,TRUE);
+ delete_avpl(avpl,TRUE);
+ return;
+ case AVPL_REPLACE:
+ cs = src->null.next;
+ cm = avpl->null.next;
+ d = FALSE;
+ while(cs->avp) {
+ if (cs->avp == cm->avp) {
+ n = cs->next;
+
+ cs->prev->next = cs->next;
+ cs->next->prev = cs->prev;
+ g_mem_chunk_free(avp_chunk,cs);
+
+ cs = n;
+ cm = cm->next;
+ } else {
+ cs = cs->next;
+ }
+ }
+
+ merge_avpl(src,avpl,TRUE);
+ delete_avpl(avpl,TRUE);
+ return;
+ }
+ }
+ }
+}
+
+
+/**
+ * new_loal:
+ * @name: the name the loal will take.
+ *
+ * Creates an empty list of avp lists.
+ *
+ * Return value: a pointer to the newly created loal.
+ **/
+extern LoAL* new_loal(guint8* name) {
+ LoAL* new_loal = g_mem_chunk_alloc(avp_chunk);
+
+ if (! name) {
+ name = "anonymous";
+ }
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal: %X name=%s",new_loal,name);
+#endif
+
+ new_loal->name = scs_subscribe(avp_strings,name);
+ new_loal->null.avpl = NULL;
+ new_loal->null.next = &new_loal->null;
+ new_loal->null.prev = &new_loal->null;
+
+ return new_loal;
+}
+
+/**
+ * loal_append:
+ * @loal: the loal on which to operate.
+ * @avpl: the avpl to append.
+ *
+ * Appends an avpl to a loal.
+ *
+ **/
+extern void loal_append(LoAL* loal, AVPL* avpl) {
+ LoALnode* node = g_mem_chunk_alloc(avp_chunk);
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"new_loal_node: %X",node);
+#endif
+
+ node->avpl = avpl;
+ node->next = &loal->null;
+ node->prev = loal->null.prev;
+
+ loal->null.prev->next = node;
+ loal->null.prev = node;
+}
+
+
+/**
+ * extract_first_avpl:
+ * @loal: the loal on which to operate.
+ *
+ * Extracts the first avpl contained in a loal.
+ *
+ * Return value: a pointer to the extracted avpl.
+ *
+ **/
+extern AVPL* extract_first_avpl(LoAL* loal) {
+ LoALnode* node;
+ AVPL* avpl;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: from: %s",loal->name);
+#endif
+
+ node = loal->null.next;
+
+ loal->null.next->next->prev = &loal->null;
+ loal->null.next = node->next;
+
+ loal->len--;
+
+ avpl = node->avpl;
+
+ if ( avpl ) {
+ g_mem_chunk_free(avp_chunk,node);
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"extract_first_avpl: got %s",avpl->name);
+ dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %X",node);
+#endif
+ }
+
+ return avpl;
+}
+
+/**
+* extract_first_avpl:
+ * @loal: the loal on which to operate.
+ *
+ * Extracts the last avpl contained in a loal.
+ *
+ * Return value: a pointer to the extracted avpl.
+ *
+ **/
+extern AVPL* extract_last_avpl(LoAL* loal){
+ LoALnode* node;
+ AVPL* avpl;
+
+ node = loal->null.prev;
+
+ loal->null.prev->prev->next = &loal->null;
+ loal->null.prev = node->prev;
+
+ loal->len--;
+
+ avpl = node->avpl;
+
+ if ( avpl ) {
+ g_mem_chunk_free(avp_chunk,node);
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal_node: %X",node);
+#endif
+ }
+
+ return avpl;
+}
+
+/**
+ * extract_first_avpl:
+ * @loal: the loal on which to operate.
+ * @cookie pointer to the pointer variable to contain the state between calls
+ *
+ * At each call will return the following avpl from a loal. The given cookie
+ * will be used to manatain the state between calls.
+ *
+ * Return value: a pointer to the next avpl.
+ *
+ **/
+extern AVPL* get_next_avpl(LoAL* loal,void** cookie) {
+ LoALnode* node;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"get_next_avpl: loal=%X node=%X",loal,*cookie);
+#endif
+
+ if (*cookie) {
+ node = (LoALnode*) *cookie;
+ } else {
+ node = loal->null.next;
+ }
+
+ *cookie = node->next;
+
+ return node->avpl;
+}
+
+/**
+ * delete_loal:
+ * @loal: the loal to be deleted.
+ * @avpls_too: whether avpls contained by the loal should be deleted as well
+ * @avps_too: whether avps contained by the avpls should be also deleted
+ *
+ * Destroys a loal and eventually desstroys avpls and avps.
+ *
+ **/
+extern void delete_loal(LoAL* loal, gboolean avpls_too, gboolean avps_too) {
+ AVPL* avpl;
+
+#ifdef _AVP_DEBUGGING
+ dbg_print(dbg_avpl_op,3,dbg_fp,"delete_loal: %X",loal);
+#endif
+
+ while(( avpl = extract_last_avpl(loal) )) {
+ if (avpls_too) {
+ delete_avpl(avpl,avps_too);
+ }
+ }
+
+ scs_unsubscribe(avp_strings,loal->name);
+ g_mem_chunk_free(avp_chunk,loal);
+}
+
+
+
+/****************************************************************************
+ ******************* the following are used in load_loal_from_file
+ ****************************************************************************/
+
+/**
+ * load_loal_error:
+ * Used by loal_from_file to handle errors while loading.
+ **/
+void load_loal_error(FILE* fp, LoAL* loal, AVPL* curr, int linenum, guint8* fmt, ...) {
+ va_list list;
+ guint8* desc;
+
+
+ va_start( list, fmt );
+ desc = g_strdup_vprintf(fmt, list);
+ va_end( list );
+
+ if (fp) fclose(fp);
+ if (loal) delete_loal(loal,TRUE,TRUE);
+ if (curr) delete_avpl(curr,TRUE);
+
+ g_warning("Error Loading LoAL from file: at line: %i, %s",linenum,desc);
+ g_free(desc);
+
+ return;
+}
+
+
+/* the maximum lenght allowed for a line */
+#define MAX_ITEM_LEN 8192
+
+/* this two ugly things are used for tokenizing */
+#define AVP_OP_CHAR '=': case '^': case '$': case '~': case '<': case '>': case '?': case '|': case '&' : case '!'
+
+#define AVP_NAME_CHAR 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':\
+case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T':\
+case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case 'a': case 'b': case 'c': case 'd':\
+case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':\
+case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x':\
+case 'y': case 'z': case '_': case '0': case '1': case '2': case '3': case '4': case '5': case '6':\
+case '7': case '8': case '9': case '.'
+
+
+/**
+ * loal_from_file:
+ * @filename: the file containing a loals text representation.
+ *
+ * Given a filename it will attempt to load a loal containing a copy of
+ * the avpls represented in the file.
+ *
+ * Return value: if successful a pointer to the new populated loal, else NULL.
+ *
+ **/
+extern LoAL* loal_from_file(guint8* filename) {
+ FILE *fp;
+ guint8 c;
+ int i = 0;
+ guint32 linenum = 1;
+ guint8 name[MAX_ITEM_LEN];
+ guint8 value[MAX_ITEM_LEN];
+ guint8 op = '?';
+ LoAL *loal = new_loal(filename);
+ AVPL* curr = NULL;
+ AVP* avp;
+
+ enum _load_loal_states {
+ START,
+ BEFORE_NAME,
+ IN_NAME,
+ IN_VALUE,
+ MY_IGNORE
+ } state;
+
+#ifndef _WIN32
+ if (! getuid()) {
+ g_warning( "MATE Will not run as root");
+ return NULL;
+ }
+#endif
+
+ state = START;
+
+ if (( fp = fopen(filename,"r") )) {
+ while(( c = (guint8) fgetc(fp) )){
+
+ if ( feof(fp) ) {
+ if ( ferror(fp) ) {
+ load_loal_error(fp,loal,curr,linenum,"Error while reading '%f'",filename);
+ return NULL;
+ }
+ break;
+ }
+
+ if ( c == '\n' ) {
+ linenum++;
+ }
+
+ if ( i >= MAX_ITEM_LEN - 1 ) {
+ load_loal_error(fp,loal,curr,linenum,"Maximum item lenght exceeded");
+ return NULL;
+ }
+
+ switch(state) {
+ case MY_IGNORE:
+ switch (c) {
+ case '\n':
+ state = START;
+ i = 0;
+ continue;
+ default:
+ continue;
+ }
+ continue;
+ case START:
+ switch (c) {
+ case ' ': case '\t':
+ /* ignore whitespace at line start */
+ continue;
+ case '\n':
+ /* ignore empty lines */
+ i = 0;
+ continue;
+ case AVP_NAME_CHAR:
+ state = IN_NAME;
+ i = 0;
+ name[i++] = c;
+ name[i] = '\0';
+
+ curr = new_avpl("");
+ continue;
+ case '#':
+ state = MY_IGNORE;
+ continue;
+ default:
+ load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
+ return NULL;
+ }
+ case BEFORE_NAME:
+ i = 0;
+ name[0] = '\0';
+ switch (c) {
+ case '\\':
+ c = fgetc(fp);
+ if (c != '\n') ungetc(c,fp);
+ continue;
+ case ' ':
+ case '\t':
+ continue;
+ case AVP_NAME_CHAR:
+ state = IN_NAME;
+
+ name[i++] = c;
+ name[i] = '\0';
+ continue;
+ case '\n':
+ loal_append(loal,curr);
+ state = START;
+ continue;
+ default:
+ load_loal_error(fp,loal,curr,linenum,"expecting name got: '%c'",c);
+ return NULL;
+ }
+ case IN_NAME:
+ switch (c) {
+ case ';':
+ state = BEFORE_NAME;
+
+ op = '?';
+ name[i] = '\0';
+ value[0] = '\0';
+ i = 0;
+
+ avp = new_avp(name,value,op);
+
+ if (! insert_avp(curr,avp) ) {
+ delete_avp(avp);
+ }
+
+ continue;
+ case AVP_OP_CHAR:
+ name[i] = '\0';
+ i = 0;
+ op = c;
+ state = IN_VALUE;
+ continue;
+ case AVP_NAME_CHAR:
+ name[i++] = c;
+ continue;
+ case '\n':
+ load_loal_error(fp,loal,curr,linenum,"operator expected found new line");
+ return NULL;
+ default:
+ load_loal_error(fp,loal,curr,linenum,"name or match operator expected found '%c'",c);
+ return NULL;
+ }
+ case IN_VALUE:
+ switch (c) {
+ case '\\':
+ value[i++] = fgetc(fp);
+ continue;
+ case ';':
+ state = BEFORE_NAME;
+
+ value[i] = '\0';
+ i = 0;
+
+ avp = new_avp(name,value,op);
+
+ if (! insert_avp(curr,avp) ) {
+ delete_avp(avp);
+ }
+ continue;
+ case '\n':
+ load_loal_error(fp,loal,curr,linenum,"';' expected found new line");
+ return NULL;
+ default:
+ value[i++] = c;
+ continue;
+ }
+ }
+ }
+ fclose (fp);
+
+ return loal;
+
+ } else {
+ load_loal_error(NULL,loal,NULL,0,"Cannot Open file '%s'",filename);
+ return NULL;
+ }
+}
diff --git a/plugins/mate/mate_util.h b/plugins/mate/mate_util.h
new file mode 100644
index 0000000000..d029cd1adf
--- /dev/null
+++ b/plugins/mate/mate_util.h
@@ -0,0 +1,284 @@
+/* mate_util.h
+*
+* Copyright 2004, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
+*
+* $Id$
+*
+* Ethereal - Network traffic analyzer
+* By Gerald Combs <gerald@ethereal.com>
+* Copyright 1998 Gerald Combs
+*
+* 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.
+*/
+
+
+/* Note:
+ * Although for now it is used only by tracing.c
+ * I decided to make it into a separate module
+ * since one day in the near future I will be using it
+ * to reimplement packet-radius.c
+ */
+
+
+#ifndef __AVP_H_
+#define __AVP_H_
+#include "epan/proto.h"
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+
+/* #define _AVP_DEBUGGING */
+
+
+/******* dbg_print *********/
+#define DEBUG_BUFFER_SIZE 4096
+extern void dbg_print(const guint* which, guint how, FILE* where, guint8* fmt, ... );
+
+
+/******* single copy strings *********/
+
+extern void scs_init(GHashTable** hash);
+extern guint8* scs_subscribe(GHashTable* collection, guint8* s);
+extern void scs_unsubscribe(GHashTable* collection, guint8* s);
+extern guint8* scs_subscribe_printf(GHashTable* collection, guint8* fmt, ...);
+
+/******* AVPs & Co. *********/
+#define AVP_CHUNK_SIZE 4096
+
+/* these are the defined oreators of avps */
+#define AVP_OP_EQUAL '='
+#define AVP_OP_NOTEQUAL '!'
+#define AVP_OP_STARTS '^'
+#define AVP_OP_ENDS '$'
+#define AVP_OP_CONTAINS '~'
+#define AVP_OP_LOWER '<'
+#define AVP_OP_HIGHER '>'
+#define AVP_OP_EXISTS '?'
+#define AVP_OP_ONEOFF '|'
+#define AVP_OP_TRANSF '&'
+
+
+/* an avp is an object made of a name a value and an operator */
+typedef struct _avp {
+ guint8* n;
+ guint8* v;
+ guint8 o;
+} AVP;
+
+/* avp nodes are used in avp lists */
+typedef struct _avp_node {
+ AVP* avp;
+ struct _avp_node* next;
+ struct _avp_node* prev;
+} AVPN;
+
+/* an avp list is a sorted set of avps */
+typedef struct _avp_list {
+ guint8* name;
+ guint32 len;
+ AVPN null;
+} AVPL;
+
+
+
+/* an avpl transformation operation */
+typedef enum _avpl_match_mode {
+ AVPL_NO_MATCH,
+ AVPL_STRICT,
+ AVPL_LOOSE,
+ AVPL_EVERY
+} avpl_match_mode;
+
+typedef enum _avpl_replace_mode {
+ AVPL_NO_REPLACE,
+ AVPL_INSERT,
+ AVPL_REPLACE,
+} avpl_replace_mode;
+
+typedef struct _avpl_transf AVPL_Transf;
+
+struct _avpl_transf {
+ guint8* name;
+
+ AVPL* match;
+ AVPL* replace;
+
+ avpl_match_mode match_mode;
+ avpl_replace_mode replace_mode;
+
+ GHashTable* map;
+ AVPL_Transf* next;
+};
+
+/* loalnodes are used in LoALs */
+typedef struct _loal_node {
+ AVPL* avpl;
+ struct _loal_node *next;
+ struct _loal_node *prev;
+} LoALnode;
+
+
+/* a loal is a list of avp lists */
+typedef struct _loal {
+ guint8* name;
+ guint len;
+ LoALnode null;
+} LoAL;
+
+
+/* avp library (re)initialization */
+extern void avp_init(void);
+
+/* If enabled set's up the debug facilities for the avp library */
+#ifdef _AVP_DEBUGGING
+extern void setup_avp_debug(FILE* fp, int* general, int* avp, int* avp_op, int* avpl, int* avpl_op);
+#endif /* _AVP_DEBUGGING */
+
+/*
+ * avp constructors
+ */
+
+/* creates a new avp */
+extern AVP* new_avp(guint8* name, guint8* value, guint8 op);
+
+/* creates a copy od an avp */
+extern AVP* avp_copy(AVP* from);
+
+/* creates an avp from a field_info record */
+extern AVP* new_avp_from_finfo(guint8* name, field_info* finfo);
+
+/*
+ * avp destructor
+ */
+extern void delete_avp(AVP* avp);
+
+/*
+ * avp methods
+ */
+/* returns a newly allocated string containing a representation of the avp */
+#define avp_to_str(avp) (g_strdup_printf("%s%c%s",avp->n,avp->o,avp->v))
+
+/* returns the src avp if the src avp matches(*) the op avp or NULL if it doesn't */
+extern AVP* match_avp(AVP* src, AVP* op);
+
+
+/*
+ * avplist constructors
+ */
+
+/* creates an empty avp list */
+extern AVPL* new_avpl(guint8* name);
+
+
+/* creates a copy of an avp list */
+extern AVPL* new_avpl_from_avpl(guint8* name, AVPL* avpl, gboolean copy_avps);
+
+/* creates an avp list containing any avps in src matching any avps in op
+ it will eventually create an empty list in none match */
+extern AVPL* new_avpl_loose_match(guint8* name,AVPL* src, AVPL* op, gboolean copy_avps);
+
+/* creates an avp list containing any avps in src matching every avp in op
+ it will not create a list if there is not a match for every attribute in op */
+extern AVPL* new_avpl_every_match(guint8* name,AVPL* src, AVPL* op, gboolean copy_avps);
+
+/* creates an avp list containing every avp in src matching every avp in op
+ it will not create a list unless every avp in op is matched only once to avery avp in op */
+extern AVPL* new_avpl_exact_match(guint8* name,AVPL* src, AVPL* op, gboolean copy_avps);
+
+/* uses mode to call one of the former matches. NO_MATCH = merge(merge(copy(src),op)) */
+extern AVPL* new_avpl_from_match(avpl_match_mode mode, guint8* name,AVPL* src, AVPL* op, gboolean copy_avps);
+
+
+
+/*
+ * avplist destructor
+ */
+extern void delete_avpl(AVPL* avpl, gboolean avps_too);
+
+/*
+ * functions on avpls
+ */
+
+/* it will insert an avp to an avpl */
+extern gboolean insert_avp(AVPL* avpl, AVP* avp);
+
+/* renames an avpl */
+extern void rename_avpl(AVPL* avpl, guint8* name);
+
+/* it will add all the avps in src which don't match(*) any attribute in dest */
+extern void merge_avpl(AVPL* dest, AVPL* src, gboolean copy);
+
+/* it will return the first avp in an avpl whose name matches the given name.
+ will return NULL if there is not anyone matching */
+extern AVP* get_avp_by_name(AVPL* avpl, guint8* name, void** cookie);
+
+/* it will get the next avp from an avpl, using cookie to keep state */
+extern AVP* get_next_avp(AVPL* avpl, void** cookie);
+
+/* it will extract the first avp from an avp list */
+extern AVP* extract_first_avp(AVPL* avpl);
+
+/* it will extract the last avp from an avp list */
+extern AVP* extract_last_avp(AVPL* avpl);
+
+/* it will extract the first avp in an avpl whose name matches the given name.
+ it will not extract any and return NULL if there is not anyone matching */
+extern AVP* extract_avp_by_name(AVPL* avpl, guint8* name);
+
+/* returns a newly allocated string containing a representation of the avp list */
+extern guint8* avpl_to_str(AVPL* avpl);
+extern guint8* avpl_to_dotstr(AVPL*);
+
+/* deletes an avp list and eventually it's contents */
+extern void delete_avpl(AVPL* avpl, gboolean avps_too);
+
+/*
+ * AVPL transformations
+ */
+extern AVPL_Transf* new_avpl_transform(guint8* name, AVPL* mixed, avpl_match_mode match_mode, avpl_replace_mode replace_mode);
+extern void delete_avpl_transform(AVPL_Transf* it);
+extern void avpl_transform(AVPL* src, AVPL_Transf* op);
+
+
+/*
+ * Lists of AVP lists
+ */
+
+/* creates an empty list of avp lists */
+extern LoAL* new_loal(guint8* name);
+
+/* given a file loads all the avpls contained in it
+ every line is formatted as it is the output of avplist_to_string */
+extern LoAL* loal_from_file(guint8* filename);
+
+/* inserts an avplist into a LoAL */
+extern void loal_append(LoAL* loal, AVPL* avpl);
+
+/* extracts the first avp list from the loal */
+extern AVPL* extract_first_avpl(LoAL* loal);
+
+/* extracts the last avp list from the loal */
+extern AVPL* extract_last_avpl(LoAL* loal);
+
+/* it will get the next avp list from a LoAL, using cookie to keep state */
+extern AVPL* get_next_avpl(LoAL* loal,void** cookie);
+
+/* deletes a loal and eventually it's contents */
+extern void delete_loal(LoAL* loal, gboolean avpls_too, gboolean avps_too);
+
+
+#endif
diff --git a/plugins/mate/matelib/dns.mate b/plugins/mate/matelib/dns.mate
new file mode 100644
index 0000000000..47db859544
--- /dev/null
+++ b/plugins/mate/matelib/dns.mate
@@ -0,0 +1,19 @@
+# dns.thing
+
+Action=Settings; SessionExpiration=300;
+
+Action=PDU; Proto=ftp; Transport=ip; addr=ip.addr; port=ftp.passive.port;
+Action=LegKey; On=ftp; addr!65.;
+Action=LegStart; On=ftp; addr!;
+
+Action=PDU; Proto=tcp; Transport=ip; addr=ip.addr; port=tcp.port; tcp_start=tcp.flags.syn; tcp_stop=tcp.flags.reset; tcp_stop=tcp.flags.fin;
+Action=LegKey; On=tcp; addr!21; addr; port; port;
+Action=LegStart; On=tcp; tcp_start=1;
+Action=LegStop; On=tcp; tcp_stop=1;
+
+Action=PDU; Proto=dns; Transport=ip; addr=ip.addr; dns_id=dns.id; dns_rsp=dns.flags.response; dns_name=dns.name;
+Action=LegKey; On=dns; addr; addr; dns_id;
+Action=LegStart; On=dns; dns_rsp=0;
+Action=LegStop; On=dns; dns_rsp=1;
+Action=LegExtra; On=dns; dns_name;
+
diff --git a/plugins/mate/matelib/h225_ras.mate b/plugins/mate/matelib/h225_ras.mate
new file mode 100644
index 0000000000..701e9b40fa
--- /dev/null
+++ b/plugins/mate/matelib/h225_ras.mate
@@ -0,0 +1,7 @@
+# h225_ras.thing
+# (c) 2004 Luis E. Garcia Ontanon
+
+Action=PDU; Proto=h225.RasMessage; Transport=ip; ras_msg=h225.RasMessage; addr=ip.addr; guid=h225.guid; seqnum=h225.RequestSeqNum;
+Action=LegKey; On=h225.RasMessage; addr; addr; seqnum;
+Action=LegStart; On=h225.RasMessage; ras_msg|0|3|6|9|12|15|18|21|26|30;
+Action=LegStop; On=h225.RasMessage; ras_msg|1|2|4|5|7|8|10|11|13|14|16|17|19|20|22|24|27|28|29|31;
diff --git a/plugins/mate/matelib/isup.mate b/plugins/mate/matelib/isup.mate
new file mode 100644
index 0000000000..0f9fbe2832
--- /dev/null
+++ b/plugins/mate/matelib/isup.mate
@@ -0,0 +1,6 @@
+# isup.thing
+
+Action=PDU; Proto=isup; Transport=mtp3; mtp3pc=mtp3.dpc; mtp3pc=mtp3.opc; cic=isup.cic; isup_msg=isup.message_type; called=isup.called; calling=isup.calling; isup_cause=isup.cause_indicator;
+Action=LegKey; On=isup; cic; mtp3pc; mtp3pc;
+Action=LegStart; On=isup; isup_msg=1;
+Action=LegStop; On=isup; isup_msg=16;
diff --git a/plugins/mate/matelib/megaco.mate b/plugins/mate/matelib/megaco.mate
new file mode 100644
index 0000000000..c8af030769
--- /dev/null
+++ b/plugins/mate/matelib/megaco.mate
@@ -0,0 +1,6 @@
+# megaco.thing
+
+Action=PDU; Proto=megaco; Transport=ip; addr=ip.addr; megaco_ctx=megaco.context; megaco_trx=megaco.transid; megaco_msg=megaco.transaction; term=megaco.termid;
+Action=LegKey; On=megaco; addr; addr; megaco_trx;
+Action=LegStart; On=megaco; megaco_msg|Request|Notify;
+Action=LegStop; On=megaco; megaco_msg=Reply;
diff --git a/plugins/mate/matelib/q931.mate b/plugins/mate/matelib/q931.mate
new file mode 100644
index 0000000000..3d66e8a7a8
--- /dev/null
+++ b/plugins/mate/matelib/q931.mate
@@ -0,0 +1,6 @@
+# q931.thing
+
+Action=PDU; Proto=q931; Transport=ip; addr=ip.addr; call_ref=q931.call_ref; q931_msg=q931.message_type; guid=h225.guid; called=q931.called_party_number.digits; calling=q931.calling_party_number.digits; q931_cause=q931.cause_value; h225_cause=h225.ReleaseCompleteReason;
+Action=LegKey; On=q931; call_ref; addr; addr;
+Action=LegStart; On=q931; q931_msg=5;
+Action=LegStop; On=q931; q931_msg=90;
diff --git a/plugins/mate/matelib/radius.mate b/plugins/mate/matelib/radius.mate
new file mode 100644
index 0000000000..0de9aab86e
--- /dev/null
+++ b/plugins/mate/matelib/radius.mate
@@ -0,0 +1,7 @@
+# radius.thing
+
+Action=pdu; Proto=radius; Transport=ip; addr=ip.addr; radius_id=radius.id; radius_code=radius.code; calling=radius.calling;
+
+Action=pdukey; On=radius; radius_id; addr; addr;
+Action=start; On=radius; radius_code=4;
+Action=stop; On=radius; radius_code=5;
diff --git a/plugins/mate/matelib/rtsp.mate b/plugins/mate/matelib/rtsp.mate
new file mode 100644
index 0000000000..c25ebf5ef3
--- /dev/null
+++ b/plugins/mate/matelib/rtsp.mate
@@ -0,0 +1,5 @@
+
+Action=PDU; Proto=rtsp; Transport=ip; isup_msg=isup.message_type; calling=X_Vig_Msisdn; rtsp_method=rtsp.method; rtsp_ses=rtsp.session; addr=ip.addr; rtsp_url=rtsp.url;
+Action=LegKey; On=rtsp; rtsp_ses;
+Action=LegStart; On=rtsp; rtsp_method=SETUP;
+Action=LegStop; On=rtsp; rtsp_method=TEARDOWN;
diff --git a/plugins/mate/matelib/sip.mate b/plugins/mate/matelib/sip.mate
new file mode 100644
index 0000000000..4da296fff9
--- /dev/null
+++ b/plugins/mate/matelib/sip.mate
@@ -0,0 +1,6 @@
+# sip.thing
+
+Action=PDU; Proto=sip; Transport=ip; addr=ip.addr; sip_method=sip.Method; sip_callid=sip.Call-ID; calling=sdp.owner.username;
+Action=LegKey; On=sip; sip_callid; addr; addr;
+Action=LegStart; On=sip; sip_method=INVITE;
+Action=LegStop; On=sip; sip_method=BYE;
diff --git a/plugins/mate/moduleinfo.h b/plugins/mate/moduleinfo.h
new file mode 100644
index 0000000000..569556f83d
--- /dev/null
+++ b/plugins/mate/moduleinfo.h
@@ -0,0 +1,16 @@
+/* Included *after* config.h, in order to re-define these macros */
+
+#ifdef PACKAGE
+#undef PACKAGE
+#endif
+
+/* Name of package */
+#define PACKAGE "mate"
+
+#ifdef VERSION
+#undef VERSION
+#endif
+
+/* Version number of package */
+#define VERSION "0.0.3"
+
diff --git a/plugins/mate/packet-mate.c b/plugins/mate/packet-mate.c
new file mode 100644
index 0000000000..53b9b4557e
--- /dev/null
+++ b/plugins/mate/packet-mate.c
@@ -0,0 +1,321 @@
+/* packet-mate.c
+ * Routines for the mate Facility's Pseudo-Protocol dissection
+ *
+ * Copyright 2004, Luis E. Garcia Ontanon <gopo@webflies.org>
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * 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.
+ */
+
+
+/**************************************************************************
+ * This is the pseudo protocol dissector for the mate module. ***
+ * It is intended for this to be just the user interface to the module. ***
+ **************************************************************************/
+
+#include "mate.h"
+
+static int mate_tap_data = 0;
+static mate_config* mc = NULL;
+
+static int proto_mate = -1;
+
+static gint ett_mate = -1;
+static gint ett_mate_pdu = -1;
+static gint ett_mate_pdu_attr = -1;
+
+static gint ett_mate_gop = -1;
+static gint ett_mate_gop_attr = -1;
+static gint ett_mate_gop_pdus = -1;
+static gint ett_mate_gop_times = -1;
+
+static gint ett_mate_gog = -1;
+static gint ett_mate_gog_attr = -1;
+static gint ett_mate_gog_gops = -1;
+static gint ett_mate_gop_in_gog = -1;
+
+static char* pref_mate_config_filename = "config.mate";
+
+static proto_item *mate_i = NULL;
+
+void attrs_tree(proto_tree* tree, tvbuff_t *tvb,mate_item* item) {
+ AVPN* c;
+ proto_item *avpl_i;
+ proto_tree *avpl_t;
+ int* hfi_p;
+
+ gint our_ett;
+
+ switch (item->cfg->type) {
+ case MATE_PDU_TYPE:
+ our_ett = ett_mate_pdu_attr;
+ break;
+ case MATE_GOP_TYPE:
+ our_ett = ett_mate_pdu_attr;
+ break;
+ case MATE_GOG_TYPE:
+ our_ett = ett_mate_pdu_attr;
+ break;
+ default:
+ our_ett = ett_mate;
+ break;
+ }
+
+ avpl_i = proto_tree_add_text(tree,tvb,0,0,"%s Attributes",item->cfg->name);
+ avpl_t = proto_item_add_subtree(avpl_i, our_ett);
+
+ for ( c = item->avpl->null.next; c->avp; c = c->next) {
+ hfi_p = g_hash_table_lookup(item->cfg->my_hfids,c->avp->n);
+
+ if (hfi_p) {
+ proto_tree_add_string(avpl_t,*hfi_p,tvb,0,0,c->avp->v);
+ } else {
+ g_warning("MATE: error: undefined attribute: mate.%s.%s",item->cfg->name,c->avp->n);
+ proto_tree_add_text(avpl_t,tvb,0,0,"Undefined attribute: %s=%s",c->avp->n, c->avp->v);
+ }
+ }
+}
+
+void mate_gop_tree(proto_tree* pdu_tree, tvbuff_t *tvb, mate_gop* gop, gint ett);
+
+void mate_gog_tree(proto_tree* tree, tvbuff_t *tvb, mate_gog* gog, mate_gop* gop) {
+ proto_item *gog_item;
+ proto_tree *gog_tree;
+ proto_item *gog_gop_item;
+ proto_tree *gog_gop_tree;
+ mate_gop* gog_gops;
+#ifdef _MATE_DEBUGGING
+ proto_item* gog_key_item;
+ proto_tree* gog_key_tree;
+ guint i;
+#endif
+
+ gog_item = proto_tree_add_string(tree,gog->cfg->hfid,tvb,0,0,gog->id);
+ gog_tree = proto_item_add_subtree(gog_item,ett_mate_gog);
+
+ attrs_tree(gog_tree,tvb,gog);
+
+ gog_gop_item = proto_tree_add_uint(gog_tree, gog->cfg->hfid_gog_num_of_gops,
+ tvb, 0, 0, gog->num_of_gops);
+
+ gog_gop_tree = proto_item_add_subtree(gog_gop_item, ett_mate_gog_gops);
+
+ for (gog_gops = gog->gops; gog_gops; gog_gops = gog_gops->next) {
+
+ if (gop != gog_gops) {
+ mate_gop_tree(gog_gop_tree, tvb, gog_gops, ett_mate_gop_in_gog);
+ } else {
+ proto_tree_add_string_format(gog_gop_tree,gop->cfg->hfid,tvb,0,0,gop->id,"GOP of current frame: %s",gop->id);
+ }
+ }
+
+}
+
+void mate_gop_tree(proto_tree* tree, tvbuff_t *tvb, mate_gop* gop, gint gop_ett) {
+ proto_item *gop_item;
+ proto_tree *gop_time_tree;
+ proto_item *gop_time_item;
+ proto_tree *gop_tree;
+ proto_item *gop_pdu_item;
+ proto_tree *gop_pdu_tree;
+ mate_pdu* gop_pdus;
+ float rel_time;
+ float gop_time;
+
+ gop_item = proto_tree_add_string(tree,gop->cfg->hfid,tvb,0,0,gop->id);
+ gop_tree = proto_item_add_subtree(gop_item, gop_ett);
+
+ if (gop->gop_key) proto_tree_add_text(gop_tree,tvb,0,0,"GOP Key: %s",gop->gop_key);
+
+ attrs_tree(gop_tree,tvb,gop);
+
+ if (gop->cfg->show_gop_times) {
+ gop_time_item = proto_tree_add_text(gop_tree,tvb,0,0,"%s Times",gop->cfg->name);
+ gop_time_tree = proto_item_add_subtree(gop_time_item, ett_mate_gop_times);
+
+ proto_tree_add_float(gop_time_tree, gop->cfg->hfid_gop_start_time, tvb, 0, 0, gop->start_time);
+
+ if (gop->released) {
+ proto_tree_add_float(gop_time_tree, gop->cfg->hfid_gop_stop_time, tvb, 0, 0, gop->release_time);
+ if (gop->release_time != gop->last_time) {
+ proto_tree_add_float(gop_time_tree, gop->cfg->hfid_gop_last_time, tvb, 0, 0, gop->last_time);
+ }
+ } else {
+ proto_tree_add_float(gop_time_tree, gop->cfg->hfid_gop_last_time, tvb, 0, 0, gop->last_time);
+ }
+ }
+
+ rel_time = gop_time = gop->start_time;
+
+ gop_pdu_item = proto_tree_add_uint(gop_tree, gop->cfg->hfid_gop_num_pdus, tvb, 0, 0,gop->num_of_pdus);
+ gop_pdu_tree = proto_item_add_subtree(gop_pdu_item, ett_mate_gop_pdus);
+
+ if (gop->cfg->show_pdu_tree) {
+ for (gop_pdus = gop->pdus; gop_pdus; gop_pdus = gop_pdus->next) {
+ if (gop_pdus->is_start) {
+ proto_tree_add_uint_format(gop_pdu_tree,gop->cfg->hfid_gop_pdu,
+ tvb,0,0,gop_pdus->frame,
+ "Start PDU: in frame %i",
+ gop_pdus->frame);
+ } else if (gop_pdus->is_stop) {
+ proto_tree_add_uint_format(gop_pdu_tree,gop->cfg->hfid_gop_pdu,
+ tvb,0,0,gop_pdus->frame,
+ "Stop PDU: in frame %i (%f : %f)",
+ gop_pdus->frame,
+ gop_pdus->rel_time,
+ gop_pdus->rel_time-rel_time);
+
+ } else if (gop_pdus->after_release) {
+ proto_tree_add_uint_format(gop_pdu_tree,gop->cfg->hfid_gop_pdu,
+ tvb,0,0,gop_pdus->frame,
+ "After stop PDU: in frame %i (%f : %f)",
+ gop_pdus->frame,
+ gop_pdus->rel_time,
+ gop_pdus->rel_time-rel_time);
+ } else {
+ proto_tree_add_uint_format(gop_pdu_tree,gop->cfg->hfid_gop_pdu,
+ tvb,0,0,gop_pdus->frame,
+ "PDU: in frame %i (%f : %f)",
+ gop_pdus->frame,
+ gop_pdus->rel_time,
+ gop_pdus->rel_time-rel_time);
+ }
+
+ rel_time = gop_pdus->rel_time;
+
+ }
+ }
+}
+
+
+void mate_pdu_tree(mate_pdu *pdu, tvbuff_t *tvb, proto_tree* tree) {
+ proto_item *pdu_item;
+ proto_tree *pdu_tree;
+ guint32 len;
+
+ if ( ! pdu ) return;
+
+ if (pdu->gop && pdu->gop->gog) {
+ proto_item_append_text(mate_i," %s->%s->%s",pdu->id,pdu->gop->id,pdu->gop->gog->id);
+ } else if (pdu->gop) {
+ proto_item_append_text(mate_i," %s->%s",pdu->id,pdu->gop->id);
+ } else {
+ proto_item_append_text(mate_i," %s",pdu->id);
+ }
+
+ len = pdu->end - pdu->start;
+ pdu_item = proto_tree_add_string(tree,pdu->cfg->hfid,tvb,pdu->start,len,pdu->id);
+ pdu_tree = proto_item_add_subtree(pdu_item, ett_mate_pdu);
+ proto_tree_add_float(pdu_tree,pdu->cfg->hfid_pdu_rel_time, tvb, 0, 0, pdu->rel_time);
+
+ if (pdu->gop) {
+ mate_gop_tree(pdu_tree,tvb,pdu->gop,ett_mate_gop);
+
+ if (pdu->gop->gog)
+ mate_gog_tree(pdu_tree,tvb,pdu->gop->gog,pdu->gop);
+ }
+
+ if (pdu->avpl) {
+ attrs_tree(pdu_tree,tvb,pdu);
+ }
+}
+
+extern void mate_tree(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
+ mate_pdu* pdus;
+ proto_tree *mate_t;
+
+ if (! tree ) return;
+
+ if (( pdus = mate_get_pdus(pinfo->fd->num) )) {
+
+ mate_i = proto_tree_add_text(tree,tvb,0,0,"mate");
+
+ mate_t = proto_item_add_subtree(mate_i, ett_mate);
+
+ for ( ; pdus; pdus = pdus->next_in_frame) {
+ mate_pdu_tree(pdus,tvb,mate_t);
+ }
+ }
+}
+
+static void init_mate(void) {
+ GString* tap_error = NULL;
+
+ tap_error = register_tap_listener("frame", &mate_tap_data,
+ mc->tap_filter,
+ NULL,
+ mate_packet,
+ NULL);
+
+ if ( tap_error ) {
+ g_warning("mate: couldn't (re)register tap: %s",tap_error->str);
+ g_string_free(tap_error, TRUE);
+ mate_tap_data = 0;
+ return;
+ } else {
+ mate_tap_data = 1;
+ }
+
+ init_mate_runtime_data();
+}
+
+extern
+void
+proto_reg_handoff_mate(void)
+{
+}
+
+
+extern
+void
+proto_register_mate(void)
+{
+ static gint *ett[] = {
+ &ett_mate,
+ &ett_mate_pdu,
+ &ett_mate_pdu_attr,
+ &ett_mate_gop,
+ &ett_mate_gop_attr,
+ &ett_mate_gop_times,
+ &ett_mate_gop_pdus,
+ &ett_mate_gog,
+ &ett_mate_gog_gops,
+ &ett_mate_gog_attr,
+ &ett_mate_gop_in_gog
+ };
+
+ mc = mate_make_config(pref_mate_config_filename);
+
+ if (mc) {
+
+ proto_mate = proto_register_protocol("Meta Analysis Tracing Engine", "mate", "mate");
+
+
+ proto_register_field_array(proto_mate, (hf_register_info*) mc->hfrs->data, mc->hfrs->len );
+
+ proto_register_subtree_array(ett, array_length(ett));
+
+ register_dissector("mate",mate_tree,proto_mate);
+
+ register_init_routine(init_mate);
+
+ }
+}
+
diff --git a/plugins/mate/presentation.txt b/plugins/mate/presentation.txt
new file mode 100644
index 0000000000..d8205cbd3b
--- /dev/null
+++ b/plugins/mate/presentation.txt
@@ -0,0 +1,91 @@
+Hi,
+
+ I think this fifth rewrite has taken it out of prototype stage and makes it
+look almost as "production" code, please tell me if it doesn't. I do not plan
+to rewrite it again. I'm realy happy with what it has become.
+
+This has surpassed my initial goal by far. It had just to to be a filter for
+packets of calls, using few protocols, based on the calling number.
+
+My original idea was just to rewrite inside ethereal a perl script I had
+written to split calls. I needed to decode h225 and could not get Decode::ASN1
+to compile the h225 syntax, I thought that migrating it into ethereal would
+had been easy. I was *VERY* wrong.
+
+At the begining it was ECTAF it extracted data from ISUP and Q931. I hard
+coded the extraction code directly in the dissectors and did an ugly job
+putting it into several hashes but kida threaded the PDUs.
+
+Later I wrote the AVP Lib for it. So that I would converge dealing with the
+different protocols into a single mechanism. H225 got into the picture but
+wasn't versatile enough. Still I used code in the dissectors to extract the
+data.
+
+As I tried to get MEGACO into the picture I wrote a parser to import the
+dpc+cic->term mapping. It took me a day to "see the light", ECTAF used the
+AVPLs as a logical engine already, I had a parser for AVPLs, 1+1=2, so:
+importing the logic from a config file wasa natuiral step for it. STTF was
+the name then (I never got it to be usable, that's why I did not release then).
+
+At that point I started working into fetching data from the tree, getting it
+into avpls match the avpls to group the pdus etc... the nice "thing" was that
+it was configurable. I called it TTT.
+
+I released about a month ago something called "Thing" that was the result of
+that metamorphosis. A configurable tool that allows to use ethereal to do
+analysis at the session and application level. Not only on what the frames
+carry but on how they interact.
+
+Now I release a nicelly wrapped version of it. I fixed many things and made
+code that I believe to be versatile enough to be able to grow, clean enough to
+be mantainable.
+
+Anyway today's MATE is just the core of an application in the application. It
+has plenty of room to grow.
+
+There are still things I will be doing on MATE's code in the very next future:
+
+- add timers to gops so that if they expire before their stop condition the gop
+ gets "marked".
+
+- merge two gogs whenever a new gog matches keys of some previous unexpired gog
+
+- spawn pre-started "empty" gops if a pdu of a gop in the gogs matches
+ a given condition.
+
+- use mem_chunks to store most of the strings in the AVP library
+ * one for small strings (<16bytes)
+ * one for midsized strings (<32 bytes)
+ * one for large strings (<64 bytes)
+ * g_malloc for the remaining cases
+
+- the avpl transformations will be reimplemeted
+ * a contextual_avp_op(AVPL_Transf* ctx, AVPL* src, AVP* avp, AVP* op)
+ has to be written to allow to transform AVPs extracting its value from
+ the source avpl and/or manupulating its contents.
+ * a map method that uses a hash will replace the "extremely slow" long
+ sequence of very similar matches that is used right now
+
+- get rid of most of the dbg_print calls in the code and give sense to the
+ debug levels, which by now are almost randomic.
+
+
+There are things other I cannot/"do not plan to" do that would be nice
+if someone else did:
+
+- build it as a plugin on Win32. However it may be better to get it in epan and
+ forget about pluginizing it.
+
+- make it work with tethereal. This has frustrated me twice:
+ first because I meant it to be used as a filter on live capture to save only
+ packets of a call from a given number. And, second, because I tried very hard
+ and failed miserably.
+
+- GUI gizmos (I don't stand GUI programming, sorry) :
+ an pane for sessions,
+ a Graphical config tool
+ ?
+
+- tap it, that is, we got plenty of information on how frames interact why
+ don't we give the users the ability to do the math with it.
+