diff options
Diffstat (limited to 'src/manager')
47 files changed, 7201 insertions, 0 deletions
diff --git a/src/manager/Makefile.am b/src/manager/Makefile.am new file mode 100644 index 000000000..17eecdbab --- /dev/null +++ b/src/manager/Makefile.am @@ -0,0 +1,53 @@ +ipsec_PROGRAMS = manager.fcgi + +manager_fcgi_SOURCES = \ +main.c manager.c manager.h gateway.h gateway.c database.h database.c \ +controller/auth_controller.c controller/auth_controller.h \ +controller/status_controller.c controller/status_controller.h \ +controller/gateway_controller.c controller/gateway_controller.h + +manager_fcgi_LDADD = $(top_builddir)/src/manager/libappserv.la -lsqlite3 + + + +lib_LTLIBRARIES = libappserv.la + +libappserv_la_SOURCES = \ +lib/context.h lib/dispatcher.c lib/request.h lib/session.h \ +lib/controller.h lib/dispatcher.h lib/request.c lib/session.c \ +lib/xml.h lib/xml.c + +libappserv_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lfcgi -lpthread -lneo_cgi -lneo_cs -lneo_utl ${xml_LIBS} + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/manager/lib -I/usr/include/ClearSilver ${xml_CFLAGS} +AM_CFLAGS = -rdynamic -DIPSECDIR=\"${ipsecdir}\" -DIPSEC_PIDDIR=\"${piddir}\" + +ipsec_DATA = manager.db + +# Don't forget to add templates to EXTRA_DIST !!! How to automate? +ipsec_templatesdir = ${ipsecdir}/templates +ipsec_templates_DATA = templates/header.cs templates/footer.cs templates/error.cs + +ipsec_templates_authdir = ${ipsec_templatesdir}/auth +ipsec_templates_auth_DATA = templates/auth/login.cs + +ipsec_templates_gatewaydir = ${ipsec_templatesdir}/gateway +ipsec_templates_gateway_DATA = templates/gateway/list.cs + +ipsec_templates_statusdir = ${ipsec_templatesdir}/status +ipsec_templates_status_DATA = templates/status/ikesalist.cs + +ipsec_templates_staticdir = ${ipsec_templatesdir}/static +ipsec_templates_static_DATA = templates/static/style.css templates/static/script.js templates/static/jquery.js \ +templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ +templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png + +EXTRA_DIST = manager.db templates/header.cs templates/footer.cs templates/error.cs \ +templates/auth/login.cs templates/gateway/list.cs templates/status/ikesalist.cs \ +templates/static/style.css templates/static/script.js templates/static/jquery.js \ +templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ +templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png diff --git a/src/manager/Makefile.in b/src/manager/Makefile.in new file mode 100644 index 000000000..5c09c22d4 --- /dev/null +++ b/src/manager/Makefile.in @@ -0,0 +1,783 @@ +# Makefile.in generated by automake 1.10 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +ipsec_PROGRAMS = manager.fcgi$(EXEEXT) +subdir = src/manager +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ipsecdir)" \ + "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsec_templatesdir)" \ + "$(DESTDIR)$(ipsec_templates_authdir)" \ + "$(DESTDIR)$(ipsec_templates_gatewaydir)" \ + "$(DESTDIR)$(ipsec_templates_staticdir)" \ + "$(DESTDIR)$(ipsec_templates_statusdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libappserv_la_DEPENDENCIES = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(am__DEPENDENCIES_1) +am_libappserv_la_OBJECTS = dispatcher.lo request.lo session.lo xml.lo +libappserv_la_OBJECTS = $(am_libappserv_la_OBJECTS) +ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(ipsec_PROGRAMS) +am_manager_fcgi_OBJECTS = main.$(OBJEXT) manager.$(OBJEXT) \ + gateway.$(OBJEXT) database.$(OBJEXT) auth_controller.$(OBJEXT) \ + status_controller.$(OBJEXT) gateway_controller.$(OBJEXT) +manager_fcgi_OBJECTS = $(am_manager_fcgi_OBJECTS) +manager_fcgi_DEPENDENCIES = $(top_builddir)/src/manager/libappserv.la +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libappserv_la_SOURCES) $(manager_fcgi_SOURCES) +DIST_SOURCES = $(libappserv_la_SOURCES) $(manager_fcgi_SOURCES) +ipsecDATA_INSTALL = $(INSTALL_DATA) +ipsec_templatesDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_authDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_gatewayDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_staticDATA_INSTALL = $(INSTALL_DATA) +ipsec_templates_statusDATA_INSTALL = $(INSTALL_DATA) +DATA = $(ipsec_DATA) $(ipsec_templates_DATA) \ + $(ipsec_templates_auth_DATA) $(ipsec_templates_gateway_DATA) \ + $(ipsec_templates_static_DATA) $(ipsec_templates_status_DATA) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IPSEC_ROUTING_TABLE = @IPSEC_ROUTING_TABLE@ +IPSEC_ROUTING_TABLE_PRIO = @IPSEC_ROUTING_TABLE_PRIO@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LINUX_HEADERS = @LINUX_HEADERS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +backenddir = @backenddir@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbus_CFLAGS = @dbus_CFLAGS@ +dbus_LIBS = @dbus_LIBS@ +docdir = @docdir@ +dvidir = @dvidir@ +eapdir = @eapdir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +interfacedir = @interfacedir@ +ipsecdir = @ipsecdir@ +ipsecgid = @ipsecgid@ +ipsecuid = @ipsecuid@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linuxdir = @linuxdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +piddir = @piddir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +manager_fcgi_SOURCES = \ +main.c manager.c manager.h gateway.h gateway.c database.h database.c \ +controller/auth_controller.c controller/auth_controller.h \ +controller/status_controller.c controller/status_controller.h \ +controller/gateway_controller.c controller/gateway_controller.h + +manager_fcgi_LDADD = $(top_builddir)/src/manager/libappserv.la -lsqlite3 +lib_LTLIBRARIES = libappserv.la +libappserv_la_SOURCES = \ +lib/context.h lib/dispatcher.c lib/request.h lib/session.h \ +lib/controller.h lib/dispatcher.h lib/request.c lib/session.c \ +lib/xml.h lib/xml.c + +libappserv_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lfcgi -lpthread -lneo_cgi -lneo_cs -lneo_utl ${xml_LIBS} +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/manager/lib -I/usr/include/ClearSilver ${xml_CFLAGS} +AM_CFLAGS = -rdynamic -DIPSECDIR=\"${ipsecdir}\" -DIPSEC_PIDDIR=\"${piddir}\" +ipsec_DATA = manager.db + +# Don't forget to add templates to EXTRA_DIST !!! How to automate? +ipsec_templatesdir = ${ipsecdir}/templates +ipsec_templates_DATA = templates/header.cs templates/footer.cs templates/error.cs +ipsec_templates_authdir = ${ipsec_templatesdir}/auth +ipsec_templates_auth_DATA = templates/auth/login.cs +ipsec_templates_gatewaydir = ${ipsec_templatesdir}/gateway +ipsec_templates_gateway_DATA = templates/gateway/list.cs +ipsec_templates_statusdir = ${ipsec_templatesdir}/status +ipsec_templates_status_DATA = templates/status/ikesalist.cs +ipsec_templates_staticdir = ${ipsec_templatesdir}/static +ipsec_templates_static_DATA = templates/static/style.css templates/static/script.js templates/static/jquery.js \ +templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ +templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png + +EXTRA_DIST = manager.db templates/header.cs templates/footer.cs templates/error.cs \ +templates/auth/login.cs templates/gateway/list.cs templates/status/ikesalist.cs \ +templates/static/style.css templates/static/script.js templates/static/jquery.js \ +templates/static/pipe.png templates/static/pipe-good.png templates/static/pipe-bad.png \ +templates/static/pipe-thin.png templates/static/pipe-thin-left.png templates/static/pipe-thin-right.png \ +templates/static/gateway-left.png templates/static/client-left.png templates/static/strongswan.png \ +templates/static/router.png templates/static/gateway-right.png templates/static/client-right.png + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/manager/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/manager/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libappserv.la: $(libappserv_la_OBJECTS) $(libappserv_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libappserv_la_OBJECTS) $(libappserv_la_LIBADD) $(LIBS) +install-ipsecPROGRAMS: $(ipsec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" + @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-ipsecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \ + done + +clean-ipsecPROGRAMS: + @list='$(ipsec_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +manager.fcgi$(EXEEXT): $(manager_fcgi_OBJECTS) $(manager_fcgi_DEPENDENCIES) + @rm -f manager.fcgi$(EXEEXT) + $(LINK) $(manager_fcgi_OBJECTS) $(manager_fcgi_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/database.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dispatcher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gateway.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gateway_controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/request.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status_controller.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +dispatcher.lo: lib/dispatcher.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dispatcher.lo -MD -MP -MF $(DEPDIR)/dispatcher.Tpo -c -o dispatcher.lo `test -f 'lib/dispatcher.c' || echo '$(srcdir)/'`lib/dispatcher.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/dispatcher.Tpo $(DEPDIR)/dispatcher.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lib/dispatcher.c' object='dispatcher.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dispatcher.lo `test -f 'lib/dispatcher.c' || echo '$(srcdir)/'`lib/dispatcher.c + +request.lo: lib/request.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT request.lo -MD -MP -MF $(DEPDIR)/request.Tpo -c -o request.lo `test -f 'lib/request.c' || echo '$(srcdir)/'`lib/request.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/request.Tpo $(DEPDIR)/request.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lib/request.c' object='request.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o request.lo `test -f 'lib/request.c' || echo '$(srcdir)/'`lib/request.c + +session.lo: lib/session.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT session.lo -MD -MP -MF $(DEPDIR)/session.Tpo -c -o session.lo `test -f 'lib/session.c' || echo '$(srcdir)/'`lib/session.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/session.Tpo $(DEPDIR)/session.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lib/session.c' object='session.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o session.lo `test -f 'lib/session.c' || echo '$(srcdir)/'`lib/session.c + +xml.lo: lib/xml.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xml.lo -MD -MP -MF $(DEPDIR)/xml.Tpo -c -o xml.lo `test -f 'lib/xml.c' || echo '$(srcdir)/'`lib/xml.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/xml.Tpo $(DEPDIR)/xml.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='lib/xml.c' object='xml.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xml.lo `test -f 'lib/xml.c' || echo '$(srcdir)/'`lib/xml.c + +auth_controller.o: controller/auth_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT auth_controller.o -MD -MP -MF $(DEPDIR)/auth_controller.Tpo -c -o auth_controller.o `test -f 'controller/auth_controller.c' || echo '$(srcdir)/'`controller/auth_controller.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/auth_controller.Tpo $(DEPDIR)/auth_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/auth_controller.c' object='auth_controller.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o auth_controller.o `test -f 'controller/auth_controller.c' || echo '$(srcdir)/'`controller/auth_controller.c + +auth_controller.obj: controller/auth_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT auth_controller.obj -MD -MP -MF $(DEPDIR)/auth_controller.Tpo -c -o auth_controller.obj `if test -f 'controller/auth_controller.c'; then $(CYGPATH_W) 'controller/auth_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/auth_controller.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/auth_controller.Tpo $(DEPDIR)/auth_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/auth_controller.c' object='auth_controller.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o auth_controller.obj `if test -f 'controller/auth_controller.c'; then $(CYGPATH_W) 'controller/auth_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/auth_controller.c'; fi` + +status_controller.o: controller/status_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT status_controller.o -MD -MP -MF $(DEPDIR)/status_controller.Tpo -c -o status_controller.o `test -f 'controller/status_controller.c' || echo '$(srcdir)/'`controller/status_controller.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/status_controller.Tpo $(DEPDIR)/status_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/status_controller.c' object='status_controller.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o status_controller.o `test -f 'controller/status_controller.c' || echo '$(srcdir)/'`controller/status_controller.c + +status_controller.obj: controller/status_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT status_controller.obj -MD -MP -MF $(DEPDIR)/status_controller.Tpo -c -o status_controller.obj `if test -f 'controller/status_controller.c'; then $(CYGPATH_W) 'controller/status_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/status_controller.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/status_controller.Tpo $(DEPDIR)/status_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/status_controller.c' object='status_controller.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o status_controller.obj `if test -f 'controller/status_controller.c'; then $(CYGPATH_W) 'controller/status_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/status_controller.c'; fi` + +gateway_controller.o: controller/gateway_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gateway_controller.o -MD -MP -MF $(DEPDIR)/gateway_controller.Tpo -c -o gateway_controller.o `test -f 'controller/gateway_controller.c' || echo '$(srcdir)/'`controller/gateway_controller.c +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/gateway_controller.Tpo $(DEPDIR)/gateway_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/gateway_controller.c' object='gateway_controller.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gateway_controller.o `test -f 'controller/gateway_controller.c' || echo '$(srcdir)/'`controller/gateway_controller.c + +gateway_controller.obj: controller/gateway_controller.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT gateway_controller.obj -MD -MP -MF $(DEPDIR)/gateway_controller.Tpo -c -o gateway_controller.obj `if test -f 'controller/gateway_controller.c'; then $(CYGPATH_W) 'controller/gateway_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/gateway_controller.c'; fi` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/gateway_controller.Tpo $(DEPDIR)/gateway_controller.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='controller/gateway_controller.c' object='gateway_controller.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o gateway_controller.obj `if test -f 'controller/gateway_controller.c'; then $(CYGPATH_W) 'controller/gateway_controller.c'; else $(CYGPATH_W) '$(srcdir)/controller/gateway_controller.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-ipsecDATA: $(ipsec_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" + @list='$(ipsec_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsecDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ + $(ipsecDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsecdir)/$$f"; \ + done + +uninstall-ipsecDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsecdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsecdir)/$$f"; \ + done +install-ipsec_templatesDATA: $(ipsec_templates_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templatesdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templatesdir)" + @list='$(ipsec_templates_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templatesDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templatesdir)/$$f'"; \ + $(ipsec_templatesDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templatesdir)/$$f"; \ + done + +uninstall-ipsec_templatesDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templatesdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templatesdir)/$$f"; \ + done +install-ipsec_templates_authDATA: $(ipsec_templates_auth_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_authdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_authdir)" + @list='$(ipsec_templates_auth_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_authDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_authdir)/$$f'"; \ + $(ipsec_templates_authDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_authdir)/$$f"; \ + done + +uninstall-ipsec_templates_authDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_auth_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_authdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_authdir)/$$f"; \ + done +install-ipsec_templates_gatewayDATA: $(ipsec_templates_gateway_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_gatewaydir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_gatewaydir)" + @list='$(ipsec_templates_gateway_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_gatewayDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_gatewaydir)/$$f'"; \ + $(ipsec_templates_gatewayDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_gatewaydir)/$$f"; \ + done + +uninstall-ipsec_templates_gatewayDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_gateway_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_gatewaydir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_gatewaydir)/$$f"; \ + done +install-ipsec_templates_staticDATA: $(ipsec_templates_static_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_staticdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_staticdir)" + @list='$(ipsec_templates_static_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_staticDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_staticdir)/$$f'"; \ + $(ipsec_templates_staticDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_staticdir)/$$f"; \ + done + +uninstall-ipsec_templates_staticDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_static_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_staticdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_staticdir)/$$f"; \ + done +install-ipsec_templates_statusDATA: $(ipsec_templates_status_DATA) + @$(NORMAL_INSTALL) + test -z "$(ipsec_templates_statusdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsec_templates_statusdir)" + @list='$(ipsec_templates_status_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(ipsec_templates_statusDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(ipsec_templates_statusdir)/$$f'"; \ + $(ipsec_templates_statusDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(ipsec_templates_statusdir)/$$f"; \ + done + +uninstall-ipsec_templates_statusDATA: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_templates_status_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(ipsec_templates_statusdir)/$$f'"; \ + rm -f "$(DESTDIR)$(ipsec_templates_statusdir)/$$f"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(ipsec_templatesdir)" "$(DESTDIR)$(ipsec_templates_authdir)" "$(DESTDIR)$(ipsec_templates_gatewaydir)" "$(DESTDIR)$(ipsec_templates_staticdir)" "$(DESTDIR)$(ipsec_templates_statusdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-ipsecPROGRAMS clean-libLTLIBRARIES \ + clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-ipsecDATA install-ipsecPROGRAMS \ + install-ipsec_templatesDATA install-ipsec_templates_authDATA \ + install-ipsec_templates_gatewayDATA \ + install-ipsec_templates_staticDATA \ + install-ipsec_templates_statusDATA + +install-dvi: install-dvi-am + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ipsecDATA uninstall-ipsecPROGRAMS \ + uninstall-ipsec_templatesDATA \ + uninstall-ipsec_templates_authDATA \ + uninstall-ipsec_templates_gatewayDATA \ + uninstall-ipsec_templates_staticDATA \ + uninstall-ipsec_templates_statusDATA uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-ipsecPROGRAMS clean-libLTLIBRARIES clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-ipsecDATA install-ipsecPROGRAMS \ + install-ipsec_templatesDATA install-ipsec_templates_authDATA \ + install-ipsec_templates_gatewayDATA \ + install-ipsec_templates_staticDATA \ + install-ipsec_templates_statusDATA install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-ipsecDATA uninstall-ipsecPROGRAMS \ + uninstall-ipsec_templatesDATA \ + uninstall-ipsec_templates_authDATA \ + uninstall-ipsec_templates_gatewayDATA \ + uninstall-ipsec_templates_staticDATA \ + uninstall-ipsec_templates_statusDATA uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/manager/controller/auth_controller.c b/src/manager/controller/auth_controller.c new file mode 100644 index 000000000..fd4a3c7a5 --- /dev/null +++ b/src/manager/controller/auth_controller.c @@ -0,0 +1,132 @@ +/** + * @file auth_controller.c + * + * @brief Implementation of auth_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "auth_controller.h" +#include "../manager.h" + +#include <library.h> + + +typedef struct private_auth_controller_t private_auth_controller_t; + +/** + * private data of the task manager + */ +struct private_auth_controller_t { + + /** + * public functions + */ + auth_controller_t public; + + /** + * manager instance + */ + manager_t *manager; +}; + +static void login(private_auth_controller_t *this, request_t *request) +{ + request->set(request, "action", "check"); + request->set(request, "title", "Login"); + request->render(request, "templates/auth/login.cs"); +} + +static void check(private_auth_controller_t *this, request_t *request) +{ + char *username, *password; + + username = request->get_query_data(request, "username"); + password = request->get_query_data(request, "password"); + if (username && password && + this->manager->login(this->manager, username, password)) + { + request->redirect(request, "status/ikesalist"); + } + else + { + request->redirect(request, "auth/login"); + } +} + +static void logout(private_auth_controller_t *this, request_t *request) +{ + this->manager->logout(this->manager); + request->redirect(request, "auth/login"); +} + +/** + * Implementation of controller_t.get_name + */ +static char* get_name(private_auth_controller_t *this) +{ + return "auth"; +} + +/** + * Implementation of controller_t.handle + */ +static void handle(private_auth_controller_t *this, + request_t *request, char *action) +{ + if (action) + { + if (streq(action, "login")) + { + return login(this, request); + } + else if (streq(action, "check")) + { + return check(this, request); + } + else if (streq(action, "logout")) + { + return logout(this, request); + } + } + request->redirect(request, "auth/login"); +} + +/** + * Implementation of controller_t.destroy + */ +static void destroy(private_auth_controller_t *this) +{ + free(this); +} + +/* + * see header file + */ +controller_t *auth_controller_create(context_t *context, void *param) +{ + private_auth_controller_t *this = malloc_thing(private_auth_controller_t); + + this->public.controller.get_name = (char*(*)(controller_t*))get_name; + this->public.controller.handle = (void(*)(controller_t*,request_t*,char*,char*,char*,char*,char*))handle; + this->public.controller.destroy = (void(*)(controller_t*))destroy; + + this->manager = (manager_t*)context; + + return &this->public.controller; +} + diff --git a/src/manager/controller/auth_controller.h b/src/manager/controller/auth_controller.h new file mode 100644 index 000000000..c90546a17 --- /dev/null +++ b/src/manager/controller/auth_controller.h @@ -0,0 +1,47 @@ +/** + * @file auth_controller.h + * + * @brief Interface of auth_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef AUTH_CONTROLLER_H_ +#define AUTH_CONTROLLER_H_ + + +#include <controller.h> + +typedef struct auth_controller_t auth_controller_t; + +/** + * @brief Authentication controller. + */ +struct auth_controller_t { + + /** + * Implements controller_t interface. + */ + controller_t controller; +}; + +/** + * @brief Create a auth_controller controller instance. + */ +controller_t *auth_controller_create(context_t *context, void *param); + +#endif /* AUTH_CONTROLLER_H_ */ diff --git a/src/manager/controller/gateway_controller.c b/src/manager/controller/gateway_controller.c new file mode 100644 index 000000000..bdc779256 --- /dev/null +++ b/src/manager/controller/gateway_controller.c @@ -0,0 +1,148 @@ +/** + * @file gateway_controller.c + * + * @brief Implementation of gateway_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "gateway_controller.h" +#include "../manager.h" +#include "../gateway.h" + +#include <library.h> + + +typedef struct private_gateway_controller_t private_gateway_controller_t; + +/** + * private data of the gateway_controller + */ +struct private_gateway_controller_t { + + /** + * public functions + */ + gateway_controller_t public; + + /** + * manager instance + */ + manager_t *manager; + +}; + +static void list(private_gateway_controller_t *this, request_t *request) +{ + enumerator_t *enumerator; + char *name, *address; + int id, port; + + enumerator = this->manager->create_gateway_enumerator(this->manager); + while (enumerator->enumerate(enumerator, &id, &name, &port, &address)) + { + request->setf(request, "gateways.%d.name=%s", id, name); + if (port) + { + request->setf(request, "gateways.%d.address=tcp://%s:%d", + id, address, port); + } + else + { + request->setf(request, "gateways.%d.address=unix://%s", + id, IPSEC_PIDDIR"/charon.xml"); + } + } + enumerator->destroy(enumerator); + request->set(request, "action", "select"); + request->set(request, "title", "Choose gateway"); + request->render(request, "templates/gateway/list.cs"); +} + +static void _select(private_gateway_controller_t *this, request_t *request) +{ + char *id; + + id = request->get_query_data(request, "gateway"); + if (id) + { + if (this->manager->select_gateway(this->manager, atoi(id))) + { + request->redirect(request, "status/ikesalist"); + return; + } + } + request->redirect(request, "gateway/list"); +} + +/** + * Implementation of controller_t.get_name + */ +static char* get_name(private_gateway_controller_t *this) +{ + return "gateway"; +} + +/** + * Implementation of controller_t.handle + */ +static void handle(private_gateway_controller_t *this, + request_t *request, char *action) +{ + if (!this->manager->logged_in(this->manager)) + { + return request->redirect(request, "auth/login"); + } + if (action) + { + if (streq(action, "list")) + { + return list(this, request); + } + else if (streq(action, "select")) + { + return _select(this, request); + } + } + request->redirect(request, "gateway/list"); +} + + +/** + * Implementation of controller_t.destroy + */ +static void destroy(private_gateway_controller_t *this) +{ + free(this); +} + +/* + * see header file + */ +controller_t *gateway_controller_create(context_t *context, void *param) +{ + private_gateway_controller_t *this = malloc_thing(private_gateway_controller_t); + + this->public.controller.get_name = (char*(*)(controller_t*))get_name; + this->public.controller.handle = (void(*)(controller_t*,request_t*,char*,char*,char*,char*,char*))handle; + this->public.controller.destroy = (void(*)(controller_t*))destroy; + + this->manager = (manager_t*)context; + + return &this->public.controller; +} + diff --git a/src/manager/controller/gateway_controller.h b/src/manager/controller/gateway_controller.h new file mode 100644 index 000000000..5872e20e2 --- /dev/null +++ b/src/manager/controller/gateway_controller.h @@ -0,0 +1,47 @@ +/** + * @file gateway_controller.h + * + * @brief Interface of gateway_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef GATEWAY_CONTROLLER_H_ +#define GATEWAY_CONTROLLER_H_ + + +#include <controller.h> + +typedef struct gateway_controller_t gateway_controller_t; + +/** + * @brief Status controller. + */ +struct gateway_controller_t { + + /** + * Implements controller_t interface. + */ + controller_t controller; +}; + +/** + * @brief Create a gateway_controller controller instance. + */ +controller_t *gateway_controller_create(context_t *context, void *param); + +#endif /* GATEWAY_CONTROLLER_H_ */ diff --git a/src/manager/controller/status_controller.c b/src/manager/controller/status_controller.c new file mode 100644 index 000000000..bcdbd26ea --- /dev/null +++ b/src/manager/controller/status_controller.c @@ -0,0 +1,238 @@ +/** + * @file status_controller.c + * + * @brief Implementation of status_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "status_controller.h" +#include "../manager.h" +#include "../gateway.h" + +#include <xml.h> + +#include <library.h> + + +typedef struct private_status_controller_t private_status_controller_t; + +/** + * private data of the task manager + */ +struct private_status_controller_t { + + /** + * public functions + */ + status_controller_t public; + + /** + * manager instance + */ + manager_t *manager; +}; + +/** + * read XML of a childsa element and fill template + */ +static void process_childsa(private_status_controller_t *this, char *id, + enumerator_t *e, request_t *r) +{ + xml_t *xml; + enumerator_t *e1, *e2; + char *name, *value, *reqid = "", *section = ""; + int num = 0; + + while (e->enumerate(e, &xml, &name, &value)) + { + if (streq(name, "reqid")) + { + reqid = value; + } + else if (streq(name, "local") || streq(name, "remote")) + { + section = name; + e1 = xml->children(xml); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "networks")) + { + e2 = xml->children(xml); + while (e2->enumerate(e2, &xml, &name, &value)) + { + if (streq(name, "network")) + { + r->setf(r, "ikesas.%s.childsas.%s.%s.networks.%d=%s", + id, reqid, section, ++num, value); + } + } + e2->destroy(e2); + } + else + { + r->setf(r, "ikesas.%s.childsas.%s.%s.%s=%s", + id, reqid, section, name, value); + } + } + e1->destroy(e1); + } + else + { + r->setf(r, "ikesas.%s.childsas.%s.%s=%s", + id, reqid, name, value); + } + } +} + +/** + * read XML of a ikesa element and fill template + */ +static void process_ikesa(private_status_controller_t *this, + enumerator_t *e, request_t *r) +{ + xml_t *xml; + enumerator_t *e1, *e2; + char *name, *value, *id = "", *section = ""; + + while (e->enumerate(e, &xml, &name, &value)) + { + if (streq(name, "id")) + { + id = value; + } + else if (streq(name, "local") || streq(name, "remote")) + { + section = name; + e1 = xml->children(xml); + while (e1->enumerate(e1, &xml, &name, &value)) + { + r->setf(r, "ikesas.%s.%s.%s=%s", id, section, name, value); + } + e1->destroy(e1); + } + else if (streq(name, "childsalist")) + { + e1 = xml->children(xml); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "childsa")) + { + e2 = xml->children(xml); + process_childsa(this, id, e2, r); + e2->destroy(e2); + } + } + e1->destroy(e1); + } + else + { + r->setf(r, "ikesas.%s.%s=%s", id, name, value); + } + } +} + +static void ikesalist(private_status_controller_t *this, request_t *r) +{ + gateway_t *gateway; + xml_t *xml; + enumerator_t *e1, *e2; + char *name, *value; + + gateway = this->manager->select_gateway(this->manager, 0); + e1 = gateway->query_ikesalist(gateway); + if (e1 == NULL) + { + r->set(r, "title", "Error"); + r->set(r, "error", "querying the gateway failed"); + r->render(r, "templates/error.cs"); + } + else + { + r->set(r, "title", "IKE SA overview"); + + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "ikesa")) + { + e2 = xml->children(xml); + process_ikesa(this, e2, r); + e2->destroy(e2); + } + } + e1->destroy(e1); + + r->render(r, "templates/status/ikesalist.cs"); + } +} + +/** + * Implementation of controller_t.get_name + */ +static char* get_name(private_status_controller_t *this) +{ + return "status"; +} + +/** + * Implementation of controller_t.handle + */ +static void handle(private_status_controller_t *this, + request_t *request, char *action) +{ + if (!this->manager->logged_in(this->manager)) + { + return request->redirect(request, "auth/login"); + } + if (this->manager->select_gateway(this->manager, 0) == NULL) + { + return request->redirect(request, "gateway/list"); + } + if (action) + { + if (streq(action, "ikesalist")) + { + return ikesalist(this, request); + } + } + return request->redirect(request, "status/ikesalist"); +} + +/** + * Implementation of controller_t.destroy + */ +static void destroy(private_status_controller_t *this) +{ + free(this); +} + +/* + * see header file + */ +controller_t *status_controller_create(context_t *context, void *param) +{ + private_status_controller_t *this = malloc_thing(private_status_controller_t); + + this->public.controller.get_name = (char*(*)(controller_t*))get_name; + this->public.controller.handle = (void(*)(controller_t*,request_t*,char*,char*,char*,char*,char*))handle; + this->public.controller.destroy = (void(*)(controller_t*))destroy; + + this->manager = (manager_t*)context; + + return &this->public.controller; +} + diff --git a/src/manager/controller/status_controller.h b/src/manager/controller/status_controller.h new file mode 100644 index 000000000..a736dda83 --- /dev/null +++ b/src/manager/controller/status_controller.h @@ -0,0 +1,47 @@ +/** + * @file status_controller.h + * + * @brief Interface of status_controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef STATUS_CONTROLLER_H_ +#define STATUS_CONTROLLER_H_ + + +#include <controller.h> + +typedef struct status_controller_t status_controller_t; + +/** + * @brief Status controller. + */ +struct status_controller_t { + + /** + * Implements controller_t interface. + */ + controller_t controller; +}; + +/** + * @brief Create a status_controller controller instance. + */ +controller_t *status_controller_create(context_t *context, void *param); + +#endif /* STATUS_CONTROLLER_H_ */ diff --git a/src/manager/database.c b/src/manager/database.c new file mode 100644 index 000000000..a7776c81e --- /dev/null +++ b/src/manager/database.c @@ -0,0 +1,183 @@ +/** + * @file database.c + * + * @brief Implementation of database_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "database.h" + +#include <sqlite3.h> +#include <library.h> +#include <crypto/hashers/hasher.h> + + +typedef struct private_database_t private_database_t; + +/** + * private data of database + */ +struct private_database_t { + + /** + * public functions + */ + database_t public; + + /** + * SQLite database handle + */ + sqlite3 *db; +}; + +/** + * database enumerator implements enumerator_t + */ +typedef struct { + enumerator_t enumerator; + sqlite3_stmt *stmt; +} db_enumerator_t; + +/** + * destroy a database enumerator + */ +static void db_enumerator_destroy(db_enumerator_t* this) +{ + sqlite3_finalize(this->stmt); + free(this); +} + +/** + * create a database enumerator + */ +static enumerator_t *db_enumerator_create(bool(*enumerate)(db_enumerator_t*,void*,...), + sqlite3_stmt *stmt) +{ + db_enumerator_t *this = malloc_thing(db_enumerator_t); + this->enumerator.enumerate = (void*)enumerate; + this->enumerator.destroy = (void*)db_enumerator_destroy; + this->stmt = stmt; + return &this->enumerator; +} + +/** + * Implementation of database_t.login. + */ +static int login(private_database_t *this, char *username, char *password) +{ + sqlite3_stmt *stmt; + hasher_t *hasher; + chunk_t hash, data; + size_t username_len, password_len; + int uid = 0; + char *str; + + /* hash = SHA1( username | password ) */ + hasher = hasher_create(HASH_SHA1); + hash = chunk_alloca(hasher->get_hash_size(hasher)); + username_len = strlen(username); + password_len = strlen(password); + data = chunk_alloca(username_len + password_len); + memcpy(data.ptr, username, username_len); + memcpy(data.ptr + username_len, password, password_len); + hasher->get_hash(hasher, data, hash.ptr); + hasher->destroy(hasher); + str = chunk_to_hex(hash, FALSE); + + if (sqlite3_prepare_v2(this->db, + "SELECT oid FROM users WHERE username = ? AND password = ?;", + -1, &stmt, NULL) == SQLITE_OK) + { + if (sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC) == SQLITE_OK && + sqlite3_bind_text(stmt, 2, str, -1, SQLITE_STATIC) == SQLITE_OK && + sqlite3_step(stmt) == SQLITE_ROW) + { + uid = sqlite3_column_int(stmt, 0); + } + sqlite3_finalize(stmt); + } + free(str); + return uid; +} + +/** + * enumerate function for gateway enumrator + */ +static bool gateway_enumerate(db_enumerator_t* e, int *id, const char **name, + int *port, const char **address) +{ + if (sqlite3_step(e->stmt) == SQLITE_ROW) + { + *id = sqlite3_column_int(e->stmt, 0); + *name = sqlite3_column_text(e->stmt, 1); + *port = sqlite3_column_int(e->stmt, 2); + *address = sqlite3_column_text(e->stmt, 3); + return TRUE; + } + return FALSE; +} + +/** + * Implementation of database_t.create_gateway_enumerator. + */ +static enumerator_t* create_gateway_enumerator(private_database_t *this, int user) +{ + sqlite3_stmt *stmt; + + if (sqlite3_prepare_v2(this->db, + "SELECT gateways.oid AS gid, name, port, address FROM " + "gateways, user_gateway AS ug ON gid = ug.gateway WHERE ug.user = ?;", + -1, &stmt, NULL) == SQLITE_OK) + { + if (sqlite3_bind_int(stmt, 1, user) == SQLITE_OK) + { + return db_enumerator_create((void*)gateway_enumerate, stmt); + } + sqlite3_finalize(stmt); + } + return enumerator_create_empty(); +} + +/** + * Implementation of database_t.destroy + */ +static void destroy(private_database_t *this) +{ + sqlite3_close(this->db); + free(this); +} + +/* + * see header file + */ +database_t *database_create(char *dbfile) +{ + private_database_t *this = malloc_thing(private_database_t); + + this->public.login = (int(*)(database_t*, char *username, char *password))login; + this->public.create_gateway_enumerator = (enumerator_t*(*)(database_t*,int))create_gateway_enumerator; + this->public.destroy = (void(*)(database_t*))destroy; + + if (sqlite3_open(dbfile, &this->db) != SQLITE_OK) + { + destroy(this); + return NULL; + } + return &this->public; +} + diff --git a/src/manager/database.h b/src/manager/database.h new file mode 100644 index 000000000..228d1cb22 --- /dev/null +++ b/src/manager/database.h @@ -0,0 +1,69 @@ +/** + * @file database.h + * + * @brief Interface of database_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef DATABASE_H_ +#define DATABASE_H_ + +#include <utils/enumerator.h> + + +typedef struct database_t database_t; + +/** + * @brief Persistent database. + */ +struct database_t { + + /** + * @brief Try to log in using specified credentials. + * + * @param username username + * @param password plaintext password + * @return user ID if login good, 0 otherwise + */ + int (*login)(database_t *this, char *username, char *password); + + /** + * @brief Create an iterator over the gateways. + * + * enumerate() arguments: int id, char *name, int port, char *address + * If port is 0, address is a Unix socket address. + * + * @param user user Id + * @return enumerator + */ + enumerator_t* (*create_gateway_enumerator)(database_t *this, int user); + + /** + * @brief Destroy a database instance. + */ + void (*destroy)(database_t *this); +}; + +/** + * @brief Create a database instance. + * + * @param dbfile SQLite database file + */ +database_t *database_create(char *dbfile); + +#endif /* DATABASE_H_ */ diff --git a/src/manager/gateway.c b/src/manager/gateway.c new file mode 100644 index 000000000..5f5a4b477 --- /dev/null +++ b/src/manager/gateway.c @@ -0,0 +1,253 @@ +/** + * @file gateway.c + * + * @brief Implementation of gateway_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "gateway.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <lib/xml.h> + +typedef struct private_gateway_t private_gateway_t; + +/** + * private data of gateway + */ +struct private_gateway_t { + + /** + * public functions + */ + gateway_t public; + + /** + * name of the gateway + */ + char *name; + + /** + * host to connect using tcp + */ + host_t *host; + + /** + * socket file descriptor, > 0 if connected + */ + int fd; +}; + +struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"}; + +/** + * establish connection to gateway + */ +static bool connect_(private_gateway_t *this) +{ + int family, len; + struct sockaddr *addr; + + if (this->fd >= 0) + { + close(this->fd); + } + if (this->host) + { + family = AF_INET; + addr = this->host->get_sockaddr(this->host); + len = *this->host->get_sockaddr_len(this->host); + } + else + { + family = AF_UNIX; + addr = (struct sockaddr*)&unix_addr; + len = sizeof(unix_addr); + } + + this->fd = socket(family, SOCK_STREAM, 0); + if (this->fd < 0) + { + return FALSE; + } + if (connect(this->fd, addr, len) != 0) + { + close(this->fd); + this->fd = -1; + return FALSE; + } + return TRUE; +} + +/** + * Implementation of gateway_t.request. + */ +static char* request(private_gateway_t *this, char *xml) +{ + if (this->fd < 0) + { + if (!connect_(this)) + { + return NULL; + } + } + while (TRUE) + { + char buf[8096]; + ssize_t len; + + len = strlen(xml); + if (send(this->fd, xml, len, 0) != len) + { + return NULL; + } + len = recv(this->fd, buf, sizeof(buf) - 1, 0); + if (len < 0) + { + return NULL; + } + if (len == 0) + { + if (!connect_(this)) + { + return NULL; + } + continue; + } + buf[len] = 0; + return strdup(buf); + } +} + +/** + * Implementation of gateway_t.query_ikesalist. + */ +static enumerator_t* query_ikesalist(private_gateway_t *this) +{ + char *str, *name, *value; + xml_t *xml; + enumerator_t *e1, *e2, *e3, *e4 = NULL; + + str = request(this, "<message type=\"request\" id=\"1\">" + "<query>" + "<ikesalist/>" + "</query>" + "</message>"); + if (str == NULL) + { + return NULL; + } + xml = xml_create(str); + if (xml == NULL) + { + return NULL; + } + + e1 = xml->children(xml); + free(str); + while (e1->enumerate(e1, &xml, &name, &value)) + { + if (streq(name, "message")) + { + e2 = xml->children(xml); + while (e2->enumerate(e2, &xml, &name, &value)) + { + if (streq(name, "query")) + { + e3 = xml->children(xml); + while (e3->enumerate(e3, &xml, &name, &value)) + { + if (streq(name, "ikesalist")) + { + e4 = xml->children(xml); + e1->destroy(e1); + e2->destroy(e2); + e3->destroy(e3); + return e4; + } + } + e3->destroy(e3); + } + } + e2->destroy(e2); + } + } + e1->destroy(e1); + return NULL; +} + +/** + * Implementation of gateway_t.destroy + */ +static void destroy(private_gateway_t *this) +{ + if (this->fd >= 0) + { + close(this->fd); + } + if (this->host) this->host->destroy(this->host); + free(this->name); + free(this); +} + +/** + * generic constructor + */ +static private_gateway_t *gateway_create(char *name) +{ + private_gateway_t *this = malloc_thing(private_gateway_t); + + this->public.request = (char*(*)(gateway_t*, char *xml))request; + this->public.query_ikesalist = (enumerator_t*(*)(gateway_t*))query_ikesalist; + this->public.destroy = (void(*)(gateway_t*))destroy; + + this->name = strdup(name); + this->host = NULL; + this->fd = -1; + + return this; +} + +/** + * see header + */ +gateway_t *gateway_create_tcp(char *name, host_t *host) +{ + private_gateway_t *this = gateway_create(name); + + this->host = host; + + return &this->public; +} + +/** + * see header + */ +gateway_t *gateway_create_unix(char *name) +{ + private_gateway_t *this = gateway_create(name); + + return &this->public; +} + diff --git a/src/manager/gateway.h b/src/manager/gateway.h new file mode 100644 index 000000000..1fe2aef4b --- /dev/null +++ b/src/manager/gateway.h @@ -0,0 +1,74 @@ +/** + * @file gateway.h + * + * @brief Interface of gateway_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef GATEWAY_H_ +#define GATEWAY_H_ + +#include <utils/host.h> +#include <utils/enumerator.h> + +typedef struct gateway_t gateway_t; + +/** + * @brief A connection to a gateway. + */ +struct gateway_t { + + /** + * @brief Send an XML request to the gateway. + * + * @param xml xml request string + * @return allocated xml response string + */ + char* (*request)(gateway_t *this, char *xml); + + /** + * @brief Query the list of IKE_SAs and all its children. + * + * @return enumerator over ikesa XML elements + */ + enumerator_t* (*query_ikesalist)(gateway_t *this); + + /** + * @brief Destroy a gateway instance. + */ + void (*destroy)(gateway_t *this); +}; + +/** + * @brief Create a gateway instance using a TCP connection. + * + * @param name name of the gateway + * @param host gateway connection endpoint + * @param + */ +gateway_t *gateway_create_tcp(char *name, host_t *host); + +/** + * @brief Create a gateway instance using a UNIX socket. + * + * @param name name of the gateway + * @param + */ +gateway_t *gateway_create_unix(char *name); + +#endif /* GATEWAY_H_ */ diff --git a/src/manager/lib/context.h b/src/manager/lib/context.h new file mode 100644 index 000000000..23c979b8e --- /dev/null +++ b/src/manager/lib/context.h @@ -0,0 +1,47 @@ +/** + * @file context.h + * + * @brief Interface of context_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef CONTEXT_H_ +#define CONTEXT_H_ + +typedef struct context_t context_t; + +/** + * @brief Constructor function for a context + */ +typedef context_t *(*context_constructor_t)(void *param); + +/** + * @brief Custom session context + * + */ +struct context_t { + + /** + * @brief Destroy the context_t. + * + * @param this calling object + */ + void (*destroy) (context_t *this); +}; + +#endif /* CONTEXT_H_ */ diff --git a/src/manager/lib/controller.h b/src/manager/lib/controller.h new file mode 100644 index 000000000..5b39f559c --- /dev/null +++ b/src/manager/lib/controller.h @@ -0,0 +1,84 @@ +/** + * @file controller.h + * + * @brief Interface controller_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef CONTROLLER_H_ +#define CONTROLLER_H_ + +#include "request.h" +#include "context.h" + +typedef struct controller_t controller_t; + +/** + * @brief Controller action handle function + * + * @param request http request + * @param response http response + */ +typedef void *(*controller_handler_t)(controller_t *this, request_t *request); + +/** + * @brief Constructor function for a controller + * + * @param context session specific context + * @param param user supplied param + */ +typedef controller_t *(*controller_constructor_t)(context_t* context, void *param); + +/** + * @brief Controller interface, to be implemented by users controllers. + * + */ +struct controller_t { + + /** + * @brief Get the name of the controller. + * + * @return name of the controller + */ + char* (*get_name)(controller_t *this); + + /** + * @brief Handle a HTTP request for that controller. + * + * Request URLs are parsed in the form + * controller_name/p1/p2/p3/p4/p5 with a maximum of 5 parameters. Each + * parameter not found in the request URL is set to NULL. + * + * @param request HTTP request + * @param p1 first parameter + * @param p2 second parameter + * @param p3 third parameter + * @param p4 forth parameter + * @param p5 fifth parameter + * @return + */ + void (*handle)(controller_t *this, request_t *request, + char *a1, char *a2, char *a3, char *a4, char *a5); + + /** + * @brief Destroy the controller instance. + */ + void (*destroy) (controller_t *this); +}; + +#endif /* CONTROLLER_H_ */ diff --git a/src/manager/lib/dispatcher.c b/src/manager/lib/dispatcher.c new file mode 100644 index 000000000..df669ceb6 --- /dev/null +++ b/src/manager/lib/dispatcher.c @@ -0,0 +1,402 @@ +/** + * @file dispatcher.c + * + * @brief Implementation of dispatcher_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "dispatcher.h" + +#include "request.h" +#include "session.h" + +#include <fcgiapp.h> +#include <pthread.h> +#include <signal.h> +#include <unistd.h> + +#include <utils/linked_list.h> + +typedef struct private_dispatcher_t private_dispatcher_t; + +/** + * private data of the task manager + */ +struct private_dispatcher_t { + + /** + * public functions + */ + dispatcher_t public; + + /** + * fcgi socket fd + */ + int fd; + + /** + * thread list + */ + pthread_t *threads; + + /** + * number of threads in "threads" + */ + int thread_count; + + /** + * session locking mutex + */ + pthread_mutex_t mutex; + + /** + * List of sessions + */ + linked_list_t *sessions; + + /** + * session timeout + */ + time_t timeout; + + /** + * List of controllers controller_constructor_t + */ + linked_list_t *controllers; + + /** + * constructor function to create session context (in constructor_entry_t) + */ + context_constructor_t context_constructor; + + /** + * user param to context constructor + */ + void *param; + + /** + * thread specific initialization handler + */ + void (*init)(void *param); + + /** + * argument to pass to thread intiializer + */ + void *init_param; + + /** + * thread specific deinitialization handler + */ + void (*deinit)(void *param); + + /** + * param tho thread specific deinitialization handler + */ + void *deinit_param; +}; + +typedef struct { + /** constructor function */ + controller_constructor_t constructor; + /** parameter to constructor */ + void *param; +} constructor_entry_t; + +typedef struct { + /** session instance */ + session_t *session; + /** condvar to wait for session */ + pthread_cond_t cond; + /** number of threads waiting for session */ + int waiting; + /** last use of the session */ + time_t used; +} session_entry_t; + +/** + * create a session and instanciate controllers + */ +static session_t* load_session(private_dispatcher_t *this) +{ + iterator_t *iterator; + constructor_entry_t *entry; + session_t *session; + context_t *context = NULL; + controller_t *controller; + + if (this->context_constructor) + { + context = this->context_constructor(this->param); + } + session = session_create(context); + + iterator = this->controllers->create_iterator(this->controllers, TRUE); + while (iterator->iterate(iterator, (void**)&entry)) + { + controller = entry->constructor(context, entry->param); + session->add_controller(session, controller); + } + iterator->destroy(iterator); + + return session; +} + +/** + * create a new session entry + */ +static session_entry_t *session_entry_create(private_dispatcher_t *this) +{ + session_entry_t *entry; + + entry = malloc_thing(session_entry_t); + entry->waiting = 1; + pthread_cond_init(&entry->cond, NULL); + entry->session = load_session(this); + entry->used = time(NULL); + + return entry; +} + +static void session_entry_destroy(session_entry_t *entry) +{ + entry->session->destroy(entry->session); + free(entry); +} + +/** + * Implementation of dispatcher_t.add_controller. + */ +static void add_controller(private_dispatcher_t *this, + controller_constructor_t constructor, void *param) +{ + constructor_entry_t *entry = malloc_thing(constructor_entry_t); + + entry->constructor = constructor; + entry->param = param; + this->controllers->insert_last(this->controllers, entry); +} + +/** + * Actual dispatching code + */ +static void dispatch(private_dispatcher_t *this) +{ + FCGX_Request fcgi_req; + + if (FCGX_InitRequest(&fcgi_req, this->fd, 0) == 0) + { + while (TRUE) + { + request_t *request; + session_entry_t *current, *found = NULL; + iterator_t *iterator; + time_t now; + char *sid; + int accepted; + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + accepted = FCGX_Accept_r(&fcgi_req); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + if (accepted != 0) + { + break; + } + + /* prepare */ + request = request_create(&fcgi_req, TRUE); + if (request == NULL) + { + continue; + } + sid = request->get_cookie(request, "SID"); + now = time(NULL); + + /* find session */ + iterator = this->sessions->create_iterator_locked(this->sessions, &this->mutex); + while (iterator->iterate(iterator, (void**)¤t)) + { + /* check all sessions for timeout */ + if (current->waiting == 0 && + current->used < now - this->timeout) + { + iterator->remove(iterator); + session_entry_destroy(current); + continue; + } + if (!found && sid && + streq(current->session->get_sid(current->session), sid)) + { + found = current; + found->waiting++; + } + } + iterator->destroy(iterator); + + if (found) + { /* wait until session is unused */ + pthread_mutex_lock(&this->mutex); + while (found->waiting > 1) + { + pthread_cond_wait(&found->cond, &this->mutex); + } + pthread_mutex_unlock(&this->mutex); + } + else + { /* create a new session if not found */ + found = session_entry_create(this); + pthread_mutex_lock(&this->mutex); + this->sessions->insert_first(this->sessions, found); + pthread_mutex_unlock(&this->mutex); + } + + /* start processing */ + found->session->process(found->session, request); + found->used = time(NULL); + + /* release session */ + pthread_mutex_lock(&this->mutex); + found->waiting--; + pthread_cond_signal(&found->cond); + pthread_mutex_unlock(&this->mutex); + + /* cleanup */ + request->destroy(request); + + /* + FCGX_FPrintF(fcgi_req.out, "<ul>"); + char **env = fcgi_req.envp; + while (*env) + { + FCGX_FPrintF(fcgi_req.out, "<li>%s</li>", *env); + env++; + } + FCGX_FPrintF(fcgi_req.out, "</ul>"); + */ + } + } +} + +/** + * Setup thread and start dispatching + */ +static void start_dispatching(private_dispatcher_t *this) +{ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + if (this->init) + { + this->init(this->init_param); + } + if (this->deinit) + { + pthread_cleanup_push(this->deinit, this->deinit_param); + dispatch(this); + pthread_cleanup_pop(1); + } + else + { + dispatch(this); + } +} + +/** + * Implementation of dispatcher_t.run. + */ +static void run(private_dispatcher_t *this, int threads, + void(*init)(void *param), void *init_param, + void(*deinit)(void *param), void *deinit_param) +{ + this->init = init; + this->init_param = init_param; + this->deinit = deinit; + this->deinit_param = deinit_param; + this->thread_count = threads; + this->threads = malloc(sizeof(pthread_t) * threads); + while (threads) + { + if (pthread_create(&this->threads[threads - 1], + NULL, (void*)start_dispatching, this) == 0) + { + threads--; + } + } +} + +/** + * Implementation of dispatcher_t.waitsignal. + */ +static void waitsignal(private_dispatcher_t *this) +{ + sigset_t set; + int sig; + + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); + sigprocmask(SIG_BLOCK, &set, NULL); + sigwait(&set, &sig); +} + +/** + * Implementation of dispatcher_t.destroy + */ +static void destroy(private_dispatcher_t *this) +{ + FCGX_ShutdownPending(); + while (this->thread_count--) + { + pthread_cancel(this->threads[this->thread_count]); + pthread_join(this->threads[this->thread_count], NULL); + } + this->sessions->destroy_function(this->sessions, (void*)session_entry_destroy); + this->controllers->destroy_function(this->controllers, free); + free(this); +} + +/* + * see header file + */ +dispatcher_t *dispatcher_create(char *socket, int timeout, + context_constructor_t constructor, void *param) +{ + private_dispatcher_t *this = malloc_thing(private_dispatcher_t); + + this->public.add_controller = (void(*)(dispatcher_t*, controller_constructor_t, void*))add_controller; + this->public.run = (void(*)(dispatcher_t*, int threads,void(*)(void *),void *,void(*)(void *),void *))run; + this->public.waitsignal = (void(*)(dispatcher_t*))waitsignal; + this->public.destroy = (void(*)(dispatcher_t*))destroy; + + this->sessions = linked_list_create(); + this->controllers = linked_list_create(); + this->context_constructor = constructor; + pthread_mutex_init(&this->mutex, NULL); + this->param = param; + this->fd = 0; + this->timeout = timeout; + + FCGX_Init(); + + if (socket) + { + unlink(socket); + this->fd = FCGX_OpenSocket(socket, 10); + } + return &this->public; +} + diff --git a/src/manager/lib/dispatcher.h b/src/manager/lib/dispatcher.h new file mode 100644 index 000000000..274837838 --- /dev/null +++ b/src/manager/lib/dispatcher.h @@ -0,0 +1,95 @@ +/** + * @file dispatcher.h + * + * @brief Interface of dispatcher_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef DISPATCHER_H_ +#define DISPATCHER_H_ + +#include "controller.h" + +typedef struct dispatcher_t dispatcher_t; + +/** + * @brief Dispatcher, accepts connections using multiple threads. + * + * The dispatcher creates a session for each client (using SID cookies). In + * each session, a session context is created using the context constructor. + * Each controller is instanciated in the session using the controller + * constructor added with add_controller. + */ +struct dispatcher_t { + + /** + * @brief Register a controller to the dispatcher. + * + * The first controller added serves as default controller. Client's + * get redirected to it if no other controller matches. + * + * @param constructor constructor function to the conntroller + * @param param param to pass to constructor + */ + void (*add_controller)(dispatcher_t *this, + controller_constructor_t constructor, void *param); + + /** + * @brief Start with dispatching. + * + * It may be necessary to call per-thread initialization functions. + * If init is not NULL, the handler is called right after thread + * creation (by the created thread) and the deinit function is called + * before the thread gets destroyed (again by the thread itself). + * + * @param thread number of dispatching threads + * @param init thread specific initialization function, or NULL + * @param init_param param to pass to init function + * @param deinit thread dpecific deinitialization function, or NULL + * @param deinit_param param to pass to deinit function + */ + void (*run)(dispatcher_t *this, int threads, + void(*init)(void *param), void *init_param, + void(*deinit)(void *param), void *deinit_param); + + /** + * @brief Wait for a relevant signal action. + */ + void (*waitsignal)(dispatcher_t *this); + + /** + * @brief Destroy the dispatcher_t. + */ + void (*destroy) (dispatcher_t *this); +}; + +/** + * @brief Create a dispatcher. + * + * The context constructor is invoked to create a session context for + * each session. + * + * @param socket FastCGI socket path, NULL for dynamic + * @param timeout session timeout + * @param constructor construction function for session context + * @param param parameter to supply to context constructor + */ +dispatcher_t *dispatcher_create(char *socket, int timeout, + context_constructor_t constructor, void *param); + +#endif /* DISPATCHER_H_ */ diff --git a/src/manager/lib/request.c b/src/manager/lib/request.c new file mode 100644 index 000000000..4623b3860 --- /dev/null +++ b/src/manager/lib/request.c @@ -0,0 +1,305 @@ +/** + * @file request.c + * + * @brief Implementation of request_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#define _GNU_SOURCE + +#include "request.h" + +#include <library.h> +#include <stdlib.h> +#include <string.h> +#include <ClearSilver/ClearSilver.h> + +typedef struct private_request_t private_request_t; + +/** + * private data of the task manager + */ +struct private_request_t { + + /** + * public functions + */ + request_t public; + + /** + * FastCGI request object + */ + FCGX_Request *req; + + /** + * ClearSilver CGI Kit context + */ + CGI *cgi; + + /** + * ClearSilver HDF dataset for this request + */ + HDF *hdf; +}; + +/** + * thread specific FCGX_Request, used for ClearSilver cgiwrap callbacks. + * ClearSilver cgiwrap is not threadsave, so we use a private + * context for each thread. + */ +static __thread FCGX_Request *req; + +/** + * length of param list in req->envp + */ +static __thread int req_env_len; + +/** + * fcgiwrap read callback + */ +static int read_cb(void *null, char *buf, int size) +{ + return FCGX_GetStr(buf, size, req->in); +} + +/** + * fcgiwrap writef callback + */ +static int writef_cb(void *null, const char *format, va_list args) +{ + FCGX_VFPrintF(req->out, format, args); + return 0; +} +/** + * fcgiwrap write callback + */ +static int write_cb(void *null, const char *buf, int size) +{ + return FCGX_PutStr(buf, size, req->out); +} + +/** + * fcgiwrap getenv callback + */ +static char *getenv_cb(void *null, const char *key) +{ + char *value; + + value = FCGX_GetParam(key, req->envp); + return value ? strdup(value) : NULL; +} + +/** + * fcgiwrap getenv callback + */ +static int putenv_cb(void *null, const char *key, const char *value) +{ + /* not supported */ + return 1; +} + +/** + * fcgiwrap iterenv callback + */ +static int iterenv_cb(void *null, int num, char **key, char **value) +{ + *key = NULL; + *value = NULL; + + if (num < req_env_len) + { + char *eq; + + eq = strchr(req->envp[num], '='); + if (eq) + { + *key = strndup(req->envp[num], eq - req->envp[num]); + *value = strdup(eq + 1); + } + if (*key == NULL || *value == NULL) + { + free(*key); + free(*value); + return 1; + } + } + return 0; +} + +/** + * Implementation of request_t.get_cookie. + */ +static char* get_cookie(private_request_t *this, char *name) +{ + return hdf_get_valuef(this->hdf, "Cookie.%s", name); +} + +/** + * Implementation of request_t.get_path. + */ +static char* get_path(private_request_t *this) +{ + char * path = FCGX_GetParam("PATH_INFO", this->req->envp); + return path ? path : ""; +} + +/** + * Implementation of request_t.get_post_data. + */ +static char* get_query_data(private_request_t *this, char *name) +{ + return hdf_get_valuef(this->hdf, "Query.%s", name); +} + +/** + * Implementation of request_t.add_cookie. + */ +static void add_cookie(private_request_t *this, char *name, char *value) +{ + cgi_cookie_set (this->cgi, name, value, + FCGX_GetParam("SCRIPT_NAME", this->req->envp), + NULL, NULL, 0, 0); +} + +/** + * Implementation of request_t.redirect. + */ +static void redirect(private_request_t *this, char *location) +{ + FCGX_FPrintF(this->req->out, "Status: 303 See Other\n"); + FCGX_FPrintF(this->req->out, "Location: %s%s%s\n\n", + FCGX_GetParam("SCRIPT_NAME", this->req->envp), + *location == '/' ? "" : "/", location); +} + +/** + * Implementation of request_t.get_base. + */ +static char* get_base(private_request_t *this) +{ + return FCGX_GetParam("SCRIPT_NAME", this->req->envp); +} + +/** + * Implementation of request_t.render. + */ +static void render(private_request_t *this, char *template) +{ + NEOERR* err; + + err = cgi_display(this->cgi, template); + if (err) + { + cgi_neo_error(this->cgi, err); + nerr_log_error(err); + } + return; +} + +/** + * Implementation of request_t.set. + */ +static void set(private_request_t *this, char *key, char *value) +{ + hdf_set_value(this->hdf, key, value); +} + +/** + * Implementation of request_t.setf. + */ +static void setf(private_request_t *this, char *format, ...) +{ + va_list args; + + va_start(args, format); + hdf_set_valuevf(this->hdf, format, args); + va_end(args); +} + +/** + * Implementation of request_t.destroy + */ +static void destroy(private_request_t *this) +{ + cgi_destroy(&this->cgi); + free(this); +} + +/* + * see header file + */ +request_t *request_create(FCGX_Request *request, bool debug) +{ + NEOERR* err; + static bool initialized = FALSE; + private_request_t *this = malloc_thing(private_request_t); + + this->public.get_path = (char*(*)(request_t*))get_path; + this->public.get_base = (char*(*)(request_t*))get_base; + this->public.add_cookie = (void(*)(request_t*, char *name, char *value))add_cookie; + this->public.get_cookie = (char*(*)(request_t*,char*))get_cookie; + this->public.get_query_data = (char*(*)(request_t*, char *name))get_query_data; + this->public.redirect = (void(*)(request_t*, char *location))redirect; + this->public.render = (void(*)(request_t*,char*))render; + this->public.set = (void(*)(request_t*, char *, char*))set; + this->public.setf = (void(*)(request_t*, char *format, ...))setf; + this->public.destroy = (void(*)(request_t*))destroy; + + if (!initialized) + { + cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb, + getenv_cb, putenv_cb, iterenv_cb); + initialized = TRUE; + } + + this->req = request; + req = request; + req_env_len = 0; + while (req->envp[req_env_len] != NULL) + { + req_env_len++; + } + + err = hdf_init(&this->hdf); + if (!err) + { + hdf_set_value(this->hdf, "base", get_base(this)); + hdf_set_value(this->hdf, "Config.NoCache", "true"); + if (!debug) + { + hdf_set_value(this->hdf, "Config.TimeFooter", "0"); + hdf_set_value(this->hdf, "Config.CompressionEnabled", "1"); + hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2"); + } + + err = cgi_init(&this->cgi, this->hdf); + if (!err) + { + err = cgi_parse(this->cgi); + if (!err) + { + return &this->public; + } + cgi_destroy(&this->cgi); + } + } + nerr_log_error(err); + free(this); + return NULL; +} + diff --git a/src/manager/lib/request.h b/src/manager/lib/request.h new file mode 100644 index 000000000..e6fd71e71 --- /dev/null +++ b/src/manager/lib/request.h @@ -0,0 +1,127 @@ +/** + * @file request.h + * + * @brief Interface of request_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef REQUEST_H_ +#define REQUEST_H_ + +#include <fcgiapp.h> +#include <library.h> + +typedef struct request_t request_t; + +/** + * @brief A HTTP request, encapsulates FCGX_Request. + * + */ +struct request_t { + + /** + * @brief Add a cookie to the reply (Set-Cookie header). + * + * @param name name of the cookie to set + * @param value value of the cookie + */ + void (*add_cookie)(request_t *this, char *name, char *value); + + /** + * @brief Get a cookie the client sent in the request. + * + * @param name name of the cookie + * @return cookie value, NULL if no such cookie found + */ + char* (*get_cookie)(request_t *this, char *name); + + /** + * @brief Get the request path relative to the application. + * + * @return path + */ + char* (*get_path)(request_t *this); + + /** + * @brief Get the base path of the application. + * + * @return base path + */ + char* (*get_base)(request_t *this); + + /** + * @brief Get a post/get variable included in the request. + * + * @param name name of the POST/GET variable + * @return value, NULL if not found + */ + char* (*get_query_data)(request_t *this, char *name); + + /** + * @brief Redirect the client to another location. + * + * @param location location to redirect to + */ + void (*redirect)(request_t *this, char *location); + + /** + * @brief Set a template value. + * + * @param key key to set + * @param value value to set key to + */ + void (*set)(request_t *this, char *key, char *value); + + /** + * @brief Set a template value using format strings. + * + * Format string is in the form "key=value", where printf like format + * substitution occurs over the whole string. + * + * @param format printf like format string + * @param ... variable argument list + */ + void (*setf)(request_t *this, char *format, ...); + + /** + * @brief Render a template. + * + * The render() function additionally sets a HDF variable "base" + * which points to the root of the web application and allows to point to + * other targets without to worry about path location. + * + * @param template clearsilver template file location + * @return rendered template string + */ + void (*render)(request_t *this, char *template); + + /** + * @brief Destroy the request_t. + */ + void (*destroy) (request_t *this); +}; + +/** + * @brief Create a request from the fastcgi struct. + * + * @param request the FCGI request + * @param debug no stripping, no compression, timing information + */ +request_t *request_create(FCGX_Request *request, bool debug); + +#endif /* REQUEST_H_ */ diff --git a/src/manager/lib/session.c b/src/manager/lib/session.c new file mode 100644 index 000000000..fe260b887 --- /dev/null +++ b/src/manager/lib/session.c @@ -0,0 +1,175 @@ +/** + * @file session.c + * + * @brief Implementation of session_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#define _GNU_SOURCE + +#include "session.h" + +#include <string.h> +#include <fcgiapp.h> +#include <stdio.h> + +#include <utils/linked_list.h> +#include <utils/randomizer.h> + +typedef struct private_session_t private_session_t; + +/** + * private data of the task manager + */ +struct private_session_t { + + /** + * public functions + */ + session_t public; + + /** + * session ID + */ + char *sid; + + /** + * list of controller instances controller_t + */ + linked_list_t *controllers; + + /** + * user defined session context + */ + context_t *context; +}; + +/** + * Implementation of session_t.load_controller. + */ +static void add_controller(private_session_t *this, controller_t *controller) +{ + this->controllers->insert_last(this->controllers, controller); +} + +/** + * Create a session ID and a cookie + */ +static void create_sid(private_session_t *this, request_t *request) +{ + char buf[16]; + chunk_t chunk = chunk_from_buf(buf); + randomizer_t *randomizer = randomizer_create(); + + randomizer->get_pseudo_random_bytes(randomizer, sizeof(buf), buf); + this->sid = chunk_to_hex(chunk, FALSE); + request->add_cookie(request, "SID", this->sid); + randomizer->destroy(randomizer); +} + +/** + * Implementation of session_t.process. + */ +static void process(private_session_t *this, request_t *request) +{ + char *pos, *start, *param[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; + iterator_t *iterator; + bool handled = FALSE; + controller_t *current; + int i = 0; + + if (this->sid == NULL) + { + create_sid(this, request); + } + + start = request->get_path(request); + if (start) + { + if (*start == '/') start++; + while ((pos = strchr(start, '/')) != NULL && i < 5) + { + param[i++] = strndup(start, pos - start); + start = pos + 1; + } + param[i] = strdup(start); + iterator = this->controllers->create_iterator(this->controllers, TRUE); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (streq(current->get_name(current), param[0])) + { + current->handle(current, request, param[1], param[2], param[3], + param[4], param[5]); + handled = TRUE; + break; + } + } + iterator->destroy(iterator); + for (i = 0; i < 6; i++) + { + free(param[i]); + } + } + if (!handled) + { + if (this->controllers->get_first(this->controllers, + (void**)¤t) == SUCCESS) + { + request->redirect(request, current->get_name(current)); + } + } +} + +/** + * Implementation of session_t.get_sid. + */ +static char* get_sid(private_session_t *this) +{ + return this->sid; +} + +/** + * Implementation of session_t.destroy + */ +static void destroy(private_session_t *this) +{ + this->controllers->destroy_offset(this->controllers, offsetof(controller_t, destroy)); + if (this->context) this->context->destroy(this->context); + free(this->sid); + free(this); +} + +/* + * see header file + */ +session_t *session_create(context_t *context) +{ + private_session_t *this = malloc_thing(private_session_t); + + this->public.add_controller = (void(*)(session_t*, controller_t*))add_controller; + this->public.process = (void(*)(session_t*,request_t*))process; + this->public.get_sid = (char*(*)(session_t*))get_sid; + this->public.destroy = (void(*)(session_t*))destroy; + + this->sid = NULL; + this->controllers = linked_list_create(); + this->context = context; + + return &this->public; +} + diff --git a/src/manager/lib/session.h b/src/manager/lib/session.h new file mode 100644 index 000000000..d18545876 --- /dev/null +++ b/src/manager/lib/session.h @@ -0,0 +1,73 @@ +/** + * @file session.h + * + * @brief Interface of session_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef SESSION_H_ +#define SESSION_H_ + +#include "request.h" +#include "controller.h" + +typedef struct session_t session_t; + +/** + * @brief A session, identified by a session ID. + * + */ +struct session_t { + + /** + * @brief Get the session ID of the session. + * + * @return session ID + */ + char* (*get_sid)(session_t *this); + + /** + * @brief Add a controller instance to the session. + * + * @param controller controller to add + */ + void (*add_controller)(session_t *this, controller_t *controller); + + /** + * @brief Process a request in this session. + * + * @param request request to process + */ + void (*process)(session_t *this, request_t *request); + + /** + * @brief Destroy the session_t. + * + * @param this calling object + */ + void (*destroy) (session_t *this); +}; + +/** + * @brief Create a session. + * + * @param context user defined session context instance + */ +session_t *session_create(context_t *context); + +#endif /* SESSION_H_ */ diff --git a/src/manager/lib/xml.c b/src/manager/lib/xml.c new file mode 100644 index 000000000..008235b69 --- /dev/null +++ b/src/manager/lib/xml.c @@ -0,0 +1,169 @@ +/** + * @file xml.c + * + * @brief Implementation of xml_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "xml.h" + +#include <libxml/parser.h> +#include <libxml/tree.h> + + +typedef struct private_xml_t private_xml_t; + +/** + * private data of xml + */ +struct private_xml_t { + + /** + * public functions + */ + xml_t public; + + /** + * root node of this xml (part) + */ + xmlNode *node; + + /** + * document, only for root xml_t + */ + xmlDoc *doc; + + /** + * Root xml_t* + */ + private_xml_t *root; + + /** + * number of enumerator instances + */ + int enums; +}; + +/** + * child element enumerator + */ +typedef struct { + /** enumerator interface */ + enumerator_t e; + /** current child context (returned to enumerate() caller) */ + private_xml_t child; + /** currently processing node */ + xmlNode *node; +} child_enum_t; + +/** + * Implementation of xml_t.children().enumerate(). + */ +static bool child_enumerate(child_enum_t *e, private_xml_t **child, + char **name, char **value) +{ + while (e->node && e->node->type != XML_ELEMENT_NODE) + { + e->node = e->node->next; + } + if (e->node) + { + xmlNode *text; + + text = e->node->children; + *value = NULL; + + while (text && text->type != XML_TEXT_NODE) + { + text = text->next; + } + if (text) + { + *value = text->content; + } + *name = (char*)e->node->name; + *child = &e->child; + e->child.node = e->node->children; + e->node = e->node->next; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of xml_t.get_attribute. + */ +static char* get_attribute(private_xml_t *this, char *name) +{ + return NULL; +} + +/** + * destroy enumerator, and complete tree if this was the last enumerator + */ +static void child_destroy(child_enum_t *this) +{ + if (--this->child.root->enums == 0) + { + xmlFreeDoc(this->child.root->doc); + free(this->child.root); + } + free(this); +} + +/** + * Implementation of xml_t.children. + */ +static enumerator_t* children(private_xml_t *this) +{ + child_enum_t *ce = malloc_thing(child_enum_t); + ce->e.enumerate = (void*)child_enumerate; + ce->e.destroy = (void*)child_destroy; + ce->node = this->node; + ce->child.public.children = (void*)children; + ce->child.public.get_attribute = (void*)get_attribute; + ce->child.node = NULL; + ce->child.doc = this->doc; + ce->child.root = this->root; + this->root->enums++; + return &ce->e; +} + +/* + * see header file + */ +xml_t *xml_create(char *xml) +{ + private_xml_t *this = malloc_thing(private_xml_t); + + this->public.get_attribute = (char*(*)(xml_t*,char*))get_attribute; + this->public.children = (enumerator_t*(*)(xml_t*))children; + + this->doc = xmlReadMemory(xml, strlen(xml), NULL, NULL, 0); + if (this->doc == NULL) + { + free(this); + return NULL; + } + this->node = xmlDocGetRootElement(this->doc); + this->root = this; + this->enums = 0; + + return &this->public; +} + diff --git a/src/manager/lib/xml.h b/src/manager/lib/xml.h new file mode 100644 index 000000000..738a8e1b3 --- /dev/null +++ b/src/manager/lib/xml.h @@ -0,0 +1,63 @@ +/** + * @file xml.h + * + * @brief Interface of xml_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef XML_H_ +#define XML_H_ + +#include <utils/enumerator.h> + +typedef struct xml_t xml_t; + +/** + * @brief Simple enumerator based XML parser. + * + * An xml_t is a single node of the XML tree, but also serves as root node + * and therefore the document. + * This object has no destructor, the tree gets destroyed when all enumerator + * instances get destroyed. + */ +struct xml_t { + + /** + * @brief Create an enumerator over all children. + * + * Enumerated values must not be manipulated or freed. + * + * @return enumerator over (xml_t* child, char *name, char *value) + */ + enumerator_t* (*children)(xml_t *this); + + /** + * @brief Get an attribute value by its name. + * + * @param name name of the attribute + * @return attribute value, NULL if not found + */ + char *(*get_attribute)(xml_t *this, char *name); +}; + +/** + * @brief Create a xml instance. + */ +xml_t *xml_create(char *xml); + +#endif /* XML_H_ */ diff --git a/src/manager/main.c b/src/manager/main.c new file mode 100644 index 000000000..bbe07cbf3 --- /dev/null +++ b/src/manager/main.c @@ -0,0 +1,68 @@ +/** + * @file main.c + * + * @brief Implementation of dispatcher_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include <dispatcher.h> +#include <stdio.h> + +#include "manager.h" +#include "database.h" +#include "controller/auth_controller.h" +#include "controller/status_controller.h" +#include "controller/gateway_controller.h" + +#define DBFILE IPSECDIR "/manager.db" +#define SESSION_TIMEOUT 180 +#define THREADS 10 + +int main (int arc, char *argv[]) +{ + dispatcher_t *dispatcher; + database_t *database; + char *socket = NULL; + +#ifdef FCGI_SOCKET + socket = FCGI_SOCKET; +#endif /* FCGI_SOCKET */ + + database = database_create(DBFILE); + if (database == NULL) + { + fprintf(stderr, "opening database '%s' failed.\n", DBFILE); + return 1; + } + + dispatcher = dispatcher_create(socket, SESSION_TIMEOUT, + (context_constructor_t)manager_create, database); + dispatcher->add_controller(dispatcher, status_controller_create, NULL); + dispatcher->add_controller(dispatcher, gateway_controller_create, NULL); + dispatcher->add_controller(dispatcher, auth_controller_create, NULL); + + dispatcher->run(dispatcher, THREADS, NULL, NULL, NULL, NULL); + + dispatcher->waitsignal(dispatcher); + + dispatcher->destroy(dispatcher); + database->destroy(database); + + return 0; +} + diff --git a/src/manager/manager.c b/src/manager/manager.c new file mode 100644 index 000000000..39c8d995a --- /dev/null +++ b/src/manager/manager.c @@ -0,0 +1,167 @@ +/** + * @file manager.c + * + * @brief Implementation of manager_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#include "manager.h" + +#include "gateway.h" + +#include <utils/linked_list.h> + +typedef struct private_manager_t private_manager_t; + +/** + * private data of manager + */ +struct private_manager_t { + + /** + * public functions + */ + manager_t public; + + /** + * underlying database + */ + database_t *db; + + /** + * user id, if we are logged in + */ + int user; + + /** + * selected gateway + */ + gateway_t *gateway; +}; + +/** + * Implementation of manager_t.create_gateway_enumerator. + */ +static enumerator_t* create_gateway_enumerator(private_manager_t *this) +{ + return this->db->create_gateway_enumerator(this->db, this->user); +} + +/** + * Implementation of manager_t.select_gateway. + */ +static gateway_t* select_gateway(private_manager_t *this, int select_id) +{ + if (select_id != 0) + { + enumerator_t *enumerator; + int id, port; + char *name, *address; + host_t *host; + + if (this->gateway) this->gateway->destroy(this->gateway); + this->gateway = NULL; + + enumerator = this->db->create_gateway_enumerator(this->db, this->user); + while (enumerator->enumerate(enumerator, &id, &name, &port, &address)) + { + if (select_id == id) + { + if (port == 0) + { + this->gateway = gateway_create_unix(name); + } + else + { + host = host_create_from_string(address, port); + if (host) + { + this->gateway = gateway_create_tcp(name, host); + } + } + break; + } + } + enumerator->destroy(enumerator); + } + return this->gateway; +} + +/** + * Implementation of manager_t.logged_in. + */ +static bool logged_in(private_manager_t *this) +{ + return this->user != 0; +} + +/** + * Implementation of manager_t.login. + */ +static bool login(private_manager_t *this, char *username, char *password) +{ + if (!this->user) + { + this->user = this->db->login(this->db, username, password); + } + return this->user != 0; +} + +/** + * Implementation of manager_t.logout. + */ +static void logout(private_manager_t *this) +{ + if (this->gateway) + { + this->gateway->destroy(this->gateway); + this->gateway = NULL; + } + this->user = 0; +} + +/** + * Implementation of manager_t.destroy + */ +static void destroy(private_manager_t *this) +{ + if (this->gateway) this->gateway->destroy(this->gateway); + free(this); +} + +/* + * see header file + */ +manager_t *manager_create(database_t *database) +{ + private_manager_t *this = malloc_thing(private_manager_t); + + this->public.login = (bool(*)(manager_t*, char *username, char *password))login; + this->public.logged_in = (bool(*)(manager_t*))logged_in; + this->public.logout = (void(*)(manager_t*))logout; + this->public.create_gateway_enumerator = (enumerator_t*(*)(manager_t*))create_gateway_enumerator; + this->public.select_gateway = (gateway_t*(*)(manager_t*, int id))select_gateway; + this->public.context.destroy = (void(*)(context_t*))destroy; + + this->user = 0; + this->db = database; + this->gateway = NULL; + + return &this->public; +} + diff --git a/src/manager/manager.db b/src/manager/manager.db Binary files differnew file mode 100644 index 000000000..23b6ed2e0 --- /dev/null +++ b/src/manager/manager.db diff --git a/src/manager/manager.h b/src/manager/manager.h new file mode 100644 index 000000000..4235618cd --- /dev/null +++ b/src/manager/manager.h @@ -0,0 +1,93 @@ +/** + * @file manager.h + * + * @brief Interface of manager_t. + * + */ + +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * 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. + */ + +#ifndef MANAGER_H_ +#define MANAGER_H_ + +#include "database.h" +#include "gateway.h" + +#include <context.h> + +#include <utils/iterator.h> + +typedef struct manager_t manager_t; + +/** + * @brief The manager, manages multiple gateways. + */ +struct manager_t { + + /** + * implements context_t interface + */ + context_t context; + + /** + * @brief Create an iterator over all configured gateways. + * + * enumerate() arguments: int id, char *name, int port, char *address + * If port is 0, address is a Unix socket address. + * + * @return enumerator + */ + enumerator_t* (*create_gateway_enumerator)(manager_t *this); + + /** + * @brief Select a gateway. + * + * If id is 0, the previously selected gateway is returned. If none has + * been selected yet, NULL is returned. + * + * @param id id of the gateway (from enumerate), or 0 + * @return selected gateway, or NULL + */ + gateway_t* (*select_gateway)(manager_t *this, int id); + + /** + * @brief Try to log in. + * + * @param username username + * @param password cleartext password + * @return TRUE if login successful + */ + bool (*login)(manager_t *this, char *username, char *password); + + /** + * @brief Check if user logged in. + * + * @return TRUE if logged in + */ + bool (*logged_in)(manager_t *this); + + /** + * @brief Log out. + */ + void (*logout)(manager_t *this); +}; + +/** + * @brief Create a manager instance. + */ +manager_t *manager_create(database_t *database); + +#endif /* MANAGER_H_ */ diff --git a/src/manager/templates/auth/login.cs b/src/manager/templates/auth/login.cs new file mode 100644 index 000000000..49a8ec6e0 --- /dev/null +++ b/src/manager/templates/auth/login.cs @@ -0,0 +1,17 @@ +<?cs include:"templates/header.cs" ?> +<div align="center"> +<form method="post" action="<?cs var:action ?>"> + <table> + <tr> + <td>Username</td><td><input type="text" name="username" size="25" /></td> + </tr> + <tr> + <td>Password</td><td><input type="password" name="password" size="25" /></td> + </tr> + <tr> + <td/><td><input type="submit" value="Login"/></td> + </tr> +</table> +</form> +</div> +<?cs include:"templates/footer.cs" ?> diff --git a/src/manager/templates/error.cs b/src/manager/templates/error.cs new file mode 100644 index 000000000..be9b1a3a1 --- /dev/null +++ b/src/manager/templates/error.cs @@ -0,0 +1,3 @@ +<?cs include:"templates/header.cs" ?> +<div><?cs var:error ?></div> +<?cs include:"templates/footer.cs" ?> diff --git a/src/manager/templates/footer.cs b/src/manager/templates/footer.cs new file mode 100644 index 000000000..db3601961 --- /dev/null +++ b/src/manager/templates/footer.cs @@ -0,0 +1,4 @@ + </div> + </div> + </body> +</html> diff --git a/src/manager/templates/gateway/list.cs b/src/manager/templates/gateway/list.cs new file mode 100644 index 000000000..b93364d6f --- /dev/null +++ b/src/manager/templates/gateway/list.cs @@ -0,0 +1,15 @@ +<?cs include:"templates/header.cs" ?> +<div class="dialog"> +<form method="post" action="<?cs var:action ?>"> + <p> + <select name="gateway" size="1"> + <?cs each:gateway = gateways ?> + <option value="<?cs name:gateway ?>"><?cs var:gateway.name ?> (<?cs var:gateway.address ?>)</option> + <?cs /each ?> + </select> + </p> + <input type="submit" value="Select"/> + <p> +</form> +</div> +<?cs include:"templates/footer.cs" ?> diff --git a/src/manager/templates/header.cs b/src/manager/templates/header.cs new file mode 100644 index 000000000..64a859a9a --- /dev/null +++ b/src/manager/templates/header.cs @@ -0,0 +1,24 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title><?cs var:title ?> - strongSwan Manager</title> + <link rel="stylesheet" type="text/css" href="<?cs var:base ?>/static/style.css" /> + <script type="text/javascript" src="<?cs var:base ?>/static/jquery.js" /> + <script type="text/javascript" src="<?cs var:base ?>/static/script.js" /> + </head> + <body> + <div class="fleft"> + <a href="<?cs var:base ?>/status/ikesalist"> + <img class="fleft" src="<?cs var:base ?>/static/strongswan.png"/> + </a> + <h1>strongSwan Manager</h1> + <h2><?cs var:title ?></h2> + </div> + <div class="menu"> + | <a href="<?cs var:base ?>/gateway/list">Select Gateway</a> + | <a href="<?cs var:base ?>/auth/logout">Logout</a> + </div> + <hr class="cleft"/> + <div class="center"> + <div class="content"> diff --git a/src/manager/templates/static/client-left.png b/src/manager/templates/static/client-left.png Binary files differnew file mode 100644 index 000000000..8a082ff9e --- /dev/null +++ b/src/manager/templates/static/client-left.png diff --git a/src/manager/templates/static/client-right.png b/src/manager/templates/static/client-right.png Binary files differnew file mode 100644 index 000000000..c841eebaf --- /dev/null +++ b/src/manager/templates/static/client-right.png diff --git a/src/manager/templates/static/gateway-left.png b/src/manager/templates/static/gateway-left.png Binary files differnew file mode 100644 index 000000000..9ddd3624d --- /dev/null +++ b/src/manager/templates/static/gateway-left.png diff --git a/src/manager/templates/static/gateway-right.png b/src/manager/templates/static/gateway-right.png Binary files differnew file mode 100644 index 000000000..0be446827 --- /dev/null +++ b/src/manager/templates/static/gateway-right.png diff --git a/src/manager/templates/static/jquery.js b/src/manager/templates/static/jquery.js new file mode 100644 index 000000000..0728760b5 --- /dev/null +++ b/src/manager/templates/static/jquery.js @@ -0,0 +1,2965 @@ +(function(){ +/* + * jQuery 1.2 - New Wave Javascript + * + * Copyright (c) 2007 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2007-09-10 15:45:49 -0400 (Mon, 10 Sep 2007) $ + * $Rev: 3219 $ + */ + +// Map over jQuery in case of overwrite +if ( typeof jQuery != "undefined" ) + var _jQuery = jQuery; + +var jQuery = window.jQuery = function(a,c) { + // If the context is global, return a new object + if ( window == this || !this.init ) + return new jQuery(a,c); + + return this.init(a,c); +}; + +// Map over the $ in case of overwrite +if ( typeof $ != "undefined" ) + var _$ = $; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +jQuery.fn = jQuery.prototype = { + init: function(a,c) { + // Make sure that a selection was provided + a = a || document; + + // Handle HTML strings + if ( typeof a == "string" ) { + var m = quickExpr.exec(a); + if ( m && (m[1] || !c) ) { + // HANDLE: $(html) -> $(array) + if ( m[1] ) + a = jQuery.clean( [ m[1] ], c ); + + // HANDLE: $("#id") + else { + var tmp = document.getElementById( m[3] ); + if ( tmp ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( tmp.id != m[3] ) + return jQuery().find( a ); + else { + this[0] = tmp; + this.length = 1; + return this; + } + else + a = []; + } + + // HANDLE: $(expr) + } else + return new jQuery( c ).find( a ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction(a) ) + return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a ); + + return this.setArray( + // HANDLE: $(array) + a.constructor == Array && a || + + // HANDLE: $(arraylike) + // Watch for when an array-like object is passed as the selector + (a.jquery || a.length && a != window && !a.nodeType && a[0] != undefined && a[0].nodeType) && jQuery.makeArray( a ) || + + // HANDLE: $(*) + [ a ] ); + }, + + jquery: "1.2", + + size: function() { + return this.length; + }, + + length: 0, + + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[num]; + }, + + pushStack: function( a ) { + var ret = jQuery(a); + ret.prevObject = this; + return ret; + }, + + setArray: function( a ) { + this.length = 0; + Array.prototype.push.apply( this, a ); + return this; + }, + + each: function( fn, args ) { + return jQuery.each( this, fn, args ); + }, + + index: function( obj ) { + var pos = -1; + this.each(function(i){ + if ( this == obj ) pos = i; + }); + return pos; + }, + + attr: function( key, value, type ) { + var obj = key; + + // Look for the case where we're accessing a style value + if ( key.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined; + else { + obj = {}; + obj[ key ] = value; + } + + // Check to see if we're setting style values + return this.each(function(index){ + // Set all the styles + for ( var prop in obj ) + jQuery.attr( + type ? this.style : this, + prop, jQuery.prop(this, obj[prop], type, index, prop) + ); + }); + }, + + css: function( key, value ) { + return this.attr( key, value, "curCSS" ); + }, + + text: function(e) { + if ( typeof e != "object" && e != null ) + return this.empty().append( document.createTextNode( e ) ); + + var t = ""; + jQuery.each( e || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + t += this.nodeType != 1 ? + this.nodeValue : jQuery.fn.text([ this ]); + }); + }); + return t; + }, + + wrapAll: function(html) { + if ( this[0] ) + // The elements to wrap the target around + jQuery(html, this[0].ownerDocument) + .clone() + .insertBefore(this[0]) + .map(function(){ + var elem = this; + while ( elem.firstChild ) + elem = elem.firstChild; + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function(html) { + return this.each(function(){ + jQuery(this).contents().wrapAll(html); + }); + }, + + wrap: function(html) { + return this.each(function(){ + jQuery(this).wrapAll(html); + }); + }, + + append: function() { + return this.domManip(arguments, true, 1, function(a){ + this.appendChild( a ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, -1, function(a){ + this.insertBefore( a, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, 1, function(a){ + this.parentNode.insertBefore( a, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, -1, function(a){ + this.parentNode.insertBefore( a, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery([]); + }, + + find: function(t) { + var data = jQuery.map(this, function(a){ return jQuery.find(t,a); }); + return this.pushStack( /[^+>] [^+>]/.test( t ) || t.indexOf("..") > -1 ? + jQuery.unique( data ) : data ); + }, + + clone: function(events) { + // Do the clone + var ret = this.map(function(){ + return this.outerHTML ? jQuery(this.outerHTML)[0] : this.cloneNode(true); + }); + + if (events === true) { + var clone = ret.find("*").andSelf(); + + this.find("*").andSelf().each(function(i) { + var events = jQuery.data(this, "events"); + for ( var type in events ) + for ( var handler in events[type] ) + jQuery.event.add(clone[i], type, events[type][handler], events[type][handler].data); + }); + } + + // Return the cloned set + return ret; + }, + + filter: function(t) { + return this.pushStack( + jQuery.isFunction( t ) && + jQuery.grep(this, function(el, index){ + return t.apply(el, [index]); + }) || + + jQuery.multiFilter(t,this) ); + }, + + not: function(t) { + return this.pushStack( + t.constructor == String && + jQuery.multiFilter(t, this, true) || + + jQuery.grep(this, function(a) { + return ( t.constructor == Array || t.jquery ) + ? jQuery.inArray( a, t ) < 0 + : a != t; + }) + ); + }, + + add: function(t) { + return this.pushStack( jQuery.merge( + this.get(), + t.constructor == String ? + jQuery(t).get() : + t.length != undefined && (!t.nodeName || t.nodeName == "FORM") ? + t : [t] ) + ); + }, + + is: function(expr) { + return expr ? jQuery.multiFilter(expr,this).length > 0 : false; + }, + + hasClass: function(expr) { + return this.is("." + expr); + }, + + val: function( val ) { + if ( val == undefined ) { + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName(elem, "select") ) { + var index = elem.selectedIndex, + a = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[i]; + if ( option.selected ) { + // Get the specifc value for the option + var val = jQuery.browser.msie && !option.attributes["value"].specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return val; + + // Multi-Selects return an array + a.push(val); + } + } + + return a; + + // Everything else, we just grab the value + } else + return this[0].value.replace(/\r/g, ""); + } + } else + return this.each(function(){ + if ( val.constructor == Array && /radio|checkbox/.test(this.type) ) + this.checked = (jQuery.inArray(this.value, val) >= 0 || + jQuery.inArray(this.name, val) >= 0); + else if ( jQuery.nodeName(this, "select") ) { + var tmp = val.constructor == Array ? val : [val]; + + jQuery("option", this).each(function(){ + this.selected = (jQuery.inArray(this.value, tmp) >= 0 || + jQuery.inArray(this.text, tmp) >= 0); + }); + + if ( !tmp.length ) + this.selectedIndex = -1; + } else + this.value = val; + }); + }, + + html: function( val ) { + return val == undefined ? + ( this.length ? this[0].innerHTML : null ) : + this.empty().append( val ); + }, + + replaceWith: function( val ) { + return this.after( val ).remove(); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function(fn) { + return this.pushStack(jQuery.map( this, function(elem,i){ + return fn.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function(args, table, dir, fn) { + var clone = this.length > 1, a; + + return this.each(function(){ + if ( !a ) { + a = jQuery.clean(args, this.ownerDocument); + if ( dir < 0 ) + a.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody")); + + jQuery.each( a, function(){ + if ( jQuery.nodeName(this, "script") ) { + if ( this.src ) + jQuery.ajax({ url: this.src, async: false, dataType: "script" }); + else + jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" ); + } else + fn.apply( obj, [ clone ? this.cloneNode(true) : this ] ); + }); + }); + } +}; + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + } + + // extend jQuery itself if only one argument is passed + if ( al == 1 ) { + target = this; + a = 0; + } + + var prop; + + for ( ; a < al; a++ ) + // Only deal with non-null/undefined values + if ( (prop = arguments[a]) != null ) + // Extend the base object + for ( var i in prop ) { + // Prevent never-ending loop + if ( target == prop[i] ) + continue; + + // Recurse if we're merging object values + if ( deep && typeof prop[i] == 'object' && target[i] ) + jQuery.extend( target[i], prop[i] ); + + // Don't bring in undefined values + else if ( prop[i] != undefined ) + target[i] = prop[i]; + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, win = {}; + +jQuery.extend({ + noConflict: function(deep) { + window.$ = _$; + if ( deep ) + window.jQuery = _jQuery; + return jQuery; + }, + + // This may seem like some crazy code, but trust me when I say that this + // is the only cross-browser way to do this. --John + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a XML document + isXMLDoc: function(elem) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + // Evaluates Async. in Safari 2 :-( + globalEval: function( data ) { + data = jQuery.trim( data ); + if ( data ) { + if ( window.execScript ) + window.execScript( data ); + else if ( jQuery.browser.safari ) + // safari doesn't provide a synchronous global eval + window.setTimeout( data, 0 ); + else + eval.call( window, data ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? win : elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? jQuery.cache[ id ][ name ] : id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? win : elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + for ( name in jQuery.cache[ id ] ) break; + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( obj, fn, args ) { + if ( args ) { + if ( obj.length == undefined ) + for ( var i in obj ) + fn.apply( obj[i], args ); + else + for ( var i = 0, ol = obj.length; i < ol; i++ ) + if ( fn.apply( obj[i], args ) === false ) break; + + // A special, fast, case for the most common use of each + } else { + if ( obj.length == undefined ) + for ( var i in obj ) + fn.call( obj[i], i, obj[i] ); + else + for ( var i = 0, ol = obj.length, val = obj[0]; + i < ol && fn.call(val,i,val) !== false; val = obj[++i] ){} + } + + return obj; + }, + + prop: function(elem, value, type, index, prop){ + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, [index] ); + + // exclude the following css properties to add px + var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, c ){ + jQuery.each( (c || "").split(/\s+/), function(i, cur){ + if ( !jQuery.className.has( elem.className, cur ) ) + elem.className += ( elem.className ? " " : "" ) + cur; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, c ){ + elem.className = c != undefined ? + jQuery.grep( elem.className.split(/\s+/), function(cur){ + return !jQuery.className.has( c, cur ); + }).join(" ") : ""; + }, + + // internal only, use is(".class") + has: function( t, c ) { + return jQuery.inArray( c, (t.className || t).toString().split(/\s+/) ) > -1; + } + }, + + swap: function(e,o,f) { + for ( var i in o ) { + e.style["old"+i] = e.style[i]; + e.style[i] = o[i]; + } + f.apply( e, [] ); + for ( var i in o ) + e.style[i] = e.style["old"+i]; + }, + + css: function(e,p) { + if ( p == "height" || p == "width" ) { + var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; + + jQuery.each( d, function(){ + old["padding" + this] = 0; + old["border" + this + "Width"] = 0; + }); + + jQuery.swap( e, old, function() { + if ( jQuery(e).is(':visible') ) { + oHeight = e.offsetHeight; + oWidth = e.offsetWidth; + } else { + e = jQuery(e.cloneNode(true)) + .find(":radio").removeAttr("checked").end() + .css({ + visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0" + }).appendTo(e.parentNode)[0]; + + var parPos = jQuery.css(e.parentNode,"position") || "static"; + if ( parPos == "static" ) + e.parentNode.style.position = "relative"; + + oHeight = e.clientHeight; + oWidth = e.clientWidth; + + if ( parPos == "static" ) + e.parentNode.style.position = "static"; + + e.parentNode.removeChild(e); + } + }); + + return p == "height" ? oHeight : oWidth; + } + + return jQuery.curCSS( e, p ); + }, + + curCSS: function(elem, prop, force) { + var ret, stack = [], swap = []; + + // A helper method for determining if an element's values are broken + function color(a){ + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle(a,null); + return !ret || ret.getPropertyValue("color") == ""; + } + + if (prop == "opacity" && jQuery.browser.msie) { + ret = jQuery.attr(elem.style, "opacity"); + return ret == "" ? "1" : ret; + } + + if (prop.match(/float/i)) + prop = styleFloat; + + if (!force && elem.style[prop]) + ret = elem.style[prop]; + + else if (document.defaultView && document.defaultView.getComputedStyle) { + + if (prop.match(/float/i)) + prop = "float"; + + prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); + var cur = document.defaultView.getComputedStyle(elem, null); + + if ( cur && !color(elem) ) + ret = cur.getPropertyValue(prop); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( a = 0; a < stack.length; a++ ) + if ( color(stack[a]) ) { + swap[a] = stack[a].style.display; + stack[a].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = prop == "display" && swap[stack.length-1] != null ? + "none" : + document.defaultView.getComputedStyle(elem,null).getPropertyValue(prop) || ""; + + // Finally, revert the display styles back + for ( a = 0; a < swap.length; a++ ) + if ( swap[a] != null ) + stack[a].style.display = swap[a]; + } + + if ( prop == "opacity" && ret == "" ) + ret = "1"; + + } else if (elem.currentStyle) { + var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}); + ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test(ret) && /^\d/.test(ret) ) { + var style = elem.style.left; + var runtimeStyle = elem.runtimeStyle.left; + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function(a, doc) { + var r = []; + doc = doc || document; + + jQuery.each( a, function(i,arg){ + if ( !arg ) return; + + if ( arg.constructor == Number ) + arg = arg.toString(); + + // Convert html string into DOM nodes + if ( typeof arg == "string" ) { + // Fix "XHTML"-style tags in all browsers + arg = arg.replace(/(<(\w+)[^>]*?)\/>/g, function(m, all, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i)? m : all+"></"+tag+">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var s = jQuery.trim(arg).toLowerCase(), div = doc.createElement("div"), tb = []; + + var wrap = + // option or optgroup + !s.indexOf("<opt") && + [1, "<select>", "</select>"] || + + !s.indexOf("<leg") && + [1, "<fieldset>", "</fieldset>"] || + + s.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [1, "<table>", "</table>"] || + + !s.indexOf("<tr") && + [2, "<table><tbody>", "</tbody></table>"] || + + // <thead> matched above + (!s.indexOf("<td") || !s.indexOf("<th")) && + [3, "<table><tbody><tr>", "</tr></tbody></table>"] || + + !s.indexOf("<col") && + [2, "<table><tbody></tbody><colgroup>", "</colgroup></table>"] || + + // IE can't serialize <link> and <script> tags normally + jQuery.browser.msie && + [1, "div<div>", "</div>"] || + + [0,"",""]; + + // Go to html and back, then peel off extra wrappers + div.innerHTML = wrap[1] + arg + wrap[2]; + + // Move to the right depth + while ( wrap[0]-- ) + div = div.lastChild; + + // Remove IE's autoinserted <tbody> from table fragments + if ( jQuery.browser.msie ) { + + // String was a <table>, *may* have spurious <tbody> + if ( !s.indexOf("<table") && s.indexOf("<tbody") < 0 ) + tb = div.firstChild && div.firstChild.childNodes; + + // String was a bare <thead> or <tfoot> + else if ( wrap[1] == "<table>" && s.indexOf("<tbody") < 0 ) + tb = div.childNodes; + + for ( var n = tb.length-1; n >= 0 ; --n ) + if ( jQuery.nodeName(tb[n], "tbody") && !tb[n].childNodes.length ) + tb[n].parentNode.removeChild(tb[n]); + + // IE completely kills leading whitespace when innerHTML is used + if ( /^\s/.test(arg) ) + div.insertBefore( doc.createTextNode( arg.match(/^\s*/)[0] ), div.firstChild ); + + } + + arg = jQuery.makeArray( div.childNodes ); + } + + if ( 0 === arg.length && (!jQuery.nodeName(arg, "form") && !jQuery.nodeName(arg, "select")) ) + return; + + if ( arg[0] == undefined || jQuery.nodeName(arg, "form") || arg.options ) + r.push( arg ); + else + r = jQuery.merge( r, arg ); + + }); + + return r; + }, + + attr: function(elem, name, value){ + var fix = jQuery.isXMLDoc(elem) ? {} : jQuery.props; + + // Safari mis-reports the default selected property of a hidden option + // Accessing the parent's selectedIndex property fixes it + if ( name == "selected" && jQuery.browser.safari ) + elem.parentNode.selectedIndex; + + // Certain attributes only work when accessed via the old DOM 0 way + if ( fix[name] ) { + if ( value != undefined ) elem[fix[name]] = value; + return elem[fix[name]]; + } else if ( jQuery.browser.msie && name == "style" ) + return jQuery.attr( elem.style, "cssText", value ); + + else if ( value == undefined && jQuery.browser.msie && jQuery.nodeName(elem, "form") && (name == "action" || name == "method") ) + return elem.getAttributeNode(name).nodeValue; + + // IE elem.getAttribute passes even for style + else if ( elem.tagName ) { + + if ( value != undefined ) { + if ( name == "type" && jQuery.nodeName(elem,"input") && elem.parentNode ) + throw "type property can't be changed"; + elem.setAttribute( name, value ); + } + + if ( jQuery.browser.msie && /href|src/.test(name) && !jQuery.isXMLDoc(elem) ) + return elem.getAttribute( name, 2 ); + + return elem.getAttribute( name ); + + // elem is actually elem.style ... set the style + } else { + // IE actually uses filters for opacity + if ( name == "opacity" && jQuery.browser.msie ) { + if ( value != undefined ) { + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + elem.zoom = 1; + + // Set the alpha filter to set the opacity + elem.filter = (elem.filter || "").replace(/alpha\([^)]*\)/,"") + + (parseFloat(value).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")"); + } + + return elem.filter ? + (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() : ""; + } + name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();}); + if ( value != undefined ) elem[name] = value; + return elem[name]; + } + }, + + trim: function(t){ + return (t||"").replace(/^\s+|\s+$/g, ""); + }, + + makeArray: function( a ) { + var r = []; + + // Need to use typeof to fight Safari childNodes crashes + if ( typeof a != "array" ) + for ( var i = 0, al = a.length; i < al; i++ ) + r.push( a[i] ); + else + r = a.slice( 0 ); + + return r; + }, + + inArray: function( b, a ) { + for ( var i = 0, al = a.length; i < al; i++ ) + if ( a[i] == b ) + return i; + return -1; + }, + + merge: function(first, second) { + // We have to loop this way because IE & Opera overwrite the length + // expando of getElementsByTagName + + // Also, we need to make sure that the correct elements are being returned + // (IE returns comment nodes in a '*' query) + if ( jQuery.browser.msie ) { + for ( var i = 0; second[i]; i++ ) + if ( second[i].nodeType != 8 ) + first.push(second[i]); + } else + for ( var i = 0; second[i]; i++ ) + first.push(second[i]); + + return first; + }, + + unique: function(first) { + var r = [], done = {}; + + try { + for ( var i = 0, fl = first.length; i < fl; i++ ) { + var id = jQuery.data(first[i]); + if ( !done[id] ) { + done[id] = true; + r.push(first[i]); + } + } + } catch(e) { + r = first; + } + + return r; + }, + + grep: function(elems, fn, inv) { + // If a string is passed in for the function, make a function + // for it (a handy shortcut) + if ( typeof fn == "string" ) + fn = eval("false||function(a,i){return " + fn + "}"); + + var result = []; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, el = elems.length; i < el; i++ ) + if ( !inv && fn(elems[i],i) || inv && !fn(elems[i],i) ) + result.push( elems[i] ); + + return result; + }, + + map: function(elems, fn) { + // If a string is passed in for the function, make a function + // for it (a handy shortcut) + if ( typeof fn == "string" ) + fn = eval("false||function(a){return " + fn + "}"); + + var result = []; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, el = elems.length; i < el; i++ ) { + var val = fn(elems[i],i); + + if ( val !== null && val != undefined ) { + if ( val.constructor != Array ) val = [val]; + result = result.concat( val ); + } + } + + return result; + } +}); + +var userAgent = navigator.userAgent.toLowerCase(); + +// Figure out what browser is being used +jQuery.browser = { + version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], + safari: /webkit/.test(userAgent), + opera: /opera/.test(userAgent), + msie: /msie/.test(userAgent) && !/opera/.test(userAgent), + mozilla: /mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent) +}; + +var styleFloat = jQuery.browser.msie ? "styleFloat" : "cssFloat"; + +jQuery.extend({ + // Check to see if the W3C box model is being used + boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat", + + styleFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat", + + props: { + "for": "htmlFor", + "class": "className", + "float": styleFloat, + cssFloat: styleFloat, + styleFloat: styleFloat, + innerHTML: "innerHTML", + className: "className", + value: "value", + disabled: "disabled", + checked: "checked", + readonly: "readOnly", + selected: "selected", + maxlength: "maxLength" + } +}); + +jQuery.each({ + parent: "a.parentNode", + parents: "jQuery.dir(a,'parentNode')", + next: "jQuery.nth(a,2,'nextSibling')", + prev: "jQuery.nth(a,2,'previousSibling')", + nextAll: "jQuery.dir(a,'nextSibling')", + prevAll: "jQuery.dir(a,'previousSibling')", + siblings: "jQuery.sibling(a.parentNode.firstChild,a)", + children: "jQuery.sibling(a.firstChild)", + contents: "jQuery.nodeName(a,'iframe')?a.contentDocument||a.contentWindow.document:jQuery.makeArray(a.childNodes)" +}, function(i,n){ + jQuery.fn[ i ] = function(a) { + var ret = jQuery.map(this,n); + if ( a && typeof a == "string" ) + ret = jQuery.multiFilter(a,ret); + return this.pushStack( jQuery.unique(ret) ); + }; +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function(i,n){ + jQuery.fn[ i ] = function(){ + var a = arguments; + return this.each(function(){ + for ( var j = 0, al = a.length; j < al; j++ ) + jQuery(a[j])[n]( this ); + }); + }; +}); + +jQuery.each( { + removeAttr: function( key ) { + jQuery.attr( this, key, "" ); + this.removeAttribute( key ); + }, + addClass: function(c){ + jQuery.className.add(this,c); + }, + removeClass: function(c){ + jQuery.className.remove(this,c); + }, + toggleClass: function( c ){ + jQuery.className[ jQuery.className.has(this,c) ? "remove" : "add" ](this, c); + }, + remove: function(a){ + if ( !a || jQuery.filter( a, [this] ).r.length ) { + jQuery.removeData( this ); + this.parentNode.removeChild( this ); + } + }, + empty: function() { + // Clean up the cache + jQuery("*", this).each(function(){ jQuery.removeData(this); }); + + while ( this.firstChild ) + this.removeChild( this.firstChild ); + } +}, function(i,n){ + jQuery.fn[ i ] = function() { + return this.each( n, arguments ); + }; +}); + +jQuery.each( [ "Height", "Width" ], function(i,name){ + var n = name.toLowerCase(); + + jQuery.fn[ n ] = function(h) { + return this[0] == window ? + jQuery.browser.safari && self["inner" + name] || + jQuery.boxModel && Math.max(document.documentElement["client" + name], document.body["client" + name]) || + document.body["client" + name] : + + this[0] == document ? + Math.max( document.body["scroll" + name], document.body["offset" + name] ) : + + h == undefined ? + ( this.length ? jQuery.css( this[0], n ) : null ) : + this.css( n, h.constructor == String ? h : h + "px" ); + }; +}); + +var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ? + "(?:[\\w*_-]|\\\\.)" : + "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)", + quickChild = new RegExp("^>\\s*(" + chars + "+)"), + quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"), + quickClass = new RegExp("^([#.]?)(" + chars + "*)"); + +jQuery.extend({ + expr: { + "": "m[2]=='*'||jQuery.nodeName(a,m[2])", + "#": "a.getAttribute('id')==m[2]", + ":": { + // Position Checks + lt: "i<m[3]-0", + gt: "i>m[3]-0", + nth: "m[3]-0==i", + eq: "m[3]-0==i", + first: "i==0", + last: "i==r.length-1", + even: "i%2==0", + odd: "i%2", + + // Child Checks + "first-child": "a.parentNode.getElementsByTagName('*')[0]==a", + "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a", + "only-child": "!jQuery.nth(a.parentNode.lastChild,2,'previousSibling')", + + // Parent Checks + parent: "a.firstChild", + empty: "!a.firstChild", + + // Text Check + contains: "(a.textContent||a.innerText||'').indexOf(m[3])>=0", + + // Visibility + visible: '"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"', + hidden: '"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"', + + // Form attributes + enabled: "!a.disabled", + disabled: "a.disabled", + checked: "a.checked", + selected: "a.selected||jQuery.attr(a,'selected')", + + // Form elements + text: "'text'==a.type", + radio: "'radio'==a.type", + checkbox: "'checkbox'==a.type", + file: "'file'==a.type", + password: "'password'==a.type", + submit: "'submit'==a.type", + image: "'image'==a.type", + reset: "'reset'==a.type", + button: '"button"==a.type||jQuery.nodeName(a,"button")', + input: "/input|select|textarea|button/i.test(a.nodeName)", + + // :has() + has: "jQuery.find(m[3],a).length", + + // :header + header: "/h\\d/i.test(a.nodeName)", + + // :animated + animated: "jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length" + } + }, + + // The regular expressions that power the parsing engine + parse: [ + // Match: [@value='test'], [@foo] + /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/, + + // Match: :contains('foo') + /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/, + + // Match: :even, :last-chlid, #id, .class + new RegExp("^([:.#]*)(" + chars + "+)") + ], + + multiFilter: function( expr, elems, not ) { + var old, cur = []; + + while ( expr && expr != old ) { + old = expr; + var f = jQuery.filter( expr, elems, not ); + expr = f.t.replace(/^\s*,\s*/, "" ); + cur = not ? elems = f.r : jQuery.merge( cur, f.r ); + } + + return cur; + }, + + find: function( t, context ) { + // Quickly handle non-string expressions + if ( typeof t != "string" ) + return [ t ]; + + // Make sure that the context is a DOM Element + if ( context && !context.nodeType ) + context = null; + + // Set the correct context (if none is provided) + context = context || document; + + // Initialize the search + var ret = [context], done = [], last; + + // Continue while a selector expression exists, and while + // we're no longer looping upon ourselves + while ( t && last != t ) { + var r = []; + last = t; + + t = jQuery.trim(t); + + var foundToken = false; + + // An attempt at speeding up child selectors that + // point to a specific element tag + var re = quickChild; + var m = re.exec(t); + + if ( m ) { + var nodeName = m[1].toUpperCase(); + + // Perform our own iteration and filter + for ( var i = 0; ret[i]; i++ ) + for ( var c = ret[i].firstChild; c; c = c.nextSibling ) + if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName.toUpperCase()) ) + r.push( c ); + + ret = r; + t = t.replace( re, "" ); + if ( t.indexOf(" ") == 0 ) continue; + foundToken = true; + } else { + re = /^([>+~])\s*(\w*)/i; + + if ( (m = re.exec(t)) != null ) { + r = []; + + var nodeName = m[2], merge = {}; + m = m[1]; + + for ( var j = 0, rl = ret.length; j < rl; j++ ) { + var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild; + for ( ; n; n = n.nextSibling ) + if ( n.nodeType == 1 ) { + var id = jQuery.data(n); + + if ( m == "~" && merge[id] ) break; + + if (!nodeName || n.nodeName.toUpperCase() == nodeName.toUpperCase() ) { + if ( m == "~" ) merge[id] = true; + r.push( n ); + } + + if ( m == "+" ) break; + } + } + + ret = r; + + // And remove the token + t = jQuery.trim( t.replace( re, "" ) ); + foundToken = true; + } + } + + // See if there's still an expression, and that we haven't already + // matched a token + if ( t && !foundToken ) { + // Handle multiple expressions + if ( !t.indexOf(",") ) { + // Clean the result set + if ( context == ret[0] ) ret.shift(); + + // Merge the result sets + done = jQuery.merge( done, ret ); + + // Reset the context + r = ret = [context]; + + // Touch up the selector string + t = " " + t.substr(1,t.length); + + } else { + // Optimize for the case nodeName#idName + var re2 = quickID; + var m = re2.exec(t); + + // Re-organize the results, so that they're consistent + if ( m ) { + m = [ 0, m[2], m[3], m[1] ]; + + } else { + // Otherwise, do a traditional filter check for + // ID, class, and element selectors + re2 = quickClass; + m = re2.exec(t); + } + + m[2] = m[2].replace(/\\/g, ""); + + var elem = ret[ret.length-1]; + + // Try to do a global search by ID, where we can + if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) { + // Optimization for HTML document case + var oid = elem.getElementById(m[2]); + + // Do a quick check for the existence of the actual ID attribute + // to avoid selecting by the name attribute in IE + // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form + if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] ) + oid = jQuery('[@id="'+m[2]+'"]', elem)[0]; + + // Do a quick check for node name (where applicable) so + // that div#foo searches will be really fast + ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : []; + } else { + // We need to find all descendant elements + for ( var i = 0; ret[i]; i++ ) { + // Grab the tag name being searched for + var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2]; + + // Handle IE7 being really dumb about <object>s + if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" ) + tag = "param"; + + r = jQuery.merge( r, ret[i].getElementsByTagName( tag )); + } + + // It's faster to filter by class and be done with it + if ( m[1] == "." ) + r = jQuery.classFilter( r, m[2] ); + + // Same with ID filtering + if ( m[1] == "#" ) { + var tmp = []; + + // Try to find the element with the ID + for ( var i = 0; r[i]; i++ ) + if ( r[i].getAttribute("id") == m[2] ) { + tmp = [ r[i] ]; + break; + } + + r = tmp; + } + + ret = r; + } + + t = t.replace( re2, "" ); + } + + } + + // If a selector string still exists + if ( t ) { + // Attempt to filter it + var val = jQuery.filter(t,r); + ret = r = val.r; + t = jQuery.trim(val.t); + } + } + + // An error occurred with the selector; + // just return an empty set instead + if ( t ) + ret = []; + + // Remove the root context + if ( ret && context == ret[0] ) + ret.shift(); + + // And combine the results + done = jQuery.merge( done, ret ); + + return done; + }, + + classFilter: function(r,m,not){ + m = " " + m + " "; + var tmp = []; + for ( var i = 0; r[i]; i++ ) { + var pass = (" " + r[i].className + " ").indexOf( m ) >= 0; + if ( !not && pass || not && !pass ) + tmp.push( r[i] ); + } + return tmp; + }, + + filter: function(t,r,not) { + var last; + + // Look for common filter expressions + while ( t && t != last ) { + last = t; + + var p = jQuery.parse, m; + + for ( var i = 0; p[i]; i++ ) { + m = p[i].exec( t ); + + if ( m ) { + // Remove what we just matched + t = t.substring( m[0].length ); + + m[2] = m[2].replace(/\\/g, ""); + break; + } + } + + if ( !m ) + break; + + // :not() is a special case that can be optimized by + // keeping it out of the expression list + if ( m[1] == ":" && m[2] == "not" ) + r = jQuery.filter(m[3], r, true).r; + + // We can get a big speed boost by filtering by class here + else if ( m[1] == "." ) + r = jQuery.classFilter(r, m[2], not); + + else if ( m[1] == "[" ) { + var tmp = [], type = m[3]; + + for ( var i = 0, rl = r.length; i < rl; i++ ) { + var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ]; + + if ( z == null || /href|src|selected/.test(m[2]) ) + z = jQuery.attr(a,m[2]) || ''; + + if ( (type == "" && !!z || + type == "=" && z == m[5] || + type == "!=" && z != m[5] || + type == "^=" && z && !z.indexOf(m[5]) || + type == "$=" && z.substr(z.length - m[5].length) == m[5] || + (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not ) + tmp.push( a ); + } + + r = tmp; + + // We can get a speed boost by handling nth-child here + } else if ( m[1] == ":" && m[2] == "nth-child" ) { + var merge = {}, tmp = [], + test = /(\d*)n\+?(\d*)/.exec( + m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" || + !/\D/.test(m[3]) && "n+" + m[3] || m[3]), + first = (test[1] || 1) - 0, last = test[2] - 0; + + for ( var i = 0, rl = r.length; i < rl; i++ ) { + var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode); + + if ( !merge[id] ) { + var c = 1; + + for ( var n = parentNode.firstChild; n; n = n.nextSibling ) + if ( n.nodeType == 1 ) + n.nodeIndex = c++; + + merge[id] = true; + } + + var add = false; + + if ( first == 1 ) { + if ( last == 0 || node.nodeIndex == last ) + add = true; + } else if ( (node.nodeIndex + last) % first == 0 ) + add = true; + + if ( add ^ not ) + tmp.push( node ); + } + + r = tmp; + + // Otherwise, find the expression to execute + } else { + var f = jQuery.expr[m[1]]; + if ( typeof f != "string" ) + f = jQuery.expr[m[1]][m[2]]; + + // Build a custom macro to enclose it + f = eval("false||function(a,i){return " + f + "}"); + + // Execute it against the current filter + r = jQuery.grep( r, f, not ); + } + } + + // Return an array of filtered elements (r) + // and the modified expression string (t) + return { r: r, t: t }; + }, + + dir: function( elem, dir ){ + var matched = []; + var cur = elem[dir]; + while ( cur && cur != document ) { + if ( cur.nodeType == 1 ) + matched.push( cur ); + cur = cur[dir]; + } + return matched; + }, + + nth: function(cur,result,dir,elem){ + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) + if ( cur.nodeType == 1 && ++num == result ) + break; + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType == 1 && (!elem || n != elem) ) + r.push( n ); + } + + return r; + } +}); +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code orignated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function(element, type, handler, data) { + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( jQuery.browser.msie && element.setInterval != undefined ) + element = window; + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) + handler.guid = this.guid++; + + // if data is passed, bind to handler + if( data != undefined ) { + // Create temporary function pointer to original handler + var fn = handler; + + // Create unique handler function, wrapped around original handler + handler = function() { + // Pass arguments and context to original handler + return fn.apply(this, arguments); + }; + + // Store data in unique handler + handler.data = data; + + // Set the guid of unique handler to the same of original handler, so it can be removed + handler.guid = fn.guid; + } + + // Namespaced event handlers + var parts = type.split("."); + type = parts[0]; + handler.type = parts[1]; + + // Init the element's event structure + var events = jQuery.data(element, "events") || jQuery.data(element, "events", {}); + + var handle = jQuery.data(element, "handle", function(){ + // returned undefined or false + var val; + + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + if ( typeof jQuery == "undefined" || jQuery.event.triggered ) + return val; + + val = jQuery.event.handle.apply(element, arguments); + + return val; + }); + + // Get the current list of functions bound to this event + var handlers = events[type]; + + // Init the event handler queue + if (!handlers) { + handlers = events[type] = {}; + + // And bind the global event handler to the element + if (element.addEventListener) + element.addEventListener(type, handle, false); + else + element.attachEvent("on" + type, handle); + } + + // Add the function to the element's handler list + handlers[handler.guid] = handler; + + // Keep track of which events have been used, for global triggering + this.global[type] = true; + }, + + guid: 1, + global: {}, + + // Detach an event or set of events from an element + remove: function(element, type, handler) { + var events = jQuery.data(element, "events"), ret, index; + + // Namespaced event handlers + if ( typeof type == "string" ) { + var parts = type.split("."); + type = parts[0]; + } + + if ( events ) { + // type is actually an event object here + if ( type && type.type ) { + handler = type.handler; + type = type.type; + } + + if ( !type ) { + for ( type in events ) + this.remove( element, type ); + + } else if ( events[type] ) { + // remove the given handler for the given type + if ( handler ) + delete events[type][handler.guid]; + + // remove all handlers for the given type + else + for ( handler in events[type] ) + // Handle the removal of namespaced events + if ( !parts[1] || events[type][handler].type == parts[1] ) + delete events[type][handler]; + + // remove generic event handler if no more handlers exist + for ( ret in events[type] ) break; + if ( !ret ) { + if (element.removeEventListener) + element.removeEventListener(type, jQuery.data(element, "handle"), false); + else + element.detachEvent("on" + type, jQuery.data(element, "handle")); + ret = null; + delete events[type]; + } + } + + // Remove the expando if it's no longer used + for ( ret in events ) break; + if ( !ret ) { + jQuery.removeData( element, "events" ); + jQuery.removeData( element, "handle" ); + } + } + }, + + trigger: function(type, data, element, donative, extra) { + // Clone the incoming data, if any + data = jQuery.makeArray(data || []); + + // Handle a global trigger + if ( !element ) { + // Only trigger if we've ever bound an event for it + if ( this.global[type] ) + jQuery("*").add([window, document]).trigger(type, data); + + // Handle triggering a single element + } else { + var val, ret, fn = jQuery.isFunction( element[ type ] || null ), + // Check to see if we need to provide a fake event, or not + evt = !data[0] || !data[0].preventDefault; + + // Pass along a fake event + if ( evt ) + data.unshift( this.fix({ type: type, target: element }) ); + + // Trigger the event + if ( jQuery.isFunction( jQuery.data(element, "handle") ) ) + val = jQuery.data(element, "handle").apply( element, data ); + + // Handle triggering native .onfoo handlers + if ( !fn && element["on"+type] && element["on"+type].apply( element, data ) === false ) + val = false; + + // Extra functions don't get the custom event object + if ( evt ) + data.shift(); + + // Handle triggering of extra function + if ( extra && extra.apply( element, data ) === false ) + val = false; + + // Trigger the native events (except for clicks on links) + if ( fn && donative !== false && val !== false && !(jQuery.nodeName(element, 'a') && type == "click") ) { + this.triggered = true; + element[ type ](); + } + + this.triggered = false; + } + + return val; + }, + + handle: function(event) { + // returned undefined or false + var val; + + // Empty object is for triggered events with no data + event = jQuery.event.fix( event || window.event || {} ); + + // Namespaced event handlers + var parts = event.type.split("."); + event.type = parts[0]; + + var c = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 ); + args.unshift( event ); + + for ( var j in c ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + args[0].handler = c[j]; + args[0].data = c[j].data; + + // Filter the functions by class + if ( !parts[1] || c[j].type == parts[1] ) { + var tmp = c[j].apply( this, args ); + + if ( val !== false ) + val = tmp; + + if ( tmp === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + + // Clean up added properties in IE to prevent memory leak + if (jQuery.browser.msie) + event.target = event.preventDefault = event.stopPropagation = + event.handler = event.data = null; + + return val; + }, + + fix: function(event) { + // store a copy of the original event object + // and clone to set read-only properties + var originalEvent = event; + event = jQuery.extend({}, originalEvent); + + // add preventDefault and stopPropagation since + // they will not work on the clone + event.preventDefault = function() { + // if preventDefault exists run it on the original event + if (originalEvent.preventDefault) + originalEvent.preventDefault(); + // otherwise set the returnValue property of the original event to false (IE) + originalEvent.returnValue = false; + }; + event.stopPropagation = function() { + // if stopPropagation exists run it on the original event + if (originalEvent.stopPropagation) + originalEvent.stopPropagation(); + // otherwise set the cancelBubble property of the original event to true (IE) + originalEvent.cancelBubble = true; + }; + + // Fix target property, if necessary + if ( !event.target && event.srcElement ) + event.target = event.srcElement; + + // check if target is a textnode (safari) + if (jQuery.browser.safari && event.target.nodeType == 3) + event.target = originalEvent.target.parentNode; + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) + event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var e = document.documentElement, b = document.body; + event.pageX = event.clientX + (e && e.scrollLeft || b.scrollLeft || 0); + event.pageY = event.clientY + (e && e.scrollTop || b.scrollTop || 0); + } + + // Add which for key events + if ( !event.which && (event.charCode || event.keyCode) ) + event.which = event.charCode || event.keyCode; + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) + event.metaKey = event.ctrlKey; + + // Add which for click: 1 == left; 2 == middle; 3 == right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button ) + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + + return event; + } +}; + +jQuery.fn.extend({ + bind: function( type, data, fn ) { + return type == "unload" ? this.one(type, data, fn) : this.each(function(){ + jQuery.event.add( this, type, fn || data, fn && data ); + }); + }, + + one: function( type, data, fn ) { + return this.each(function(){ + jQuery.event.add( this, type, function(event) { + jQuery(this).unbind(event); + return (fn || data).apply( this, arguments); + }, fn && data); + }); + }, + + unbind: function( type, fn ) { + return this.each(function(){ + jQuery.event.remove( this, type, fn ); + }); + }, + + trigger: function( type, data, fn ) { + return this.each(function(){ + jQuery.event.trigger( type, data, this, true, fn ); + }); + }, + + triggerHandler: function( type, data, fn ) { + if ( this[0] ) + return jQuery.event.trigger( type, data, this[0], false, fn ); + }, + + toggle: function() { + // Save reference to arguments for access in closure + var a = arguments; + + return this.click(function(e) { + // Figure out which function to execute + this.lastToggle = 0 == this.lastToggle ? 1 : 0; + + // Make sure that clicks stop + e.preventDefault(); + + // and execute the function + return a[this.lastToggle].apply( this, [e] ) || false; + }); + }, + + hover: function(f,g) { + + // A private function for handling mouse 'hovering' + function handleHover(e) { + // Check if mouse(over|out) are still within the same parent element + var p = e.relatedTarget; + + // Traverse up the tree + while ( p && p != this ) try { p = p.parentNode; } catch(e) { p = this; }; + + // If we actually just moused on to a sub-element, ignore it + if ( p == this ) return false; + + // Execute the right function + return (e.type == "mouseover" ? f : g).apply(this, [e]); + } + + // Bind the function to the two event listeners + return this.mouseover(handleHover).mouseout(handleHover); + }, + + ready: function(f) { + // Attach the listeners + bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) + // Execute the function immediately + f.apply( document, [jQuery] ); + + // Otherwise, remember the function for later + else + // Add the function to the wait list + jQuery.readyList.push( function() { return f.apply(this, [jQuery]); } ); + + return this; + } +}); + +jQuery.extend({ + /* + * All the code that makes DOM Ready work nicely. + */ + isReady: false, + readyList: [], + + // Handle when the DOM is ready + ready: function() { + // Make sure that the DOM is not already loaded + if ( !jQuery.isReady ) { + // Remember that the DOM is ready + jQuery.isReady = true; + + // If there are functions bound, to execute + if ( jQuery.readyList ) { + // Execute all of them + jQuery.each( jQuery.readyList, function(){ + this.apply( document ); + }); + + // Reset the list of functions + jQuery.readyList = null; + } + // Remove event listener to avoid memory leak + if ( jQuery.browser.mozilla || jQuery.browser.opera ) + document.removeEventListener( "DOMContentLoaded", jQuery.ready, false ); + + // Remove script element used by IE hack + if( !window.frames.length ) // don't remove if frames are present (#1187) + jQuery(window).load(function(){ jQuery("#__ie_init").remove(); }); + } + } +}); + +jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," + + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + + "submit,keydown,keypress,keyup,error").split(","), function(i,o){ + + // Handle event binding + jQuery.fn[o] = function(f){ + return f ? this.bind(o, f) : this.trigger(o); + }; +}); + +var readyBound = false; + +function bindReady(){ + if ( readyBound ) return; + readyBound = true; + + // If Mozilla is used + if ( jQuery.browser.mozilla || jQuery.browser.opera ) + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", jQuery.ready, false ); + + // If IE is used, use the excellent hack by Matthias Miller + // http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited + else if ( jQuery.browser.msie ) { + + // Only works if you document.write() it + document.write("<scr" + "ipt id=__ie_init defer=true " + + "src=//:><\/script>"); + + // Use the defer script hack + var script = document.getElementById("__ie_init"); + + // script does not exist if jQuery is loaded dynamically + if ( script ) + script.onreadystatechange = function() { + if ( this.readyState != "complete" ) return; + jQuery.ready(); + }; + + // Clear from memory + script = null; + + // If Safari is used + } else if ( jQuery.browser.safari ) + // Continually check to see if the document.readyState is valid + jQuery.safariTimer = setInterval(function(){ + // loaded and complete are both valid states + if ( document.readyState == "loaded" || + document.readyState == "complete" ) { + + // If either one are found, remove the timer + clearInterval( jQuery.safariTimer ); + jQuery.safariTimer = null; + + // and execute any waiting functions + jQuery.ready(); + } + }, 10); + + // A fallback to window.onload, that will always work + jQuery.event.add( window, "load", jQuery.ready ); +} +jQuery.fn.extend({ + load: function( url, params, callback ) { + if ( jQuery.isFunction( url ) ) + return this.bind("load", url); + + var off = url.indexOf(" "); + if ( off >= 0 ) { + var selector = url.slice(off, url.length); + url = url.slice(0, off); + } + + callback = callback || function(){}; + + // Default to a GET request + var type = "GET"; + + // If the second parameter was provided + if ( params ) + // If it's a function + if ( jQuery.isFunction( params ) ) { + // We assume that it's the callback + callback = params; + params = null; + + // Otherwise, build a param string + } else { + params = jQuery.param( params ); + type = "POST"; + } + + var self = this; + + // Request the remote document + jQuery.ajax({ + url: url, + type: type, + data: params, + complete: function(res, status){ + // If successful, inject the HTML into all the matched elements + if ( status == "success" || status == "notmodified" ) + // See if a selector was specified + self.html( selector ? + // Create a dummy div to hold the results + jQuery("<div/>") + // inject the contents of the document in, removing the scripts + // to avoid any 'Permission Denied' errors in IE + .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, "")) + + // Locate the specified elements + .find(selector) : + + // If not, just inject the full result + res.responseText ); + + // Add delay to account for Safari's delay in globalEval + setTimeout(function(){ + self.each( callback, [res.responseText, status, res] ); + }, 13); + } + }); + return this; + }, + + serialize: function() { + return jQuery.param(this.serializeArray()); + }, + serializeArray: function() { + return this.map(function(){ + return jQuery.nodeName(this, "form") ? + jQuery.makeArray(this.elements) : this; + }) + .filter(function(){ + return this.name && !this.disabled && + (this.checked || /select|textarea/i.test(this.nodeName) || + /text|hidden|password/i.test(this.type)); + }) + .map(function(i, elem){ + var val = jQuery(this).val(); + return val == null ? null : + val.constructor == Array ? + jQuery.map( val, function(i, val){ + return {name: elem.name, value: val}; + }) : + {name: elem.name, value: val}; + }).get(); + } +}); + +// Attach a bunch of functions for handling common AJAX events +jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){ + jQuery.fn[o] = function(f){ + return this.bind(o, f); + }; +}); + +var jsc = (new Date).getTime(); + +jQuery.extend({ + get: function( url, data, callback, type ) { + // shift arguments if data argument was ommited + if ( jQuery.isFunction( data ) ) { + callback = data; + data = null; + } + + return jQuery.ajax({ + type: "GET", + url: url, + data: data, + success: callback, + dataType: type + }); + }, + + getScript: function( url, callback ) { + return jQuery.get(url, null, callback, "script"); + }, + + getJSON: function( url, data, callback ) { + return jQuery.get(url, data, callback, "json"); + }, + + post: function( url, data, callback, type ) { + if ( jQuery.isFunction( data ) ) { + callback = data; + data = {}; + } + + return jQuery.ajax({ + type: "POST", + url: url, + data: data, + success: callback, + dataType: type + }); + }, + + ajaxSetup: function( settings ) { + jQuery.extend( jQuery.ajaxSettings, settings ); + }, + + ajaxSettings: { + global: true, + type: "GET", + timeout: 0, + contentType: "application/x-www-form-urlencoded", + processData: true, + async: true, + data: null + }, + + // Last-Modified header cache for next request + lastModified: {}, + + ajax: function( s ) { + var jsonp, jsre = /=(\?|%3F)/g, status, data; + + // Extend the settings, but re-extend 's' so that it can be + // checked again later (in the test suite, specifically) + s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s)); + + // convert data if not already a string + if ( s.data && s.processData && typeof s.data != "string" ) + s.data = jQuery.param(s.data); + + // Break the data into one single string + var q = s.url.indexOf("?"); + if ( q > -1 ) { + s.data = (s.data ? s.data + "&" : "") + s.url.slice(q + 1); + s.url = s.url.slice(0, q); + } + + // Handle JSONP Parameter Callbacks + if ( s.dataType == "jsonp" ) { + if ( !s.data || !s.data.match(jsre) ) + s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?"; + s.dataType = "json"; + } + + // Build temporary JSONP function + if ( s.dataType == "json" && s.data && s.data.match(jsre) ) { + jsonp = "jsonp" + jsc++; + s.data = s.data.replace(jsre, "=" + jsonp); + + // We need to make sure + // that a JSONP style response is executed properly + s.dataType = "script"; + + // Handle JSONP-style loading + window[ jsonp ] = function(tmp){ + data = tmp; + success(); + // Garbage collect + window[ jsonp ] = undefined; + try{ delete window[ jsonp ]; } catch(e){} + }; + } + + if ( s.dataType == "script" && s.cache == null ) + s.cache = false; + + if ( s.cache === false && s.type.toLowerCase() == "get" ) + s.data = (s.data ? s.data + "&" : "") + "_=" + (new Date()).getTime(); + + // If data is available, append data to url for get requests + if ( s.data && s.type.toLowerCase() == "get" ) { + s.url += "?" + s.data; + + // IE likes to send both get and post data, prevent this + s.data = null; + } + + // Watch for a new set of requests + if ( s.global && ! jQuery.active++ ) + jQuery.event.trigger( "ajaxStart" ); + + // If we're requesting a remote document + // and trying to load JSON or Script + if ( !s.url.indexOf("http") && s.dataType == "script" ) { + var head = document.getElementsByTagName("head")[0]; + var script = document.createElement("script"); + script.src = s.url; + + // Handle Script loading + if ( !jsonp && (s.success || s.complete) ) { + var done = false; + + // Attach handlers for all browsers + script.onload = script.onreadystatechange = function(){ + if ( !done && (!this.readyState || + this.readyState == "loaded" || this.readyState == "complete") ) { + done = true; + success(); + complete(); + head.removeChild( script ); + } + }; + } + + head.appendChild(script); + + // We handle everything using the script element injection + return; + } + + var requestDone = false; + + // Create the request object; Microsoft failed to properly + // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available + var xml = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(); + + // Open the socket + xml.open(s.type, s.url, s.async); + + // Set the correct header, if data is being sent + if ( s.data ) + xml.setRequestHeader("Content-Type", s.contentType); + + // Set the If-Modified-Since header, if ifModified mode. + if ( s.ifModified ) + xml.setRequestHeader("If-Modified-Since", + jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" ); + + // Set header so the called script knows that it's an XMLHttpRequest + xml.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + + // Allow custom headers/mimetypes + if ( s.beforeSend ) + s.beforeSend(xml); + + if ( s.global ) + jQuery.event.trigger("ajaxSend", [xml, s]); + + // Wait for a response to come back + var onreadystatechange = function(isTimeout){ + // The transfer is complete and the data is available, or the request timed out + if ( !requestDone && xml && (xml.readyState == 4 || isTimeout == "timeout") ) { + requestDone = true; + + // clear poll interval + if (ival) { + clearInterval(ival); + ival = null; + } + + status = isTimeout == "timeout" && "timeout" || + !jQuery.httpSuccess( xml ) && "error" || + s.ifModified && jQuery.httpNotModified( xml, s.url ) && "notmodified" || + "success"; + + if ( status == "success" ) { + // Watch for, and catch, XML document parse errors + try { + // process the data (runs the xml through httpData regardless of callback) + data = jQuery.httpData( xml, s.dataType ); + } catch(e) { + status = "parsererror"; + } + } + + // Make sure that the request was successful or notmodified + if ( status == "success" ) { + // Cache Last-Modified header, if ifModified mode. + var modRes; + try { + modRes = xml.getResponseHeader("Last-Modified"); + } catch(e) {} // swallow exception thrown by FF if header is not available + + if ( s.ifModified && modRes ) + jQuery.lastModified[s.url] = modRes; + + // JSONP handles its own success callback + if ( !jsonp ) + success(); + } else + jQuery.handleError(s, xml, status); + + // Fire the complete handlers + complete(); + + // Stop memory leaks + if ( s.async ) + xml = null; + } + }; + + if ( s.async ) { + // don't attach the handler to the request, just poll it instead + var ival = setInterval(onreadystatechange, 13); + + // Timeout checker + if ( s.timeout > 0 ) + setTimeout(function(){ + // Check to see if the request is still happening + if ( xml ) { + // Cancel the request + xml.abort(); + + if( !requestDone ) + onreadystatechange( "timeout" ); + } + }, s.timeout); + } + + // Send the data + try { + xml.send(s.data); + } catch(e) { + jQuery.handleError(s, xml, null, e); + } + + // firefox 1.5 doesn't fire statechange for sync requests + if ( !s.async ) + onreadystatechange(); + + // return XMLHttpRequest to allow aborting the request etc. + return xml; + + function success(){ + // If a local callback was specified, fire it and pass it the data + if ( s.success ) + s.success( data, status ); + + // Fire the global callback + if ( s.global ) + jQuery.event.trigger( "ajaxSuccess", [xml, s] ); + } + + function complete(){ + // Process result + if ( s.complete ) + s.complete(xml, status); + + // The request was completed + if ( s.global ) + jQuery.event.trigger( "ajaxComplete", [xml, s] ); + + // Handle the global AJAX counter + if ( s.global && ! --jQuery.active ) + jQuery.event.trigger( "ajaxStop" ); + } + }, + + handleError: function( s, xml, status, e ) { + // If a local callback was specified, fire it + if ( s.error ) s.error( xml, status, e ); + + // Fire the global callback + if ( s.global ) + jQuery.event.trigger( "ajaxError", [xml, s, e] ); + }, + + // Counter for holding the number of active queries + active: 0, + + // Determines if an XMLHttpRequest was successful or not + httpSuccess: function( r ) { + try { + return !r.status && location.protocol == "file:" || + ( r.status >= 200 && r.status < 300 ) || r.status == 304 || + jQuery.browser.safari && r.status == undefined; + } catch(e){} + return false; + }, + + // Determines if an XMLHttpRequest returns NotModified + httpNotModified: function( xml, url ) { + try { + var xmlRes = xml.getResponseHeader("Last-Modified"); + + // Firefox always returns 200. check Last-Modified date + return xml.status == 304 || xmlRes == jQuery.lastModified[url] || + jQuery.browser.safari && xml.status == undefined; + } catch(e){} + return false; + }, + + httpData: function( r, type ) { + var ct = r.getResponseHeader("content-type"); + var xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0; + var data = xml ? r.responseXML : r.responseText; + + if ( xml && data.documentElement.tagName == "parsererror" ) + throw "parsererror"; + + // If the type is "script", eval it in global context + if ( type == "script" ) + jQuery.globalEval( data ); + + // Get the JavaScript object, if JSON is used. + if ( type == "json" ) + data = eval("(" + data + ")"); + + return data; + }, + + // Serialize an array of form elements or a set of + // key/values into a query string + param: function( a ) { + var s = []; + + // If an array was passed in, assume that it is an array + // of form elements + if ( a.constructor == Array || a.jquery ) + // Serialize the form elements + jQuery.each( a, function(){ + s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) ); + }); + + // Otherwise, assume that it's an object of key/value pairs + else + // Serialize the key/values + for ( var j in a ) + // If the value is an array then the key names need to be repeated + if ( a[j] && a[j].constructor == Array ) + jQuery.each( a[j], function(){ + s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) ); + }); + else + s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) ); + + // Return the resulting serialization + return s.join("&").replace(/%20/g, "+"); + } + +}); +jQuery.fn.extend({ + show: function(speed,callback){ + return speed ? + this.animate({ + height: "show", width: "show", opacity: "show" + }, speed, callback) : + + this.filter(":hidden").each(function(){ + this.style.display = this.oldblock ? this.oldblock : ""; + if ( jQuery.css(this,"display") == "none" ) + this.style.display = "block"; + }).end(); + }, + + hide: function(speed,callback){ + return speed ? + this.animate({ + height: "hide", width: "hide", opacity: "hide" + }, speed, callback) : + + this.filter(":visible").each(function(){ + this.oldblock = this.oldblock || jQuery.css(this,"display"); + if ( this.oldblock == "none" ) + this.oldblock = "block"; + this.style.display = "none"; + }).end(); + }, + + // Save the old toggle function + _toggle: jQuery.fn.toggle, + + toggle: function( fn, fn2 ){ + return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ? + this._toggle( fn, fn2 ) : + fn ? + this.animate({ + height: "toggle", width: "toggle", opacity: "toggle" + }, fn, fn2) : + this.each(function(){ + jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ](); + }); + }, + + slideDown: function(speed,callback){ + return this.animate({height: "show"}, speed, callback); + }, + + slideUp: function(speed,callback){ + return this.animate({height: "hide"}, speed, callback); + }, + + slideToggle: function(speed, callback){ + return this.animate({height: "toggle"}, speed, callback); + }, + + fadeIn: function(speed, callback){ + return this.animate({opacity: "show"}, speed, callback); + }, + + fadeOut: function(speed, callback){ + return this.animate({opacity: "hide"}, speed, callback); + }, + + fadeTo: function(speed,to,callback){ + return this.animate({opacity: to}, speed, callback); + }, + + animate: function( prop, speed, easing, callback ) { + var opt = jQuery.speed(speed, easing, callback); + + return this[ opt.queue === false ? "each" : "queue" ](function(){ + opt = jQuery.extend({}, opt); + var hidden = jQuery(this).is(":hidden"), self = this; + + for ( var p in prop ) { + if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) + return jQuery.isFunction(opt.complete) && opt.complete.apply(this); + + if ( p == "height" || p == "width" ) { + // Store display property + opt.display = jQuery.css(this, "display"); + + // Make sure that nothing sneaks out + opt.overflow = this.style.overflow; + } + } + + if ( opt.overflow != null ) + this.style.overflow = "hidden"; + + opt.curAnim = jQuery.extend({}, prop); + + jQuery.each( prop, function(name, val){ + var e = new jQuery.fx( self, opt, name ); + + if ( /toggle|show|hide/.test(val) ) + e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); + else { + var parts = val.toString().match(/^([+-]?)([\d.]+)(.*)$/), + start = e.cur(true) || 0; + + if ( parts ) { + end = parseFloat(parts[2]), + unit = parts[3] || "px"; + + // We need to compute starting value + if ( unit != "px" ) { + self.style[ name ] = end + unit; + start = (end / e.cur(true)) * start; + self.style[ name ] = start + unit; + } + + // If a +/- token was provided, we're doing a relative animation + if ( parts[1] ) + end = ((parts[1] == "-" ? -1 : 1) * end) + start; + + e.custom( start, end, unit ); + } else + e.custom( start, val, "" ); + } + }); + + // For JS strict compliance + return true; + }); + }, + + queue: function(type, fn){ + if ( !fn ) { + fn = type; + type = "fx"; + } + + if ( !arguments.length ) + return queue( this[0], type ); + + return this.each(function(){ + if ( fn.constructor == Array ) + queue(this, type, fn); + else { + queue(this, type).push( fn ); + + if ( queue(this, type).length == 1 ) + fn.apply(this); + } + }); + }, + + stop: function(){ + var timers = jQuery.timers; + + return this.each(function(){ + for ( var i = 0; i < timers.length; i++ ) + if ( timers[i].elem == this ) + timers.splice(i--, 1); + }).dequeue(); + } + +}); + +var queue = function( elem, type, array ) { + if ( !elem ) + return; + + var q = jQuery.data( elem, type + "queue" ); + + if ( !q || array ) + q = jQuery.data( elem, type + "queue", + array ? jQuery.makeArray(array) : [] ); + + return q; +}; + +jQuery.fn.dequeue = function(type){ + type = type || "fx"; + + return this.each(function(){ + var q = queue(this, type); + + q.shift(); + + if ( q.length ) + q[0].apply( this ); + }); +}; + +jQuery.extend({ + + speed: function(speed, easing, fn) { + var opt = speed && speed.constructor == Object ? speed : { + complete: fn || !fn && easing || + jQuery.isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && easing.constructor != Function && easing + }; + + opt.duration = (opt.duration && opt.duration.constructor == Number ? + opt.duration : + { slow: 600, fast: 200 }[opt.duration]) || 400; + + // Queueing + opt.old = opt.complete; + opt.complete = function(){ + jQuery(this).dequeue(); + if ( jQuery.isFunction( opt.old ) ) + opt.old.apply( this ); + }; + + return opt; + }, + + easing: { + linear: function( p, n, firstNum, diff ) { + return firstNum + diff * p; + }, + swing: function( p, n, firstNum, diff ) { + return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum; + } + }, + + timers: [], + + fx: function( elem, options, prop ){ + this.options = options; + this.elem = elem; + this.prop = prop; + + if ( !options.orig ) + options.orig = {}; + } + +}); + +jQuery.fx.prototype = { + + // Simple function for setting a style value + update: function(){ + if ( this.options.step ) + this.options.step.apply( this.elem, [ this.now, this ] ); + + (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); + + // Set display property to block for height/width animations + if ( this.prop == "height" || this.prop == "width" ) + this.elem.style.display = "block"; + }, + + // Get the current size + cur: function(force){ + if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null ) + return this.elem[ this.prop ]; + + var r = parseFloat(jQuery.curCSS(this.elem, this.prop, force)); + return r && r > -10000 ? r : parseFloat(jQuery.css(this.elem, this.prop)) || 0; + }, + + // Start an animation from one number to another + custom: function(from, to, unit){ + this.startTime = (new Date()).getTime(); + this.start = from; + this.end = to; + this.unit = unit || this.unit || "px"; + this.now = this.start; + this.pos = this.state = 0; + this.update(); + + var self = this; + function t(){ + return self.step(); + } + + t.elem = this.elem; + + jQuery.timers.push(t); + + if ( jQuery.timers.length == 1 ) { + var timer = setInterval(function(){ + var timers = jQuery.timers; + + for ( var i = 0; i < timers.length; i++ ) + if ( !timers[i]() ) + timers.splice(i--, 1); + + if ( !timers.length ) + clearInterval( timer ); + }, 13); + } + }, + + // Simple 'show' function + show: function(){ + // Remember where we started, so that we can go back to it later + this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop ); + this.options.show = true; + + // Begin the animation + this.custom(0, this.cur()); + + // Make sure that we start at a small width/height to avoid any + // flash of content + if ( this.prop == "width" || this.prop == "height" ) + this.elem.style[this.prop] = "1px"; + + // Start by showing the element + jQuery(this.elem).show(); + }, + + // Simple 'hide' function + hide: function(){ + // Remember where we started, so that we can go back to it later + this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop ); + this.options.hide = true; + + // Begin the animation + this.custom(this.cur(), 0); + }, + + // Each step of an animation + step: function(){ + var t = (new Date()).getTime(); + + if ( t > this.options.duration + this.startTime ) { + this.now = this.end; + this.pos = this.state = 1; + this.update(); + + this.options.curAnim[ this.prop ] = true; + + var done = true; + for ( var i in this.options.curAnim ) + if ( this.options.curAnim[i] !== true ) + done = false; + + if ( done ) { + if ( this.options.display != null ) { + // Reset the overflow + this.elem.style.overflow = this.options.overflow; + + // Reset the display + this.elem.style.display = this.options.display; + if ( jQuery.css(this.elem, "display") == "none" ) + this.elem.style.display = "block"; + } + + // Hide the element if the "hide" operation was done + if ( this.options.hide ) + this.elem.style.display = "none"; + + // Reset the properties, if the item has been hidden or shown + if ( this.options.hide || this.options.show ) + for ( var p in this.options.curAnim ) + jQuery.attr(this.elem.style, p, this.options.orig[p]); + } + + // If a callback was provided, execute it + if ( done && jQuery.isFunction( this.options.complete ) ) + // Execute the complete function + this.options.complete.apply( this.elem ); + + return false; + } else { + var n = t - this.startTime; + this.state = n / this.options.duration; + + // Perform the easing function, defaults to swing + this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration); + this.now = this.start + ((this.end - this.start) * this.pos); + + // Perform the next step of the animation + this.update(); + } + + return true; + } + +}; + +jQuery.fx.step = { + scrollLeft: function(fx){ + fx.elem.scrollLeft = fx.now; + }, + + scrollTop: function(fx){ + fx.elem.scrollTop = fx.now; + }, + + opacity: function(fx){ + jQuery.attr(fx.elem.style, "opacity", fx.now); + }, + + _default: function(fx){ + fx.elem.style[ fx.prop ] = fx.now + fx.unit; + } +}; +// The Offset Method +// Originally By Brandon Aaron, part of the Dimension Plugin +// http://jquery.com/plugins/project/dimensions +jQuery.fn.offset = function() { + var left = 0, top = 0, elem = this[0], results; + + if ( elem ) with ( jQuery.browser ) { + var absolute = jQuery.css(elem, "position") == "absolute", + parent = elem.parentNode, + offsetParent = elem.offsetParent, + doc = elem.ownerDocument, + safari2 = safari && !absolute && parseInt(version) < 522; + + // Use getBoundingClientRect if available + if ( elem.getBoundingClientRect ) { + box = elem.getBoundingClientRect(); + + // Add the document scroll offsets + add( + box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft), + box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop) + ); + + // IE adds the HTML element's border, by default it is medium which is 2px + // IE 6 and IE 7 quirks mode the border width is overwritable by the following css html { border: 0; } + // IE 7 standards mode, the border is always 2px + if ( msie ) { + var border = jQuery("html").css("borderWidth"); + border = (border == "medium" || jQuery.boxModel && parseInt(version) >= 7) && 2 || border; + add( -border, -border ); + } + + // Otherwise loop through the offsetParents and parentNodes + } else { + + // Initial element offsets + add( elem.offsetLeft, elem.offsetTop ); + + // Get parent offsets + while ( offsetParent ) { + // Add offsetParent offsets + add( offsetParent.offsetLeft, offsetParent.offsetTop ); + + // Mozilla and Safari > 2 does not include the border on offset parents + // However Mozilla adds the border for table cells + if ( mozilla && /^t[d|h]$/i.test(parent.tagName) || !safari2 ) + border( offsetParent ); + + // Safari <= 2 doubles body offsets with an absolutely positioned element or parent + if ( safari2 && !absolute && jQuery.css(offsetParent, "position") == "absolute" ) + absolute = true; + + // Get next offsetParent + offsetParent = offsetParent.offsetParent; + } + + // Get parent scroll offsets + while ( parent.tagName && /^body|html$/i.test(parent.tagName) ) { + // Work around opera inline/table scrollLeft/Top bug + if ( /^inline|table-row.*$/i.test(jQuery.css(parent, "display")) ) + // Subtract parent scroll offsets + add( -parent.scrollLeft, -parent.scrollTop ); + + // Mozilla does not add the border for a parent that has overflow != visible + if ( mozilla && jQuery.css(parent, "overflow") != "visible" ) + border( parent ); + + // Get next parent + parent = parent.parentNode; + } + + // Safari doubles body offsets with an absolutely positioned element or parent + if ( safari && absolute ) + add( -doc.body.offsetLeft, -doc.body.offsetTop ); + } + + // Return an object with top and left properties + results = { top: top, left: left }; + } + + return results; + + function border(elem) { + add( jQuery.css(elem, "borderLeftWidth"), jQuery.css(elem, "borderTopWidth") ); + } + + function add(l, t) { + left += parseInt(l) || 0; + top += parseInt(t) || 0; + } +}; +})(); diff --git a/src/manager/templates/static/pipe-bad.png b/src/manager/templates/static/pipe-bad.png Binary files differnew file mode 100644 index 000000000..dce7e836e --- /dev/null +++ b/src/manager/templates/static/pipe-bad.png diff --git a/src/manager/templates/static/pipe-good.png b/src/manager/templates/static/pipe-good.png Binary files differnew file mode 100644 index 000000000..1e254711c --- /dev/null +++ b/src/manager/templates/static/pipe-good.png diff --git a/src/manager/templates/static/pipe-thin-left.png b/src/manager/templates/static/pipe-thin-left.png Binary files differnew file mode 100644 index 000000000..6ccc59a17 --- /dev/null +++ b/src/manager/templates/static/pipe-thin-left.png diff --git a/src/manager/templates/static/pipe-thin-right.png b/src/manager/templates/static/pipe-thin-right.png Binary files differnew file mode 100644 index 000000000..1f582d24b --- /dev/null +++ b/src/manager/templates/static/pipe-thin-right.png diff --git a/src/manager/templates/static/pipe-thin.png b/src/manager/templates/static/pipe-thin.png Binary files differnew file mode 100644 index 000000000..d25f1b625 --- /dev/null +++ b/src/manager/templates/static/pipe-thin.png diff --git a/src/manager/templates/static/pipe.png b/src/manager/templates/static/pipe.png Binary files differnew file mode 100644 index 000000000..1e254711c --- /dev/null +++ b/src/manager/templates/static/pipe.png diff --git a/src/manager/templates/static/router.png b/src/manager/templates/static/router.png Binary files differnew file mode 100644 index 000000000..12a68fc90 --- /dev/null +++ b/src/manager/templates/static/router.png diff --git a/src/manager/templates/static/script.js b/src/manager/templates/static/script.js new file mode 100644 index 000000000..7b2a5823c --- /dev/null +++ b/src/manager/templates/static/script.js @@ -0,0 +1,8 @@ + +$(function(){ + $(".expand > div").hide(); + $(".expand > h1").toggle( + function(){$(this).parent(".expand").find("div").slideDown('fast');}, + function(){$(this).parent(".expand").find("div").slideUp('fast');} + ); +}); diff --git a/src/manager/templates/static/strongswan.png b/src/manager/templates/static/strongswan.png Binary files differnew file mode 100644 index 000000000..869188cdf --- /dev/null +++ b/src/manager/templates/static/strongswan.png diff --git a/src/manager/templates/static/style.css b/src/manager/templates/static/style.css new file mode 100644 index 000000000..8a7f4960d --- /dev/null +++ b/src/manager/templates/static/style.css @@ -0,0 +1,122 @@ + +body { + font-family: Verdana, Helvetica, sans-serif; + font-size: .9em; + color: #230100; + background-color: #f7f4d3; + margin: 0; +} + +.content { + text-align: center; +} + +.content > * { + background-color: #e5bf5e; + border: solid 2px; + padding: .2em 1em .2em 1em; + margin: 1em; + text-align: left; +} + +textarea, select, input { + background-color: #ffec9e; + border: 1px solid; + padding: 1px 3px 1px 3px; +} + +.menu { + text-align: right; + background-color: #e5bf5e; + padding: 3px; + border-bottom: solid 2px; +} + +a { + color: black; + text-decoration: none; +} + +h1 { + margin-top: 1em; + +} + +hr { + border: solid 1px; +} + +a img { + border: none; +} + +.expand { +} + +.expand h1 { + font-size: 1em; + cursor: pointer; + margin: 0; +} + +.expand h1 span { + margin-left: 2em; + margin-right: 2em; +} + +.center { + text-align: center; +} + +.left { + text-align: left; +} + +.right { + text-align: right; +} + +.highlight { +} + +.fleft { + margin-right: 2em; + float: left; +} + +.fright { + float: left; +} + +.cleft { + clear:left; +} + +.cright { + clear:right; +} + +.both { + clear:both; +} + +.drawing { + border-collapse:collapse +} + +.drawing .images { + height: 100px; +} + +.drawing .images td { + padding: 0px; + width: 100px; +} + +.drawing tr .left { + text-align: left; +} +.drawing tr .right { + text-align: right; +} + diff --git a/src/manager/templates/status/ikesalist.cs b/src/manager/templates/status/ikesalist.cs new file mode 100644 index 000000000..2238aafd3 --- /dev/null +++ b/src/manager/templates/status/ikesalist.cs @@ -0,0 +1,101 @@ +<?cs include:"templates/header.cs" ?> +<?cs each:ikesa = ikesas ?> + <div class="expand" id="ikesa-<?cs name:ikesa ?>"> + <h1> + IKE #<?cs name:ikesa ?> [<?cs var:ikesa.peerconfig ?>]: + <span><?cs var:ikesa.local.identification ?></span> <-> + <span><?cs var:ikesa.remote.identification ?></span> + </h1> + <div> + <hr/> + <table class="drawing"> + <tr> + <td class="left" colspan="3"> + <?cs var:ikesa.local.identification ?> + </td> + <td> + </td> + <td class="right" colspan="3"> + <?cs var:ikesa.remote.identification ?> + </td> + </tr> + <tr class="images"> + <td> + <?cs if:ikesa.role == "initiator" ?> + <img title="Local host is the initiator" src="<?cs var:base ?>/static/client-left.png"></img> + <?cs else ?> + <img title="Local host is the responder" src="<?cs var:base ?>/static/gateway-left.png"></img> + <?cs /if ?> + </td> + <td style="background-image:url(<?cs var:base ?>/static/pipe.png)"> + <?cs var:ikesa.local.spi ?><br/><br/><br/> + <?cs var:ikesa.local.address ?> + </td> + <td> + <?cs if:ikesa.local.nat == "true" ?> + <img title="Local host is behind NAT" src="<?cs var:base ?>/static/router.png"></img> + <?cs else ?> + <img title="Local host is not NATed" src="<?cs var:base ?>/static/pipe.png"></img> + <?cs /if ?> + </td> + <td> + <?cs if:ikesa.status == "established" ?> + <img title="IKE connection <?cs var:ikesa.status ?>" src="<?cs var:base ?>/static/pipe-good.png"></img> + <?cs else ?> + <img title="IKE connection in state <?cs var:ikesa.status ?>" src="<?cs var:base ?>/static/pipe-bad.png"></img> + <?cs /if ?> + </td> + <td> + <?cs if:ikesa.remote.nat == "true" ?> + <img title="Remote host is behind NAT" src="<?cs var:base ?>/static/router.png"></img> + <?cs else ?> + <img title="Remote host is not NATed" src="<?cs var:base ?>/static/pipe.png"></img> + <?cs /if ?> + </td> + <td class="right" style="background-image:url(<?cs var:base ?>/static/pipe.png)"> + <?cs var:ikesa.remote.spi ?><br/><br/><br/> + <?cs var:ikesa.remote.address ?> + </td> + <td> + <?cs if:ikesa.role == "responder" ?> + <img title="Remote host is the initiator" src="<?cs var:base ?>/static/client-right.png"></img> + <?cs else ?> + <img title="Remote host is the responder" src="<?cs var:base ?>/static/gateway-right.png"></img> + <?cs /if ?> + </td> + </tr> + <?cs each:childsa = ikesa.childsas ?> + <tr> + <td colspan="7" class="expand"> + <h1>IPsec #<?cs name:childsa ?> [<?cs var:childsa.childconfig ?>]:</h1> + </td> + </tr> + <tr> + <td colspan="7"><hr/></td> + </tr> + <tr class="images"> + <td colspan="2"> + <?cs each:net = childsa.local.networks ?> + <p><?cs var:net ?></p> + <?cs /each ?> + </td> + <td style="background-image:url(<?cs var:base ?>/static/pipe-thin-left.png)"> + <?cs var:childsa.local.spi ?> <-<br/><br/><br/> + </td> + <td style="background-image:url(<?cs var:base ?>/static/pipe-thin.png)"> + </td> + <td class="right" style="background-image:url(<?cs var:base ?>/static/pipe-thin-right.png)"> + -> <?cs var:childsa.remote.spi ?><br/><br/><br/> + </td> + <td class="right" colspan="2"> + <?cs each:net = childsa.remote.networks ?> + <p><?cs var:net ?></p> + <?cs /each ?> + </td> + </tr> + <?cs /each ?> + </table> + </div> + </div> +<?cs /each ?> +<?cs include:"templates/footer.cs" ?> |