diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 29 | ||||
-rw-r--r-- | src/Makefile.in | 577 | ||||
-rw-r--r-- | src/base64.c | 103 | ||||
-rw-r--r-- | src/dom.c | 181 | ||||
-rw-r--r-- | src/filter.c | 181 | ||||
-rw-r--r-- | src/iks.c | 762 | ||||
-rw-r--r-- | src/ikstack.c | 202 | ||||
-rw-r--r-- | src/io-posix.c | 137 | ||||
-rw-r--r-- | src/jabber.c | 330 | ||||
-rw-r--r-- | src/md5.c | 189 | ||||
-rw-r--r-- | src/sax.c | 634 | ||||
-rw-r--r-- | src/sha.c | 152 | ||||
-rw-r--r-- | src/stream.c | 642 | ||||
-rw-r--r-- | src/utility.c | 180 |
14 files changed, 4299 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..20ca263 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,29 @@ +## +## Process this file with automake to produce Makefile.in +## + +INCLUDES = -I$(top_srcdir)/include + +lib_LTLIBRARIES = libiksemel.la + +if DO_POSIX +posix_c = io-posix.c +endif + +libiksemel_la_SOURCES = \ + ikstack.c \ + utility.c \ + iks.c \ + sax.c \ + dom.c \ + $(posix_c) \ + stream.c \ + sha.c \ + jabber.c \ + filter.c \ + md5.c \ + base64.c + +libiksemel_la_LDFLAGS = -version-info 4:0:1 -no-undefined +libiksemel_la_CFLAGS = $(CFLAGS) $(LIBGNUTLS_CFLAGS) +libiksemel_la_LIBADD = $(LIBGNUTLS_LIBS) diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..3b2093c --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,577 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 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@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +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@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +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)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libiksemel_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__libiksemel_la_SOURCES_DIST = ikstack.c utility.c iks.c sax.c dom.c \ + io-posix.c stream.c sha.c jabber.c filter.c md5.c base64.c +@DO_POSIX_TRUE@am__objects_1 = libiksemel_la-io-posix.lo +am_libiksemel_la_OBJECTS = libiksemel_la-ikstack.lo \ + libiksemel_la-utility.lo libiksemel_la-iks.lo \ + libiksemel_la-sax.lo libiksemel_la-dom.lo $(am__objects_1) \ + libiksemel_la-stream.lo libiksemel_la-sha.lo \ + libiksemel_la-jabber.lo libiksemel_la-filter.lo \ + libiksemel_la-md5.lo libiksemel_la-base64.lo +libiksemel_la_OBJECTS = $(am_libiksemel_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include +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 --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libiksemel_la_SOURCES) +DIST_SOURCES = $(am__libiksemel_la_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +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@ +DO_POSIX_FALSE = @DO_POSIX_FALSE@ +DO_POSIX_TRUE = @DO_POSIX_TRUE@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ +LIBGNUTLS_CONFIG = @LIBGNUTLS_CONFIG@ +LIBGNUTLS_LIBS = @LIBGNUTLS_LIBS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +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@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_OBJDUMP = @ac_ct_OBJDUMP@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +INCLUDES = -I$(top_srcdir)/include +lib_LTLIBRARIES = libiksemel.la +@DO_POSIX_TRUE@posix_c = io-posix.c +libiksemel_la_SOURCES = \ + ikstack.c \ + utility.c \ + iks.c \ + sax.c \ + dom.c \ + $(posix_c) \ + stream.c \ + sha.c \ + jabber.c \ + filter.c \ + md5.c \ + base64.c + +libiksemel_la_LDFLAGS = -version-info 4:0:1 -no-undefined +libiksemel_la_CFLAGS = $(CFLAGS) $(LIBGNUTLS_CFLAGS) +libiksemel_la_LIBADD = $(LIBGNUTLS_LIBS) +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/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/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) + @set -x; 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 +libiksemel.la: $(libiksemel_la_OBJECTS) $(libiksemel_la_DEPENDENCIES) + $(LINK) -rpath $(libdir) $(libiksemel_la_LDFLAGS) $(libiksemel_la_OBJECTS) $(libiksemel_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-base64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-dom.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-filter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-iks.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-ikstack.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-io-posix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-jabber.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-md5.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-sax.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-sha.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-stream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libiksemel_la-utility.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@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 $@ $< + +libiksemel_la-ikstack.lo: ikstack.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-ikstack.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-ikstack.Tpo" -c -o libiksemel_la-ikstack.lo `test -f 'ikstack.c' || echo '$(srcdir)/'`ikstack.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-ikstack.Tpo" "$(DEPDIR)/libiksemel_la-ikstack.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-ikstack.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ikstack.c' object='libiksemel_la-ikstack.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-ikstack.lo `test -f 'ikstack.c' || echo '$(srcdir)/'`ikstack.c + +libiksemel_la-utility.lo: utility.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-utility.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-utility.Tpo" -c -o libiksemel_la-utility.lo `test -f 'utility.c' || echo '$(srcdir)/'`utility.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-utility.Tpo" "$(DEPDIR)/libiksemel_la-utility.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-utility.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utility.c' object='libiksemel_la-utility.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-utility.lo `test -f 'utility.c' || echo '$(srcdir)/'`utility.c + +libiksemel_la-iks.lo: iks.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-iks.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-iks.Tpo" -c -o libiksemel_la-iks.lo `test -f 'iks.c' || echo '$(srcdir)/'`iks.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-iks.Tpo" "$(DEPDIR)/libiksemel_la-iks.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-iks.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='iks.c' object='libiksemel_la-iks.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-iks.lo `test -f 'iks.c' || echo '$(srcdir)/'`iks.c + +libiksemel_la-sax.lo: sax.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-sax.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-sax.Tpo" -c -o libiksemel_la-sax.lo `test -f 'sax.c' || echo '$(srcdir)/'`sax.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-sax.Tpo" "$(DEPDIR)/libiksemel_la-sax.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-sax.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sax.c' object='libiksemel_la-sax.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-sax.lo `test -f 'sax.c' || echo '$(srcdir)/'`sax.c + +libiksemel_la-dom.lo: dom.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-dom.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-dom.Tpo" -c -o libiksemel_la-dom.lo `test -f 'dom.c' || echo '$(srcdir)/'`dom.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-dom.Tpo" "$(DEPDIR)/libiksemel_la-dom.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-dom.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dom.c' object='libiksemel_la-dom.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-dom.lo `test -f 'dom.c' || echo '$(srcdir)/'`dom.c + +libiksemel_la-io-posix.lo: io-posix.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-io-posix.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-io-posix.Tpo" -c -o libiksemel_la-io-posix.lo `test -f 'io-posix.c' || echo '$(srcdir)/'`io-posix.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-io-posix.Tpo" "$(DEPDIR)/libiksemel_la-io-posix.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-io-posix.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='io-posix.c' object='libiksemel_la-io-posix.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-io-posix.lo `test -f 'io-posix.c' || echo '$(srcdir)/'`io-posix.c + +libiksemel_la-stream.lo: stream.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-stream.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-stream.Tpo" -c -o libiksemel_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-stream.Tpo" "$(DEPDIR)/libiksemel_la-stream.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-stream.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='stream.c' object='libiksemel_la-stream.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-stream.lo `test -f 'stream.c' || echo '$(srcdir)/'`stream.c + +libiksemel_la-sha.lo: sha.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-sha.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-sha.Tpo" -c -o libiksemel_la-sha.lo `test -f 'sha.c' || echo '$(srcdir)/'`sha.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-sha.Tpo" "$(DEPDIR)/libiksemel_la-sha.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-sha.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sha.c' object='libiksemel_la-sha.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-sha.lo `test -f 'sha.c' || echo '$(srcdir)/'`sha.c + +libiksemel_la-jabber.lo: jabber.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-jabber.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-jabber.Tpo" -c -o libiksemel_la-jabber.lo `test -f 'jabber.c' || echo '$(srcdir)/'`jabber.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-jabber.Tpo" "$(DEPDIR)/libiksemel_la-jabber.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-jabber.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='jabber.c' object='libiksemel_la-jabber.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-jabber.lo `test -f 'jabber.c' || echo '$(srcdir)/'`jabber.c + +libiksemel_la-filter.lo: filter.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-filter.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-filter.Tpo" -c -o libiksemel_la-filter.lo `test -f 'filter.c' || echo '$(srcdir)/'`filter.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-filter.Tpo" "$(DEPDIR)/libiksemel_la-filter.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-filter.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='filter.c' object='libiksemel_la-filter.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-filter.lo `test -f 'filter.c' || echo '$(srcdir)/'`filter.c + +libiksemel_la-md5.lo: md5.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-md5.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-md5.Tpo" -c -o libiksemel_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-md5.Tpo" "$(DEPDIR)/libiksemel_la-md5.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-md5.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='md5.c' object='libiksemel_la-md5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c + +libiksemel_la-base64.lo: base64.c +@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -MT libiksemel_la-base64.lo -MD -MP -MF "$(DEPDIR)/libiksemel_la-base64.Tpo" -c -o libiksemel_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libiksemel_la-base64.Tpo" "$(DEPDIR)/libiksemel_la-base64.Plo"; else rm -f "$(DEPDIR)/libiksemel_la-base64.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='base64.c' object='libiksemel_la-base64.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libiksemel_la_CFLAGS) $(CFLAGS) -c -o libiksemel_la-base64.lo `test -f 'base64.c' || echo '$(srcdir)/'`base64.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +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)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + 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) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; 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-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +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-info-am uninstall-libLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + 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-exec \ + install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-man 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-info-am \ + 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/base64.c b/src/base64.c new file mode 100644 index 0000000..bb89ce8 --- /dev/null +++ b/src/base64.c @@ -0,0 +1,103 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +static const char base64_charset[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +char *iks_base64_decode(const char *buf) +{ + char *res, *save; + char val; + const char *foo; + const char *end; + int index; + size_t len; + + if (!buf) + return NULL; + + len = iks_strlen(buf) * 6 / 8 + 1; + + save = res = iks_malloc(len); + if (!save) + return NULL; + memset(res, 0, len); + + index = 0; + end = buf + iks_strlen(buf); + + while (*buf && buf < end) { + if (!(foo = strchr(base64_charset, *buf))) + foo = base64_charset; + val = (int)(foo - base64_charset); + buf++; + switch (index) { + case 0: + *res |= val << 2; + break; + case 1: + *res++ |= val >> 4; + *res |= val << 4; + break; + case 2: + *res++ |= val >> 2; + *res |= val << 6; + break; + case 3: + *res++ |= val; + break; + } + index++; + index %= 4; + } + *res = 0; + + return save; +} + +char *iks_base64_encode(const char *buf, int len) +{ + char *res, *save; + int k, t; + + len = (len > 0) ? (len) : (iks_strlen(buf)); + save = res = iks_malloc((len*8) / 6 + 4); + if (!save) return NULL; + + for (k = 0; k < len/3; ++k) { + *res++ = base64_charset[*buf >> 2]; + t = ((*buf & 0x03) << 4); + buf++; + *res++ = base64_charset[t | (*buf >> 4)]; + t = ((*buf & 0x0F) << 2); + buf++; + *res++ = base64_charset[t | (*buf >> 6)]; + *res++ = base64_charset[*buf++ & 0x3F]; + } + + switch (len % 3) { + case 2: + *res++ = base64_charset[*buf >> 2]; + t = ((*buf & 0x03) << 4); + buf++; + *res++ = base64_charset[t | (*buf >> 4)]; + *res++ = base64_charset[((*buf++ & 0x0F) << 2)]; + *res++ = '='; + break; + case 1: + *res++ = base64_charset[*buf >> 2]; + *res++ = base64_charset[(*buf++ & 0x03) << 4]; + *res++ = '='; + *res++ = '='; + break; + } + *res = 0; + return save; +} diff --git a/src/dom.c b/src/dom.c new file mode 100644 index 0000000..849bf20 --- /dev/null +++ b/src/dom.c @@ -0,0 +1,181 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +struct dom_data { + iks **iksptr; + iks *current; + size_t chunk_size; +}; + +static int +tagHook (struct dom_data *data, char *name, char **atts, int type) +{ + iks *x; + + if (IKS_OPEN == type || IKS_SINGLE == type) { + if (data->current) { + x = iks_insert (data->current, name); + } else { + ikstack *s; + s = iks_stack_new (data->chunk_size, data->chunk_size); + x = iks_new_within (name, s); + } + if (atts) { + int i=0; + while (atts[i]) { + iks_insert_attrib (x, atts[i], atts[i+1]); + i += 2; + } + } + data->current = x; + } + if (IKS_CLOSE == type || IKS_SINGLE == type) { + x = iks_parent (data->current); + if (iks_strcmp(iks_name(data->current), name) != 0) + return IKS_BADXML; + if (x) + data->current = x; + else { + *(data->iksptr) = data->current; + data->current = NULL; + } + } + return IKS_OK; +} + +static int +cdataHook (struct dom_data *data, char *cdata, size_t len) +{ + if (data->current) iks_insert_cdata (data->current, cdata, len); + return IKS_OK; +} + +static void +deleteHook (struct dom_data *data) +{ + if (data->current) iks_delete (data->current); + data->current = NULL; +} + +iksparser * +iks_dom_new (iks **iksptr) +{ + ikstack *s; + struct dom_data *data; + + *iksptr = NULL; + s = iks_stack_new (DEFAULT_DOM_CHUNK_SIZE, 0); + if (!s) return NULL; + data = iks_stack_alloc (s, sizeof (struct dom_data)); + data->iksptr = iksptr; + data->current = NULL; + data->chunk_size = DEFAULT_DOM_IKS_CHUNK_SIZE; + return iks_sax_extend (s, data, (iksTagHook *) tagHook, (iksCDataHook *) cdataHook, (iksDeleteHook *) deleteHook); +} + +void +iks_set_size_hint (iksparser *prs, size_t approx_size) +{ + size_t cs; + struct dom_data *data = iks_user_data (prs); + + cs = approx_size / 10; + if (cs < DEFAULT_DOM_IKS_CHUNK_SIZE) cs = DEFAULT_DOM_IKS_CHUNK_SIZE; + data->chunk_size = cs; +} + +iks * +iks_tree (const char *xml_str, size_t len, int *err) +{ + iksparser *prs; + iks *x; + int e; + + if (0 == len) len = strlen (xml_str); + prs = iks_dom_new (&x); + if (!prs) { + if (err) *err = IKS_NOMEM; + return NULL; + } + e = iks_parse (prs, xml_str, len, 1); + if (err) *err = e; + iks_parser_delete (prs); + return x; +} + +int +iks_load (const char *fname, iks **xptr) +{ + iksparser *prs; + char *buf; + FILE *f; + int len, done = 0; + int ret; + + *xptr = NULL; + + buf = iks_malloc (FILE_IO_BUF_SIZE); + if (!buf) return IKS_NOMEM; + ret = IKS_NOMEM; + prs = iks_dom_new (xptr); + if (prs) { + f = fopen (fname, "r"); + if (f) { + while (0 == done) { + len = fread (buf, 1, FILE_IO_BUF_SIZE, f); + if (len < FILE_IO_BUF_SIZE) { + if (0 == feof (f)) { + ret = IKS_FILE_RWERR; + break; + } + if (0 == len) ret = IKS_OK; + done = 1; + } + if (len > 0) { + int e; + e = iks_parse (prs, buf, len, done); + if (IKS_OK != e) { + ret = e; + break; + } + if (done) ret = IKS_OK; + } + } + fclose (f); + } else { + if (ENOENT == errno) ret = IKS_FILE_NOFILE; + else ret = IKS_FILE_NOACCESS; + } + iks_parser_delete (prs); + } + iks_free (buf); + return ret; +} + +int +iks_save (const char *fname, iks *x) +{ + FILE *f; + char *data; + int ret; + + ret = IKS_NOMEM; + data = iks_string (NULL, x); + if (data) { + ret = IKS_FILE_NOACCESS; + f = fopen (fname, "w"); + if (f) { + ret = IKS_FILE_RWERR; + if (fputs (data, f) >= 0) ret = IKS_OK; + fclose (f); + } + iks_free (data); + } + return ret; +} diff --git a/src/filter.c b/src/filter.c new file mode 100644 index 0000000..9af451f --- /dev/null +++ b/src/filter.c @@ -0,0 +1,181 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +struct iksrule_struct { + struct iksrule_struct *next, *prev; + ikstack *s; + void *user_data; + iksFilterHook *filterHook; + char *id; + char *from; + char *ns; + int score; + int rules; + enum ikstype type; + enum iksubtype subtype; +}; + +struct iksfilter_struct { + iksrule *rules; + iksrule *last_rule; +}; + +iksfilter * +iks_filter_new (void) +{ + iksfilter *f; + + f = iks_malloc (sizeof (iksfilter)); + if (!f) return NULL; + memset (f, 0, sizeof (iksfilter)); + + return f; +} + +iksrule * +iks_filter_add_rule (iksfilter *f, iksFilterHook *filterHook, void *user_data, ...) +{ + ikstack *s; + iksrule *rule; + va_list ap; + int type; + + s = iks_stack_new (sizeof (iksrule), DEFAULT_RULE_CHUNK_SIZE); + if (!s) return NULL; + rule = iks_stack_alloc (s, sizeof (iksrule)); + memset (rule, 0, sizeof (iksrule)); + rule->s = s; + rule->user_data = user_data; + rule->filterHook = filterHook; + + va_start (ap, user_data); + while (1) { + type = va_arg (ap, int); + if (IKS_RULE_DONE == type) break; + rule->rules += type; + switch (type) { + case IKS_RULE_TYPE: + rule->type = va_arg (ap, int); + break; + case IKS_RULE_SUBTYPE: + rule->subtype = va_arg (ap, int); + break; + case IKS_RULE_ID: + rule->id = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + case IKS_RULE_NS: + rule->ns = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + case IKS_RULE_FROM: + rule->from = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + case IKS_RULE_FROM_PARTIAL: + rule->from = iks_stack_strdup (s, va_arg (ap, char *), 0); + break; + } + } + va_end (ap); + + if (!f->rules) f->rules = rule; + if (f->last_rule) f->last_rule->next = rule; + rule->prev = f->last_rule; + f->last_rule = rule; + return rule; +} + +void +iks_filter_remove_rule (iksfilter *f, iksrule *rule) +{ + if (rule->prev) rule->prev->next = rule->next; + if (rule->next) rule->next->prev = rule->prev; + if (f->rules == rule) f->rules = rule->next; + if (f->last_rule == rule) f->last_rule = rule->prev; + iks_stack_delete (rule->s); +} + +void +iks_filter_remove_hook (iksfilter *f, iksFilterHook *filterHook) +{ + iksrule *rule, *tmp; + + rule = f->rules; + while (rule) { + tmp = rule->next; + if (rule->filterHook == filterHook) iks_filter_remove_rule (f, rule); + rule = tmp; + } +} + +void +iks_filter_packet (iksfilter *f, ikspak *pak) +{ + iksrule *rule, *max_rule; + int fail, score, max_score; + + rule = f->rules; + max_rule = NULL; + max_score = 0; + while (rule) { + score = 0; + fail = 0; + if (rule->rules & IKS_RULE_TYPE) { + if (rule->type == pak->type) score += 1; else fail = 1; + } + if (rule->rules & IKS_RULE_SUBTYPE) { + if (rule->subtype == pak->subtype) score += 2; else fail = 1; + } + if (rule->rules & IKS_RULE_ID) { + if (iks_strcmp (rule->id, pak->id) == 0) score += 16; else fail = 1; + } + if (rule->rules & IKS_RULE_NS) { + if (iks_strcmp (rule->ns, pak->ns) == 0) score += 4; else fail = 1; + } + if (rule->rules & IKS_RULE_FROM) { + if (pak->from && iks_strcmp (rule->from, pak->from->full) == 0) score += 8; else fail = 1; + } + if (rule->rules & IKS_RULE_FROM_PARTIAL) { + if (pak->from && iks_strcmp (rule->from, pak->from->partial) == 0) score += 8; else fail = 1; + } + if (fail != 0) score = 0; + rule->score = score; + if (score > max_score) { + max_rule = rule; + max_score = score; + } + rule = rule->next; + } + while (max_rule) { + if (IKS_FILTER_EAT == max_rule->filterHook (max_rule->user_data, pak)) return; + max_rule->score = 0; + max_rule = NULL; + max_score = 0; + rule = f->rules; + while (rule) { + if (rule->score > max_score) { + max_rule = rule; + max_score = rule->score; + } + rule = rule->next; + } + } +} + +void +iks_filter_delete (iksfilter *f) +{ + iksrule *rule, *tmp; + + rule = f->rules; + while (rule) { + tmp = rule->next; + iks_stack_delete (rule->s); + rule = tmp; + } + iks_free (f); +} diff --git a/src/iks.c b/src/iks.c new file mode 100644 index 0000000..fe61f79 --- /dev/null +++ b/src/iks.c @@ -0,0 +1,762 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2007 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +#define IKS_COMMON \ + struct iks_struct *next, *prev; \ + struct iks_struct *parent; \ + enum ikstype type; \ + ikstack *s + +struct iks_struct { + IKS_COMMON; +}; + +struct iks_tag { + IKS_COMMON; + struct iks_struct *children, *last_child; + struct iks_struct *attribs, *last_attrib; + char *name; +}; + +#define IKS_TAG_NAME(x) ((struct iks_tag *) (x) )->name +#define IKS_TAG_CHILDREN(x) ((struct iks_tag *) (x) )->children +#define IKS_TAG_LAST_CHILD(x) ((struct iks_tag *) (x) )->last_child +#define IKS_TAG_ATTRIBS(x) ((struct iks_tag *) (x) )->attribs +#define IKS_TAG_LAST_ATTRIB(x) ((struct iks_tag *) (x) )->last_attrib + +struct iks_cdata { + IKS_COMMON; + char *cdata; + size_t len; +}; + +#define IKS_CDATA_CDATA(x) ((struct iks_cdata *) (x) )->cdata +#define IKS_CDATA_LEN(x) ((struct iks_cdata *) (x) )->len + +struct iks_attrib { + IKS_COMMON; + char *name; + char *value; +}; + +#define IKS_ATTRIB_NAME(x) ((struct iks_attrib *) (x) )->name +#define IKS_ATTRIB_VALUE(x) ((struct iks_attrib *) (x) )->value + +/***** Node Creating & Deleting *****/ + +iks * +iks_new (const char *name) +{ + ikstack *s; + iks *x; + + s = iks_stack_new (sizeof (struct iks_tag) * 6, 256); + if (!s) return NULL; + x = iks_new_within (name, s); + if (!x) { + iks_stack_delete (s); + return NULL; + } + return x; +} + +iks * +iks_new_within (const char *name, ikstack *s) +{ + iks *x; + size_t len; + + if (name) len = sizeof (struct iks_tag); else len = sizeof (struct iks_cdata); + x = iks_stack_alloc (s, len); + if (!x) return NULL; + memset (x, 0, len); + x->s = s; + x->type = IKS_TAG; + if (name) { + IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0); + if (!IKS_TAG_NAME (x)) return NULL; + } + return x; +} + +iks * +iks_insert (iks *x, const char *name) +{ + iks *y; + + if (!x) return NULL; + + y = iks_new_within (name, x->s); + if (!y) return NULL; + y->parent = x; + if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y; + if (IKS_TAG_LAST_CHILD (x)) { + IKS_TAG_LAST_CHILD (x)->next = y; + y->prev = IKS_TAG_LAST_CHILD (x); + } + IKS_TAG_LAST_CHILD (x) = y; + return y; +} + +iks * +iks_insert_cdata (iks *x, const char *data, size_t len) +{ + iks *y; + + if(!x || !data) return NULL; + if(len == 0) len = strlen (data); + + y = IKS_TAG_LAST_CHILD (x); + if (y && y->type == IKS_CDATA) { + IKS_CDATA_CDATA (y) = iks_stack_strcat (x->s, IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y), data, len); + IKS_CDATA_LEN (y) += len; + } else { + y = iks_insert (x, NULL); + if (!y) return NULL; + y->type = IKS_CDATA; + IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len); + if (!IKS_CDATA_CDATA (y)) return NULL; + IKS_CDATA_LEN (y) = len; + } + return y; +} + +iks * +iks_insert_attrib (iks *x, const char *name, const char *value) +{ + iks *y; + + if (!x) return NULL; + + y = IKS_TAG_ATTRIBS (x); + while (y) { + if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break; + y = y->next; + } + if (NULL == y) { + if (!value) return NULL; + y = iks_stack_alloc (x->s, sizeof (struct iks_attrib)); + if (!y) return NULL; + memset (y, 0, sizeof (struct iks_attrib)); + y->type = IKS_ATTRIBUTE; + y->s = x->s; + IKS_ATTRIB_NAME (y) = iks_stack_strdup (x->s, name, 0); + if (!IKS_ATTRIB_NAME (y)) return NULL; + y->parent = x; + if (!IKS_TAG_ATTRIBS (x)) IKS_TAG_ATTRIBS (x) = y; + if (IKS_TAG_LAST_ATTRIB (x)) { + IKS_TAG_LAST_ATTRIB (x)->next = y; + y->prev = IKS_TAG_LAST_ATTRIB (x); + } + IKS_TAG_LAST_ATTRIB (x) = y; + } + + if (value) { + IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, 0); + if (!IKS_ATTRIB_VALUE (y)) return NULL; + } else { + if (y->next) y->next->prev = y->prev; + if (y->prev) y->prev->next = y->next; + if (IKS_TAG_ATTRIBS (x) == y) IKS_TAG_ATTRIBS (x) = y->next; + if (IKS_TAG_LAST_ATTRIB (x) == y) IKS_TAG_LAST_ATTRIB (x) = y->prev; + } + + return y; +} + +iks * +iks_insert_node (iks *x, iks *y) +{ + y->parent = x; + if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y; + if (IKS_TAG_LAST_CHILD (x)) { + IKS_TAG_LAST_CHILD (x)->next = y; + y->prev = IKS_TAG_LAST_CHILD (x); + } + IKS_TAG_LAST_CHILD (x) = y; + return y; +} + +iks * +iks_append (iks *x, const char *name) +{ + iks *y; + + if (!x) return NULL; + y = iks_new_within (name, x->s); + if (!y) return NULL; + + if (x->next) { + x->next->prev = y; + } else { + IKS_TAG_LAST_CHILD (x->parent) = y; + } + y->next = x->next; + x->next = y; + y->parent = x->parent; + y->prev = x; + + return y; +} + +iks * +iks_prepend (iks *x, const char *name) +{ + iks *y; + + if (!x) return NULL; + y = iks_new_within (name, x->s); + if (!y) return NULL; + + if (x->prev) { + x->prev->next = y; + } else { + IKS_TAG_CHILDREN (x->parent) = y; + } + y->prev = x->prev; + x->prev = y; + y->parent = x->parent; + y->next = x; + + return y; +} + +iks * +iks_append_cdata (iks *x, const char *data, size_t len) +{ + iks *y; + + if (!x || !data) return NULL; + if (len == 0) len = strlen (data); + + y = iks_new_within (NULL, x->s); + if (!y) return NULL; + y->type = IKS_CDATA; + IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len); + if (!IKS_CDATA_CDATA (y)) return NULL; + IKS_CDATA_LEN (y) = len; + + if (x->next) { + x->next->prev = y; + } else { + IKS_TAG_LAST_CHILD (x->parent) = y; + } + y->next = x->next; + x->next = y; + y->parent = x->parent; + y->prev = x; + + return y; +} + +iks * +iks_prepend_cdata (iks *x, const char *data, size_t len) +{ + iks *y; + + if (!x || !data) return NULL; + if (len == 0) len = strlen (data); + + y = iks_new_within (NULL, x->s); + if (!y) return NULL; + y->type = IKS_CDATA; + IKS_CDATA_CDATA(y) = iks_stack_strdup (x->s, data, len); + if (!IKS_CDATA_CDATA (y)) return NULL; + IKS_CDATA_LEN (y) = len; + + if (x->prev) { + x->prev->next = y; + } else { + IKS_TAG_CHILDREN (x->parent) = y; + } + y->prev = x->prev; + x->prev = y; + y->parent = x->parent; + y->next = x; + + return y; +} + +void +iks_hide (iks *x) +{ + iks *y; + + if (!x) return; + + if (x->prev) x->prev->next = x->next; + if (x->next) x->next->prev = x->prev; + y = x->parent; + if (y) { + if (IKS_TAG_CHILDREN (y) == x) IKS_TAG_CHILDREN (y) = x->next; + if (IKS_TAG_LAST_CHILD (y) == x) IKS_TAG_LAST_CHILD (y) = x->prev; + } +} + +void +iks_delete (iks *x) +{ + if (x) iks_stack_delete (x->s); +} + +/***** Node Traversing *****/ + +iks * +iks_next (iks *x) +{ + if (x) return x->next; + return NULL; +} + +iks * +iks_next_tag (iks *x) +{ + if (x) { + while (1) { + x = x->next; + if (NULL == x) break; + if (IKS_TAG == x->type) return x; + } + } + return NULL; +} + +iks * +iks_prev (iks *x) +{ + if (x) return x->prev; + return NULL; +} + +iks * +iks_prev_tag (iks *x) +{ + if (x) { + while (1) { + x = x->prev; + if (NULL == x) break; + if (IKS_TAG == x->type) return x; + } + } + return NULL; +} + +iks * +iks_parent (iks *x) +{ + if (x) return x->parent; + return NULL; +} + +iks * +iks_root (iks *x) +{ + if (x) { + while (x->parent) + x = x->parent; + } + return x; +} + +iks * +iks_child (iks *x) +{ + if (x && IKS_TAG == x->type) return IKS_TAG_CHILDREN (x); + return NULL; +} + +iks * +iks_first_tag (iks *x) +{ + if (x) { + x = IKS_TAG_CHILDREN (x); + while (x) { + if (IKS_TAG == x->type) return x; + x = x->next; + } + } + return NULL; +} + +iks * +iks_attrib (iks *x) +{ + if (x) return IKS_TAG_ATTRIBS (x); + return NULL; +} + +iks * +iks_find (iks *x, const char *name) +{ + iks *y; + + if (!x) return NULL; + y = IKS_TAG_CHILDREN (x); + while (y) { + if (IKS_TAG == y->type && IKS_TAG_NAME (y) && strcmp (IKS_TAG_NAME (y), name) == 0) return y; + y = y->next; + } + return NULL; +} + +char * +iks_find_cdata (iks *x, const char *name) +{ + iks *y; + + y = iks_find (x, name); + if (!y) return NULL; + y = IKS_TAG_CHILDREN (y); + if (!y || IKS_CDATA != y->type) return NULL; + return IKS_CDATA_CDATA (y); +} + +char * +iks_find_attrib (iks *x, const char *name) +{ + iks *y; + + if (!x) return NULL; + + y = IKS_TAG_ATTRIBS (x); + while (y) { + if (IKS_ATTRIB_NAME (y) && strcmp (IKS_ATTRIB_NAME (y), name) == 0) + return IKS_ATTRIB_VALUE (y); + y = y->next; + } + return NULL; +} + +iks * +iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value) +{ + iks *y; + + if (NULL == x) return NULL; + + if (tagname) { + for (y = IKS_TAG_CHILDREN (x); y; y = y->next) { + if (IKS_TAG == y->type + && strcmp (IKS_TAG_NAME (y), tagname) == 0 + && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) { + return y; + } + } + } else { + for (y = IKS_TAG_CHILDREN (x); y; y = y->next) { + if (IKS_TAG == y->type + && iks_strcmp (iks_find_attrib (y, attrname), value) == 0) { + return y; + } + } + } + return NULL; +} + +/***** Node Information *****/ + +ikstack * +iks_stack (iks *x) +{ + if (x) return x->s; + return NULL; +} + +enum ikstype +iks_type (iks *x) +{ + if (x) return x->type; + return IKS_NONE; +} + +char * +iks_name (iks *x) +{ + if (x) { + if (IKS_TAG == x->type) + return IKS_TAG_NAME (x); + else + return IKS_ATTRIB_NAME (x); + } + return NULL; +} + +char * +iks_cdata (iks *x) +{ + if (x) { + if (IKS_CDATA == x->type) + return IKS_CDATA_CDATA (x); + else + return IKS_ATTRIB_VALUE (x); + } + return NULL; +} + +size_t +iks_cdata_size (iks *x) +{ + if (x) return IKS_CDATA_LEN (x); + return 0; +} + +int +iks_has_children (iks *x) +{ + if (x && IKS_TAG == x->type && IKS_TAG_CHILDREN (x)) return 1; + return 0; +} + +int +iks_has_attribs (iks *x) +{ + if (x && IKS_TAG == x->type && IKS_TAG_ATTRIBS (x)) return 1; + return 0; +} + +/***** Serializing *****/ + +static size_t +escape_size (char *src, size_t len) +{ + size_t sz; + char c; + int i; + + sz = 0; + for (i = 0; i < len; i++) { + c = src[i]; + switch (c) { + case '&': sz += 5; break; + case '\'': sz += 6; break; + case '"': sz += 6; break; + case '<': sz += 4; break; + case '>': sz += 4; break; + default: sz++; break; + } + } + return sz; +} + +static char * +my_strcat (char *dest, char *src, size_t len) +{ + if (0 == len) len = strlen (src); + memcpy (dest, src, len); + return dest + len; +} + +static char * +escape (char *dest, char *src, size_t len) +{ + char c; + int i; + int j = 0; + + for (i = 0; i < len; i++) { + c = src[i]; + if ('&' == c || '<' == c || '>' == c || '\'' == c || '"' == c) { + if (i - j > 0) dest = my_strcat (dest, src + j, i - j); + j = i + 1; + switch (c) { + case '&': dest = my_strcat (dest, "&", 5); break; + case '\'': dest = my_strcat (dest, "'", 6); break; + case '"': dest = my_strcat (dest, """, 6); break; + case '<': dest = my_strcat (dest, "<", 4); break; + case '>': dest = my_strcat (dest, ">", 4); break; + } + } + } + if (i - j > 0) dest = my_strcat (dest, src + j, i - j); + return dest; +} + +char * +iks_string (ikstack *s, iks *x) +{ + size_t size; + int level, dir; + iks *y, *z; + char *ret, *t; + + if (!x) return NULL; + + if (x->type == IKS_CDATA) { + if (s) { + return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); + } else { + ret = iks_malloc (IKS_CDATA_LEN (x)); + memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); + return ret; + } + } + + size = 0; + level = 0; + dir = 0; + y = x; + while (1) { + if (dir==0) { + if (y->type == IKS_TAG) { + size++; + size += strlen (IKS_TAG_NAME (y)); + for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) { + size += 4 + strlen (IKS_ATTRIB_NAME (z)) + + escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z))); + } + if (IKS_TAG_CHILDREN (y)) { + size++; + y = IKS_TAG_CHILDREN (y); + level++; + continue; + } else { + size += 2; + } + } else { + size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y)); + } + } + z = y->next; + if (z) { + if (0 == level) { + if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y)); + break; + } + y = z; + dir = 0; + } else { + y = y->parent; + level--; + if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y)); + if (level < 1) break; + dir = 1; + } + } + + if (s) ret = iks_stack_alloc (s, size + 1); + else ret = iks_malloc (size + 1); + + if (!ret) return NULL; + + t = ret; + level = 0; + dir = 0; + while (1) { + if (dir==0) { + if (x->type == IKS_TAG) { + *t++ = '<'; + t = my_strcat (t, IKS_TAG_NAME (x), 0); + y = IKS_TAG_ATTRIBS (x); + while (y) { + *t++ = ' '; + t = my_strcat (t, IKS_ATTRIB_NAME (y), 0); + *t++ = '='; + *t++ = '\''; + t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y))); + *t++ = '\''; + y = y->next; + } + if (IKS_TAG_CHILDREN (x)) { + *t++ = '>'; + x = IKS_TAG_CHILDREN (x); + level++; + continue; + } else { + *t++ = '/'; + *t++ = '>'; + } + } else { + t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); + } + } + y = x->next; + if (y) { + if (0 == level) { + if (IKS_TAG_CHILDREN (x)) { + *t++ = '<'; + *t++ = '/'; + t = my_strcat (t, IKS_TAG_NAME (x), 0); + *t++ = '>'; + } + break; + } + x = y; + dir = 0; + } else { + x = x->parent; + level--; + if (level >= 0) { + *t++ = '<'; + *t++ = '/'; + t = my_strcat (t, IKS_TAG_NAME (x), 0); + *t++ = '>'; + } + if (level < 1) break; + dir = 1; + } + } + *t = '\0'; + + return ret; +} + +/***** Copying *****/ + +iks * +iks_copy_within (iks *x, ikstack *s) +{ + int level=0, dir=0; + iks *copy = NULL; + iks *cur = NULL; + iks *y; + + while (1) { + if (dir == 0) { + if (x->type == IKS_TAG) { + if (copy == NULL) { + copy = iks_new_within (IKS_TAG_NAME (x), s); + cur = copy; + } else { + cur = iks_insert (cur, IKS_TAG_NAME (x)); + } + for (y = IKS_TAG_ATTRIBS (x); y; y = y->next) { + iks_insert_attrib (cur, IKS_ATTRIB_NAME (y), IKS_ATTRIB_VALUE (y)); + } + if (IKS_TAG_CHILDREN (x)) { + x = IKS_TAG_CHILDREN (x); + level++; + continue; + } else { + cur = cur->parent; + } + } else { + iks_insert_cdata (cur, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x)); + } + } + y = x->next; + if (y) { + if (0 == level) break; + x = y; + dir = 0; + } else { + if (level < 2) break; + level--; + x = x->parent; + cur = cur->parent; + dir = 1; + } + } + return copy; +} + +iks * +iks_copy (iks *x) +{ + return iks_copy_within (x, iks_stack_new (sizeof (struct iks_tag) * 6, 256)); +} diff --git a/src/ikstack.c b/src/ikstack.c new file mode 100644 index 0000000..a1dc654 --- /dev/null +++ b/src/ikstack.c @@ -0,0 +1,202 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +struct align_test { char a; double b; }; +#define DEFAULT_ALIGNMENT ((size_t) ((char *) &((struct align_test *) 0)->b - (char *) 0)) +#define ALIGN_MASK ( DEFAULT_ALIGNMENT - 1 ) +#define MIN_CHUNK_SIZE ( DEFAULT_ALIGNMENT * 8 ) +#define MIN_ALLOC_SIZE DEFAULT_ALIGNMENT +#define ALIGN(x) ( (x) + (DEFAULT_ALIGNMENT - ( (x) & ALIGN_MASK)) ) + +typedef struct ikschunk_struct { + struct ikschunk_struct *next; + size_t size; + size_t used; + size_t last; + char data[4]; +} ikschunk; + +struct ikstack_struct { + size_t allocated; + ikschunk *meta; + ikschunk *data; +}; + +static ikschunk * +find_space (ikstack *s, ikschunk *c, size_t size) +{ + /* FIXME: dont use *2 after over allocated chunks */ + while (1) { + if (c->size - c->used >= size) return c; + if (!c->next) { + if ((c->size * 2) > size) size = c->size * 2; + c->next = iks_malloc (sizeof (ikschunk) + size); + if (!c->next) return NULL; + s->allocated += sizeof (ikschunk) + size; + c = c->next; + c->next = NULL; + c->size = size; + c->used = 0; + c->last = (size_t) -1; + return c; + } + c = c->next; + } + return NULL; +} + +ikstack * +iks_stack_new (size_t meta_chunk, size_t data_chunk) +{ + ikstack *s; + size_t len; + + if (meta_chunk < MIN_CHUNK_SIZE) meta_chunk = MIN_CHUNK_SIZE; + if (meta_chunk & ALIGN_MASK) meta_chunk = ALIGN (meta_chunk); + if (data_chunk < MIN_CHUNK_SIZE) data_chunk = MIN_CHUNK_SIZE; + if (data_chunk & ALIGN_MASK) data_chunk = ALIGN (data_chunk); + + len = sizeof (ikstack) + meta_chunk + data_chunk + (sizeof (ikschunk) * 2); + s = iks_malloc (len); + if (!s) return NULL; + s->allocated = len; + s->meta = (ikschunk *) ((char *) s + sizeof (ikstack)); + s->meta->next = NULL; + s->meta->size = meta_chunk; + s->meta->used = 0; + s->meta->last = (size_t) -1; + s->data = (ikschunk *) ((char *) s + sizeof (ikstack) + sizeof (ikschunk) + meta_chunk); + s->data->next = NULL; + s->data->size = data_chunk; + s->data->used = 0; + s->data->last = (size_t) -1; + return s; +} + +void * +iks_stack_alloc (ikstack *s, size_t size) +{ + ikschunk *c; + void *mem; + + if (size < MIN_ALLOC_SIZE) size = MIN_ALLOC_SIZE; + if (size & ALIGN_MASK) size = ALIGN (size); + + c = find_space (s, s->meta, size); + if (!c) return NULL; + mem = c->data + c->used; + c->used += size; + return mem; +} + +char * +iks_stack_strdup (ikstack *s, const char *src, size_t len) +{ + ikschunk *c; + char *dest; + + if (!src) return NULL; + if (0 == len) len = strlen (src); + + c = find_space (s, s->data, len + 1); + if (!c) return NULL; + dest = c->data + c->used; + c->last = c->used; + c->used += len + 1; + memcpy (dest, src, len); + dest[len] = '\0'; + return dest; +} + +char * +iks_stack_strcat (ikstack *s, char *old, size_t old_len, const char *src, size_t src_len) +{ + char *ret; + ikschunk *c; + + if (!old) { + return iks_stack_strdup (s, src, src_len); + } + if (0 == old_len) old_len = strlen (old); + if (0 == src_len) src_len = strlen (src); + + for (c = s->data; c; c = c->next) { + if (c->data + c->last == old) break; + } + if (!c) { + c = find_space (s, s->data, old_len + src_len + 1); + if (!c) return NULL; + ret = c->data + c->used; + c->last = c->used; + c->used += old_len + src_len + 1; + memcpy (ret, old, old_len); + memcpy (ret + old_len, src, src_len); + ret[old_len + src_len] = '\0'; + return ret; + } + + if (c->size - c->used > src_len) { + ret = c->data + c->last; + memcpy (ret + old_len, src, src_len); + c->used += src_len; + ret[old_len + src_len] = '\0'; + } else { + /* FIXME: decrease c->used before moving string to new place */ + c = find_space (s, s->data, old_len + src_len + 1); + if (!c) return NULL; + c->last = c->used; + ret = c->data + c->used; + memcpy (ret, old, old_len); + c->used += old_len; + memcpy (c->data + c->used, src, src_len); + c->used += src_len; + c->data[c->used] = '\0'; + c->used++; + } + return ret; +} + +void +iks_stack_stat (ikstack *s, size_t *allocated, size_t *used) +{ + ikschunk *c; + + if (allocated) { + *allocated = s->allocated; + } + if (used) { + *used = 0; + for (c = s->meta; c; c = c->next) { + (*used) += c->used; + } + for (c = s->data; c; c = c->next) { + (*used) += c->used; + } + } +} + +void +iks_stack_delete (ikstack *s) +{ + ikschunk *c, *tmp; + + c = s->meta->next; + while (c) { + tmp = c->next; + iks_free (c); + c = tmp; + } + c = s->data->next; + while (c) { + tmp = c->next; + iks_free (c); + c = tmp; + } + iks_free (s); +} diff --git a/src/io-posix.c b/src/io-posix.c new file mode 100644 index 0000000..a46fdfe --- /dev/null +++ b/src/io-posix.c @@ -0,0 +1,137 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2004 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +#ifdef _WIN32 +#include <winsock.h> +#else +#include <netdb.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#endif + +static void +io_close (void *socket) +{ + int sock = (int) socket; +#ifdef _WIN32 + closesocket (sock); +#else + close (sock); +#endif +} + +static int +io_connect (iksparser *prs, void **socketptr, const char *server, int port) +{ + int sock = -1; + int tmp; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints; + struct addrinfo *addr_res, *addr_ptr; + char port_str[6]; + int err = 0; + + hints.ai_flags = AI_CANONNAME; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + sprintf (port_str, "%i", port); + + if (getaddrinfo (server, port_str, &hints, &addr_res) != 0) + return IKS_NET_NODNS; + + addr_ptr = addr_res; + while (addr_ptr) { + err = IKS_NET_NOSOCK; + sock = socket (addr_ptr->ai_family, addr_ptr->ai_socktype, addr_ptr->ai_protocol); + if (sock != -1) { + err = IKS_NET_NOCONN; + tmp = connect (sock, addr_ptr->ai_addr, addr_ptr->ai_addrlen); + if (tmp == 0) break; + io_close ((void *) sock); + sock = -1; + } + addr_ptr = addr_ptr->ai_next; + } + freeaddrinfo (addr_res); + + if (sock == -1) return err; +#else + struct hostent *host; + struct sockaddr_in sin; + + host = gethostbyname (server); + if (!host) return IKS_NET_NODNS; + + memcpy (&sin.sin_addr, host->h_addr, host->h_length); + sin.sin_family = host->h_addrtype; + sin.sin_port = htons (port); + sock = socket (host->h_addrtype, SOCK_STREAM, 0); + if (sock == -1) return IKS_NET_NOSOCK; + + tmp = connect (sock, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); + if (tmp != 0) { + io_close ((void *) sock); + return IKS_NET_NOCONN; + } +#endif + + *socketptr = (void *) sock; + + return IKS_OK; +} + +static int +io_send (void *socket, const char *data, size_t len) +{ + int sock = (int) socket; + + if (send (sock, data, len, 0) == -1) return IKS_NET_RWERR; + return IKS_OK; +} + +static int +io_recv (void *socket, char *buffer, size_t buf_len, int timeout) +{ + int sock = (int) socket; + fd_set fds; + struct timeval tv, *tvptr; + int len; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO (&fds); + FD_SET (sock, &fds); + tv.tv_sec = timeout; + if (timeout != -1) tvptr = &tv; else tvptr = NULL; + if (select (sock + 1, &fds, NULL, NULL, tvptr) > 0) { + len = recv (sock, buffer, buf_len, 0); + if (len > 0) { + return len; + } else if (len <= 0) { + return -1; + } + } + return 0; +} + +ikstransport iks_default_transport = { + IKS_TRANSPORT_V1, + io_connect, + io_send, + io_recv, + io_close, + NULL +}; diff --git a/src/jabber.c b/src/jabber.c new file mode 100644 index 0000000..9143751 --- /dev/null +++ b/src/jabber.c @@ -0,0 +1,330 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +iksid * +iks_id_new (ikstack *s, const char *jid) +{ + iksid *id; + char *src, *tmp; + +/* FIXME: add jabber id validity checks to this function */ +/* which characters are allowed in id parts? */ + + if (!jid) return NULL; + id = iks_stack_alloc (s, sizeof (iksid)); + if (!id) return NULL; + memset (id, 0, sizeof (iksid)); + + /* skip scheme */ + if (strncmp ("jabber:", jid, 7) == 0) jid += 7; + + id->full = iks_stack_strdup (s, jid, 0); + src = id->full; + + /* split resource */ + tmp = strchr (src, '/'); + if (tmp) { + id->partial = iks_stack_strdup (s, src, tmp - src); + id->resource = tmp + 1; + src = id->partial; + } else { + id->partial = src; + } + + /* split user */ + tmp = strchr (src, '@'); + if (tmp) { + id->user = iks_stack_strdup (s, src, tmp - src); + src = ++tmp; + } + + id->server = src; + + return id; +} + +int +iks_id_cmp (iksid *a, iksid *b, int parts) +{ + int diff; + + if (!a || !b) return (IKS_ID_RESOURCE | IKS_ID_USER | IKS_ID_SERVER); + diff = 0; + if (parts & IKS_ID_RESOURCE && !(!a->resource && !b->resource) && iks_strcmp (a->resource, b->resource) != 0) + diff += IKS_ID_RESOURCE; + if (parts & IKS_ID_USER && !(!a->user && !b->user) && iks_strcasecmp (a->user, b->user) != 0) + diff += IKS_ID_USER; + if (parts & IKS_ID_SERVER && !(!a->server && !b->server) && iks_strcmp (a->server, b->server) != 0) + diff += IKS_ID_SERVER; + return diff; +} + +ikspak * +iks_packet (iks *x) +{ + ikspak *pak; + ikstack *s; + char *tmp; + + s = iks_stack (x); + pak = iks_stack_alloc (s, sizeof (ikspak)); + if (!pak) return NULL; + memset (pak, 0, sizeof (ikspak)); + pak->x = x; + tmp = iks_find_attrib (x, "from"); + if (tmp) pak->from = iks_id_new (s, tmp); + pak->id = iks_find_attrib (x, "id"); + + tmp = iks_find_attrib (x, "type"); + if (strcmp (iks_name (x), "message") == 0) { + pak->type = IKS_PAK_MESSAGE; + if (tmp) { + if (strcmp (tmp, "chat") == 0) + pak->subtype = IKS_TYPE_CHAT; + else if (strcmp (tmp, "groupchat") == 0) + pak->subtype = IKS_TYPE_GROUPCHAT; + else if (strcmp (tmp, "headline") == 0) + pak->subtype = IKS_TYPE_HEADLINE; + else if (strcmp (tmp, "error") == 0) + pak->subtype = IKS_TYPE_ERROR; + } + } else if (strcmp (iks_name (x), "presence") == 0) { + pak->type = IKS_PAK_S10N; + if (tmp) { + if (strcmp (tmp, "unavailable") == 0) { + pak->type = IKS_PAK_PRESENCE; + pak->subtype = IKS_TYPE_UNAVAILABLE; + pak->show = IKS_SHOW_UNAVAILABLE; + } else if (strcmp (tmp, "probe") == 0) { + pak->type = IKS_PAK_PRESENCE; + pak->subtype = IKS_TYPE_PROBE; + } else if(strcmp(tmp, "subscribe") == 0) + pak->subtype = IKS_TYPE_SUBSCRIBE; + else if(strcmp(tmp, "subscribed") == 0) + pak->subtype = IKS_TYPE_SUBSCRIBED; + else if(strcmp(tmp, "unsubscribe") == 0) + pak->subtype = IKS_TYPE_UNSUBSCRIBE; + else if(strcmp(tmp, "unsubscribed") == 0) + pak->subtype = IKS_TYPE_UNSUBSCRIBED; + else if(strcmp(tmp, "error") == 0) + pak->subtype = IKS_TYPE_ERROR; + } else { + pak->type = IKS_PAK_PRESENCE; + pak->subtype = IKS_TYPE_AVAILABLE; + tmp = iks_find_cdata (x, "show"); + pak->show = IKS_SHOW_AVAILABLE; + if (tmp) { + if (strcmp (tmp, "chat") == 0) + pak->show = IKS_SHOW_CHAT; + else if (strcmp (tmp, "away") == 0) + pak->show = IKS_SHOW_AWAY; + else if (strcmp (tmp, "xa") == 0) + pak->show = IKS_SHOW_XA; + else if (strcmp (tmp, "dnd") == 0) + pak->show = IKS_SHOW_DND; + } + } + } else if (strcmp (iks_name (x), "iq") == 0) { + iks *q; + pak->type = IKS_PAK_IQ; + if (tmp) { + if (strcmp (tmp, "get") == 0) + pak->subtype = IKS_TYPE_GET; + else if (strcmp (tmp, "set") == 0) + pak->subtype = IKS_TYPE_SET; + else if (strcmp (tmp, "result") == 0) + pak->subtype = IKS_TYPE_RESULT; + else if (strcmp (tmp, "error") == 0) + pak->subtype = IKS_TYPE_ERROR; + } + for (q = iks_child (x); q; q = iks_next (q)) { + if (IKS_TAG == iks_type (q)) { + char *ns; + ns = iks_find_attrib (q, "xmlns"); + if (ns) { + pak->query = q; + pak->ns = ns; + break; + } + } + } + } + return pak; +} + +iks * +iks_make_auth (iksid *id, const char *pass, const char *sid) +{ + iks *x, *y; + + x = iks_new ("iq"); + iks_insert_attrib (x, "type", "set"); + y = iks_insert (x, "query"); + iks_insert_attrib (y, "xmlns", IKS_NS_AUTH); + iks_insert_cdata (iks_insert (y, "username"), id->user, 0); + iks_insert_cdata (iks_insert (y, "resource"), id->resource, 0); + if(sid) { + char buf[41]; + iksha *sha; + sha = iks_sha_new (); + iks_sha_hash (sha, (const unsigned char*)sid, strlen (sid), 0); + iks_sha_hash (sha, (const unsigned char*)pass, strlen (pass), 1); + iks_sha_print (sha, buf); + iks_sha_delete (sha); + iks_insert_cdata (iks_insert (y, "digest"), buf, 40); + } else { + iks_insert_cdata (iks_insert (y, "password"), pass, 0); + } + return x; +} + +iks * +iks_make_msg (enum iksubtype type, const char *to, const char *body) +{ + iks *x; + char *t = NULL; + + x = iks_new ("message"); + switch (type) { + case IKS_TYPE_CHAT: t = "chat"; break; + case IKS_TYPE_GROUPCHAT: t = "groupchat"; break; + case IKS_TYPE_HEADLINE: t = "headline"; break; + default: break; + } + if (t) iks_insert_attrib (x, "type", t); + if (to) iks_insert_attrib (x, "to", to); + if (body) iks_insert_cdata (iks_insert (x, "body"), body, 0); + return x; +} + +iks * +iks_make_s10n (enum iksubtype type, const char *to, const char *msg) +{ + iks *x; + char *t; + + x = iks_new ("presence"); + switch (type) { + case IKS_TYPE_SUBSCRIBE: t = "subscribe"; break; + case IKS_TYPE_SUBSCRIBED: t = "subscribed"; break; + case IKS_TYPE_UNSUBSCRIBE: t = "unsubscribe"; break; + case IKS_TYPE_UNSUBSCRIBED: t = "unsubscribed"; break; + case IKS_TYPE_PROBE: t = "probe"; break; + default: t = NULL; break; + } + if (t) iks_insert_attrib (x, "type", t); + if (to) iks_insert_attrib (x, "to", to); + if (msg) iks_insert_cdata(iks_insert (x, "status"), msg, 0); + return x; +} + +iks * +iks_make_pres (enum ikshowtype show, const char *status) +{ + iks *x; + char *t; + + x = iks_new ("presence"); + switch (show) { + case IKS_SHOW_CHAT: t = "chat"; break; + case IKS_SHOW_AWAY: t = "away"; break; + case IKS_SHOW_XA: t = "xa"; break; + case IKS_SHOW_DND: t = "dnd"; break; + case IKS_SHOW_UNAVAILABLE: + t = NULL; + iks_insert_attrib (x, "type", "unavailable"); + break; + default: t = NULL; break; + } + if (t) iks_insert_cdata (iks_insert (x, "show"), t, 0); + if (status) iks_insert_cdata(iks_insert (x, "status"), status, 0); + return x; +} + +iks * +iks_make_iq (enum iksubtype type, const char *xmlns) +{ + iks *x; + char *t = NULL; + + x = iks_new ("iq"); + switch (type) { + case IKS_TYPE_GET: t = "get"; break; + case IKS_TYPE_SET: t = "set"; break; + case IKS_TYPE_RESULT: t = "result"; break; + case IKS_TYPE_ERROR: t = "error"; break; + default: break; + } + if (t) iks_insert_attrib (x, "type", t); + iks_insert_attrib (iks_insert (x, "query"), "xmlns", xmlns); + + return x; +} + +iks * +iks_make_resource_bind (iksid *id) +{ + iks *x, *y, *z; + + x = iks_new("iq"); + iks_insert_attrib(x, "type", "set"); + y = iks_insert(x, "bind"); + iks_insert_attrib(y, "xmlns", IKS_NS_XMPP_BIND); + if (id->resource && iks_strcmp(id->resource, "")) { + z = iks_insert(y, "resource"); + iks_insert_cdata(z, id->resource, 0); + } + return x; +} + +iks * +iks_make_session (void) +{ + iks *x, *y; + + x = iks_new ("iq"); + iks_insert_attrib (x, "type", "set"); + y = iks_insert (x, "session"); + iks_insert_attrib (y, "xmlns", IKS_NS_XMPP_SESSION); + return x; +} + +static int +iks_sasl_mechanisms (iks *x) +{ + int sasl_mech = 0; + + while (x) { + if (!iks_strcmp(iks_cdata(iks_child(x)), "DIGEST-MD5")) + sasl_mech |= IKS_STREAM_SASL_MD5; + else if (!iks_strcmp(iks_cdata(iks_child(x)), "PLAIN")) + sasl_mech |= IKS_STREAM_SASL_PLAIN; + x = iks_next_tag(x); + } + return sasl_mech; +} + +int +iks_stream_features (iks *x) +{ + int features = 0; + + if (iks_strcmp(iks_name(x), "stream:features")) + return 0; + for (x = iks_child(x); x; x = iks_next_tag(x)) + if (!iks_strcmp(iks_name(x), "starttls")) + features |= IKS_STREAM_STARTTLS; + else if (!iks_strcmp(iks_name(x), "bind")) + features |= IKS_STREAM_BIND; + else if (!iks_strcmp(iks_name(x), "session")) + features |= IKS_STREAM_SESSION; + else if (!iks_strcmp(iks_name(x), "mechanisms")) + features |= iks_sasl_mechanisms(iks_child(x)); + return features; +} diff --git a/src/md5.c b/src/md5.c new file mode 100644 index 0000000..11af2d8 --- /dev/null +++ b/src/md5.c @@ -0,0 +1,189 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +#define GET_UINT32(n,b,i) { \ + (n) = ( (unsigned long int) (b)[(i) ] ) \ + | ( (unsigned long int) (b)[(i) + 1] << 8 ) \ + | ( (unsigned long int) (b)[(i) + 2] << 16 ) \ + | ( (unsigned long int) (b)[(i) + 3] << 24 ); \ +} + +#define PUT_UINT32(n,b,i) { \ + (b)[(i) ] = (unsigned char) ( (n) ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ +} + +#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) + +#define G(x,y,z) ((y) ^ ((z) & ((x) ^ (y)))) + +#define H(x,y,z) ((x) ^ (y) ^ (z)) + +#define I(x,y,z) ((y) ^ ((x) | ~(z))) + +#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) + +#define P(r,i,f,k,s,t) { \ + r[i] += f(r[((i)+1)%4],r[((i)+2)%4],r[((i)+3)%4]) + X[k] + t; \ + r[i] = S(r[i],s) + r[((i)+1)%4]; \ +} + +struct iksmd5_struct { + unsigned long int total[2]; + unsigned long int state[4]; + unsigned char buffer[64]; + unsigned char blen; +}; + +static const unsigned long int T[] = + { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; + +static void iks_md5_compute(iksmd5 *md5); + +void iks_md5_reset(iksmd5 *md5) +{ + memset(md5, 0, sizeof(iksmd5)); + md5->state[0] = 0x67452301; + md5->state[1] = 0xEFCDAB89; + md5->state[2] = 0x98BADCFE; + md5->state[3] = 0x10325476; +} + +iksmd5 *iks_md5_new(void) +{ + iksmd5 *md5 = malloc(sizeof(iksmd5)); + + if (!md5) + return NULL; + iks_md5_reset(md5); + return md5; +} + +void iks_md5_hash(iksmd5 *md5, const unsigned char *data, size_t slen, int finish) +{ + int i, j; + int len = slen; + + i = (64 - md5->blen); + j = (len < i) ? (len) : (i); + memcpy(md5->buffer + md5->blen, data, j); + md5->blen += j; + len -= j; + data += j; + while (len > 0) { + iks_md5_compute(md5); + md5->blen = 0; + md5->total[0] += 8*64; + md5->total[1] += (md5->total[0] < 8*64); + j = (len < 64) ? (len) : (64); + memcpy(md5->buffer, data, j); + md5->blen = j; + len -= j; + data += j; + } + if (finish) { + md5->total[0] += 8*md5->blen; + md5->total[1] += (md5->total[0] < 8*md5->blen); + md5->buffer[(md5->blen)++] = 0x80; + if (md5->blen > 56) { + while (md5->blen < 64) + md5->buffer[(md5->blen)++] = 0x00; + iks_md5_compute(md5); + md5->blen = 0; + } + while (md5->blen < 56) + md5->buffer[(md5->blen)++] = 0x00; + PUT_UINT32(md5->total[0], md5->buffer, 56); + PUT_UINT32(md5->total[1], md5->buffer, 60); + iks_md5_compute(md5); + } +} + +void iks_md5_delete(iksmd5 *md5) +{ + free(md5); +} + +void iks_md5_digest(iksmd5 *md5, unsigned char *digest) +{ + PUT_UINT32(md5->state[0], digest, 0); + PUT_UINT32(md5->state[1], digest, 4); + PUT_UINT32(md5->state[2], digest, 8); + PUT_UINT32(md5->state[3], digest, 12); +} + +void iks_md5_print(iksmd5 *md5, char *buf) +{ + int i; + unsigned char digest[16]; + + iks_md5_digest(md5, digest); + for (i = 0; i < 16; i++) { + sprintf (buf, "%02x", digest[i]); + buf += 2; + } +} + +void iks_md5(const char *data, char *buf) +{ + iksmd5 *md5 = iks_md5_new(); + + iks_md5_hash(md5, (const unsigned char*)data, strlen(data), 1); + iks_md5_print(md5, buf); + iks_md5_delete(md5); +} + +static void iks_md5_compute(iksmd5 *md5) +{ + unsigned long int X[16], R[4]; + unsigned char RS1[] = { 7, 12 ,17, 22 }; + unsigned char RS2[] = { 5, 9 ,14, 20 }; + unsigned char RS3[] = { 4, 11 ,16, 23 }; + unsigned char RS4[] = { 6, 10 ,15, 21 }; + int i, j, k, p; + + for (i = 0; i < 16; ++i) + GET_UINT32(X[i], md5->buffer, i*4); + + for (i = 0; i < 4; ++i) + R[i] = md5->state[i]; + + for (i = j = k = 0; i < 16; ++i, j = i%4, k = (k+3)%4) + P(R, k, F, i, RS1[j], T[i]); + + for (i = j = k = 0, p = 1; i < 16; ++i, j = i%4, k = (k+3)%4, p = (p+5)%16) + P(R, k, G, p, RS2[j], T[i+16]); + + for (i = j = k = 0, p = 5; i < 16; ++i, j = i%4, k = (k+3)%4, p = (p+3)%16) + P(R, k, H, p, RS3[j], T[i+32]); + + for (i = j = k = p = 0; i < 16; ++i, j = i%4, k = (k+3)%4, p = (p+7)%16) + P(R, k, I, p, RS4[j], T[i+48]); + + for (i = 0; i < 4; ++i) + md5->state[i] += R[i]; +} + diff --git a/src/sax.c b/src/sax.c new file mode 100644 index 0000000..cb3caef --- /dev/null +++ b/src/sax.c @@ -0,0 +1,634 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2004 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +enum cons_e { + C_CDATA = 0, + C_TAG_START, + C_TAG, + C_TAG_END, + C_ATTRIBUTE, + C_ATTRIBUTE_1, + C_ATTRIBUTE_2, + C_VALUE, + C_VALUE_APOS, + C_VALUE_QUOT, + C_WHITESPACE, + C_ENTITY, + C_COMMENT, + C_COMMENT_1, + C_COMMENT_2, + C_COMMENT_3, + C_MARKUP, + C_MARKUP_1, + C_SECT, + C_SECT_CDATA, + C_SECT_CDATA_1, + C_SECT_CDATA_2, + C_SECT_CDATA_3, + C_SECT_CDATA_4, + C_SECT_CDATA_C, + C_SECT_CDATA_E, + C_SECT_CDATA_E2, + C_PI +}; + +/* if you add a variable here, dont forget changing iks_parser_reset */ +struct iksparser_struct { + ikstack *s; + void *user_data; + iksTagHook *tagHook; + iksCDataHook *cdataHook; + iksDeleteHook *deleteHook; + /* parser context */ + char *stack; + size_t stack_pos; + size_t stack_max; + + enum cons_e context; + enum cons_e oldcontext; + + char *tag_name; + enum ikstagtype tagtype; + + unsigned int attmax; + unsigned int attcur; + int attflag; + char **atts; + int valflag; + + unsigned int entpos; + char entity[8]; + + unsigned long nr_bytes; + unsigned long nr_lines; + + int uni_max; + int uni_len; +}; + +iksparser * +iks_sax_new (void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook) +{ + iksparser *prs; + + prs = iks_malloc (sizeof (iksparser)); + if (NULL == prs) return NULL; + memset (prs, 0, sizeof (iksparser)); + prs->user_data = user_data; + prs->tagHook = tagHook; + prs->cdataHook = cdataHook; + return prs; +} + +iksparser * +iks_sax_extend (ikstack *s, void *user_data, iksTagHook *tagHook, iksCDataHook *cdataHook, iksDeleteHook *deleteHook) +{ + iksparser *prs; + + prs = iks_stack_alloc (s, sizeof (iksparser)); + if (NULL == prs) return NULL; + memset (prs, 0, sizeof (iksparser)); + prs->s = s; + prs->user_data = user_data; + prs->tagHook = tagHook; + prs->cdataHook = cdataHook; + prs->deleteHook = deleteHook; + return prs; +} + +ikstack * +iks_parser_stack (iksparser *prs) +{ + return prs->s; +} + +void * +iks_user_data (iksparser *prs) +{ + return prs->user_data; +} + +unsigned long +iks_nr_bytes (iksparser *prs) +{ + return prs->nr_bytes; +} + +unsigned long +iks_nr_lines (iksparser *prs) +{ + return prs->nr_lines; +} + +#define IS_WHITESPACE(x) ' ' == (x) || '\t' == (x) || '\r' == (x) || '\n' == (x) +#define NOT_WHITESPACE(x) ' ' != (x) && '\t' != (x) && '\r' != (x) && '\n' != (x) + +static int +stack_init (iksparser *prs) +{ + prs->stack = iks_malloc (128); + if (!prs->stack) return 0; + prs->stack_max = 128; + prs->stack_pos = 0; + return 1; +} + +static int +stack_expand (iksparser *prs, int len) +{ + size_t need; + off_t diff; + char *tmp; + need = len - (prs->stack_max - prs->stack_pos); + if (need < prs->stack_max) { + need = prs->stack_max * 2; + } else { + /* need x 1.2 for integer only archs like ARM */ + need = prs->stack_max + ( (need * 6) / 5); + } + tmp = iks_malloc (need); + if (!tmp) return 0; + diff = tmp - prs->stack; + memcpy (tmp, prs->stack, prs->stack_max); + iks_free (prs->stack); + prs->stack = tmp; + prs->stack_max = need; + prs->tag_name += diff; + if (prs->attflag != 0) { + int i = 0; + while (i < (prs->attmax * 2)) { + if (prs->atts[i]) prs->atts[i] += diff; + i++; + } + } + return 1; +} + +#define STACK_INIT \ + if (NULL == prs->stack && 0 == stack_init (prs)) return IKS_NOMEM + +#define STACK_PUSH_START (prs->stack + prs->stack_pos) + +#define STACK_PUSH(buf,len) \ +{ \ + char *sbuf = (buf); \ + size_t slen = (len); \ + if (prs->stack_max - prs->stack_pos <= slen) { \ + if (0 == stack_expand (prs, slen)) return IKS_NOMEM; \ + } \ + memcpy (prs->stack + prs->stack_pos, sbuf, slen); \ + prs->stack_pos += slen; \ +} + +#define STACK_PUSH_END \ +{ \ + if (prs->stack_pos >= prs->stack_max) { \ + if (0 == stack_expand (prs, 1)) return IKS_NOMEM; \ + } \ + prs->stack[prs->stack_pos] = '\0'; \ + prs->stack_pos++; \ +} + +static enum ikserror +sax_core (iksparser *prs, char *buf, int len) +{ + enum ikserror err; + int pos = 0, old = 0, re, stack_old = -1; + unsigned char c; + + while (pos < len) { + re = 0; + c = buf[pos]; + if (0 == c || 0xFE == c || 0xFF == c) return IKS_BADXML; + if (prs->uni_max) { + if ((c & 0xC0) != 0x80) return IKS_BADXML; + prs->uni_len++; + if (prs->uni_len == prs->uni_max) prs->uni_max = 0; + goto cont; + } else { + if (c & 0x80) { + unsigned char mask; + if ((c & 0x60) == 0x40) { + prs->uni_max = 2; + mask = 0x1F; + } else if ((c & 0x70) == 0x60) { + prs->uni_max = 3; + mask = 0x0F; + } else if ((c & 0x78) == 0x70) { + prs->uni_max = 4; + mask = 0x07; + } else if ((c & 0x7C) == 0x78) { + prs->uni_max = 5; + mask = 0x03; + } else if ((c & 0x7E) == 0x7C) { + prs->uni_max = 6; + mask = 0x01; + } else { + return IKS_BADXML; + } + if ((c & mask) == 0) return IKS_BADXML; + prs->uni_len = 1; + if (stack_old == -1 + && (prs->context == C_TAG + || prs->context == C_ATTRIBUTE_1 + || prs->context == C_VALUE_APOS + || prs->context == C_VALUE_QUOT)) stack_old = pos; + goto cont; + } + } + + switch (prs->context) { + case C_CDATA: + if ('&' == c) { + if (old < pos && prs->cdataHook) { + err = prs->cdataHook (prs->user_data, &buf[old], pos - old); + if (IKS_OK != err) return err; + } + prs->context = C_ENTITY; + prs->entpos = 0; + break; + } + if ('<' == c) { + if (old < pos && prs->cdataHook) { + err = prs->cdataHook (prs->user_data, &buf[old], pos - old); + if (IKS_OK != err) return err; + } + STACK_INIT; + prs->tag_name = STACK_PUSH_START; + if (!prs->tag_name) return IKS_NOMEM; + prs->context = C_TAG_START; + } + break; + + case C_TAG_START: + prs->context = C_TAG; + if ('/' == c) { + prs->tagtype = IKS_CLOSE; + break; + } + if ('?' == c) { + prs->context = C_PI; + break; + } + if ('!' == c) { + prs->context = C_MARKUP; + break; + } + prs->tagtype = IKS_OPEN; + stack_old = pos; + break; + + case C_TAG: + if (IS_WHITESPACE(c)) { + if (IKS_CLOSE == prs->tagtype) + prs->oldcontext = C_TAG_END; + else + prs->oldcontext = C_ATTRIBUTE; + prs->context = C_WHITESPACE; + if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); + stack_old = -1; + STACK_PUSH_END; + break; + } + if ('/' == c) { + if (IKS_CLOSE == prs->tagtype) return IKS_BADXML; + prs->tagtype = IKS_SINGLE; + prs->context = C_TAG_END; + if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); + stack_old = -1; + STACK_PUSH_END; + break; + } + if ('>' == c) { + prs->context = C_TAG_END; + if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); + stack_old = -1; + STACK_PUSH_END; + re = 1; + break; + } + if (stack_old == -1) stack_old = pos; + break; + + case C_TAG_END: + if (c != '>') return IKS_BADXML; + if (prs->tagHook) { + char **tmp; + if (prs->attcur == 0) tmp = NULL; else tmp = prs->atts; + err = prs->tagHook (prs->user_data, prs->tag_name, tmp, prs->tagtype); + if (IKS_OK != err) return err; + } + prs->stack_pos = 0; + stack_old = -1; + prs->attcur = 0; + prs->attflag = 0; + prs->context = C_CDATA; + old = pos + 1; + break; + + case C_ATTRIBUTE: + if ('/' == c) { + prs->tagtype = IKS_SINGLE; + prs->context = C_TAG_END; + break; + } + if ('>' == c) { + prs->context = C_TAG_END; + re = 1; + break; + } + if (!prs->atts) { + prs->attmax = 12; + prs->atts = iks_malloc (sizeof(char *) * 2 * 12); + if (!prs->atts) return IKS_NOMEM; + memset (prs->atts, 0, sizeof(char *) * 2 * 12); + prs->attcur = 0; + } else { + if (prs->attcur >= (prs->attmax * 2)) { + void *tmp; + prs->attmax += 12; + tmp = iks_malloc (sizeof(char *) * 2 * prs->attmax); + if (!tmp) return IKS_NOMEM; + memset (tmp, 0, sizeof(char *) * 2 * prs->attmax); + memcpy (tmp, prs->atts, sizeof(char *) * prs->attcur); + free (prs->atts); + prs->atts = tmp; + } + } + prs->attflag = 1; + prs->atts[prs->attcur] = STACK_PUSH_START; + stack_old = pos; + prs->context = C_ATTRIBUTE_1; + break; + + case C_ATTRIBUTE_1: + if ('=' == c) { + if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); + stack_old = -1; + STACK_PUSH_END; + prs->context = C_VALUE; + break; + } + if (stack_old == -1) stack_old = pos; + break; + + case C_ATTRIBUTE_2: + if ('/' == c) { + prs->tagtype = IKS_SINGLE; + prs->atts[prs->attcur] = NULL; + prs->context = C_TAG_END; + break; + } + if ('>' == c) { + prs->atts[prs->attcur] = NULL; + prs->context = C_TAG_END; + re = 1; + break; + } + prs->context = C_ATTRIBUTE; + re = 1; + break; + + case C_VALUE: + prs->atts[prs->attcur + 1] = STACK_PUSH_START; + if ('\'' == c) { + prs->context = C_VALUE_APOS; + break; + } + if ('"' == c) { + prs->context = C_VALUE_QUOT; + break; + } + return IKS_BADXML; + + case C_VALUE_APOS: + if ('\'' == c) { + if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); + stack_old = -1; + STACK_PUSH_END; + prs->oldcontext = C_ATTRIBUTE_2; + prs->context = C_WHITESPACE; + prs->attcur += 2; + } + if (stack_old == -1) stack_old = pos; + break; + + case C_VALUE_QUOT: + if ('"' == c) { + if (stack_old != -1) STACK_PUSH (buf + stack_old, pos - stack_old); + stack_old = -1; + STACK_PUSH_END; + prs->oldcontext = C_ATTRIBUTE_2; + prs->context = C_WHITESPACE; + prs->attcur += 2; + } + if (stack_old == -1) stack_old = pos; + break; + + case C_WHITESPACE: + if (NOT_WHITESPACE(c)) { + prs->context = prs->oldcontext; + re = 1; + } + break; + + case C_ENTITY: + if (';' == c) { + char hede[2]; + char t = '?'; + prs->entity[prs->entpos] = '\0'; + if (strcmp(prs->entity, "amp") == 0) + t = '&'; + else if (strcmp(prs->entity, "quot") == 0) + t = '"'; + else if (strcmp(prs->entity, "apos") == 0) + t = '\''; + else if (strcmp(prs->entity, "lt") == 0) + t = '<'; + else if (strcmp(prs->entity, "gt") == 0) + t = '>'; + old = pos + 1; + hede[0] = t; + if (prs->cdataHook) { + err = prs->cdataHook (prs->user_data, &hede[0], 1); + if (IKS_OK != err) return err; + } + prs->context = C_CDATA; + } else { + prs->entity[prs->entpos++] = buf[pos]; + if (prs->entpos > 7) return IKS_BADXML; + } + break; + + case C_COMMENT: + if ('-' != c) return IKS_BADXML; + prs->context = C_COMMENT_1; + break; + + case C_COMMENT_1: + if ('-' == c) prs->context = C_COMMENT_2; + break; + + case C_COMMENT_2: + if ('-' == c) + prs->context = C_COMMENT_3; + else + prs->context = C_COMMENT_1; + break; + + case C_COMMENT_3: + if ('>' != c) return IKS_BADXML; + prs->context = C_CDATA; + old = pos + 1; + break; + + case C_MARKUP: + if ('[' == c) { + prs->context = C_SECT; + break; + } + if ('-' == c) { + prs->context = C_COMMENT; + break; + } + prs->context = C_MARKUP_1; + + case C_MARKUP_1: + if ('>' == c) { + old = pos + 1; + prs->context = C_CDATA; + } + break; + + case C_SECT: + if ('C' == c) { + prs->context = C_SECT_CDATA; + break; + } + return IKS_BADXML; + + case C_SECT_CDATA: + if ('D' != c) return IKS_BADXML; + prs->context = C_SECT_CDATA_1; + break; + + case C_SECT_CDATA_1: + if ('A' != c) return IKS_BADXML; + prs->context = C_SECT_CDATA_2; + break; + + case C_SECT_CDATA_2: + if ('T' != c) return IKS_BADXML; + prs->context = C_SECT_CDATA_3; + break; + + case C_SECT_CDATA_3: + if ('A' != c) return IKS_BADXML; + prs->context = C_SECT_CDATA_4; + break; + + case C_SECT_CDATA_4: + if ('[' != c) return IKS_BADXML; + old = pos + 1; + prs->context = C_SECT_CDATA_C; + break; + + case C_SECT_CDATA_C: + if (']' == c) { + prs->context = C_SECT_CDATA_E; + if (prs->cdataHook && old < pos) { + err = prs->cdataHook (prs->user_data, &buf[old], pos - old); + if (IKS_OK != err) return err; + } + } + break; + + case C_SECT_CDATA_E: + if (']' == c) { + prs->context = C_SECT_CDATA_E2; + } else { + if (prs->cdataHook) { + err = prs->cdataHook (prs->user_data, "]", 1); + if (IKS_OK != err) return err; + } + old = pos; + prs->context = C_SECT_CDATA_C; + } + break; + + case C_SECT_CDATA_E2: + if ('>' == c) { + old = pos + 1; + prs->context = C_CDATA; + } else { + if (prs->cdataHook) { + err = prs->cdataHook (prs->user_data, "]]", 2); + if (IKS_OK != err) return err; + } + old = pos; + prs->context = C_SECT_CDATA_C; + } + break; + + case C_PI: + old = pos + 1; + if ('>' == c) prs->context = C_CDATA; + break; + } +cont: + if (0 == re) { + pos++; + prs->nr_bytes++; + if ('\n' == c) prs->nr_lines++; + } + } + + if (stack_old != -1) + STACK_PUSH (buf + stack_old, pos - stack_old); + + err = IKS_OK; + if (prs->cdataHook && (prs->context == C_CDATA || prs->context == C_SECT_CDATA_C) && old < pos) + err = prs->cdataHook (prs->user_data, &buf[old], pos - old); + return err; +} + +int +iks_parse (iksparser *prs, const char *data, size_t len, int finish) +{ + if (!data) return IKS_OK; + if (len == 0) len = strlen (data); + return sax_core (prs, (char *) data, len); +} + +void +iks_parser_reset (iksparser *prs) +{ + if (prs->deleteHook) prs->deleteHook (prs->user_data); + prs->stack_pos = 0; + prs->context = 0; + prs->oldcontext = 0; + prs->tagtype = 0; + prs->attcur = 0; + prs->attflag = 0; + prs->valflag = 0; + prs->entpos = 0; + prs->nr_bytes = 0; + prs->nr_lines = 0; + prs->uni_max = 0; + prs->uni_len = 0; +} + +void +iks_parser_delete (iksparser *prs) +{ + if (prs->deleteHook) prs->deleteHook (prs->user_data); + if (prs->stack) iks_free (prs->stack); + if (prs->atts) iks_free (prs->atts); + if (prs->s) iks_stack_delete (prs->s); else iks_free (prs); +} diff --git a/src/sha.c b/src/sha.c new file mode 100644 index 0000000..330e1b0 --- /dev/null +++ b/src/sha.c @@ -0,0 +1,152 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +static void sha_buffer (iksha *sha, const unsigned char *data, int len); +static void sha_calculate (iksha *sha); + +struct iksha_struct { + unsigned int hash[5]; + unsigned int buf[80]; + int blen; + unsigned int lenhi, lenlo; +}; + +iksha * +iks_sha_new (void) +{ + iksha *sha; + + sha = iks_malloc (sizeof (iksha)); + if (!sha) return NULL; + iks_sha_reset (sha); + return sha; +} + +void +iks_sha_reset (iksha *sha) +{ + memset (sha, 0, sizeof (iksha)); + sha->hash[0] = 0x67452301; + sha->hash[1] = 0xefcdab89; + sha->hash[2] = 0x98badcfe; + sha->hash[3] = 0x10325476; + sha->hash[4] = 0xc3d2e1f0; +} + +void +iks_sha_hash (iksha *sha, const unsigned char *data, size_t len, int finish) +{ + unsigned char pad[8]; + unsigned char padc; + + if (data && len != 0) sha_buffer (sha, data, len); + if (!finish) return; + + pad[0] = (unsigned char)((sha->lenhi >> 24) & 0xff); + pad[1] = (unsigned char)((sha->lenhi >> 16) & 0xff); + pad[2] = (unsigned char)((sha->lenhi >> 8) & 0xff); + pad[3] = (unsigned char)(sha->lenhi & 0xff); + pad[4] = (unsigned char)((sha->lenlo >> 24) & 0xff); + pad[5] = (unsigned char)((sha->lenlo >> 16) & 0xff); + pad[6] = (unsigned char)((sha->lenlo >> 8) & 0xff); + pad[7] = (unsigned char)(sha->lenlo & 255); + + padc = 0x80; + sha_buffer (sha, &padc, 1); + + padc = 0x00; + while (sha->blen != 56) + sha_buffer (sha, &padc, 1); + + sha_buffer (sha, pad, 8); +} + +void +iks_sha_print (iksha *sha, char *hash) +{ + int i; + + for (i=0; i<5; i++) + { + sprintf (hash, "%08x", sha->hash[i]); + hash += 8; + } +} + +void +iks_sha_delete (iksha *sha) +{ + iks_free (sha); +} + +void +iks_sha (const char *data, char *hash) +{ + iksha *sha; + + sha = iks_sha_new (); + iks_sha_hash (sha, (const unsigned char*)data, strlen (data), 1); + iks_sha_print (sha, hash); + iks_free (sha); +} + +static void +sha_buffer (iksha *sha, const unsigned char *data, int len) +{ + int i; + + for (i=0; i<len; i++) { + sha->buf[sha->blen / 4] <<= 8; + sha->buf[sha->blen / 4] |= (unsigned int)data[i]; + if ((++sha->blen) % 64 == 0) { + sha_calculate (sha); + sha->blen = 0; + } + sha->lenlo += 8; + sha->lenhi += (sha->lenlo < 8); + } +} + +#define SRL(x,y) (((x) << (y)) | ((x) >> (32-(y)))) +#define SHA(a,b,f,c) \ + for (i= (a) ; i<= (b) ; i++) { \ + TMP = SRL(A,5) + ( (f) ) + E + sha->buf[i] + (c) ; \ + E = D; \ + D = C; \ + C = SRL(B,30); \ + B = A; \ + A = TMP; \ + } + +static void +sha_calculate (iksha *sha) +{ + int i; + unsigned int A, B, C, D, E, TMP; + + for (i=16; i<80; i++) + sha->buf[i] = SRL (sha->buf[i-3] ^ sha->buf[i-8] ^ sha->buf[i-14] ^ sha->buf[i-16], 1); + + A = sha->hash[0]; + B = sha->hash[1]; + C = sha->hash[2]; + D = sha->hash[3]; + E = sha->hash[4]; + + SHA (0, 19, ((C^D)&B)^D, 0x5a827999); + SHA (20, 39, B^C^D, 0x6ed9eba1); + SHA (40, 59, (B&C)|(D&(B|C)), 0x8f1bbcdc); + SHA (60, 79, B^C^D, 0xca62c1d6); + + sha->hash[0] += A; + sha->hash[1] += B; + sha->hash[2] += C; + sha->hash[3] += D; + sha->hash[4] += E; +} diff --git a/src/stream.c b/src/stream.c new file mode 100644 index 0000000..6bb316e --- /dev/null +++ b/src/stream.c @@ -0,0 +1,642 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2007 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + +#define SF_FOREIGN 1 +#define SF_TRY_SECURE 2 +#define SF_SECURE 4 + +struct stream_data { + iksparser *prs; + ikstack *s; + ikstransport *trans; + char *name_space; + void *user_data; + const char *server; + iksStreamHook *streamHook; + iksLogHook *logHook; + iks *current; + char *buf; + void *sock; + unsigned int flags; + char *auth_username; + char *auth_pass; +#ifdef HAVE_GNUTLS + gnutls_session sess; + gnutls_certificate_credentials cred; +#endif +}; + +#ifdef HAVE_GNUTLS + +static size_t +tls_push (iksparser *prs, const char *buffer, size_t len) +{ + struct stream_data *data = iks_user_data (prs); + int ret; + + ret = data->trans->send (data->sock, buffer, len); + if (ret) return (size_t) -1; + return len; +} + +static size_t +tls_pull (iksparser *prs, char *buffer, size_t len) +{ + struct stream_data *data = iks_user_data (prs); + int ret; + + ret = data->trans->recv (data->sock, buffer, len, -1); + if (ret == -1) return (size_t) -1; + return ret; +} + +static int +handshake (struct stream_data *data) +{ + const int protocol_priority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 }; + const int kx_priority[] = { GNUTLS_KX_RSA, 0 }; + const int cipher_priority[] = { GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0}; + const int comp_priority[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 }; + const int mac_priority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 }; + int ret; + + if (gnutls_global_init () != 0) + return IKS_NOMEM; + + if (gnutls_certificate_allocate_credentials (&data->cred) < 0) + return IKS_NOMEM; + + if (gnutls_init (&data->sess, GNUTLS_CLIENT) != 0) { + gnutls_certificate_free_credentials (data->cred); + return IKS_NOMEM; + } + gnutls_protocol_set_priority (data->sess, protocol_priority); + gnutls_cipher_set_priority(data->sess, cipher_priority); + gnutls_compression_set_priority(data->sess, comp_priority); + gnutls_kx_set_priority(data->sess, kx_priority); + gnutls_mac_set_priority(data->sess, mac_priority); + gnutls_credentials_set (data->sess, GNUTLS_CRD_CERTIFICATE, data->cred); + + gnutls_transport_set_push_function (data->sess, (gnutls_push_func) tls_push); + gnutls_transport_set_pull_function (data->sess, (gnutls_pull_func) tls_pull); + gnutls_transport_set_ptr (data->sess, data->prs); + + ret = gnutls_handshake (data->sess); + if (ret != 0) { + gnutls_deinit (data->sess); + gnutls_certificate_free_credentials (data->cred); + return IKS_NET_TLSFAIL; + } + + data->flags &= (~SF_TRY_SECURE); + data->flags |= SF_SECURE; + + iks_send_header (data->prs, data->server); + + return IKS_OK; +} +#endif + +static void +insert_attribs (iks *x, char **atts) +{ + if (atts) { + int i = 0; + while (atts[i]) { + iks_insert_attrib (x, atts[i], atts[i+1]); + i += 2; + } + } +} + +#define CNONCE_LEN 4 + +static void +parse_digest (char *message, const char *key, char **value_ptr, char **value_end_ptr) +{ + char *t; + + *value_ptr = NULL; + *value_end_ptr = NULL; + + t = strstr(message, key); + if (t) { + t += strlen(key); + *value_ptr = t; + while (t[0] != '\0') { + if (t[0] != '\\' && t[1] == '"') { + ++t; + *value_end_ptr = t; + return; + } + ++t; + } + } +} + +static iks * +make_sasl_response (struct stream_data *data, char *message) +{ + iks *x = NULL; + char *realm, *realm_end; + char *nonce, *nonce_end; + char cnonce[CNONCE_LEN*8 + 1]; + iksmd5 *md5; + unsigned char a1_h[16], a1[33], a2[33], response_value[33]; + char *response, *response_coded; + int i; + + parse_digest(message, "realm=\"", &realm, &realm_end); + parse_digest(message, "nonce=\"", &nonce, &nonce_end); + + /* nonce is necessary for auth */ + if (!nonce || !nonce_end) return NULL; + *nonce_end = '\0'; + + /* if no realm is given use the server hostname */ + if (realm) { + if (!realm_end) return NULL; + *realm_end = '\0'; + } else { + realm = (char *) data->server; + } + + /* generate random client challenge */ + for (i = 0; i < CNONCE_LEN; ++i) + sprintf (cnonce + i*8, "%08x", rand()); + + md5 = iks_md5_new(); + if (!md5) return NULL; + + iks_md5_hash (md5, (const unsigned char*)data->auth_username, iks_strlen (data->auth_username), 0); + iks_md5_hash (md5, (const unsigned char*)":", 1, 0); + iks_md5_hash (md5, (const unsigned char*)realm, iks_strlen (realm), 0); + iks_md5_hash (md5, (const unsigned char*)":", 1, 0); + iks_md5_hash (md5, (const unsigned char*)data->auth_pass, iks_strlen (data->auth_pass), 1); + iks_md5_digest (md5, a1_h); + + iks_md5_reset (md5); + iks_md5_hash (md5, (const unsigned char*)a1_h, 16, 0); + iks_md5_hash (md5, (const unsigned char*)":", 1, 0); + iks_md5_hash (md5, (const unsigned char*)nonce, iks_strlen (nonce), 0); + iks_md5_hash (md5, (const unsigned char*)":", 1, 0); + iks_md5_hash (md5, (const unsigned char*)cnonce, iks_strlen (cnonce), 1); + iks_md5_print (md5, (char*)a1); + + iks_md5_reset (md5); + iks_md5_hash (md5, (const unsigned char*)"AUTHENTICATE:xmpp/", 18, 0); + iks_md5_hash (md5, (const unsigned char*)data->server, iks_strlen (data->server), 1); + iks_md5_print (md5, (char*)a2); + + iks_md5_reset (md5); + iks_md5_hash (md5, (const unsigned char*)a1, 32, 0); + iks_md5_hash (md5, (const unsigned char*)":", 1, 0); + iks_md5_hash (md5, (const unsigned char*)nonce, iks_strlen (nonce), 0); + iks_md5_hash (md5, (const unsigned char*)":00000001:", 10, 0); + iks_md5_hash (md5, (const unsigned char*)cnonce, iks_strlen (cnonce), 0); + iks_md5_hash (md5, (const unsigned char*)":auth:", 6, 0); + iks_md5_hash (md5, (const unsigned char*)a2, 32, 1); + iks_md5_print (md5, (char*)response_value); + + iks_md5_delete (md5); + + i = iks_strlen (data->auth_username) + iks_strlen (realm) + + iks_strlen (nonce) + iks_strlen (data->server) + + CNONCE_LEN*8 + 136; + response = iks_malloc (i); + if (!response) return NULL; + + sprintf (response, "username=\"%s\",realm=\"%s\",nonce=\"%s\"" + ",cnonce=\"%s\",nc=00000001,qop=auth,digest-uri=\"" + "xmpp/%s\",response=%s,charset=utf-8", + data->auth_username, realm, nonce, cnonce, + data->server, response_value); + + response_coded = iks_base64_encode (response, 0); + if (response_coded) { + x = iks_new ("response"); + iks_insert_cdata (x, response_coded, 0); + iks_free (response_coded); + } + iks_free (response); + + return x; +} + +static void +iks_sasl_challenge (struct stream_data *data, iks *challenge) +{ + char *message; + iks *x; + char *tmp; + + tmp = iks_cdata (iks_child (challenge)); + if (!tmp) return; + + /* decode received blob */ + message = iks_base64_decode (tmp); + if (!message) return; + + /* reply the challenge */ + if (strstr (message, "rspauth")) { + x = iks_new ("response"); + } else { + x = make_sasl_response (data, message); + } + if (x) { + iks_insert_attrib (x, "xmlns", IKS_NS_XMPP_SASL); + iks_send (data->prs, x); + iks_delete (x); + } + iks_free (message); +} + +static int +tagHook (struct stream_data *data, char *name, char **atts, int type) +{ + iks *x; + int err; + + switch (type) { + case IKS_OPEN: + case IKS_SINGLE: +#ifdef HAVE_GNUTLS + if (data->flags & SF_TRY_SECURE) { + if (strcmp (name, "proceed") == 0) { + err = handshake (data); + return err; + } else if (strcmp (name, "failure") == 0){ + return IKS_NET_TLSFAIL; + } + } +#endif + if (data->current) { + x = iks_insert (data->current, name); + insert_attribs (x, atts); + } else { + x = iks_new (name); + insert_attribs (x, atts); + if (iks_strcmp (name, "stream:stream") == 0) { + err = data->streamHook (data->user_data, IKS_NODE_START, x); + if (err != IKS_OK) return err; + break; + } + } + data->current = x; + if (IKS_OPEN == type) break; + case IKS_CLOSE: + x = data->current; + if (NULL == x) { + err = data->streamHook (data->user_data, IKS_NODE_STOP, NULL); + if (err != IKS_OK) return err; + break; + } + if (NULL == iks_parent (x)) { + data->current = NULL; + if (iks_strcmp (name, "challenge") == 0) + iks_sasl_challenge(data, x); + else if (iks_strcmp (name, "stream:error") == 0) { + err = data->streamHook (data->user_data, IKS_NODE_ERROR, x); + if (err != IKS_OK) return err; + } else { + err = data->streamHook (data->user_data, IKS_NODE_NORMAL, x); + if (err != IKS_OK) return err; + } + break; + } + data->current = iks_parent (x); + } + return IKS_OK; +} + +static int +cdataHook (struct stream_data *data, char *cdata, size_t len) +{ + if (data->current) iks_insert_cdata (data->current, cdata, len); + return IKS_OK; +} + +static void +deleteHook (struct stream_data *data) +{ +#ifdef HAVE_GNUTLS + if (data->flags & SF_SECURE) { + gnutls_bye (data->sess, GNUTLS_SHUT_WR); + gnutls_deinit (data->sess); + gnutls_certificate_free_credentials (data->cred); + } +#endif + if (data->trans) data->trans->close (data->sock); + data->trans = NULL; + if (data->current) iks_delete (data->current); + data->current = NULL; + data->flags = 0; +} + +iksparser * +iks_stream_new (char *name_space, void *user_data, iksStreamHook *streamHook) +{ + ikstack *s; + struct stream_data *data; + + s = iks_stack_new (DEFAULT_STREAM_CHUNK_SIZE, 0); + if (NULL == s) return NULL; + data = iks_stack_alloc (s, sizeof (struct stream_data)); + memset (data, 0, sizeof (struct stream_data)); + data->s = s; + data->prs = iks_sax_extend (s, data, (iksTagHook *)tagHook, (iksCDataHook *)cdataHook, (iksDeleteHook *)deleteHook); + data->name_space = name_space; + data->user_data = user_data; + data->streamHook = streamHook; + return data->prs; +} + +void * +iks_stream_user_data (iksparser *prs) +{ + struct stream_data *data = iks_user_data (prs); + + return data->user_data; +} + +void +iks_set_log_hook (iksparser *prs, iksLogHook *logHook) +{ + struct stream_data *data = iks_user_data (prs); + + data->logHook = logHook; +} + +int +iks_connect_tcp (iksparser *prs, const char *server, int port) +{ +#ifdef USE_DEFAULT_IO + return iks_connect_with (prs, server, port, server, &iks_default_transport); +#else + return IKS_NET_NOTSUPP; +#endif +} + +int +iks_connect_via (iksparser *prs, const char *server, int port, const char *server_name) +{ +#ifdef USE_DEFAULT_IO + return iks_connect_with (prs, server, port, server_name, &iks_default_transport); +#else + return IKS_NET_NOTSUPP; +#endif +} + +int +iks_connect_with (iksparser *prs, const char *server, int port, const char *server_name, ikstransport *trans) +{ + struct stream_data *data = iks_user_data (prs); + int ret; + + if (!trans->connect) return IKS_NET_NOTSUPP; + + if (!data->buf) { + data->buf = iks_stack_alloc (data->s, NET_IO_BUF_SIZE); + if (NULL == data->buf) return IKS_NOMEM; + } + + ret = trans->connect (prs, &data->sock, server, port); + if (ret) return ret; + + data->trans = trans; + + return iks_send_header (prs, server_name); +} + +int +iks_connect_async (iksparser *prs, const char *server, int port, void *notify_data, iksAsyncNotify *notify_func) +{ +#ifdef USE_DEFAULT_IO + return iks_connect_async_with (prs, server, port, server, &iks_default_transport, notify_data, notify_func); +#else + return IKS_NET_NOTSUPP; +#endif +} + +int +iks_connect_async_with (iksparser *prs, const char *server, int port, const char *server_name, ikstransport *trans, void *notify_data, iksAsyncNotify *notify_func) +{ + struct stream_data *data = iks_user_data (prs); + int ret; + + if (NULL == trans->connect_async) + return IKS_NET_NOTSUPP; + + if (!data->buf) { + data->buf = iks_stack_alloc (data->s, NET_IO_BUF_SIZE); + if (NULL == data->buf) return IKS_NOMEM; + } + + ret = trans->connect_async (prs, &data->sock, server, server_name, port, notify_data, notify_func); + if (ret) return ret; + + data->trans = trans; + data->server = server_name; + + return IKS_OK; +} + +int +iks_connect_fd (iksparser *prs, int fd) +{ +#ifdef USE_DEFAULT_IO + struct stream_data *data = iks_user_data (prs); + + if (!data->buf) { + data->buf = iks_stack_alloc (data->s, NET_IO_BUF_SIZE); + if (NULL == data->buf) return IKS_NOMEM; + } + + data->sock = (void *) fd; + data->flags |= SF_FOREIGN; + data->trans = &iks_default_transport; + + return IKS_OK; +#else + return IKS_NET_NOTSUPP; +#endif +} + +int +iks_fd (iksparser *prs) +{ + struct stream_data *data = iks_user_data (prs); + + return (int) data->sock; +} + +int +iks_recv (iksparser *prs, int timeout) +{ + struct stream_data *data = iks_user_data (prs); + int len, ret; + + while (1) { +#ifdef HAVE_GNUTLS + if (data->flags & SF_SECURE) { + len = gnutls_record_recv (data->sess, data->buf, NET_IO_BUF_SIZE - 1); + } else +#endif + { + len = data->trans->recv (data->sock, data->buf, NET_IO_BUF_SIZE - 1, timeout); + } + if (len < 0) return IKS_NET_RWERR; + if (len == 0) break; + data->buf[len] = '\0'; + if (data->logHook) data->logHook (data->user_data, data->buf, len, 1); + ret = iks_parse (prs, data->buf, len, 0); + if (ret != IKS_OK) return ret; + if (!data->trans) { + /* stream hook called iks_disconnect */ + return IKS_NET_NOCONN; + } + timeout = 0; + } + return IKS_OK; +} + +int +iks_send_header (iksparser *prs, const char *to) +{ + struct stream_data *data = iks_user_data (prs); + char *msg; + int len, err; + + len = 91 + strlen (data->name_space) + 6 + strlen (to) + 16 + 1; + msg = iks_malloc (len); + if (!msg) return IKS_NOMEM; + sprintf (msg, "<?xml version='1.0'?>" + "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='" + "%s' to='%s' version='1.0'>", data->name_space, to); + err = iks_send_raw (prs, msg); + iks_free (msg); + if (err) return err; + data->server = to; + return IKS_OK; +} + +int +iks_send (iksparser *prs, iks *x) +{ + return iks_send_raw (prs, iks_string (iks_stack (x), x)); +} + +int +iks_send_raw (iksparser *prs, const char *xmlstr) +{ + struct stream_data *data = iks_user_data (prs); + int ret; + +#ifdef HAVE_GNUTLS + if (data->flags & SF_SECURE) { + if (gnutls_record_send (data->sess, xmlstr, strlen (xmlstr)) < 0) return IKS_NET_RWERR; + } else +#endif + { + ret = data->trans->send (data->sock, xmlstr, strlen (xmlstr)); + if (ret) return ret; + } + if (data->logHook) data->logHook (data->user_data, xmlstr, strlen (xmlstr), 0); + return IKS_OK; +} + +void +iks_disconnect (iksparser *prs) +{ + iks_parser_reset (prs); +} + +/***** tls api *****/ + +int +iks_has_tls (void) +{ +#ifdef HAVE_GNUTLS + return 1; +#else + return 0; +#endif +} + +int +iks_is_secure (iksparser *prs) +{ +#ifdef HAVE_GNUTLS + struct stream_data *data = iks_user_data (prs); + + return data->flags & SF_SECURE; +#else + return 0; +#endif +} + +int +iks_start_tls (iksparser *prs) +{ +#ifdef HAVE_GNUTLS + int ret; + struct stream_data *data = iks_user_data (prs); + + ret = iks_send_raw (prs, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); + if (ret) return ret; + data->flags |= SF_TRY_SECURE; + return IKS_OK; +#else + return IKS_NET_NOTSUPP; +#endif +} + +/***** sasl *****/ + +int +iks_start_sasl (iksparser *prs, enum ikssasltype type, char *username, char *pass) +{ + iks *x; + + x = iks_new ("auth"); + iks_insert_attrib (x, "xmlns", IKS_NS_XMPP_SASL); + switch (type) { + case IKS_SASL_PLAIN: { + int len = iks_strlen (username) + iks_strlen (pass) + 2; + char *s = iks_malloc (80+len); + char *base64; + + iks_insert_attrib (x, "mechanism", "PLAIN"); + sprintf (s, "%c%s%c%s", 0, username, 0, pass); + base64 = iks_base64_encode (s, len); + iks_insert_cdata (x, base64, 0); + iks_free (base64); + iks_free (s); + break; + } + case IKS_SASL_DIGEST_MD5: { + struct stream_data *data = iks_user_data (prs); + + iks_insert_attrib (x, "mechanism", "DIGEST-MD5"); + data->auth_username = username; + data->auth_pass = pass; + break; + } + default: + iks_delete (x); + return IKS_NET_NOTSUPP; + } + iks_send (prs, x); + iks_delete (x); + return IKS_OK; +} diff --git a/src/utility.c b/src/utility.c new file mode 100644 index 0000000..1586b32 --- /dev/null +++ b/src/utility.c @@ -0,0 +1,180 @@ +/* iksemel (XML parser for Jabber) +** Copyright (C) 2000-2003 Gurer Ozen <madcat@e-kolay.net> +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU Lesser General Public License. +*/ + +#include "common.h" +#include "iksemel.h" + +/***** malloc wrapper *****/ + +static void *(*my_malloc_func)(size_t size); +static void (*my_free_func)(void *ptr); + +void * +iks_malloc (size_t size) +{ + if (my_malloc_func) + return my_malloc_func (size); + else + return malloc (size); +} + +void +iks_free (void *ptr) +{ + if (my_free_func) + my_free_func (ptr); + else + free (ptr); +} + +void +iks_set_mem_funcs (void *(*malloc_func)(size_t size), void (*free_func)(void *ptr)) +{ + my_malloc_func = malloc_func; + my_free_func = free_func; +} + +/***** NULL-safe Functions *****/ + +char * +iks_strdup (const char *src) +{ + if (src) return strdup(src); + return NULL; +} + +char * +iks_strcat (char *dest, const char *src) +{ + size_t len; + + if (!src) return dest; + + len = strlen (src); + memcpy (dest, src, len); + dest[len] = '\0'; + return dest + len; +} + +int +iks_strcmp (const char *a, const char *b) +{ + if (!a || !b) return -1; + return strcmp (a, b); +} + +int +iks_strcasecmp (const char *a, const char *b) +{ + if (!a || !b) return -1; + return strcasecmp (a, b); +} + +int +iks_strncmp (const char *a, const char *b, size_t n) +{ + if (!a || !b) return -1; + return strncmp (a, b, n); +} + +int +iks_strncasecmp (const char *a, const char *b, size_t n) +{ + if (!a || !b) return -1; + return strncasecmp (a, b, n); +} + +size_t +iks_strlen (const char *src) +{ + if (!src) return 0; + return strlen (src); +} + +/***** XML Escaping *****/ + +char * +iks_escape (ikstack *s, char *src, size_t len) +{ + char *ret; + int i, j, nlen; + + if (!src || !s) return NULL; + if (len == -1) len = strlen (src); + + nlen = len; + for (i=0; i<len; i++) { + switch (src[i]) { + case '&': nlen += 4; break; + case '<': nlen += 3; break; + case '>': nlen += 3; break; + case '\'': nlen += 5; break; + case '"': nlen += 5; break; + } + } + if (len == nlen) return src; + + ret = iks_stack_alloc (s, nlen + 1); + if (!ret) return NULL; + + for (i=j=0; i<len; i++) { + switch (src[i]) { + case '&': memcpy (&ret[j], "&", 5); j += 5; break; + case '\'': memcpy (&ret[j], "'", 6); j += 6; break; + case '"': memcpy (&ret[j], """, 6); j += 6; break; + case '<': memcpy (&ret[j], "<", 4); j += 4; break; + case '>': memcpy (&ret[j], ">", 4); j += 4; break; + default: ret[j++] = src[i]; + } + } + ret[j] = '\0'; + + return ret; +} + +char * +iks_unescape (ikstack *s, char *src, size_t len) +{ + int i,j; + char *ret; + + if (!s || !src) return NULL; + if (!strchr (src, '&')) return src; + if (len == -1) len = strlen (src); + + ret = iks_stack_alloc (s, len + 1); + if (!ret) return NULL; + + for (i=j=0; i<len; i++) { + if (src[i] == '&') { + i++; + if (strncmp (&src[i], "amp;", 4) == 0) { + ret[j] = '&'; + i += 3; + } else if (strncmp (&src[i], "quot;", 5) == 0) { + ret[j] = '"'; + i += 4; + } else if (strncmp (&src[i], "apos;", 5) == 0) { + ret[j] = '\''; + i += 4; + } else if (strncmp (&src[i], "lt;", 3) == 0) { + ret[j] = '<'; + i += 2; + } else if (strncmp (&src[i], "gt;", 3) == 0) { + ret[j] = '>'; + i += 2; + } else { + ret[j] = src[--i]; + } + } else { + ret[j] = src[i]; + } + j++; + } + ret[j] = '\0'; + + return ret; +} |