diff --git a/mbuni/Makefile.am b/mbuni/Makefile.am
new file mode 100644
index 0000000..ef215c3
--- /dev/null
+++ b/mbuni/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = mmlib mmsc
diff --git a/mbuni/Makefile.in b/mbuni/Makefile.in
new file mode 100644
index 0000000..2c73b3c
--- /dev/null
+++ b/mbuni/Makefile.in
@@ -0,0 +1,563 @@
+# Makefile.in generated by automake 1.9.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004 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 = :
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
+ TODO config.guess config.sub depcomp install-sh ltmain.sh \
+ missing
+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)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno configure.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-exec-recursive install-info-recursive \
+ install-recursive installcheck-recursive installdirs-recursive \
+ pdf-recursive ps-recursive uninstall-info-recursive \
+ uninstall-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXE_EXT = @EXE_EXT@
+GW_CONFIG = @GW_CONFIG@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+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_CC = @ac_ct_CC@
+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__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+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@
+SUBDIRS = mmlib mmsc
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
+ cd $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+
+config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ cd $(top_srcdir) && $(AUTOHEADER)
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+uninstall-info-am:
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ @set fnord $$MAKEFLAGS; amf=$$2; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(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: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) config.h.in $(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)
+ $(am__remove_distdir)
+ mkdir $(distdir)
+ @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
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(mkdir_p) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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-recursive
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-recursive
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+uninstall-info: uninstall-info-recursive
+
+.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \
+ check-am clean clean-generic clean-recursive ctags \
+ ctags-recursive dist dist-all dist-bzip2 dist-gzip dist-shar \
+ dist-tarZ dist-zip distcheck distclean distclean-generic \
+ distclean-hdr distclean-recursive distclean-tags \
+ distcleancheck distdir distuninstallcheck 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-man install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic maintainer-clean-recursive \
+ mostlyclean mostlyclean-generic mostlyclean-recursive pdf \
+ pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-info-am
+
+# 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/mbuni/NEWS b/mbuni/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/mbuni/Notes b/mbuni/Notes
new file mode 100644
index 0000000..85ca60b
--- /dev/null
+++ b/mbuni/Notes
@@ -0,0 +1,15 @@
+Requires:
+- For media
+ - libiconv
+ - sox, lame, mpg123, amrencoder/amrdecoder (audio)
+ - imagemagick (image)
+
+- Mail server (postfix/sendmail)
+
+Wap setup:
+ - Port 9200/9201 for UDP WAP when not using security (connectless or otherwise) should be set aside
+ - Send port param with 9201 as port ID
+ - Put http proxy on ports 9200 and 9201 for HTTP based connections
+ - For nokia 6600, either manual setup, or send GPRS settings then change to use GSM and put in number to call (send
+ ) proxy address, etc.
+
diff --git a/mbuni/README b/mbuni/README
new file mode 100644
index 0000000..e69de29
diff --git a/mbuni/doc/examples/mmsc.conf b/mbuni/doc/examples/mmsc.conf
new file mode 100644
index 0000000..de2287a
--- /dev/null
+++ b/mbuni/doc/examples/mmsc.conf
@@ -0,0 +1,45 @@
+group = core
+log-file = log/ours.log
+log-level = 0
+
+group = mmsbox
+name = "My MMSC"
+hostname = ds.co.ug
+host-alias = mmsc
+local-mmsc-domains = ds.co.ug,dsmagic.com,lilo,lilo.ds.co.ug
+local-prefixes = 034;+25634;25634
+send-queue-directory = spool/global
+mm1-queue-directory = spool/mm1
+mm4-queue-directory = spool/mm4
+max-send-threads = 5
+send-mail-prog = /usr/sbin/sendmail -f '%f' '%t'
+unified-prefix = "+25634,034,34"
+maximum-send-attempts = 50
+default-message-expiry = 360000
+queue-run-interval = 0.1
+send-attempt-back-off = 300
+sendsms-url = http://localhost:13013/cgi-bin/sendsms
+sendsms-username = tester
+sendsms-password = foobar
+#sendsms-global-sender = 198
+mms-port = 1981
+#allow-ip = 192.168.129.11
+email2mms-relay-prefixes = "034;035;25634"
+ua-profile-cache-directory = misc/profiles
+billing-module-parameters = "log/cdr.log"
+# billing-library = billdemo.so
+prov-server-notify-script = ~/src/mmprov/provnotify.sh
+prov-server-sub-status-script = ~/src/mmprov/rcptstatus.sh
+notify-unprovisioned = yes
+mms-notify-text = "You have received a multimedia message from %S, go to XXX to view it"
+mm-box-host = test.ds.co.ug
+mms-notify-unprovisioned-text = "This is a test"
+mms-to-email-txt = "This is a multimedia message (HTML suppressed)"
+mms-to-email-html = "This is a multimedia message powered by Digital Solutions"
+mms-message-too-large-txt = "You have received a multimedia message from %S that is too large for your phone. Go to xxx to view it"
+
+group = mmsproxy
+name = "A test mms proxy"
+host = test.com
+allowed-prefix = "035"
+denied-prefix = "034"
diff --git a/mbuni/ltmain.sh b/mbuni/ltmain.sh
new file mode 100755
index 0000000..5eb4c3a
--- /dev/null
+++ b/mbuni/ltmain.sh
@@ -0,0 +1,6402 @@
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit , 1996
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+win32_libid () {
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+ grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ win32_nmres=`eval $NM -f posix -A $1 | \
+ sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'`
+ if test "X$win32_nmres" = "Ximport" ; then
+ win32_libid_type="x86 archive import"
+ else
+ win32_libid_type="x86 archive static"
+ fi
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $echo $win32_libid_type
+}
+
+# End of Shell function definitions
+#####################################
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+ arg="$1"
+ shift
+
+ case $arg in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ execute_dlfiles)
+ execute_dlfiles="$execute_dlfiles $arg"
+ ;;
+ tag)
+ tagname="$arg"
+ preserve_args="${preserve_args}=$arg"
+
+ # Check whether tagname contains only valid characters
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ $echo "$progname: invalid tag name: $tagname" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $tagname in
+ CC)
+ # Don't test for the "default" C tag, as we know, it's there, but
+ # not specially marked.
+ ;;
+ *)
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then
+ taglist="$taglist $tagname"
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`"
+ else
+ $echo "$progname: ignoring unknown tag $tagname" 1>&2
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case $arg in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+ $echo
+ $echo "Copyright (C) 2003 Free Software Foundation, Inc."
+ $echo "This is free software; see the source for copying conditions. There is NO"
+ $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+ exit 0
+ ;;
+
+ --config)
+ ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0"
+ done
+ exit 0
+ ;;
+
+ --debug)
+ $echo "$progname: enabling shell trace mode"
+ set -x
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ $echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ $echo "enable shared libraries"
+ else
+ $echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ $echo "enable static libraries"
+ else
+ $echo "disable static libraries"
+ fi
+ exit 0
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --preserve-dup-deps) duplicate_deps="yes" ;;
+
+ --quiet | --silent)
+ show=:
+ preserve_args="$preserve_args $arg"
+ ;;
+
+ --tag) prevopt="--tag" prev=tag ;;
+ --tag=*)
+ set tag "$optarg" ${1+"$@"}
+ shift
+ prev=tag
+ preserve_args="$preserve_args --tag"
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+fi
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+ $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2
+ case $nonopt in
+ *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+ mode=link
+ for arg
+ do
+ case $arg in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case $mode in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+
+ for arg
+ do
+ case "$arg_mode" in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ if test -n "$libobj" ; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit 1
+ fi
+ arg_mode=target
+ continue
+ ;;
+
+ -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ lastarg="$lastarg $arg"
+ done
+ IFS="$save_ifs"
+ lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ * )
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ case $lastarg in
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ base_compile="$base_compile $lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ $echo "$modename: you must specify an argument for -Xcompile"
+ exit 1
+ ;;
+ target)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit 1
+ ;;
+ *)
+ # Get the name of the library object.
+ [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSifmso]'
+ case $libobj in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.ii) xform=ii ;;
+ *.class) xform=class ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.f90) xform=f90 ;;
+ *.for) xform=for ;;
+ *.java) xform=java ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case $libobj in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Infer tagged configuration to use if any are available and
+ # if one wasn't chosen via the "--tag" command line option.
+ # Only attempt this if the compiler in the base compile
+ # command doesn't match the default compiler.
+ if test -n "$available_tags" && test -z "$tagname"; then
+ case $base_compile in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
+ case "$base_compile " in
+ "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit 1
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+
+ for arg in $later; do
+ case $arg in
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$obj"; then
+ xdir=
+ else
+ xdir=$xdir/
+ fi
+ lobj=${xdir}$objdir/$objname
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit 1" 1 2 15
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit 1" 1 2 15
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $run ln "$0" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+ $echo $srcfile > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+
+ $run $rm "$libobj" "${libobj}T"
+
+ # Create a libtool object file (analogous to a ".la" file),
+ # but don't create it if we're doing a dry run.
+ test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ $show "$mv $output_obj $lobj"
+ if $run $mv $output_obj $lobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the PIC object to the libtool object file.
+ test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <> ${libobj}T < /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
+ case $base_compile in
+ "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*)
+ # The compiler in $compile_command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit 1
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -all-static | -static)
+ if test "X$arg" = "X-all-static"; then
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ else
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ fi
+ build_libtool_libs=no
+ build_old_libs=yes
+ prefer_static_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+ ;;
+ *) qarg=$arg ;;
+ esac
+ libtool_args="$libtool_args $qarg"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit 1
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat $save_arg`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit 1
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ done
+ else
+ $echo "$modename: link input file \`$save_arg' does not exist"
+ exit 1
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ compile_command="$compile_command $wl$qarg"
+ finalize_command="$finalize_command $wl$qarg"
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: more than one -exported-symbols argument is not allowed"
+ exit 1
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+ exit 1
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-pw32* | *-*-beos*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-mingw* | *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs -framework System"
+ continue
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # gcc -m* arguments should be passed to the linker via $compiler_flags
+ # in order to pass architecture information to the linker
+ # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+ -m*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ if test "$with_gcc" = "yes" ; then
+ compiler_flags="$compiler_flags $arg"
+ fi
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # in order for the loader to find any dlls it needs.
+ $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+ $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Wl,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $wl$flag"
+ linker_flags="$linker_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit 1
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done # argument parsing loop
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+ # Create the object directory.
+ if test ! -d "$output_objdir"; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$output_objdir"; then
+ exit $status
+ fi
+ fi
+
+ # Determine the type of output
+ case $output in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ case $host in
+ *cygwin* | *mingw* | *pw32*)
+ # don't eliminate duplcations in $postdeps and $predeps
+ duplicate_compiler_generated_deps=yes
+ ;;
+ *)
+ duplicate_compiler_generated_deps=$duplicate_deps
+ ;;
+ esac
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+ case $linkmode in
+ lib)
+ passes="conv link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+ for pass in $passes; do
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+ continue
+ fi
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+ for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ for search_ext in .la $shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if (${SED} -e '2q' $lib |
+ grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ library_names=
+ old_library=
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ ;;
+ *)
+ $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ if test "$deplibs_check_method" != pass_all; then
+ $echo
+ $echo "*** Warning: Trying to link with static lib archive $deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because the file extensions .$libext of this argument makes me believe"
+ $echo "*** that it is just a static archive that I should not used here."
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the"
+ $echo "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ $echo "$modename: cannot find the library \`$lib'" 1>&2
+ exit 1
+ fi
+
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+
+ # Read the .la file
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit 1
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ $echo "$modename: \`$lib' is not a convenience library" 1>&2
+ exit 1
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit 1
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+ exit 1
+ fi
+ if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ $echo "$modename: warning: library \`$lib' was moved." 1>&2
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi # $installed = yes
+ name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+ exit 1
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var"; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *" $absdir "*) ;;
+ *) temp_rpath="$temp_rpath $dir" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some systems (darwin)
+ if test "$shouldnotlink" = yes && test "$pass" = link ; then
+ $echo
+ if test "$linkmode" = prog; then
+ $echo "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $echo "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $echo "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+ libname=`eval \\$echo \"$libname_spec\"`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw*)
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+ newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ $show "extracting exported symbol list from \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$extract_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ $show "generating import library for \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ cmds=$old_archive_from_expsyms_cmds
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5* ) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a module then we can not link against it, someone
+ # is ignoring the new warnings I added
+ if /usr/bin/file -L $add 2> /dev/null | grep "bundle" >/dev/null ; then
+ $echo "** Warning, lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ $echo
+ $echo "** And there doesn't seem to be a static archive available"
+ $echo "** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case "$libdir" in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit 1
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes && \
+ test "$hardcode_minus_L" != yes && \
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case "$libdir" in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ $echo
+ $echo "*** Warning: This system can not link to static lib archive $lib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ $echo "*** But as you try to build a module library, libtool will still create "
+ $echo "*** a static module, that should work as long as the dlopening application"
+ $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ convenience="$convenience $dir/$old_library"
+ old_convenience="$old_convenience $dir/$old_library"
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$deplib" && dir="."
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if grep "^installed=no" $deplib > /dev/null; then
+ path="$absdir/$objdir"
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ if test "$absdir" != "$libdir"; then
+ $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+ fi
+ path="$absdir"
+ fi
+ depdepl=
+ case $host in
+ *-*-darwin*)
+ # we do not want to link against static libs, but need to link against shared
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$path/$depdepl" ; then
+ depdepl="$path/$depdepl"
+ fi
+ # do not add paths which are already there
+ case " $newlib_search_path " in
+ *" $path "*) ;;
+ *) newlib_search_path="$newlib_search_path $path";;
+ esac
+ fi
+ path=""
+ ;;
+ *)
+ path="-L$path"
+ ;;
+ esac
+
+ ;;
+ -l*)
+ case $host in
+ *-*-darwin*)
+ # Again, we only want to link against shared libraries
+ eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+ for tmp in $newlib_search_path ; do
+ if test -f "$tmp/lib$tmp_libs.dylib" ; then
+ eval depdepl="$tmp/lib$tmp_libs.dylib"
+ break
+ fi
+ done
+ path=""
+ ;;
+ *) continue ;;
+ esac
+ ;;
+ *) continue ;;
+ esac
+ case " $deplibs " in
+ *" $depdepl "*) ;;
+ *) deplibs="$deplibs $depdepl" ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$deplibs $path" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval shared_ext=\"$shrext\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval shared_ext=\"$shrext\"
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+ exit 1
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the non-libtool"
+ $echo "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ if test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test "$#" -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$2"
+ number_minor="$3"
+ number_revision="$4"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows)
+ current=`expr $number_major + $number_minor`
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ current=`expr $number_major + $number_minor - 1`
+ age="$number_minor"
+ revision="$number_minor"
+ ;;
+ esac
+ ;;
+ no)
+ current="$2"
+ revision="$3"
+ age="$4"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $revision in
+ 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $age in
+ 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
+ *)
+ $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ minor_current=`expr $current + 1`
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ irix | nonstopux)
+ major=`expr $current - $age + 1`
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=.`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+ fi
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$echo "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ if test -n "$removelist"; then
+ $show "${rm}r $removelist"
+ $run ${rm}r $removelist
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ for path in $notinst_path; do
+ lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'`
+ deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'`
+ dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'`
+ done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs -framework System"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c </dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval $echo \"$potent_lib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+ done
+ fi
+ if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \
+ | grep . >/dev/null; then
+ $echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ $echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ $echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ $echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ $echo
+ $echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $echo "*** dependencies of module $libname. Therefore, libtool will create"
+ $echo "*** a static module, that should work as long as the dlopening"
+ $echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ $echo "*** The inter-library dependencies that have been dropped here will be"
+ $echo "*** automatically added whenever a program is linked with this library"
+ $echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ $echo
+ $echo "*** Since this library must not contain undefined symbols,"
+ $echo "*** because either the platform does not support them or"
+ $echo "*** it was explicitly requested with -no-undefined,"
+ $echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ if len=`expr "X$cmd" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ $show "using reloadable object file for export list..."
+ skipped_export=:
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise.
+ $echo "creating reloadable object files..."
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ delfiles=
+ last_robj=
+ k=1
+ output=$output_objdir/$save_output-${k}.$objext
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+ if test "X$objlist" = X ||
+ { len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len"; }; then
+ objlist="$objlist $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+ fi
+ last_robj=$output_objdir/$save_output-${k}.$objext
+ k=`expr $k + 1`
+ output=$output_objdir/$save_output-${k}.$objext
+ objlist=$obj
+ len=1
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+ if ${skipped_export-false}; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+ fi
+
+ # Set up a command to remove the reloadale object files
+ # after they are used.
+ i=0
+ while test "$i" -lt "$k"
+ do
+ i=`expr $i + 1`
+ delfiles="$delfiles $output_objdir/$save_output-${i}.$objext"
+ done
+
+ $echo "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+
+ # Append the command to remove the reloadable object files
+ # to the just-reset $cmds.
+ eval cmds=\"\$cmds~\$rm $delfiles\"
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+ exit 0
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case $output in
+ *.lo)
+ if test -n "$objs$old_deplibs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit 1
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${obj}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $run eval "echo timestamp > $libobj" || exit $?
+ exit 0
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ cmds=$reload_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+ esac
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ case $host in
+ *darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ if test "$tagname" = CXX ; then
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ fi
+ ;;
+ esac
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case $dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$output.exp"
+ $run $rm $export_symbols
+ $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ else
+ $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+ $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+ $run eval '$echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" |
+ if sort -k 3 /dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+ esac;;
+ *-*-hpux*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit 1
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $run $rm $output
+ # Link the executable and exit
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+ exit 0
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
+ case $0 in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ cwrappersource=`$echo ${objdir}/lt-${output}.c`
+ cwrapper=`$echo ${output}.exe`
+ $rm $cwrappersource $cwrapper
+ trap "$rm $cwrappersource $cwrapper; exit 1" 1 2 15
+
+ cat > $cwrappersource <> $cwrappersource<<"EOF"
+#include
+#include
+#include
+#include
+#include
+#include
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+#define HAVE_DOS_BASED_FILE_SYSTEM
+#ifndef DIR_SEPARATOR_2
+#define DIR_SEPARATOR_2 '\\'
+#endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+char * basename (const char *name);
+char * fnqualify(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int i;
+
+ program_name = (char *) xstrdup ((char *) basename (argv[0]));
+ newargz = XMALLOC(char *, argc+2);
+EOF
+
+ cat >> $cwrappersource <> $cwrappersource <<"EOF"
+ newargz[1] = fnqualify(argv[0]);
+ /* we know the script has the same name, without the .exe */
+ /* so make sure newargz[1] doesn't end in .exe */
+ strendzap(newargz[1],".exe");
+ for (i = 1; i < argc; i++)
+ newargz[i+1] = xstrdup(argv[i]);
+ newargz[argc+1] = NULL;
+EOF
+
+ cat >> $cwrappersource <> $cwrappersource <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void * p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+char *
+basename (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha (name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return (char *) base;
+}
+
+char *
+fnqualify(const char *path)
+{
+ size_t size;
+ char *p;
+ char tmp[LT_PATHMAX + 1];
+
+ assert(path != NULL);
+
+ /* Is it qualified already? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha (path[0]) && path[1] == ':')
+ return xstrdup (path);
+#endif
+ if (IS_DIR_SEPARATOR (path[0]))
+ return xstrdup (path);
+
+ /* prepend the current directory */
+ /* doesn't handle '~' */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */
+ p = XMALLOC(char, size);
+ sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path);
+ return p;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert(str != NULL);
+ assert(pat != NULL);
+
+ len = strlen(str);
+ patlen = strlen(pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp(str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+ const char * message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+EOF
+ # we should really use a build-platform specific compiler
+ # here, but OTOH, the wrappers (shell script and this C one)
+ # are only useful if you want to execute the "real" binary.
+ # Since the "real" binary is built for $host, then this
+ # wrapper might as well be built for $host, too.
+ $run $LTCC -s -o $cwrapper $cwrappersource
+ ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit 1" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $echo >> $output "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ $echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $echo \"\$relink_command_output\" >&2
+ $rm \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ $echo >> $output "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2*)
+ $echo >> $output "\
+ exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $echo >> $output "\
+ exec \$progdir/\$program \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit 0
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ # Add in members from convenience archives.
+ for xlib in $addlibs; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+ eval cmds=\"$old_archive_cmds\"
+
+ if len=`expr "X$cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ $echo "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ # GNU ar 2.10+ was changed to match POSIX; thus no paths are
+ # encoded into archives. This makes 'ar r' malfunction in
+ # this piecewise linking case whenever conflicting object
+ # names appear in distinct ar calls; check, warn and compensate.
+ if (for obj in $save_oldobjs
+ do
+ $echo "X$obj" | $Xsed -e 's%^.*/%%'
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2
+ $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2
+ AR_FLAGS=cq
+ fi
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ for obj in $save_oldobjs
+ do
+ oldobjs="$objlist $obj"
+ objlist="$objlist $obj"
+ eval test_cmds=\"$old_archive_cmds\"
+ if len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ eval cmd=\"$cmd\"
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $0 $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+ for lib in $dlfiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdlfiles="$newdlfiles $libdir/$name"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $rm $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $echo >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+ ;;
+ esac
+ exit 0
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg="$nonopt"
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest="$arg"
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f) prev="-f" ;;
+ -g) prev="-g" ;;
+ -m) prev="-m" ;;
+ -o) prev="-o" ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*) ;;
+
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest="$arg"
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test "$#" -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ library_names=
+ old_library=
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ if test "$inst_prefix_dir" = "$destdir"; then
+ $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+ exit 1
+ fi
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ $echo "$modename: warning: relinking \`$file'" 1>&2
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ exit 1
+ fi
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$srcname $destdir/$realname"
+ $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$striplib $destdir/$realname"
+ $run eval "$striplib $destdir/$realname" || exit $?
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ cmds=$postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit 0
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin*|*mingw*)
+ wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+ notinst_deplibs=
+ relink_command=
+
+ # To insure that "foo" is sourced, and not "foo.exe",
+ # finese the cygwin/MSYS system by explicitly sourcing "foo."
+ # which disallows the automatic-append-.exe behavior.
+ case $build in
+ *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+ *) wrapperdot=${wrapper} ;;
+ esac
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . ${wrapperdot} ;;
+ *) . ./${wrapperdot} ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$notinst_deplibs"; then
+ $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+ exit 1
+ fi
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ # To insure that "foo" is sourced, and not "foo.exe",
+ # finese the cygwin/MSYS system by explicitly sourcing "foo."
+ # which disallows the automatic-append-.exe behavior.
+ case $build in
+ *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+ *) wrapperdot=${wrapper} ;;
+ esac
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . ${wrapperdot} ;;
+ *) . ./${wrapperdot} ;;
+ esac
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir="/tmp"
+ test -n "$TMPDIR" && tmpdir="$TMPDIR"
+ if tmpdir=`mktemp -d $tmpdir/libtool-XXXXXX 2> /dev/null`; then :
+ else
+ tmpdir="$tmpdir/libtool-$$"
+ if $mkdir "$tmpdir" && chmod 700 "$tmpdir"; then :
+ else
+ $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+ continue
+ fi
+ fi
+ file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyways
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+ ;;
+ esac
+ ;;
+ esac
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ $show "$old_striplib $oldlib"
+ $run eval "$old_striplib $oldlib" || exit $?
+ fi
+
+ # Do each command in the postinstall commands.
+ cmds=$old_postinstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $0 $preserve_args --finish$current_libdirs'
+ else
+ exit 0
+ fi
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ cmds=$finish_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = : && exit 0
+
+ $echo "----------------------------------------------------------------------"
+ $echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $echo " $libdir"
+ done
+ $echo
+ $echo "If you ever happen to want to link against installed libraries"
+ $echo "in a given directory, LIBDIR, you must either use libtool, and"
+ $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ $echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ $echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ $echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ $echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ $echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ $echo
+ $echo "See any operating system documentation about shared libraries for"
+ $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ $echo "----------------------------------------------------------------------"
+ exit 0
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit 1
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit 1
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ if test "${save_LC_ALL+set}" = set; then
+ LC_ALL="$save_LC_ALL"; export LC_ALL
+ fi
+ if test "${save_LANG+set}" = set; then
+ LANG="$save_LANG"; export LANG
+ fi
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\"\$cmd\"$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ fi
+ eval \$echo \"\$cmd\"$args
+ exit 0
+ fi
+ ;;
+
+ # libtool clean and uninstall mode
+ clean | uninstall)
+ modename="$modename: $mode"
+ rm="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) rm="$rm $arg"; rmforce=yes ;;
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$file"; then
+ dir=.
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if (test -L "$file") >/dev/null 2>&1 \
+ || (test -h "$file") >/dev/null 2>&1 \
+ || test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+ test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+
+ if test "$mode" = uninstall; then
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ cmds=$postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ cmds=$old_postuninstall_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+ # Read the .lo file
+ . $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" \
+ && test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" \
+ && test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ noexename=`$echo $name|${SED} 's,.exe$,,'`
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ relink_command=
+ . $dir/$noexename
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles || exit_status=1
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ $show "rmdir $dir"
+ $run rmdir $dir >/dev/null 2>&1
+ fi
+ done
+
+ exit $exit_status
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test -z "$exec_cmd"; then
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+ eval exec $exec_cmd
+ exit 1
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ --version print version information
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to ."
+ exit 0
+ ;;
+
+clean)
+ $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit 0
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/mbuni/missing b/mbuni/missing
new file mode 100755
index 0000000..e7ef83a
--- /dev/null
+++ b/mbuni/missing
@@ -0,0 +1,360 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2003-09-02.23
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard , 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to ."
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+ aclocal*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
+ # We have makeinfo, but it failed.
+ exit 1
+ fi
+
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
+ fi
+ touch $file
+ ;;
+
+ tar)
+ shift
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ fi
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/mbuni/mmlib/Makefile.am b/mbuni/mmlib/Makefile.am
new file mode 100644
index 0000000..f49b58a
--- /dev/null
+++ b/mbuni/mmlib/Makefile.am
@@ -0,0 +1,4 @@
+noinst_LIBRARIES = libmms.a
+libmms_a_SOURCES = mms_billing.c mms_billing.h mms_msg.c mms_msg.h mms_queue.c mms_queue.h mms_strings.c mms_strings.h mms_uaprof.c mms_uaprof.h mms_util.c mms_util.h mms_resolve.c
+
+
diff --git a/mbuni/mmlib/Makefile.in b/mbuni/mmlib/Makefile.in
new file mode 100644
index 0000000..9390dfd
--- /dev/null
+++ b/mbuni/mmlib/Makefile.in
@@ -0,0 +1,381 @@
+# Makefile.in generated by automake 1.9.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004 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@
+
+SOURCES = $(libmms_a_SOURCES)
+
+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 = :
+subdir = mmlib
+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)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+AR = ar
+ARFLAGS = cru
+libmms_a_AR = $(AR) $(ARFLAGS)
+libmms_a_LIBADD =
+am_libmms_a_OBJECTS = mms_billing.$(OBJEXT) mms_msg.$(OBJEXT) \
+ mms_queue.$(OBJEXT) mms_strings.$(OBJEXT) mms_uaprof.$(OBJEXT) \
+ mms_util.$(OBJEXT) mms_resolve.$(OBJEXT)
+libmms_a_OBJECTS = $(am_libmms_a_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libmms_a_SOURCES)
+DIST_SOURCES = $(libmms_a_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXE_EXT = @EXE_EXT@
+GW_CONFIG = @GW_CONFIG@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+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_CC = @ac_ct_CC@
+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__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+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@
+noinst_LIBRARIES = libmms.a
+libmms_a_SOURCES = mms_billing.c mms_billing.h mms_msg.c mms_msg.h mms_queue.c mms_queue.h mms_strings.c mms_strings.h mms_uaprof.c mms_uaprof.h mms_util.c mms_util.h mms_resolve.c
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .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 mmlib/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu mmlib/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
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libmms.a: $(libmms_a_OBJECTS) $(libmms_a_DEPENDENCIES)
+ -rm -f libmms.a
+ $(libmms_a_AR) libmms.a $(libmms_a_OBJECTS) $(libmms_a_LIBADD)
+ $(RANLIB) libmms.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_billing.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_msg.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_queue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_resolve.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_strings.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_uaprof.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mms_util.Po@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) '$<'`
+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 $(LIBRARIES)
+installdirs:
+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-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES ctags distclean distclean-compile \
+ distclean-generic 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-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am
+
+# 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/mbuni/mmlib/mms_billing.c b/mbuni/mmlib/mms_billing.c
new file mode 100644
index 0000000..8d2b51d
--- /dev/null
+++ b/mbuni/mmlib/mms_billing.c
@@ -0,0 +1,51 @@
+#include
+#include
+
+#include "mms_billing.h"
+
+/* This module provides a basic biller and CDR implementation. Totally no frills, but a basis
+ * for implementing a 'real' module.
+ * It does CDR but no billing (of course).
+ */
+
+
+static void *mms_billingmodule_init(char *settings)
+{
+ return fopen(settings, "a"); /* Settings is interpreted as a file name. */
+}
+
+
+static int mms_billingmodule_fini(void *module_data)
+{
+ return module_data ? fclose(module_data) : -1;
+}
+
+static double mms_billmsg(Octstr *from, List *to, unsigned long msg_size, void *module_data)
+{
+ return 0;
+}
+
+static int mms_logcdr(MmsCdrStruct *cdr)
+{
+ if (cdr && cdr->module_data) {
+ char buf[CBUFSIZE];
+ struct tm tm;
+
+ localtime_r(&cdr->sdate, &tm);
+ gw_strftime(buf, sizeof buf, "%Y-%m-%d %H:%M:%S", &tm);
+ fprintf(cdr->module_data, "%s\t%.128s\t%.256s\t%.256s\t%ld\n",
+ buf, cdr->from, cdr->to, cdr->msgid, cdr->msg_size);
+ fflush(cdr->module_data);
+ } else
+ return -1;
+
+ return 0;
+}
+
+/* The function itself. */
+MmsBillingFuncStruct mms_billfuncs = {
+ mms_billingmodule_init,
+ mms_logcdr,
+ mms_billmsg,
+ mms_billingmodule_fini
+};
diff --git a/mbuni/mmlib/mms_billing.h b/mbuni/mmlib/mms_billing.h
new file mode 100644
index 0000000..f6cb7d1
--- /dev/null
+++ b/mbuni/mmlib/mms_billing.h
@@ -0,0 +1,42 @@
+#ifndef __MMS_BILLING_INCLUDED__
+#define __MMS_BILLING_INCLUDED__
+
+#include
+#include "gwlib/gwlib.h"
+
+/* Billing and CDR module. This file provides prototypes for all billing functions.
+ * The idea is that for each site a DSO will be created that the mmsglobalsender loads and gets
+ * from functions to do billing. This .h file provides prototypes for these functions.
+ * It has an attendant function to provide basic biller and CDR functions
+ */
+#define CBUFSIZE 256
+typedef struct MmsCdrStruct {
+ void *module_data;
+ time_t sdate;
+ char from[CBUFSIZE];
+ char to[CBUFSIZE];
+ char msgid[CBUFSIZE];
+ unsigned long msg_size;
+} MmsCdrStruct;
+
+
+typedef struct MmsBillingFuncStruct {
+/* This function is called once to initialise the billing module. Return a generic object,
+ * which is passed with each CDR.
+ */
+ void *(*mms_billingmodule_init)(char *settings);
+
+/* This function logs a cdr to wherever it is logging to. */
+ int (*mms_logcdr)(MmsCdrStruct *cdr);
+
+/* Bills a message. Returns >= 0 if billed ok, -1 if message should be rejected,
+ * -2 on internal (temporary) error.
+ */
+ double (*mms_billmsg)(Octstr *from, List *to, unsigned long msg_size, void *module_data);
+
+ int (*mms_billingmodule_fini)(void *module_data);
+} MmsBillingFuncStruct;
+
+extern MmsBillingFuncStruct mms_billfuncs; /* The module must expose this symbol. */
+
+#endif
diff --git a/mbuni/mmlib/mms_msg.c b/mbuni/mmlib/mms_msg.c
new file mode 100644
index 0000000..2ed41eb
--- /dev/null
+++ b/mbuni/mmlib/mms_msg.c
@@ -0,0 +1,1285 @@
+/* MMS Message structure definition, encoder and decoder and helper functions
+ *
+ */
+#include
+#include
+#include "mms_msg.h"
+#include "mms_util.h"
+
+struct MmsMsg {
+ int message_type;
+ Octstr *msgId;
+ List *headers; /* Of type HTTPHeader. */
+
+ unsigned char ismultipart;
+ union {
+ List *l;
+ Octstr *s;
+ } body; /* list of MIMEEntity (for multipart), text otherwise.*/
+};
+
+
+#define SIZHINT 47
+
+static void mm_destroy(MIMEEntity *mx);
+static void pack_short_integer(Octstr *s, int ch)
+{
+ unsigned char c = ch|0x80;
+
+ octstr_append_data(s, &c, 1);
+}
+#if 0
+static void encode_uint(Octstr *os, unsigned int l)
+{
+ char xbuf[5];
+ int i = 0;
+
+ do {
+ xbuf[i++] = l&0x7f;
+ l>>=7;
+ } while (i < 5 && l);
+
+ while (--i > 0) {
+ xbuf[i] |= 0x80;
+ octstr_append_data(os, &xbuf[i], 1);
+ }
+
+ octstr_append_data(os, &xbuf[0], 1);
+}
+#endif
+
+int mms_validate_address(Octstr *s)
+{
+
+ int i = octstr_search_char(s, '/', 0);
+ int l = octstr_len(s);
+
+ if (octstr_search_char(s, '@', 0) > 0)
+ return 0;
+ else if (i >= 0)
+ if (octstr_case_search(s, octstr_imm("PLMN"), 0) + 4 == l ||
+ octstr_case_search(s, octstr_imm("IPv4"), 0) + 4 == l ||
+ octstr_case_search(s, octstr_imm("IPv6"), 0) + 4 == l)
+ return 0;
+ else
+ return -1;
+ else
+ return -1;
+
+}
+
+
+static int decode_multipart(ParseContext *context, List *body)
+{
+ int i=0, n;
+
+ n = parse_get_uintvar(context);
+
+ for (i = 0; i 0 ; i++) {
+ int dlen, hlen;
+ MIMEEntity *x = gw_malloc(sizeof *x);
+
+ Octstr *hs;
+ Octstr *content;
+ Octstr *content_type;
+
+ memset(x, 0,sizeof *x);
+
+ hlen = parse_get_uintvar(context);
+ dlen = parse_get_uintvar(context);
+
+ parse_limit(context, hlen);
+
+
+
+ hs = parse_get_octets(context, parse_octets_left(context));
+ x->headers = wsp_headers_unpack(hs, 1);
+
+ octstr_destroy(hs);
+
+ parse_skip_to_limit(context);
+ parse_pop_limit(context);
+
+ content_type = http_header_value(x->headers, octstr_imm("Content-Type"));
+ content = parse_get_octets(context, dlen);
+
+ if (!content || !content_type) {
+ int pleft = parse_octets_left(context);
+ warning(0, "Parse error reading mime body [hlen=%d, dlen=%d, left=%d]!",hlen,dlen, pleft);
+ mime_entity_destroy(x);
+ if (content_type) octstr_destroy(content_type);
+ return -1;
+ }
+ if (octstr_case_compare(content_type,
+ octstr_imm("application/vnd.wap.multipart.related")) == 0 ||
+ octstr_case_compare(content_type,
+ octstr_imm("application/vnd.wap.multipart.alternative")) == 0 ||
+ octstr_case_compare(content_type,
+ octstr_imm("application/vnd.wap.multipart.mixed")) == 0) { /* Body is multipart. */
+ ParseContext *p = parse_context_create(content);
+ int res;
+ List *ml = x->multiparts = list_create();
+
+ res = decode_multipart(p, x->multiparts);
+ octstr_destroy(content);
+ parse_context_destroy(p);
+
+ if (res < 0) {
+ list_destroy(ml, (list_item_destructor_t *)mime_entity_destroy);
+ return -1;
+ }
+ } else
+ x->body = content;
+
+ octstr_destroy(content_type);
+
+ list_append(body, x);
+ }
+ return 0;
+}
+
+static int encode_multipart(Octstr *os, List *body)
+{
+ int i=0, n;
+
+ n = list_len(body);
+ octstr_append_uintvar(os, n);
+
+ while (iheaders, 1, WSP_1_3);
+
+ if (x->multiparts &&
+ list_len(x->multiparts) > 0) /* This is a multi-part, go down further. */
+ encode_multipart(mbody, x->multiparts);
+ else if (x->body)
+ octstr_append(mbody, x->body);
+
+ octstr_append_uintvar(os, octstr_len(mhdr));
+ octstr_append_uintvar(os, octstr_len(mbody));
+
+ octstr_append(os, mhdr);
+ octstr_append(os, mbody);
+
+ octstr_destroy(mhdr);
+ octstr_destroy(mbody);
+
+ i++;
+ }
+ return 0;
+}
+
+static int decode_msgbody(ParseContext *context, MmsMsg *msg)
+{
+ int res = 0;
+ if (msg->ismultipart) {
+ msg->body.l = list_create();
+ res = decode_multipart(context, msg->body.l);
+ } else
+ msg->body.s = parse_get_rest(context);
+
+ return res;
+}
+
+static void encode_msgbody(Octstr *os, MmsMsg *msg)
+{
+ if (msg->ismultipart)
+ encode_multipart(os, msg->body.l);
+ else
+ octstr_append(os, msg->body.s);
+}
+
+/* Decodes it and returns the value, which is a pointer into the string so be careful! */
+static void mms_unpack_well_known_field(List *unpacked, int field_type,
+ ParseContext *context, Octstr *xfrom)
+{
+ int val, ret;
+ char *hname = NULL;
+
+ Octstr *decoded = NULL;
+ char *ch = NULL;
+
+ ret = wsp_field_value(context, &val);
+
+ if (parse_error(context)) {
+ warning(0, "Faulty header [code = %d], skipping remaining headers.", field_type);
+ parse_skip_to_limit(context);
+ return;
+ }
+
+ hname = mms_header_to_cstr(field_type);
+
+ if (ret == WSP_FIELD_VALUE_NUL_STRING)
+ decoded = parse_get_nul_string(context);
+
+ switch (field_type) {
+
+ case MMS_HEADER_TO:
+ case MMS_HEADER_CC:
+ case MMS_HEADER_BCC:
+
+ if (ret == WSP_FIELD_VALUE_DATA) { /* expect charset text. */
+ long charset; /* Get it and ignore it. */
+ wsp_secondary_field_value(context, &charset);
+ decoded = parse_get_nul_string(context);
+ } else if (ret != WSP_FIELD_VALUE_NUL_STRING) {
+ warning(0, "Faulty header value for %s!\n", hname);
+ decoded = octstr_imm("");
+ }
+
+ if (mms_validate_address(decoded))
+ warning(0, "Faulty address [%s] format in field %s!",
+ octstr_get_cstr(decoded), hname);
+ break;
+ case MMS_HEADER_SUBJECT:
+ case MMS_HEADER_RESPONSE_TEXT:
+ case MMS_HEADER_RETRIEVE_TEXT:
+
+ if (ret == WSP_FIELD_VALUE_DATA) { /* encoded string, expect charset then text. */
+ long charset; /* Get it and ignore it. */
+ wsp_secondary_field_value(context, &charset);
+ decoded = parse_get_nul_string(context);
+ } else if (ret != WSP_FIELD_VALUE_NUL_STRING) {
+ warning(0, "Faulty header value for %s!\n", hname);
+ decoded = octstr_imm("");
+ }
+ break;
+ case MMS_HEADER_TRANSACTION_ID:
+ case MMS_HEADER_CONTENT_LOCATION:
+ case MMS_HEADER_MESSAGE_ID:
+ case MMS_HEADER_REPLY_CHARGING_ID:
+ if (ret != WSP_FIELD_VALUE_NUL_STRING)
+ warning(0, "Unexpected field value type %d for header %s\n",
+ ret, hname);
+
+ break;
+ case MMS_HEADER_MMS_VERSION:
+ if (ret == WSP_FIELD_VALUE_ENCODED)
+ decoded = wsp_unpack_version_value(val);
+ break;
+ /* integer/octet values */
+ case MMS_HEADER_DELIVERY_REPORT:
+ case MMS_HEADER_REPORT_ALLOWED:
+ case MMS_HEADER_READ_REPORT:
+ ch = mms_reports_to_cstr(val);
+ break;
+ case MMS_HEADER_MESSAGE_TYPE:
+ ch = mms_message_type_to_cstr(val);
+ break;
+ case MMS_HEADER_PRIORITY:
+ ch = mms_priority_to_cstr(val);
+ break;
+ case MMS_HEADER_READ_STATUS:
+ ch = mms_read_status_to_cstr(val);
+ break;
+ case MMS_HEADER_REPLY_CHARGING:
+ ch = mms_reply_charging_to_cstr(val);
+ break;
+
+ case MMS_HEADER_RESPONSE_STATUS:
+ ch = mms_response_status_to_cstr(val);
+ break;
+ case MMS_HEADER_RETRIEVE_STATUS:
+ ch = mms_retrieve_status_to_cstr(val);
+ break;
+ case MMS_HEADER_STATUS:
+ ch = mms_status_to_cstr(val);
+ break;
+ case MMS_HEADER_SENDER_VISIBILITY:
+ ch = mms_visibility_to_cstr(val);
+ break;
+ case MMS_HEADER_MESSAGE_CLASS:
+ if (ret != WSP_FIELD_VALUE_NUL_STRING)
+ ch = mms_message_class_to_cstr(val);
+ break;
+
+ case MMS_HEADER_DATE: /* Date values. */
+ parse_skip(context, -1);
+ decoded = wsp_unpack_date_value(context);
+ break;
+
+ case MMS_HEADER_MESSAGE_SIZE:
+ parse_skip(context, -1);
+ decoded = wsp_unpack_integer_value(context);
+ break;
+
+ case MMS_HEADER_CONTENT_TYPE:
+ if (ret == WSP_FIELD_VALUE_ENCODED)
+ ch = wsp_content_type_to_cstr(val);
+ else if (ret == WSP_FIELD_VALUE_DATA)
+ decoded = wsp_unpack_accept_general_form(context);
+
+ break;
+
+ case MMS_HEADER_DELIVERY_TIME:
+ case MMS_HEADER_EXPIRY:
+ case MMS_HEADER_REPLY_CHARGING_DEADLINE:
+
+
+ if (ret != WSP_FIELD_VALUE_DATA)
+ warning(0, "Error in value format, field %s!",
+ hname);
+ else {
+ int n = parse_get_char(context);
+
+ if (n == 0x80) /* Absolute time */
+ decoded = wsp_unpack_date_value(context);
+ else if (n == 0x81) { /* Relative time. */
+ long l = 0;
+ time_t t = time(NULL);
+ Octstr *s = wsp_unpack_integer_value(context);
+
+ octstr_parse_long(&l, s, 0, 10);
+ octstr_destroy(s);
+
+ t += l;
+ decoded = date_format_http(t);
+ } else
+ decoded = date_format_http(time(NULL)); /* A default. */
+ }
+ break;
+ case MMS_HEADER_FROM:
+ if (ret != WSP_FIELD_VALUE_DATA)
+ warning(0, "Error in value format, field %s!",hname);
+
+ else {
+ int n = parse_get_char(context);
+
+ if (n == 0x80) { /* Address present. */
+ int val = 0;
+ int ret2 = wsp_field_value(context, &val);
+
+ if (ret2 == WSP_FIELD_VALUE_DATA) { /* expect charset text. */
+ long charset; /* Get it and ignore it. */
+ wsp_secondary_field_value(context, &charset);
+ decoded = parse_get_nul_string(context);
+ parse_skip_to_limit(context);
+ parse_pop_limit(context);
+ } else if (ret2 != WSP_FIELD_VALUE_NUL_STRING) {
+ warning(0, "Faulty header value for %s!\n", hname);
+ decoded = octstr_imm("");
+ } else
+ decoded = parse_get_nul_string(context);
+ if (mms_validate_address(decoded))
+ warning(0, "Faulty address [%s] format in field %s!",
+ octstr_get_cstr(decoded), hname);
+ } else /* Insert address. */
+ decoded = octstr_duplicate(xfrom);
+ }
+ break;
+ case MMS_HEADER_PREVIOUSLY_SENT_BY:
+ case MMS_HEADER_PREVIOUSLY_SENT_DATE:
+ if (ret != WSP_FIELD_VALUE_DATA)
+ warning(0, "Error in value format, field %s!",hname);
+ else {
+ Octstr *t;
+ decoded = wsp_unpack_integer_value(context);
+
+ if (field_type == MMS_HEADER_PREVIOUSLY_SENT_BY) {
+ int val = 0;
+ int ret2 = wsp_field_value(context, &val);
+
+ if (ret2 == WSP_FIELD_VALUE_DATA) { /* expect charset text. */
+ long charset; /* Get it and ignore it. */
+ wsp_secondary_field_value(context, &charset);
+ t = parse_get_nul_string(context);
+ parse_skip_to_limit(context);
+ parse_pop_limit(context);
+ } else if (ret2 != WSP_FIELD_VALUE_NUL_STRING) {
+ warning(0, "Faulty header value for %s!\n", hname);
+ t = octstr_imm("");
+ } else
+ t = parse_get_nul_string(context);
+ } else
+ t = wsp_unpack_date_value(context);
+
+ octstr_append(decoded, t);
+ octstr_destroy(t);
+ }
+ break;
+ default:
+ warning(0, "MMS: Unknown header with code 0x%02x!", field_type);
+ }
+
+ if (ret == WSP_FIELD_VALUE_DATA) {
+ parse_skip_to_limit(context);
+ parse_pop_limit(context);
+ }
+
+ if (ch == NULL && decoded != NULL)
+ ch = octstr_get_cstr(decoded);
+
+ if (ch == NULL)
+ goto value_error;
+
+ if (!hname) {
+ warning(0, "Unknown header number 0x%02x.", field_type);
+ goto value_error;
+ }
+
+ http_header_add(unpacked, hname, ch);
+ if (decoded) octstr_destroy(decoded);
+ return;
+
+ value_error:
+ warning(0, "Skipping faulty header [code = %d, val=%d]!", field_type, val);
+ octstr_destroy(decoded);
+}
+
+static int decode_msgheaders(ParseContext *context, MmsMsg *msg, Octstr *from)
+{
+ int fcont = 1;
+
+ gw_assert(msg->headers == NULL);
+ msg->headers = list_create();
+
+ mms_strings_init(); /* Just in case. */
+
+ while (fcont && parse_octets_left(context) &&
+ !parse_error(context)) {
+ int byte = parse_get_char(context);
+
+
+ if (byte >= 128)
+ mms_unpack_well_known_field(msg->headers, byte&0x7f, context, from);
+ else {
+ parse_skip(context, -1); /* Go back a bit. */
+ wsp_unpack_app_header(msg->headers, context);
+ }
+ if ((byte&0x7f) == MMS_HEADER_CONTENT_TYPE)
+ fcont = 0;
+ }
+
+ return 0;
+}
+
+
+static void mms_pack_well_known_field(Octstr *os, int field_type, Octstr *value)
+{
+ Octstr *encoded = octstr_create("");
+ int ch = 0;
+ unsigned char c;
+
+ switch (field_type) {
+
+ case MMS_HEADER_TO:
+ case MMS_HEADER_CC:
+ case MMS_HEADER_BCC:
+ case MMS_HEADER_SUBJECT:
+ case MMS_HEADER_TRANSACTION_ID:
+ case MMS_HEADER_CONTENT_LOCATION:
+ case MMS_HEADER_MESSAGE_ID:
+ case MMS_HEADER_REPLY_CHARGING_ID:
+ case MMS_HEADER_RESPONSE_TEXT:
+ case MMS_HEADER_RETRIEVE_TEXT:
+ wsp_pack_text(os, value);
+ break;
+ case MMS_HEADER_MMS_VERSION:
+ wsp_pack_version_value(os, value);
+ break;
+ /* integer/octet values: Need to stream line this with better error-checking */
+ case MMS_HEADER_DELIVERY_REPORT:
+ case MMS_HEADER_REPORT_ALLOWED:
+ case MMS_HEADER_READ_REPORT:
+ pack_short_integer(os, mms_string_to_reports(value));
+ break;
+ case MMS_HEADER_MESSAGE_TYPE:
+ pack_short_integer(os, mms_string_to_message_type(value));
+ break;
+ case MMS_HEADER_PRIORITY:
+ pack_short_integer(os, mms_string_to_priority(value));
+ break;
+ case MMS_HEADER_READ_STATUS:
+ pack_short_integer(os, mms_string_to_read_status(value));
+ break;
+ case MMS_HEADER_REPLY_CHARGING:
+ pack_short_integer(os, mms_string_to_reply_charging(value));
+ break;
+
+ case MMS_HEADER_RESPONSE_STATUS:
+ pack_short_integer(os, mms_string_to_response_status(value));
+ break;
+ case MMS_HEADER_RETRIEVE_STATUS:
+ pack_short_integer(os, mms_string_to_retrieve_status(value));
+ break;
+ case MMS_HEADER_STATUS:
+ pack_short_integer(os, mms_string_to_status(value));
+ break;
+ case MMS_HEADER_SENDER_VISIBILITY:
+ pack_short_integer(os, mms_string_to_visibility(value));
+ break;
+ case MMS_HEADER_MESSAGE_CLASS:
+ ch = mms_string_to_message_class(value);
+ if (ch < 0)
+ wsp_pack_text(os, value);
+ else
+ pack_short_integer(os, ch);
+ break;
+
+ case MMS_HEADER_DATE: /* Date values. */
+ wsp_pack_date(os, value);
+ break;
+
+ case MMS_HEADER_MESSAGE_SIZE:
+ wsp_pack_integer_string(os, value);
+ break;
+
+ case MMS_HEADER_CONTENT_TYPE:
+ wsp_pack_content_type(os, value);
+ break;
+
+ case MMS_HEADER_DELIVERY_TIME:
+ case MMS_HEADER_EXPIRY:
+ case MMS_HEADER_REPLY_CHARGING_DEADLINE:
+
+ if (octstr_isnum(value) == 1) { /* A delta value. */
+
+ long l;
+
+ sscanf(octstr_get_cstr(value), "%ld", &l);
+ c = 129;
+ octstr_append_char(encoded, c);
+ wsp_pack_long_integer(encoded, l);
+ } else { /* Must be a date value .*/
+ c = 128;
+ octstr_append_char(encoded, c);
+ wsp_pack_date(encoded, value);
+ }
+
+ wsp_pack_value(os, encoded);
+
+ break;
+ case MMS_HEADER_FROM:
+
+ if (octstr_compare(octstr_imm("#insert"), value) == 0) {
+ c = 129;
+ octstr_append_data(encoded, &c, 1);
+ } else {
+ c = 128;
+ octstr_append_data(encoded, &c, 1);
+ wsp_pack_text(encoded, value);
+ }
+ wsp_pack_value(os, encoded);
+
+ break;
+ case MMS_HEADER_PREVIOUSLY_SENT_BY:
+ case MMS_HEADER_PREVIOUSLY_SENT_DATE:
+ {
+ long i, l;
+ Octstr *s;
+
+ i = octstr_parse_long(&l, value, 0, 10);
+
+ if (i <0) {
+ warning(0, "Bad counter indicator for field!");
+ i = 0;
+ }
+
+ wsp_pack_integer_value(encoded, l);
+ s = octstr_copy(value, i, octstr_len(value));
+
+ if (field_type == MMS_HEADER_PREVIOUSLY_SENT_BY)
+ wsp_pack_text(encoded, s);
+ else
+ wsp_pack_date(encoded, s);
+
+ octstr_destroy(s);
+ wsp_pack_value(os, encoded);
+ }
+ break;
+ default:
+ warning(0, "MMS: Unknown header with code 0x%02x!", field_type);
+ }
+
+ if (encoded) octstr_destroy(encoded);
+ return;
+}
+
+static int encode_msgheaders(Octstr *os, MmsMsg *msg)
+{
+ int fcont = 1;
+ List *hdrs = msg->headers;
+ int i, l = list_len(hdrs), mtype;
+
+ Octstr *msgtype = NULL, *transid = NULL, *version = NULL, *ctype;
+
+ /* First ensure that top headers are in place. */
+
+ version = http_header_value(hdrs,
+ octstr_imm("X-Mms-MMS-Version"));
+ transid = http_header_value(hdrs,
+ octstr_imm("X-Mms-Transaction-Id"));
+ msgtype = http_header_value(hdrs,
+ octstr_imm("X-Mms-Message-Type"));
+
+ ctype = http_header_value(hdrs,
+ octstr_imm("Content-Type"));
+
+ mtype = mms_string_to_message_type(msgtype);
+
+ pack_short_integer(os, MMS_HEADER_MESSAGE_TYPE);
+ pack_short_integer(os, mtype);
+ octstr_destroy(msgtype);
+
+ if (transid) {
+ pack_short_integer(os, MMS_HEADER_TRANSACTION_ID);
+ wsp_pack_text(os, transid);
+ octstr_destroy(transid);
+ }
+ pack_short_integer(os, MMS_HEADER_MMS_VERSION);
+ wsp_pack_version_value(os, version);
+ octstr_destroy(version);
+
+ /* Now pack the rest. */
+ for (i = 0; fcont && i < l; i++) {
+ Octstr *field = NULL, *value = NULL;
+ int htype;
+
+ http_header_get(hdrs, i, &field, &value);
+
+ htype = mms_string_to_header(field);
+
+ if (htype == MMS_HEADER_MMS_VERSION ||
+ htype == MMS_HEADER_MESSAGE_TYPE ||
+ htype == MMS_HEADER_TRANSACTION_ID ||
+ htype == MMS_HEADER_CONTENT_TYPE)
+ goto loop1;
+
+ if (htype < 0)
+ wsp_pack_application_header(os, field, value);
+ else {
+ pack_short_integer(os, htype);
+ mms_pack_well_known_field(os, htype, value);
+ }
+ loop1:
+ if (field) octstr_destroy(field);
+ if (value) octstr_destroy(value);
+ }
+
+ if (ctype) {
+ pack_short_integer(os, MMS_HEADER_CONTENT_TYPE);
+ wsp_pack_content_type(os, ctype);
+ octstr_destroy(ctype);
+ } else if (mtype == MMS_MSGTYPE_SEND_REQ ||
+ mtype == MMS_MSGTYPE_RETRIEVE_CONF)
+ warning(0, "MMS: Content type missing in encode_headers!");
+
+ return 0;
+
+}
+
+/* Does basic fixups on a message. */
+static int fixup_msg(MmsMsg *m, Octstr *from)
+{
+ if (!m)
+ return -1;
+
+ if (m->message_type == MMS_MSGTYPE_SEND_REQ) {
+ Octstr *s = NULL;
+
+ /* Check for from. */
+ if (from && (s = http_header_value(m->headers, octstr_imm("From"))) == NULL)
+ http_header_add(m->headers, "From", octstr_get_cstr(from));
+ else if (s)
+ octstr_destroy(s);
+
+ /* Check for date. */
+
+ if ((s = http_header_value(m->headers, octstr_imm("Date"))) == NULL) {
+ Octstr *t = date_format_http(time(NULL));
+ http_header_add(m->headers, "Date", octstr_get_cstr(t));
+ octstr_destroy(t);
+ } else
+ octstr_destroy(s);
+
+ }
+
+ return 0;
+}
+MmsMsg *mms_frombinary(Octstr *msg, Octstr *from)
+{
+ int res = 0;
+ MmsMsg _m = {0}, *m = NULL;
+ ParseContext *p = parse_context_create(msg);
+
+ Octstr *s;
+
+ decode_msgheaders(p, &_m, from);
+
+ if (_m.headers == NULL ||
+ list_len(_m.headers) == 0)
+ goto done;
+
+ /* Get the message type and also set flag for whether multipart.*/
+
+ s = http_header_value(_m.headers, octstr_imm("Content-Type"));
+ if (s &&
+ octstr_search(s, octstr_imm("application/vnd.wap.multipart"), 0) == 0)
+ _m.ismultipart = 1;
+ if (s)
+ octstr_destroy(s);
+
+ s = http_header_value(_m.headers, octstr_imm("X-Mms-Message-Type"));
+ if (s) {
+ _m.message_type = mms_string_to_message_type(s);
+ octstr_destroy(s);
+ } else {
+ if (_m.headers) http_destroy_headers(_m.headers);
+ goto done;
+ }
+ s = http_header_value(_m.headers, octstr_imm("Message-ID"));
+ _m.msgId = s;
+
+ if ((res = decode_msgbody(p, &_m)) < 0) {
+ MmsMsg *msg = &_m;
+ if (msg->ismultipart && msg->body.l)
+ list_destroy(msg->body.l, (list_item_destructor_t *)mm_destroy);
+ else if (msg->body.s)
+ octstr_destroy(msg->body.s);
+ }
+
+ m = gw_malloc(sizeof (*m));
+ *m = _m;
+
+ fixup_msg(m, from);
+
+ /* XXXX better error checking needed. */
+ done:
+ parse_context_destroy(p);
+
+ return m;
+}
+
+static void _x_mime_entity_dump(MIMEEntity *x, int level, int headers_only)
+{
+ int i, n, ism;
+
+ ism = (x->multiparts && list_len(x->multiparts) > 0) ? 1 : 0;
+ debug("part.dump", 0, "%sMultipart -> ", ism ? "" : "Not ");
+ http_header_dump(x->headers);
+
+ if (ism)
+ for (i = 0, n = list_len(x->multiparts); imultiparts, i), level+1, headers_only);
+ else if (x->body && !headers_only)
+ octstr_dump(x->body, level);
+}
+
+void mms_msgdump(MmsMsg *m, int headers_only)
+{
+ int i, n;
+
+ http_header_dump(m->headers);
+
+ debug("mms.dump", 0, "Dumping MMS message body (%s) [%ld parts] --> ",
+ m->ismultipart ? "mulitpart" : "not multipart",
+ m->ismultipart ? list_len(m->body.l) : 0);
+
+ if (m->ismultipart)
+ for (i = 0, n = list_len(m->body.l); i< n; i++) {
+ MIMEEntity *x = list_get(m->body.l, i);
+ debug("mms.dump", 0, "--->Message part: %d --->", i);
+
+ _x_mime_entity_dump(x,0,headers_only);
+ }
+ else if (!headers_only)
+ octstr_dump(m->body.s, 0);
+
+}
+
+Octstr *mms_tobinary(MmsMsg *msg)
+{
+ Octstr *s = octstr_create("");
+
+ encode_msgheaders(s, msg);
+
+ if (msg->body.s)
+ encode_msgbody(s, msg);
+ return s;
+}
+
+int mms_messagetype(MmsMsg *msg)
+{
+ return msg->message_type;
+}
+
+
+static void convert_mime_msg(MIMEEntity *m)
+{
+ int i, n;
+ Octstr *content_type, *params;
+ char *s = NULL;
+
+ get_content_type(m->headers, &content_type, ¶ms);
+
+ if (content_type) {
+ if (octstr_str_compare(content_type,
+ "application/vnd.wap.multipart.related") == 0)
+ s = "multipart/related";
+ else if (octstr_str_compare(content_type,
+ "application/vnd.wap.multipart.alternative") == 0)
+ s = "multipart/alternative";
+ else if (octstr_str_compare(content_type,
+ "application/vnd.wap.multipart.mixed") == 0)
+ s = "multipart/mixed";
+ octstr_destroy(content_type);
+ }
+ if (s) {
+ Octstr *value;
+
+ value = (params && octstr_len(params) > 0) ?
+ octstr_format("%s; %S", s, params) : octstr_create(s);
+
+ http_header_remove_all(m->headers, "Content-Type");
+ http_header_add(m->headers, "Content-Type", octstr_get_cstr(value));
+
+
+ octstr_destroy(value);
+ }
+
+ if (params)
+ octstr_destroy(params);
+ if (m->multiparts)
+ for (i = 0, n = list_len(m->multiparts); i < n; i++)
+ convert_mime_msg(list_get(m->multiparts, i));
+
+}
+
+static void unconvert_mime_msg(MIMEEntity *m)
+{
+ int i, n;
+ Octstr *content_type, *params;
+ char *s = NULL;
+
+ get_content_type(m->headers, &content_type, ¶ms);
+
+ if (content_type) {
+ if (octstr_case_compare(content_type,
+ octstr_imm("multipart/related")) == 0)
+ s = "application/vnd.wap.multipart.related";
+ else if (octstr_case_compare(content_type,
+ octstr_imm("multipart/alternative")) == 0)
+ s = "application/vnd.wap.multipart.alternative";
+ else if (octstr_case_compare(content_type,
+ octstr_imm("multipart/mixed")) == 0)
+ s = "application/vnd.wap.multipart.mixed";
+ octstr_destroy(content_type);
+ }
+ if (s) {
+ Octstr *value;
+ if (params) {
+ List *h = get_value_parameters(params);
+ Octstr *ps;
+ http_header_remove_all(h,"boundary"); /* We don't need the boundary param if it is there. */
+ ps = make_value_parameters(h);
+
+ value = octstr_format("%s%s%S", s,
+ (ps && octstr_len(ps) > 0) ? "; " : "",
+ ps);
+ octstr_destroy(ps);
+ http_destroy_headers(h);
+ } else
+ value = octstr_create(s);
+
+ http_header_remove_all(m->headers, "Content-Type");
+ http_header_add(m->headers, "Content-Type", octstr_get_cstr(value));
+
+ octstr_destroy(value);
+ }
+
+ if (params)
+ octstr_destroy(params);
+
+ if (m->multiparts && list_len(m->multiparts) > 0)
+ for (i = 0, n = list_len(m->multiparts); i < n; i++)
+ unconvert_mime_msg(list_get(m->multiparts, i));
+
+}
+
+static MIMEEntity *mime_entity_duplicate(MIMEEntity *m)
+{
+ MIMEEntity *mx = gw_malloc(sizeof *mx);
+
+ mx->headers = http_header_duplicate(m->headers);
+ if (m->multiparts && list_len(m->multiparts) > 0) {
+ int i, n;
+ mx->multiparts = list_create();
+ for (i = 0, n = list_len(m->multiparts); i < n; i++) {
+ MIMEEntity *x = mime_entity_duplicate(list_get(m->multiparts, i));
+ list_append(mx->multiparts, x);
+ }
+ mx->body = NULL;
+ } else {
+ mx->body = m->body ? octstr_duplicate(m->body) : NULL;
+ mx->multiparts = NULL;
+ }
+ mx->start = NULL;
+
+ return mx;
+}
+
+MIMEEntity *mms_tomime(MmsMsg *msg)
+{
+ MIMEEntity *m = gw_malloc(sizeof *m);
+ int i, n;
+
+ memset(m, 0, sizeof *m);
+ m->body = NULL;
+ m->multiparts = NULL;
+ m->start = NULL;
+ m->headers = http_header_duplicate(msg->headers);
+
+ if (!msg->ismultipart)
+ m->body = msg->body.s ? octstr_duplicate(msg->body.s) : NULL;
+ else {
+ m->multiparts = list_create();
+ for (i = 0, n = list_len(msg->body.l); i < n; i++) {
+ MIMEEntity *mx = mime_entity_duplicate(list_get(msg->body.l, i));
+ list_append(m->multiparts, mx);
+ }
+ }
+ convert_mime_msg(m);
+
+ return m;
+}
+
+MmsMsg *mms_frommime(MIMEEntity *mime)
+{
+ MmsMsg *m = gw_malloc(sizeof *m);
+ Octstr *s;
+ MIMEEntity *mx;
+
+ memset(m, 0, sizeof *m);
+
+ mx = mime_entity_duplicate(mime);
+ unconvert_mime_msg(mx); /* Fix-up content type issues. */
+ unpack_mimeheaders(mx);
+ unbase64_mimeparts(mx);
+
+ m->headers = mx->headers;
+
+ if (mx->multiparts && list_len(mx->multiparts) > 0) {
+ m->ismultipart = 1;
+ m->body.l = mx->multiparts;
+ } else {
+ m->ismultipart = 0;
+ m->body.s = mx->body ? mx->body : octstr_imm("");
+ }
+
+ gw_free(mx); /* Because all its bits are used above. XXX not very clean! */
+ /* Now check for important headers. If missing, put them in */
+ m->msgId = http_header_value(m->headers, octstr_imm("Message-ID"));
+
+ /* Default type is send */
+ if ((s = http_header_value(m->headers, octstr_imm("X-Mms-Message-Type"))) == NULL) {
+ http_header_add(m->headers, "X-Mms-Message-Type",
+ mms_message_type_to_cstr(MMS_MSGTYPE_SEND_REQ));
+ m->message_type = MMS_MSGTYPE_SEND_REQ;
+ } else {
+ m->message_type = mms_string_to_message_type(s);
+ if (m->message_type < 0) {
+ error(0, "Unknown message type: %s while parsing mime entity.", octstr_get_cstr(s));
+ octstr_destroy(s);
+ goto failed;
+ }
+ octstr_destroy(s);
+ }
+
+ if ((s = http_header_value(m->headers, octstr_imm("X-Mms-MMS-Version"))) == NULL)
+ http_header_add(m->headers, "X-Mms-MMS-Version", MMS_VERSION);
+ else
+ octstr_destroy(s);
+
+ /* Fix-up date string: Put it in GMT format, since it might not be. */
+ if ((s = http_header_value(m->headers, octstr_imm("Date"))) != NULL) {
+ struct tm xtm, ytm, *tm;
+ time_t t = time(NULL), t2;
+ char buf[64], *p, *q;
+
+ http_header_remove_all(m->headers, "Date");
+ localtime_r(&t, &xtm); /* Initialise it. */
+
+ strptime(octstr_get_cstr(s), "%a, %d %b %Y %T %z", &xtm); /* Parse date value with time zone. */
+
+ t2 = gw_mktime(&xtm); /* Convert to unix time... */
+ tm = gmtime_r(&t2, &ytm); /* Then convert to GM time. */
+
+ if (!tm || asctime_r(tm, buf) == NULL) /* Then convert to ascii. If that fails...*/
+ ctime_r(&t, buf); /* .. just use current time. */
+
+ /* Strip leading and trailing blanks. */
+ for (p = buf; *p && p < buf + sizeof buf; p++)
+ if (!isspace(*p))
+ break;
+ q = p + (strlen(p) - 1);
+ while (isspace(*q) && q > p)
+ *q-- = 0;
+
+ http_header_add(m->headers, "Date", p);
+ octstr_destroy(s);
+
+
+ }
+ /* XXXX Probably ought to handle some more headers here:
+ * Return-Receipt-To becomes Read request is yes
+ * Disposition-Notification-To: becomes X-Mms-Delivery-Report = Yes
+ */
+
+ /* XXXX Also need to validate this message a bit better. */
+ fixup_msg(m, octstr_imm("anon@unknown"));
+
+ return m;
+
+ failed:
+ mms_destroy(m);
+ return NULL;
+}
+
+static void mm_destroy(MIMEEntity *mx)
+{
+ http_destroy_headers(mx->headers);
+ if (mx->body)
+ octstr_destroy(mx->body);
+ else if (mx->multiparts)
+ list_destroy(mx->multiparts, (list_item_destructor_t *)mm_destroy);
+ gw_free(mx);
+}
+
+void mms_destroy(MmsMsg *msg)
+{
+
+ if (msg->ismultipart)
+ list_destroy(msg->body.l, (list_item_destructor_t *)mm_destroy);
+ else if (msg->body.s)
+ octstr_destroy(msg->body.s);
+ http_destroy_headers(msg->headers);
+ octstr_destroy(msg->msgId);
+ gw_free(msg);
+}
+
+List *mms_message_headers(MmsMsg *msg)
+{
+
+ return http_header_duplicate(msg->headers);
+}
+
+MmsMsg *mms_deliveryreport(Octstr *msgid, Octstr *to, time_t date, Octstr *status)
+{
+
+ MmsMsg *m = gw_malloc(sizeof *m);
+ Octstr *s;
+
+
+ m->ismultipart = 0;
+ m->headers = http_create_empty_headers();
+
+ m->message_type = MMS_MSGTYPE_DELIVERY_IND;
+ m->body.s = NULL;
+ m->msgId = octstr_duplicate(msgid);
+
+ /* Now append headers. */
+
+ http_header_add(m->headers, "X-Mms-Message-Type", "m-delivery-ind");
+ http_header_add(m->headers, "X-Mms-MMS-Version", MMS_VERSION);
+ http_header_add(m->headers, "Message-ID", octstr_get_cstr(msgid));
+ http_header_add(m->headers, "To", octstr_get_cstr(to));
+
+ s = date_format_http(date);
+ http_header_add(m->headers, "Date", octstr_get_cstr(s));
+
+ http_header_add(m->headers, "X-Mms-Status", octstr_get_cstr(status));
+
+ octstr_destroy(s);
+
+ return m;
+}
+
+MmsMsg *mms_notification(MmsMsg *msg, unsigned int msize, Octstr *url,
+ Octstr *transactionid, time_t expiryt)
+{
+ MmsMsg *m = gw_malloc(sizeof *m);
+ char buf[10];
+
+ time_t tnow = time(NULL);
+
+ m->ismultipart = 0;
+ m->msgId = NULL;
+ m->body.s = NULL;
+ m->headers = http_create_empty_headers();
+ m->message_type = MMS_MSGTYPE_NOTIFICATION_IND;
+
+ http_header_add(m->headers, "X-Mms-Message-Type", "m-notification-ind");
+ http_header_add(m->headers, "X-Mms-Transaction-ID",
+ octstr_get_cstr(transactionid));
+ http_header_add(m->headers, "X-Mms-MMS-Version", MMS_VERSION);
+
+
+#define HX(h,d) do {\
+ Octstr *s = http_header_value(msg->headers, octstr_imm(#h)); \
+ if (s) { \
+ http_header_add(m->headers, #h, octstr_get_cstr(s)); \
+ octstr_destroy(s); \
+ } else if (d) \
+ http_header_add(m->headers, #h, d); \
+ } while(0)
+
+ HX(From,NULL);
+ HX(Subject,NULL);
+ HX(X-Mms-Message-Class, "Personal");
+#undef HX
+
+ sprintf(buf, "%d", msize);
+ http_header_add(m->headers, "X-Mms-Message-Size", buf);
+
+#define LARGET 365*24*3600
+
+ sprintf(buf, "%ld", expiryt ? expiryt - tnow : LARGET);
+ http_header_add(m->headers, "X-Mms-Expiry", buf);
+
+
+ /* No reply charge stuff for now. */
+
+ http_header_add(m->headers, "X-Mms-Content-Location", octstr_get_cstr(url));
+
+ return m;
+}
+
+MmsMsg *mms_retrieveconf(MmsMsg *msg, Octstr *transactionid,
+ char *err, char *errtxt, Octstr *opt_from)
+{
+ MmsMsg *m;
+
+
+ if (msg) {
+ if (msg->message_type == MMS_MSGTYPE_RETRIEVE_CONF)
+ return msg; /* Unchanged. XXX should we copy it instead?!! */
+
+ if (msg->message_type != MMS_MSGTYPE_SEND_REQ)
+ return NULL;
+ }
+
+ m = gw_malloc(sizeof *m);
+ m->msgId = msg ? octstr_duplicate(msg->msgId) : NULL;
+
+ m->headers = http_create_empty_headers();
+ m->message_type = MMS_MSGTYPE_RETRIEVE_CONF;
+
+ http_header_add(m->headers, "X-Mms-Message-Type", "m-retrieve-conf");
+ if (transactionid)
+ http_header_add(m->headers, "X-Mms-Transaction-ID",
+ octstr_get_cstr(transactionid));
+ http_header_add(m->headers, "X-Mms-MMS-Version", MMS_VERSION);
+
+ if (!msg) {
+ Octstr *x = date_format_http(time(NULL));
+
+ m->ismultipart = 0;
+
+ http_header_add(m->headers, "Date", octstr_get_cstr(x));
+ http_header_add(m->headers, "X-Mms-Retrieve-Status",err);
+ if (err)
+ http_header_add(m->headers, "X-Mms-Retrieve-Text",err);
+ if (opt_from)
+ http_header_add(m->headers, "From", octstr_get_cstr(opt_from));
+ http_header_add(m->headers, "Content-Type", "text/plain");
+
+ if (errtxt)
+ m->body.s = octstr_create(errtxt);
+ else
+ m->body.s = octstr_create(" ");
+
+ octstr_destroy(x);
+ } else { /* Otherwise copy from message. */
+ List *h = mms_message_headers(msg);
+ int i, n;
+
+#if 0 /* Some phones do not like this header! */
+ http_header_add(m->headers, "X-Mms-Retrieve-Status", "Ok");
+#endif
+
+ http_header_combine(h, m->headers);
+ http_destroy_headers(m->headers);
+ m->headers = h;
+
+ m->ismultipart = msg->ismultipart;
+
+ if (!m->ismultipart)
+ m->body.s = octstr_duplicate(msg->body.s);
+ else
+ /* Body is a list of MIMEEntities, so recreate it. */
+
+ for (m->body.l = list_create(), i = 0,
+ n = list_len(msg->body.l);
+ ibody.l,
+ mime_entity_duplicate(list_get(msg->body.l, i)));
+ }
+ return m;
+}
+
+int mms_remove_headers(MmsMsg *m, char *name)
+{
+ http_header_remove_all(m->headers, name);
+
+ return 0;
+}
+
+MmsMsg *mms_sendconf(char *errstr, char *msgid, char *transid, int isforward)
+{
+ MmsMsg *m = gw_malloc(sizeof *m);
+
+
+ m->ismultipart = 0;
+ m->msgId = msgid ? octstr_create(msgid) : NULL;
+ m->body.s = NULL;
+
+ m->headers = http_create_empty_headers();
+
+ if (!isforward) {
+ m->message_type = MMS_MSGTYPE_SEND_CONF;
+ http_header_add(m->headers, "X-Mms-Message-Type", "m-send-conf");
+ } else {
+ m->message_type = MMS_MSGTYPE_FORWARD_CONF;
+ http_header_add(m->headers, "X-Mms-Message-Type", "m-forward-conf");
+ }
+ http_header_add(m->headers, "X-Mms-Transaction-ID", transid);
+ http_header_add(m->headers, "X-Mms-MMS-Version", MMS_VERSION);
+
+ http_header_add(m->headers, "X-Mms-Response-Status", errstr);
+
+ if (msgid)
+ http_header_add(m->headers, "Message-ID", msgid);
+
+ return m;
+}
+
+
+int mms_replace_header_value(MmsMsg *msg, char *hname, char *value)
+{
+
+ http_header_remove_all(msg->headers, hname);
+
+ http_header_add(msg->headers, hname, value);
+ return 0;
+}
+
+Octstr *mms_get_header_value(MmsMsg *msg, Octstr *header)
+{
+
+ return http_header_value(msg->headers, header);
+
+}
+
+
+int mms_convert_readrec2readorig(MmsMsg *msg)
+{
+ if (msg->message_type != MMS_MSGTYPE_READ_REC_IND)
+ return -1;
+
+ mms_replace_header_value(msg, "X-Mms-Message-Type", "m-read-orig-ind");
+ msg->message_type = MMS_MSGTYPE_READ_ORIG_IND;
+ return 0;
+}
diff --git a/mbuni/mmlib/mms_msg.h b/mbuni/mmlib/mms_msg.h
new file mode 100644
index 0000000..86684bb
--- /dev/null
+++ b/mbuni/mmlib/mms_msg.h
@@ -0,0 +1,57 @@
+#ifndef __MMS_MSG_INCLUDED__
+#define __MMS_MSG_INCLUDED__
+#include "gwlib/gwlib.h"
+#include "wap/wsp_headers.h"
+#include "gwlib/mime.h"
+
+
+#include "mms_strings.h"
+
+typedef struct MmsMsg MmsMsg; /* Opaque type. */
+
+extern int mms_validate_address(Octstr *s);
+
+/*
+ * mms_frombinary: Parse MMS binary representation, return a Message or NULL.
+ * errors are reported in errors string.
+ * Takes from param which is put in if insert-address is requested.
+ */
+extern MmsMsg *mms_frombinary(Octstr *msg, Octstr *from);
+
+/*
+ * mms_tobinary: Return binary encoded Mms message
+ */
+extern Octstr *mms_tobinary(MmsMsg *msg);
+
+extern int mms_messagetype(MmsMsg *msg);
+
+/*
+ * Convert Mms Message to standard Mime entity.
+ * Does not recode any of the body parts.
+ */
+extern MIMEEntity *mms_tomime(MmsMsg *msg);
+extern MmsMsg *mms_frommime(MIMEEntity *mime);
+
+extern void mms_msgdump(MmsMsg *m, int headers_only);
+extern void mms_destroy(MmsMsg *msg);
+
+/* Make a delivery report message. */
+extern MmsMsg *mms_deliveryreport(Octstr *msgid, Octstr *to, time_t date, Octstr *status);
+
+/* Return message headers. */
+extern List *mms_message_headers(MmsMsg *msg);
+
+/* Make a notification message out of this one and the url given. */
+extern MmsMsg *mms_notification(MmsMsg *msg, unsigned int msize,
+ Octstr *url,
+ Octstr *transactionid, time_t expiryt);
+
+MmsMsg *mms_retrieveconf(MmsMsg *msg, Octstr *transactionid, char *err, char *errtxt, Octstr *opt_from);
+int mms_remove_headers(MmsMsg *m, char *name);
+MmsMsg *mms_sendconf(char *errstr, char *msgid, char *transid, int isforward);
+Octstr *mms_get_header_value(MmsMsg *msg, Octstr *header);
+int mms_replace_header_value(MmsMsg *msg, char *hname, char *value);
+
+int mms_convert_readrec2readorig(MmsMsg *msg);
+
+#endif
diff --git a/mbuni/mmlib/mms_queue.c b/mbuni/mmlib/mms_queue.c
new file mode 100644
index 0000000..2df64da
--- /dev/null
+++ b/mbuni/mmlib/mms_queue.c
@@ -0,0 +1,797 @@
+/*
+ * MMS Queue handler functions - P. A. Bagyenda
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "mms_queue.h"
+#include "gwlib/log.h"
+#include "gwlib/accesslog.h"
+
+#define MQF 'q'
+#define MDF 'd'
+#define MTF 't'
+
+
+static int free_envelope(MmsEnvelope *e, int removefromqueue);
+/*
+ * lockfile: tries to lock a file, returns 0 if success, errno (which could be +ve) otherwise.
+ * we use flock()
+ */
+static int lockfile(int fd, int shouldblock)
+{
+ int n, stop;
+ unsigned flg = shouldblock ? 0 : LOCK_NB;
+
+ do {
+ n = flock(fd, LOCK_EX|flg);
+ if (n < 0) {
+ if (errno == EINTR)
+ stop = 0;
+ else
+ stop = 1;
+ } else
+ stop = 1;
+ } while (!stop);
+
+ return (n == 0) ? 0 : errno;
+}
+
+static int check_lock(int fd, char *fname)
+{
+ struct stat fs = {0}, ds = {0};
+
+
+ if (fstat(fd, &ds) < 0 ||
+ stat(fname, &fs) < 0 ||
+
+ ds.st_nlink != fs.st_nlink ||
+ memcmp(&ds.st_dev,&fs.st_dev, sizeof ds.st_dev) != 0 ||
+ memcmp(&ds.st_ino,&fs.st_ino, sizeof ds.st_ino) != 0 ||
+ ds.st_uid != fs.st_uid ||
+ ds.st_gid != fs.st_gid ||
+ ds.st_size != fs.st_size)
+ return -1;
+ else
+ return 0;
+}
+/* Queue file structure:
+ * - File consists of a series of lines, each line begins with a single letter, followed by
+ * a parameter. Letters mean:
+ * T - message type (full text string -- MMS message type.
+ * I - message ID
+ * F - From address
+ * R - Recipient (the ones pending) for this message
+ * C - Time queue entry was created
+ * L - Time of last delivery attempt
+ * D - Time of (next) delivery attempt
+ * X - Time of expiry of message
+ * N - Number of delivery attempts so far
+ * P - Proxy who sent it to us
+ * V - Proxy through which this message shd be delivered (e.g. delivery report)
+ * S - Message size
+ * s - Message subject.
+ * f - time of last content fetch
+ * t - user defined token.
+ * b - billed amount.
+ * r - whether delivery receipts are required or not.
+ * M - Application specific data (string)
+ */
+
+
+static int _putline(int fd, char *code, char buf[])
+{
+ Octstr *s = octstr_format("%s%s\n", code, buf);
+ int res;
+
+ res = octstr_write_to_socket(fd, s);
+ octstr_destroy(s);
+ return res;
+}
+
+
+/*
+ * Attempt to read an envelope from queue file:
+ * - opens and locks the file.
+ * - if the lock succeeds, check that file hasn't changed since opening. If it has
+ * return NULL (i.e. file is being processed elsewhere -- race condition), otherwise read it.
+ * - If should block is 1, then does a potentially blocking attempt to lock the file.
+ */
+MmsEnvelope *mms_queue_readenvelope(char *qf, char *mms_queuedir, int shouldblock)
+{
+ Octstr *fname;
+ int fd;
+ Octstr *qdata, *s;
+ ParseContext *p;
+ MmsEnvelope *e;
+ int okfile = 0;
+
+ fname = octstr_format( "%.128s/%s", mms_queuedir, qf);
+
+ if ((fd = open(octstr_get_cstr(fname), O_RDONLY)) < 0) {
+ octstr_destroy(fname);
+ return NULL;
+ }
+
+ if (lockfile(fd, shouldblock) != 0 ||
+ check_lock(fd, octstr_get_cstr(fname)) != 0) {
+ close(fd);
+ octstr_destroy(fname);
+ return NULL;
+ }
+
+
+ e = gw_malloc(sizeof *e);
+ memset(e, 0, sizeof *e); /* Clear it all .*/
+
+ e->to = list_create();
+ e->qf.fd = fd;
+ strncpy(e->qf.name, qf, sizeof e->qf.name);
+ strncpy(e->qf.dir, mms_queuedir, sizeof e->qf.dir);
+
+ qdata = octstr_read_file(octstr_get_cstr(fname));
+ octstr_destroy(fname);
+ if (qdata == NULL)
+ qdata = octstr_imm("");
+ p = parse_context_create(qdata);
+
+ for (s = parse_get_line(p); s;
+ s = parse_get_line(p)) {
+ char *line = octstr_get_cstr(s);
+ int ch = line[0];
+ char *res = line + 1;
+
+ switch (ch) {
+ Octstr *t;
+ MmsEnvelopeTo *to;
+ case 'T':
+ t = octstr_create(res);
+ e->msgtype = mms_string_to_message_type(t);
+ octstr_destroy(t);
+ if (e->msgtype < 0) {
+ e->msgtype = 0;
+ error(0, "mms_queueread: Unknown MMS message type (%s) in file %s/%s, skipped!\n",
+ res, mms_queuedir, qf);
+ }
+ break;
+ case 'I':
+ e->msgId = octstr_create(res);
+ break;
+ case 'F':
+ e->from = octstr_create(res);
+ if (mms_validate_address(e->from) != 0)
+ error(0, "mms_queueread: Mal-formed address %s in file %s/%s!", res, mms_queuedir, qf);
+ break;
+ case 'R':
+
+ t = octstr_create(res);
+ if (mms_validate_address(t) != 0)
+ error(0, "mms_queueread: Mal-formed address %s in file %s/%s!", res, mms_queuedir, qf);;
+ to = gw_malloc(sizeof *to);
+ to->rcpt = t;
+ to->process = 1;
+ list_append(e->to, to);
+ break;
+ case 'C':
+ e->created = atol(res);
+ break;
+ case 'L':
+ e->lasttry = atol(res);
+ break;
+ case 'D':
+ e->sendt = atol(res);
+ break;
+ case 'X':
+ e->expiryt = atol(res);
+ break;
+ case 'N':
+ e->attempts = atol(res);
+ break;
+ case 'P':
+ e->fromproxy = octstr_create(res);
+ break;
+ case 'M':
+ e->mdata = octstr_create(res);
+ break;
+ case 'V':
+ e->viaproxy = octstr_create(res);
+ break;
+ case 'S':
+ e->msize = atol(res);
+ break;
+ case 's':
+ e->subject = octstr_create(res);
+ break;
+ case 't':
+ e->token = octstr_create(res);
+ break;
+ case 'f':
+ e->lastaccess = atol(res);
+ break;
+ case 'b':
+ e->bill.billed = 1;
+ e->bill.amt = atof(res);
+ break;
+ case 'r':
+ e->dlr = 1;
+ break;
+ case '.':
+ okfile = 1;
+ break;
+ default:
+ error(0, "Unknown QF header %c in file %s/%s!", ch, mms_queuedir, qf);
+ break;
+ }
+ octstr_destroy(s);
+ if (okfile)
+ break; /* We are done. */
+ }
+ parse_context_destroy(p);
+ octstr_destroy(qdata);
+
+ /* We should properly validate the queue file here. */
+ if (!okfile) {
+ free_envelope(e,0);
+ e = NULL;
+ error(0, "Corrupt queue control file: %s/%s", mms_queuedir, qf);
+ }
+ return e;
+}
+
+
+/* Updates envelope to queue file:
+ * - opens temp file
+ * - writes output to temp file, if not new else writes directly.
+ * - renames temp file to queue file (if not new)
+ * This function doesn't check that this envelope is useless (i.e. no recipients)
+ * - If function returns -1, caller should check errno for error.
+ */
+static int writeenvelope(MmsEnvelope *e, int newenv)
+{
+ Octstr *tfname = NULL;
+ char *s;
+ char buf[16];
+ int fd;
+ int i, n;
+ int res = 0;
+
+ if (newenv)
+ fd = e->qf.fd;
+ else {
+ tfname = octstr_format(
+ "%s/%c%s", e->qf.dir,
+ MTF, e->qf.name + 1);
+ fd = open(octstr_get_cstr(tfname),
+ O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (fd < 0 ) {
+ error(0, "mms_queueadd: Failed to open temp file %s: error = %s\n",
+ octstr_get_cstr(tfname), strerror(errno));
+
+ res = -1;
+ goto done;
+ } else if (lockfile(fd, 0) != 0 ||
+ check_lock(fd, octstr_get_cstr(tfname)) != 0) { /* Lock it. */
+ error(0, "mms_queueadd: Failed lock temp file %s: error = %s\n",
+ octstr_get_cstr(tfname), strerror(errno));
+ res = -1;
+ goto done;
+
+ }
+ }
+
+ /* Write out. */
+
+ s = mms_message_type_to_cstr(e->msgtype);
+ if (!s) {
+ error(0, "mms_queuewrite: Unknown MMS message type %d! Skipped\n", e->msgtype);
+ s = "";
+ }
+ _putline(fd, "T", s);
+
+ if (e->msgId)
+ _putline(fd, "I", octstr_get_cstr(e->msgId));
+
+ _putline(fd, "F", octstr_get_cstr(e->from));
+
+ if (e->to)
+ n = list_len(e->to);
+ else
+ n = 0;
+
+ for (i = 0; i < n; i++) {
+ MmsEnvelopeTo *to = list_get(e->to, i);
+
+ if (to->process)
+ _putline(fd, "R", octstr_get_cstr(to->rcpt));
+ }
+
+ sprintf(buf, "%ld", e->created);
+ _putline(fd, "C", buf);
+
+ if (e->lasttry) {
+ sprintf(buf, "%ld", e->lasttry);
+ _putline(fd, "L", buf);
+ }
+
+ if (e->sendt) {
+ sprintf(buf, "%ld", e->sendt);
+ _putline(fd, "D", buf);
+ }
+
+ if (e->expiryt) {
+ sprintf(buf, "%ld", e->expiryt);
+ _putline(fd, "X", buf);
+ }
+
+ if (e->attempts) {
+ sprintf(buf, "%ld", e->attempts);
+ _putline(fd, "N", buf);
+ }
+
+ if (e->lastaccess) {
+ sprintf(buf, "%ld", e->lastaccess);
+ _putline(fd, "f", buf);
+ }
+
+ sprintf(buf, "%ld", e->msize);
+ _putline(fd, "S", buf);
+
+
+ if (e->fromproxy)
+ _putline(fd, "P", octstr_get_cstr(e->fromproxy));
+
+
+ if (e->mdata)
+ _putline(fd, "M", octstr_get_cstr(e->mdata));
+
+ if (e->subject)
+ _putline(fd, "s", octstr_get_cstr(e->subject));
+
+
+ if (e->viaproxy)
+ _putline(fd, "V", octstr_get_cstr(e->viaproxy));
+
+ if (e->token)
+ _putline(fd, "t", octstr_get_cstr(e->token));
+
+
+ if (e->dlr)
+ _putline(fd, "r", "Yes");
+
+ if (e->bill.billed) {
+ sprintf(buf, "%.3f", e->bill.amt);
+ _putline(fd,"b", buf);
+ }
+
+ _putline(fd, "", ".");
+
+ fsync(fd); /* Sync data. */
+
+ if (!newenv) { /* An update */
+ Octstr *qfname;
+
+ qfname = octstr_format("%s/%s", e->qf.dir, e->qf.name);
+ if (rename(octstr_get_cstr(tfname), octstr_get_cstr(qfname)) < 0) {
+ error(0, "mms_queuewrite: Failed to rename %s to %s: error = %s\n",
+ octstr_get_cstr(qfname), octstr_get_cstr(tfname), strerror(errno));
+
+ close(fd); /* Close new one, keep old one. */
+ res = -1;
+ } else { /* On success, new descriptor replaces old one and we close old one. */
+ close(e->qf.fd);
+ e->qf.fd = fd;
+ }
+ octstr_destroy(qfname);
+ }
+
+ done:
+ if (tfname) octstr_destroy(tfname);
+ return res;
+}
+
+
+#define MAXTRIES 10
+
+/* Makes a qf file in the queue directory.
+ * Makes several attempts then fails (returns -1) if it can't, fd otherwise
+ * puts queue file name in qf (without directory name).
+ * It is up to the caller to lock the file descriptor if needed.
+ */
+static int mkqf(char qf[32], char *mms_queuedir)
+{
+ Octstr *tmp;
+ char *ctmp;
+ int i = 0, fd = -1;
+ static int ect;
+
+ if (!mms_queuedir)
+ gw_panic(0, "Queue directory passed as null!");
+
+ do {
+ tmp = octstr_format("%.64s/%cf%ld.%d.x%d%ld",
+ mms_queuedir, MQF,
+ time(NULL),
+ ++ect, getpid(), random() % 100);
+ ctmp = octstr_get_cstr(tmp);
+ fd = open(ctmp, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (fd >= 0 &&
+ (lockfile(fd,1) != 0 ||
+ check_lock(fd, ctmp) != 0)) {
+ unlink(ctmp);
+ close(fd);
+ fd = -1;
+ }
+
+ if (fd < 0) {
+ octstr_destroy(tmp);
+ tmp = NULL;
+ }
+ } while (i++ < MAXTRIES && fd < 0);
+
+ if (fd >= 0) {
+ char *s = strrchr(ctmp, '/');
+ if (s)
+ strncpy(qf, s + 1, 32);
+ else /* ???! */
+ gw_panic(0, "Queue directory name is too long!\n");
+ }
+
+ if (tmp) octstr_destroy(tmp);
+ return fd;
+}
+
+static int writemmsdata(Octstr *ms, char *df, char *mms_queuedir)
+{
+ Octstr *dfname;
+ int fd, n, res = 0;
+
+
+ dfname = octstr_format("%s/%s", mms_queuedir, df);
+
+ fd = open(octstr_get_cstr(dfname),
+ O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (fd < 0) {
+ error(0, "mms_queuadd: Failed to open data file %s: error = %s\n",
+ octstr_get_cstr(dfname), strerror(errno));
+ res = -1;
+ goto done;
+ }
+
+ n = octstr_write_to_socket(fd, ms);
+ close(fd);
+
+ if (n != 0) {
+ error(0, "mms_queuadd: Failed to write data file %s: error = %s\n",
+ octstr_get_cstr(dfname), strerror(errno));
+ unlink(octstr_get_cstr(dfname));
+ res = -1;
+ }
+
+ done:
+ octstr_destroy(dfname);
+ return res;
+}
+
+
+Octstr *mms_queue_add(Octstr *from, List *to, Octstr *msgid,
+ Octstr *subject,
+ Octstr *fromproxy, Octstr *viaproxy,
+ time_t senddate, time_t expirydate, MmsMsg *m, Octstr *token,
+ int dlr,
+ char *directory)
+{
+ char qf[32];
+ int fd, i, n;
+ MmsEnvelope *e;
+
+ Octstr *ms, *res = NULL;
+
+ fd = mkqf(qf, directory);
+
+ if (fd < 0) {
+ error(0, "mms_queue_add: Failed err=%s\n", strerror(errno));
+ return NULL;
+ }
+
+ res = octstr_create(qf);
+ ms = mms_tobinary(m); /* Convert message to string. */
+
+
+ e = gw_malloc(sizeof *e); /* Make envelope, clear it. */
+ memset(e, 0, sizeof *e);
+
+ strncpy(e->qf.name, qf, sizeof e->qf.name);
+ strncpy(e->qf.dir, directory, sizeof e->qf.dir);
+
+ e->qf.fd = fd;
+
+ e->msgtype = mms_messagetype(m);
+ e->from = from;
+ e->created = time(NULL);
+ e->sendt = senddate;
+ e->expiryt = expirydate;
+ e->lasttry = 0;
+ e->attempts = 0;
+ e->lastaccess = 0;
+ e->fromproxy = fromproxy;
+ e->viaproxy = viaproxy;
+ e->subject = subject;
+ e->to = list_create();
+ e->msize = octstr_len(ms);
+ e->msgId = msgid ? msgid : res;
+ e->token = token;
+ e->dlr = dlr;
+ e->bill.billed = 0;
+
+ /* Insert message ID into message if it is missing. */
+ if (!msgid && mms_messagetype(m) == MMS_MSGTYPE_SEND_REQ)
+ mms_replace_header_value(m, "Message-ID", octstr_get_cstr(res));
+
+ n = to ? list_len(to) : 0;
+
+ for (i = 0; ircpt = a;
+ t->process = 1;
+
+ list_append(e->to, t);
+ }
+
+ /* Write queue data. */
+ if (writeenvelope(e, 1) < 0) {
+ octstr_destroy(res);
+ res = NULL;
+ goto done;
+ }
+
+
+ /* Write actual data before relinquishing lock on queue file. */
+
+ qf[0]= MDF;
+
+ if (writemmsdata(ms, qf, directory) < 0) {
+ octstr_destroy(res);
+ res = NULL;
+ goto done;
+ }
+
+ close(fd); /* Close queue file, thereby letting go of locks. */
+
+
+
+ done:
+ /* Free the envelope stuff since we do not need it any more, then free e */
+ for (i = 0, n = list_len(e->to); ito, i);
+ gw_free(to);
+ }
+ list_destroy(e->to, NULL);
+ gw_free(e);
+ octstr_destroy(ms);
+
+ return res;
+}
+
+static int free_envelope(MmsEnvelope *e, int removefromqueue)
+{
+ int i, n;
+
+ if (e->msgId)
+ octstr_destroy(e->msgId);
+
+ for (i = 0, n = list_len(e->to); i < n; i++) {
+ MmsEnvelopeTo *x = list_get(e->to, i);
+
+ octstr_destroy(x->rcpt);
+ gw_free(x);
+ }
+ list_destroy(e->to, NULL);
+
+ if (e->from)
+ octstr_destroy(e->from);
+
+ if (e->fromproxy)
+ octstr_destroy(e->fromproxy);
+ if (e->mdata)
+ octstr_destroy(e->mdata);
+ if (e->viaproxy)
+ octstr_destroy(e->viaproxy);
+ if (e->token)
+ octstr_destroy(e->token);
+
+ if (e->subject)
+ octstr_destroy(e->subject);
+
+ if (removefromqueue) {
+ char fname[2*QFNAMEMAX];
+
+ snprintf(fname, -1 + sizeof fname, "%s/%s", e->qf.dir, e->qf.name);
+ unlink(fname);
+ e->qf.name[0] = MDF;
+ snprintf(fname, -1 + sizeof fname, "%s/%s", e->qf.dir, e->qf.name);
+ unlink(fname);
+ }
+ close(e->qf.fd); /* close and unlock now that we have deleted it. */
+
+ gw_free(e);
+
+ return 0;
+}
+
+int mms_queue_free_env(MmsEnvelope *e)
+{
+
+ return free_envelope(e, 0);
+}
+int mms_queue_update(MmsEnvelope *e)
+{
+ int i, n = (e && e->to) ? list_len(e->to) : 0;
+ int hasrcpt = 0;
+ MmsEnvelopeTo *x;
+
+ if (!e) return -1;
+
+ for (i = 0; i < n; i++)
+ if ((x = list_get(e->to, i)) &&
+ x->process) {
+ hasrcpt = 1;
+ break;
+ }
+
+ if (!hasrcpt) {
+ free_envelope(e,1);
+ return 1;
+ } else
+ return writeenvelope(e, 0);
+}
+
+MmsMsg *mms_queue_getdata(MmsEnvelope *e)
+{
+ Octstr *fname;
+ Octstr *ms;
+ MmsMsg *m;
+
+ if (!e) return NULL;
+
+ fname = octstr_format("%s/%c%s", e->qf.dir, MDF, e->qf.name + 1);
+
+ ms = octstr_read_file(octstr_get_cstr(fname));
+ if (!ms) {
+ error(0, "mms_queue_getdata: Failed to load data file for queue entry %s in %s",
+ e->qf.name, e->qf.dir);
+ octstr_destroy(fname);
+ return NULL;
+ }
+ m = mms_frombinary(ms, octstr_imm(""));
+ if (!m) {
+ error(0, "mms_queue_getdata: Failed to load decode data file for queue entry %s in %s",
+ e->qf.name, e->qf.dir);
+ octstr_destroy(fname);
+ return NULL;
+ }
+ octstr_destroy(ms);
+ octstr_destroy(fname);
+
+ return m;
+}
+
+
+struct Qthread_t {
+ List *l;
+ int (*deliver)(MmsEnvelope *e);
+};
+
+static void tdeliver(struct Qthread_t *qt)
+{
+ MmsEnvelope *e;
+
+ while ((e = list_consume(qt->l)) != NULL) {
+ int res = qt->deliver(e); /* If it is on the queue, it has to be delivered. */
+
+ if (res != 1) /* Then delete as it wasn't deleted. */
+ free_envelope(e, 0);
+ }
+ /* Consume failed, time to go away. */
+ if (qt->l)
+ list_destroy(qt->l, NULL);
+ qt->l = NULL; /* Signal that we are gone. */
+}
+
+void mms_queue_run(char *dir,
+ int (*deliver)(MmsEnvelope *),
+ double sleepsecs, int num_threads, int *rstop)
+{
+ struct Qthread_t *tlist;
+ int i;
+ int qstop = 0;
+
+ gw_assert(num_threads>0);
+
+ tlist = gw_malloc(num_threads*sizeof tlist[0]);
+
+ for (i = 0; id_name[0] == MQF &&
+ dp->d_name[1] == 'f') {
+ MmsEnvelope *e = mms_queue_readenvelope(dp->d_name,dir, 0);
+
+ if (!e)
+ continue;
+
+ if (e->sendt <= tnow) {
+ int queued = 0;
+ int j = i; /* This is the next queue to use. Checking for cycles. */
+ do {
+ if (tlist[i].l) {
+ debug("queuerun", 0, "Queued to thread %d for %s/%s",
+ i, dir, dp->d_name);
+ list_produce(tlist[i].l, e);
+ queued = 1;
+ }
+ i = (i+1)%num_threads;
+ } while (!queued && i != j);
+
+ if (!queued) { /* A problem. There are no sender threads! */
+ free_envelope(e, 0);
+ qstop = 1;
+ error(0, "mms_queue_run: No active sender queues for directory %s. Quiting.",
+ dir);
+ goto qloop;
+ }
+ } else
+ free_envelope(e,0); /* Let go of it. */
+
+ }
+
+ if (dirp) closedir(dirp);
+ qsleep:
+ gwthread_sleep(sleepsecs);
+ qloop:
+ (void)0;
+ } while (!*rstop && !qstop);
+
+ /* We are out of the queue, time to go away. */
+ for (i = 0; i
+#include
+#include "mms_resolve.h"
+#include "mms_util.h"
+
+static void *mms_resolvermodule_init(char *settings)
+{
+ return NULL;
+}
+
+static int mms_resolvermodule_fini(void *module_data)
+{
+ return 0;
+}
+
+static Octstr *mms_resolve(Octstr * phonenum, void *module_data, void *settings_p, void *proxyrelays_p)
+{
+ /* Most custom implementations of this library will probably just ignore the two last arguments,
+ * but this one needs them
+ */
+
+ MmsBoxSettings *settings = (MmsBoxSettings *) settings_p;
+ List *proxyrelays = (List *) proxyrelays_p;
+ int j, m;
+
+ if (does_prefix_match(settings->local_prefix, phonenum)) {
+ return settings->hostname;
+ } else if (proxyrelays && list_len(proxyrelays) > 0) /* Step through proxies. */
+ for (j = 0, m = list_len(proxyrelays); j < m; j++) {
+ MmsProxyRelay *mp = list_get(proxyrelays, j);
+ if (does_prefix_match(mp->allowed_prefix, phonenum) &&
+ !does_prefix_match(mp->denied_prefix, phonenum)) {
+ return mp->host;
+ }
+ }
+
+ return 0;
+}
+
+/* The function itself. */
+MmsResolverFuncStruct mms_resolvefuncs = {
+ mms_resolvermodule_init,
+ mms_resolve,
+ mms_resolvermodule_fini
+};
diff --git a/mbuni/mmlib/mms_resolve.h b/mbuni/mmlib/mms_resolve.h
new file mode 100644
index 0000000..ae5bb3f
--- /dev/null
+++ b/mbuni/mmlib/mms_resolve.h
@@ -0,0 +1,31 @@
+#ifndef __MMS_RESOLVE_INCLUDED__
+#define __MMS_RESOLVE_INCLUDED__
+
+#include
+#include "gwlib/gwlib.h"
+
+/* Resolver module. This file provides prototypes for all resolver functions.
+ * The idea is that for each site a DSO will be created that the mmsglobalsender loads and gets
+ * functions to resolve msisdn's to mmsc addresses. If the string returned is the same as our
+ * hostname, the msisdn is considered local.
+ */
+
+typedef struct MmsRevolverFuncStruct {
+/* This function is called once to initialise the resolver module. Return a generic object,
+ * which is passed with each resolution request..
+ */
+ void *(*mms_resolvermodule_init)(char *settings);
+
+/* Looks up the msisdn and returns the hostname of the msisdn's mmsc. If returned mmsc matches
+ * our hostname, the user is considered local.
+ *
+ * Return NULL on error, otherwise an Octstr
+ */
+ Octstr *(*mms_resolve)(Octstr * phonenum, void *module_data, void *settings, void *proxyrelays);
+
+ int (*mms_resolvermodule_fini)(void *module_data);
+} MmsResolverFuncStruct;
+
+extern MmsResolverFuncStruct mms_resolvefuncs; /* The module must expose this symbol. */
+
+#endif
diff --git a/mbuni/mmlib/mms_strings.c b/mbuni/mmlib/mms_strings.c
new file mode 100644
index 0000000..6292d54
--- /dev/null
+++ b/mbuni/mmlib/mms_strings.c
@@ -0,0 +1,242 @@
+#include "gwlib/gwlib.h"
+#include "mms_strings.h"
+
+
+/* mms_strings.c: lookup code for various tables defined by MMS standard
+ * Adapted from wsp_strings.c
+ */
+
+#include "gwlib/gwlib.h"
+
+#include "mms_strings.h"
+
+
+#define TABLE_SIZE(table) ((long)(sizeof(table) / sizeof(table[0])))
+
+static int initialized;
+
+/* The arrays in a table structure are all of equal length, and their
+ * elements correspond. The number for string 0 is in numbers[0], etc.
+ * Table structures are initialized dynamically.
+ */
+struct table
+{
+ long size; /* Nr of entries in each of the tables below */
+ Octstr **strings; /* Immutable octstrs */
+ long *numbers; /* Assigned numbers, or NULL for linear tables */
+ int *versions; /* WSP Encoding-versions, or NULL if non-versioned */
+ int linear; /* True for tables defined as LINEAR */
+};
+
+struct numbered_element
+{
+ unsigned char *str;
+ long number;
+ int version;
+};
+
+struct linear_element
+{
+ unsigned char *str;
+ int version;
+};
+
+/* Local functions */
+static Octstr *number_to_string(long number, struct table *table);
+static unsigned char *number_to_cstr(long number, struct table *table);
+static long string_to_number(Octstr *ostr, struct table *table);
+static long string_to_versioned_number(Octstr *ostr, struct table *table, int version);
+
+
+/* Declare the data. For each table "foo", create a foo_strings array
+ * to hold the data, and a (still empty) foo_table structure. */
+#define LINEAR(name, strings) \
+ static const struct linear_element name##_strings[] = { strings }; \
+ static struct table name##_table;
+#define STRING(string) { string, 0 },
+#define VSTRING(version, string) { string, version },
+#define NUMBERED(name, strings) \
+ static const struct numbered_element name##_strings[] = { strings }; \
+ static struct table name##_table;
+#define ASSIGN(string, number) { string, number, 0 },
+#define VASSIGN(version, string, number) { string, number, version },
+#include "mms_strings.def"
+
+/* Define the functions for translating number to Octstr */
+#define LINEAR(name, strings) \
+Octstr *mms_##name##_to_string(long number) { \
+ return number_to_string(number, &name##_table); \
+}
+#include "mms_strings.def"
+
+/* Define the functions for translating number to constant string */
+#define LINEAR(name, strings) \
+unsigned char *mms_##name##_to_cstr(long number) { \
+ return number_to_cstr(number, &name##_table); \
+}
+#include "mms_strings.def"
+
+#define LINEAR(name, strings) \
+long mms_string_to_##name(Octstr *ostr) { \
+ return string_to_number(ostr, &name##_table); \
+}
+#include "mms_strings.def"
+
+#define LINEAR(name, strings) \
+long mms_string_to_versioned_##name(Octstr *ostr, int version) { \
+ return string_to_versioned_number(ostr, &name##_table, version); \
+}
+#include "mms_strings.def"
+
+static Octstr *number_to_string(long number, struct table *table)
+{
+ long i;
+
+ gw_assert(initialized);
+
+ if (table->linear) {
+ if (number >= 0 && number < table->size)
+ return octstr_duplicate(table->strings[number]);
+ } else {
+ for (i = 0; i < table->size; i++) {
+ if (table->numbers[i] == number)
+ return octstr_duplicate(table->strings[i]);
+ }
+ }
+ return NULL;
+}
+
+static unsigned char *number_to_cstr(long number, struct table *table)
+{
+ long i;
+
+ gw_assert(initialized);
+
+ if (table->linear) {
+ if (number >= 0 && number < table->size)
+ return octstr_get_cstr(table->strings[number]);
+ } else {
+ for (i = 0; i < table->size; i++) {
+ if (table->numbers[i] == number)
+ return octstr_get_cstr(table->strings[i]);
+ }
+ }
+ return NULL;
+}
+
+/* Case-insensitive string lookup */
+static long string_to_number(Octstr *ostr, struct table *table)
+{
+ long i;
+
+ gw_assert(initialized);
+
+ for (i = 0; i < table->size; i++) {
+ if (octstr_case_compare(ostr, table->strings[i]) == 0) {
+ return table->linear ? i : table->numbers[i];
+ }
+ }
+
+ return -1;
+}
+
+/* Case-insensitive string lookup according to passed WSP encoding version */
+static long string_to_versioned_number(Octstr *ostr, struct table *table,
+ int version)
+{
+ unsigned int i, ret;
+
+ gw_assert(initialized);
+
+ /* walk the whole table and pick the highest versioned token */
+ ret = -1;
+ for (i = 0; i < table->size; i++) {
+ if (octstr_case_compare(ostr, table->strings[i]) == 0 &&
+ table->versions[i] <= version) {
+ ret = table->linear ? i : table->numbers[i];
+ }
+ }
+
+ debug("mms.strings",0,"MMS: Mapping string `%s', MMS version 1.%d to binary "
+ "representation `0x%04x'.", octstr_get_cstr(ostr), version, ret);
+
+ return ret;
+}
+
+static void construct_linear_table(struct table *table, const struct linear_element *strings,
+ long size)
+{
+ long i;
+
+ table->size = size;
+ table->strings = gw_malloc(size * (sizeof table->strings[0]));
+ table->numbers = NULL;
+ table->versions = gw_malloc(size * (sizeof table->versions[0]));
+ table->linear = 1;
+
+ for (i = 0; i < size; i++) {
+ table->strings[i] = octstr_imm(strings[i].str);
+ table->versions[i] = strings[i].version;
+ }
+}
+
+static void construct_numbered_table(struct table *table, const struct numbered_element *strings,
+ long size)
+{
+ long i;
+
+ table->size = size;
+ table->strings = gw_malloc(size * (sizeof table->strings[0]));
+ table->numbers = gw_malloc(size * (sizeof table->numbers[0]));
+ table->versions = gw_malloc(size * (sizeof table->versions[0]));
+ table->linear = 0;
+
+ for (i = 0; i < size; i++) {
+ table->strings[i] = octstr_imm(strings[i].str);
+ table->numbers[i] = strings[i].number;
+ table->versions[i] = strings[i].version;
+ }
+}
+
+static void destroy_table(struct table *table)
+{
+ /* No need to call octstr_destroy on immutable octstrs */
+
+ gw_free(table->strings);
+ gw_free(table->numbers);
+ gw_free(table->versions);
+}
+
+void mms_strings_init(void)
+{
+ wsp_strings_init();
+ if (initialized > 0) {
+ initialized++;
+ return;
+ }
+
+#define LINEAR(name, strings) \
+ construct_linear_table(&name##_table, \
+ name##_strings, TABLE_SIZE(name##_strings));
+#define NUMBERED(name, strings) \
+ construct_numbered_table(&name##_table, \
+ name##_strings, TABLE_SIZE(name##_strings));
+#include "mms_strings.def"
+ initialized++;
+}
+
+void mms_strings_shutdown(void)
+{
+ /* If we were initialized more than once, then wait for more than
+ * one shutdown. */
+ if (initialized > 1) {
+ initialized--;
+ return;
+ }
+
+#define LINEAR(name, strings) \
+ destroy_table(&name##_table);
+#include "mms_strings.def"
+
+ initialized = 0;
+}
diff --git a/mbuni/mmlib/mms_strings.def b/mbuni/mmlib/mms_strings.def
new file mode 100644
index 0000000..b821cd4
--- /dev/null
+++ b/mbuni/mmlib/mms_strings.def
@@ -0,0 +1,191 @@
+/**** Preprocessor magic ****/
+
+/* String table with entries starting at 0 and numbered upwards. */
+#if !defined(LINEAR)
+#error "Required macro LINEAR is missing."
+#endif
+
+/* Entry in a LINEAR table. Default is to do nothing for it. */
+#if !defined(STRING)
+#define STRING
+#endif
+
+/* String table where entries have assigned numbers. Multiple
+ * entries can have the same number (the first listed entry is used
+ * when looking up by number). */
+#if !defined(NUMBERED)
+#define NUMBERED LINEAR
+#endif
+
+/* Entry in a NUMBERED table */
+#if !defined(ASSIGN)
+#define ASSIGN(string, number) STRING(string)
+#endif
+
+/* Entry in a versioned NUMBERED table */
+#if !defined(VASSIGN)
+#define VASSIGN(version, string, number) VSTRING(version, string)
+#endif
+
+/* Just like LINEAR, but an enumerated type name##_enum is defined for
+ * the entries. */
+#if !defined(NAMED)
+#define NAMED LINEAR
+#endif
+
+/* Entry in a NAMED table */
+#if !defined(NSTRING)
+#define NSTRING(string, name) STRING(string)
+#endif
+
+/* Entry in a versioned NAMED table */
+#if !defined(VNSTRING)
+#define VNSTRING(version,string, name) VSTRING(version,string)
+#endif
+
+NAMED(header,
+VNSTRING(MS_1_1, "Unknown",MMS_HEADER_NONE)
+VNSTRING(MS_1_1, "Bcc",MMS_HEADER_BCC)
+VNSTRING(MS_1_1, "Cc",MMS_HEADER_CC)
+VNSTRING(MS_1_1, "X-Mms-Content-Location",MMS_HEADER_CONTENT_LOCATION)
+VNSTRING(MS_1_1, "Content-Type",MMS_HEADER_CONTENT_TYPE)
+VNSTRING(MS_1_1, "Date",MMS_HEADER_DATE)
+VNSTRING(MS_1_1, "X-Mms-Delivery-Report",MMS_HEADER_DELIVERY_REPORT)
+VNSTRING(MS_1_1, "X-Mms-Delivery-Time",MMS_HEADER_DELIVERY_TIME)
+VNSTRING(MS_1_1, "X-Mms-Expiry",MMS_HEADER_EXPIRY)
+VNSTRING(MS_1_1, "From",MMS_HEADER_FROM)
+VNSTRING(MS_1_1, "X-Mms-Message-Class",MMS_HEADER_MESSAGE_CLASS)
+VNSTRING(MS_1_1, "Message-ID",MMS_HEADER_MESSAGE_ID)
+VNSTRING(MS_1_1, "X-Mms-Message-Type",MMS_HEADER_MESSAGE_TYPE)
+VNSTRING(MS_1_1, "X-Mms-MMS-Version",MMS_HEADER_MMS_VERSION)
+VNSTRING(MS_1_1, "X-Mms-Message-Size",MMS_HEADER_MESSAGE_SIZE)
+VNSTRING(MS_1_1, "X-Mms-Priority",MMS_HEADER_PRIORITY)
+VNSTRING(MS_1_1, "X-Mms-Read-Report",MMS_HEADER_READ_REPORT)
+VNSTRING(MS_1_1, "X-Mms-Report-Allowed",MMS_HEADER_REPORT_ALLOWED)
+VNSTRING(MS_1_1, "X-Mms-Response-Status",MMS_HEADER_RESPONSE_STATUS)
+VNSTRING(MS_1_1, "X-Mms-Response-Text",MMS_HEADER_RESPONSE_TEXT)
+VNSTRING(MS_1_1, "X-Mms-Sender-Visibility",MMS_HEADER_SENDER_VISIBILITY)
+VNSTRING(MS_1_1, "X-Mms-Status",MMS_HEADER_STATUS)
+VNSTRING(MS_1_1, "Subject",MMS_HEADER_SUBJECT)
+VNSTRING(MS_1_1, "To",MMS_HEADER_TO)
+VNSTRING(MS_1_1, "X-Mms-Transaction-Id",MMS_HEADER_TRANSACTION_ID)
+VNSTRING(MS_1_1, "X-Mms-Retrieve-Status",MMS_HEADER_RETRIEVE_STATUS)
+VNSTRING(MS_1_1, "X-Mms-Retrieve-Text",MMS_HEADER_RETRIEVE_TEXT)
+VNSTRING(MS_1_1, "X-Mms-Read-Status",MMS_HEADER_READ_STATUS)
+VNSTRING(MS_1_1, "X-Mms-Reply-Charging",MMS_HEADER_REPLY_CHARGING)
+VNSTRING(MS_1_1, "X-Mms-Reply-Charging-Deadline",MMS_HEADER_REPLY_CHARGING_DEADLINE)
+VNSTRING(MS_1_1, "X-Mms-Reply-Charging-ID",MMS_HEADER_REPLY_CHARGING_ID)
+VNSTRING(MS_1_1, "X-Mms-Reply-Charging-Size",MMS_HEADER_REPLY_CHARGING_SIZE)
+VNSTRING(MS_1_1, "X-Mms-Previously-Sent-By",MMS_HEADER_PREVIOUSLY_SENT_BY)
+VNSTRING(MS_1_1, "X-Mms-Previously-Sent-Date",MMS_HEADER_PREVIOUSLY_SENT_DATE)
+)
+
+LINEAR(reports,
+STRING("yes")
+STRING("no")
+)
+
+NAMED(message_type,
+VNSTRING(MS_1_1,"m-send-req", MMS_MSGTYPE_SEND_REQ)
+VNSTRING(MS_1_1,"m-send-conf", MMS_MSGTYPE_SEND_CONF)
+VNSTRING(MS_1_1,"m-notification-ind", MMS_MSGTYPE_NOTIFICATION_IND)
+VNSTRING(MS_1_1,"m-notifyresp-ind", MMS_MSGTYPE_NOTIFYRESP)
+VNSTRING(MS_1_1,"m-retrieve-conf", MMS_MSGTYPE_RETRIEVE_CONF)
+VNSTRING(MS_1_1,"m-acknowledge-ind", MMS_MSGTYPE_ACKNOWLEDGE_IND)
+VNSTRING(MS_1_1,"m-delivery-ind", MMS_MSGTYPE_DELIVERY_IND)
+VNSTRING(MS_1_1,"m-read-rec-ind", MMS_MSGTYPE_READ_REC_IND)
+VNSTRING(MS_1_1,"m-read-orig-ind", MMS_MSGTYPE_READ_ORIG_IND)
+VNSTRING(MS_1_1,"m-forward-req", MMS_MSGTYPE_FORWARD_REQ)
+VNSTRING(MS_1_1,"m-forward-conf", MMS_MSGTYPE_FORWARD_CONF)
+)
+
+LINEAR(message_class,
+STRING("Personal")
+STRING("Advertisement")
+STRING("Informational")
+STRING("Auto")
+)
+
+
+NUMBERED(response_status,
+ASSIGN("Ok",128)
+ASSIGN("Error-unspecified",129)
+ASSIGN("Error-service-denied",130)
+ASSIGN("Error-message-format-corrupt",131)
+ASSIGN("Error-sending-address-unresolved",132)
+ASSIGN("Error-message-not-found",133)
+ASSIGN("Error-network-problem",134)
+ASSIGN("Error-content-not-accepted",135)
+ASSIGN("Error-unsupported-message",136)
+ASSIGN("Error-transient-failure",192)
+ASSIGN("Error-transient-sending-address-unresolved",193)
+ASSIGN("Error-transient-message-not-found",194)
+ASSIGN("Error-transient-network-problem",195)
+ASSIGN("Error-permanent-failure",224)
+ASSIGN("Error-permanent-service-denied",225)
+ASSIGN("Error-permanent-message-format-corrupt",226)
+ASSIGN("Error-permanent-sending-address-unresolved",227)
+ASSIGN("Error-permanent-message-not-found",228)
+ASSIGN("Error-permanent-content-not-accepted",229)
+ASSIGN("Error-permanent-reply-charging-limitations-not-met",230)
+ASSIGN("Error-permanent-reply-charging-request-not-accepted",231)
+ASSIGN("Error-permanent-reply-charging-forwarding-denied",232)
+ASSIGN("Error-permanent-reply-charging-not-supported",233)
+)
+
+NUMBERED(retrieve_status,
+ASSIGN("Ok",128)
+ASSIGN("Error-transient-failure",192)
+ASSIGN("Error-transient-message-not-found",193)
+ASSIGN("Error-transient-network-problem",194)
+ASSIGN("Error-permanent-failure",224)
+ASSIGN("Error-permanent-service-denied",225)
+ASSIGN("Error-permanent-message-not-found",226)
+ASSIGN("Error-permanent-content-unsupported",227)
+)
+
+
+LINEAR(priority,
+STRING("Low")
+STRING("Normal")
+STRING("High")
+)
+
+LINEAR(read_status,
+STRING("Read")
+STRING("Deleted without being read")
+)
+
+LINEAR(visibility,
+STRING("Hide")
+STRING("Show")
+)
+
+LINEAR(reply_charging,
+STRING("Requested")
+STRING("Requested text only")
+STRING("Accepted")
+STRING("Accepted text only")
+)
+
+LINEAR(status,
+STRING("Expired")
+STRING("Retrieved")
+STRING("Rejected")
+STRING("Deferred")
+STRING("Unrecognised")
+STRING("Indeterminate")
+STRING("Forwarded")
+)
+
+
+
+#undef LINEAR
+#undef STRING
+#undef VSTRING
+#undef NUMBERED
+#undef ASSIGN
+#undef VASSIGN
+#undef NAMED
+#undef NSTRING
+#undef VNSTRING
diff --git a/mbuni/mmlib/mms_strings.h b/mbuni/mmlib/mms_strings.h
new file mode 100644
index 0000000..2b3a092
--- /dev/null
+++ b/mbuni/mmlib/mms_strings.h
@@ -0,0 +1,29 @@
+#ifndef __MMS_STRINGS_DEFINED__
+#define __MMS_STRINGS_DEFINED__
+
+typedef enum {
+ MS_1_1 = 1
+} mms_encoding;
+#define MMS_VERSION "1.0"
+/* Declare the functions */
+#define LINEAR(name, strings) \
+Octstr *mms_##name##_to_string(long number); \
+unsigned char *mms_##name##_to_cstr(long number); \
+long mms_string_to_##name(Octstr *ostr); \
+long mms_string_to_versioned_##name(Octstr *ostr, int version);
+#define STRING(string)
+#include "mms_strings.def"
+
+
+#define LINEAR(name,strings)
+#define LINEAR(name, strings)
+#define STRING(string)
+#define NAMED(name, strings) enum mms_##name##_enum { strings mms_##name##_dummy };
+#define NSTRING(string, name) name,
+#define VNSTRING(version, string, name) name,
+#include "mms_strings.def"
+
+#include "wap/wsp_strings.h"
+
+void mms_strings_init(void);
+#endif
diff --git a/mbuni/mmlib/mms_uaprof.c b/mbuni/mmlib/mms_uaprof.c
new file mode 100644
index 0000000..bad779f
--- /dev/null
+++ b/mbuni/mmlib/mms_uaprof.c
@@ -0,0 +1,1313 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "mms_uaprof.h"
+#include "mms_util.h"
+
+struct MmsUaProfile {
+ List *versions;
+ unsigned long maxmsgsize;
+ struct {
+ long x, y;
+ } maxres;
+ struct {
+ unsigned char all;
+ unsigned char presentation;
+ List *content, *_hash; /* List of accepted content formats (+ hash keys for fast look-up). */
+
+ List *charset, *_chash; /* List of accepted charsets. */
+ List *lang; /* List of accepted languages. */
+ List *enc; /* List of accepted encodings. */
+ } ccppaccept;
+};
+
+static Dict *profile_dict; /* Of MmsUaProfile *. */
+static HTTPCaller *client;
+
+/* Hash function -- case insensitive. */
+static unsigned long hash_key(Octstr *s)
+{
+ unsigned long h = 0;
+ int i, n;
+ char *x;
+
+ if (!s) return 0;
+ for (x = octstr_get_cstr(s), i = 0, n = octstr_len(s); iversions)
+ list_destroy(prof->versions,
+ (list_item_destructor_t *)octstr_destroy);
+
+ if (prof->ccppaccept.content) {
+ list_destroy(prof->ccppaccept.content, (list_item_destructor_t *)octstr_destroy);
+ list_destroy(prof->ccppaccept._hash, NULL);
+ }
+
+ if (prof->ccppaccept.charset) {
+ list_destroy(prof->ccppaccept.charset, (list_item_destructor_t *)octstr_destroy);
+ list_destroy(prof->ccppaccept._chash, NULL);
+ } if (prof->ccppaccept.lang)
+ list_destroy(prof->ccppaccept.lang, (list_item_destructor_t *)octstr_destroy);
+ if (prof->ccppaccept.enc)
+ list_destroy(prof->ccppaccept.enc, (list_item_destructor_t *)octstr_destroy);
+
+ gw_free(prof);
+}
+
+static void dump_profile(MmsUaProfile *prof, Octstr *name)
+{
+ int i;
+ Octstr *s;
+
+ debug("mms.uaprof", 0, "Dumping profile for %s", octstr_get_cstr(name));
+
+ debug("mms.uaprof", 0, "MaxMsgSize: %ld", prof->maxmsgsize);
+ debug("mms.uaprof", 0, "MaxRes: %ldx%ld", prof->maxres.x,prof->maxres.y);
+
+
+ s = octstr_create("");
+ if (prof->ccppaccept.content)
+ for (i=0; iccppaccept.content); i++)
+ octstr_format_append(s, "%S, ", list_get(prof->ccppaccept.content,i));
+ debug("mms.uaprof", 0, "Accept content: %s", octstr_get_cstr(s));
+ octstr_destroy(s);
+
+
+ s = octstr_create("");
+ if (prof->ccppaccept.enc)
+ for (i=0; iccppaccept.enc); i++)
+ octstr_format_append(s, "%S, ", list_get(prof->ccppaccept.enc,i));
+ debug("mms.uaprof", 0, "Accept encodings: %s", octstr_get_cstr(s));
+ octstr_destroy(s);
+
+ s = octstr_create("");
+ if (prof->ccppaccept.lang)
+ for (i=0; iccppaccept.lang); i++)
+ octstr_format_append(s, "%S, ", list_get(prof->ccppaccept.lang,i));
+ debug("mms.uaprof", 0, "Accept language: %s", octstr_get_cstr(s));
+ octstr_destroy(s);
+
+ s = octstr_create("");
+ if (prof->ccppaccept.charset)
+ for (i=0; iccppaccept.charset); i++)
+ octstr_format_append(s, "%S, ", list_get(prof->ccppaccept.charset,i));
+ debug("mms.uaprof", 0, "Accept charset: %s", octstr_get_cstr(s));
+ octstr_destroy(s);
+
+ s = octstr_create("");
+ if (prof->versions)
+ for (i=0; iversions); i++)
+ octstr_format_append(s, "%S, ", list_get(prof->versions,i));
+ debug("mms.uaprof", 0, "Mms Version: %s", octstr_get_cstr(s));
+ octstr_destroy(s);
+
+}
+
+/* Helper function: find a node. Uses breadth first search */
+static xmlNodePtr find_node(xmlNodePtr start, char *name, char *id, int level, int maxlevel)
+{
+ xmlNodePtr node, x, list;
+
+
+ if (level >= maxlevel) return NULL;
+
+ /* First search at top level. */
+ for (list=start; list; list=list->next)
+ if (list->type == XML_COMMENT_NODE)
+ continue;
+ else if (xmlStrcasecmp(list->name, (const xmlChar *)name) == 0) {
+ if (!id)
+ return list;
+ else {
+ char *s;
+ if ((s= xmlGetProp(list,"ID")) != NULL &&
+ xmlStrcasecmp(s,id) == 0) {
+ xmlFree(s);
+ return list;
+ }
+ if (s) xmlFree(s);
+ }
+ }
+ /* Then recurse...*/
+ for (list = start; list; list=list->next)
+ for (node = list->xmlChildrenNode; node; node = node->next)
+ if (xmlStrcasecmp(node->name, (const xmlChar *)name) == 0) {
+ if (!id)
+ return node;
+ else {
+ char *s;
+ if ((s = xmlGetProp(node,"ID")) != NULL &&
+ xmlStrcasecmp(s,id) == 0) {
+ xmlFree(s);
+ return node;
+ }
+ if (s) xmlFree(s);
+ }
+ } else if (node->type != XML_COMMENT_NODE &&
+ (x = find_node(node, name,id, level+1,maxlevel)) != NULL)
+ return x;
+ return NULL;
+}
+
+MmsUaProfile *mms_make_ua_profile(List *req_headers)
+{
+ MmsUaProfile *prof = NULL;
+ Octstr *s, *ua;
+ List *l;
+ int i, n;
+ static int uacounter;
+
+ /* Check cache first, if not, then construct. */
+ if ((ua = http_header_value(req_headers, octstr_imm("User-Agent"))) == NULL)
+ ua = octstr_format("dummy-ua-%d", uacounter++);
+
+ if ((prof = dict_get(profile_dict, ua)) != NULL)
+ goto done;
+
+ prof = gw_malloc(sizeof *prof);
+ memset(prof, 0, sizeof *prof);
+
+ /* Put in some defaults. then read then check accepts. */
+ prof->maxres.x = 640;
+ prof->maxres.y = 480;
+ prof->maxmsgsize = 100*1024;
+ prof->versions = list_create();
+
+
+ list_append(prof->versions, octstr_imm("1.0")); /* Assume 1.0 for now. */
+
+ /* Get accepted charsets. */
+ s = http_header_value(req_headers, octstr_imm("Accept-Charset"));
+
+ if (s && (l = http_header_split_value(s)) != NULL) {
+ prof->ccppaccept.charset = l;
+ prof->ccppaccept._chash = list_create();
+ for (i = 0, n = list_len(l); iccppaccept._chash, (void *)hash_key(list_get(l, i)));
+ }
+ if (s) octstr_destroy(s);
+
+
+ /* Get accepted encodings. */
+ s = http_header_value(req_headers, octstr_imm("Accept-Encoding"));
+
+ if (s && (l = http_header_split_value(s)) != NULL)
+ prof->ccppaccept.enc = l;
+
+ if (s) octstr_destroy(s);
+
+
+
+ /* Get accepted language. */
+ s = http_header_value(req_headers, octstr_imm("Accept-Language"));
+ if (s && (l = http_header_split_value(s)) != NULL)
+ prof->ccppaccept.lang = l;
+
+ if (s) octstr_destroy(s);
+
+ s = http_header_value(req_headers, octstr_imm("Accept"));
+ if (s && (l = http_header_split_value(s)) != NULL) {
+ prof->ccppaccept.content = l;
+ prof->ccppaccept._hash = list_create();
+
+ for (i = 0, n = l ? list_len(l) : 0; iccppaccept.all = 1;
+ else if (octstr_case_compare(x, octstr_imm(PRES_TYPE)) == 0)
+ prof->ccppaccept.presentation = 1;
+
+ list_append(prof->ccppaccept._hash, (void *)hash_key(x));
+ }
+ }
+
+ if (s) octstr_destroy(s);
+
+ /* Put it in with the UA string as the key. */
+ if (dict_put_once(profile_dict, ua, prof) != 1)
+ warning(0, "mms_uaprof: Duplicate cache entry(%s)?\n",
+ octstr_get_cstr(ua));
+
+ /* Done. Dump it while debugging. */
+ done:
+
+#if 1
+ dump_profile(prof, ua ? ua : octstr_imm(""));
+#endif
+
+ if (ua)
+ octstr_destroy(ua);
+ return prof;
+}
+
+static MmsUaProfile *parse_uaprofile(Octstr *xml)
+{
+ char *s = octstr_get_cstr(xml);
+ xmlDocPtr doc = xmlParseMemory(s, octstr_len(xml));
+ xmlNodePtr node, xnode;
+ MmsUaProfile *prof = NULL;
+
+ if (!doc || !doc->xmlChildrenNode)
+ goto done;
+
+ node = find_node(doc->xmlChildrenNode, "Description", "MmsCharacteristics",0,3);
+
+ prof = gw_malloc(sizeof *prof);
+ memset(prof, 0, sizeof *prof);
+
+ /* Put in some defaults. then read the file. */
+ prof->versions = NULL;
+ prof->maxres.x = 640;
+ prof->maxres.y = 480;
+ prof->maxmsgsize = 100*1024;
+ prof->versions = NULL;
+
+
+ if (!node)
+ goto done;
+
+ for (xnode = node->xmlChildrenNode; xnode; xnode = xnode->next) {
+ xmlNodePtr child = xnode->xmlChildrenNode, lnode, rdfnode;
+ const char *xname = xnode->name;
+ char *childtext = xmlNodeListGetString(doc, child, 1);
+ List *l;
+
+ /* If there is a Bag, get the list. */
+ if ((rdfnode = find_node(xnode->xmlChildrenNode, "Bag", NULL,0,1)) != NULL) {
+ l = list_create();
+ for (lnode = rdfnode->xmlChildrenNode; lnode; lnode = lnode->next)
+ if (xmlStrcasecmp(lnode->name, (const xmlChar *)"li") == 0) {
+ char *t = xmlNodeListGetString(doc, lnode->xmlChildrenNode,1);
+ if (t) {
+ list_append(l, octstr_create(t));
+ xmlFree(t);
+ }
+ }
+ } else
+ l = NULL;
+
+ if (xmlStrcasecmp(xname, (const xmlChar *)"MmsMaxMessageSize") == 0)
+ sscanf(childtext, "%ld", &prof->maxmsgsize);
+ else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsMaxImageResolution") == 0)
+ sscanf(childtext, "%ldx%ld", &prof->maxres.x, &prof->maxres.y);
+ else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAcceptCharSet") == 0 ||
+ xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAccept-CharSet") == 0) {/* Cranky old ones! */
+ int i, n;
+ prof->ccppaccept.charset = l;
+ prof->ccppaccept._chash = list_create();
+ for (i = 0, n = list_len(l); iccppaccept._chash, (void *)hash_key(list_get(l, i)));
+ } else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAcceptLanguage") == 0)
+ prof->ccppaccept.lang = l;
+ else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAcceptEncoding") == 0)
+ prof->ccppaccept.enc = l;
+ else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsVersion") == 0) {
+ if (!l && childtext) { /* SonyEriccson uses old format! */
+ l = list_create();
+ list_append(l, octstr_create(childtext));
+ }
+ prof->versions = l;
+ } else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAccept") == 0) {
+ int i, n;
+ prof->ccppaccept.content = l;
+ prof->ccppaccept._hash = list_create();
+
+ for (i = 0, n = l ? list_len(l) : 0; iccppaccept.all = 1;
+ else if (octstr_case_compare(x, octstr_imm(PRES_TYPE)) == 0)
+ prof->ccppaccept.presentation = 1;
+
+ list_append(prof->ccppaccept._hash, (void *)hash_key(x));
+ }
+ }
+ if (childtext) xmlFree(childtext);
+ }
+
+ done:
+ if (doc) xmlFreeDoc(doc);
+ return prof;
+}
+
+
+static int replace_slash(int ch)
+{
+ return (ch == '/') ? '$' : ch;
+}
+
+static int unreplace_slash(int ch)
+{
+ return (ch == '$') ? '/' : ch;
+}
+
+#define UACOUNT_PROFILE 1023
+static void init_profiledict(void)
+{
+ if (!profile_dict)
+ profile_dict = dict_create(UACOUNT_PROFILE, (void (*)(void *))destroy_uaprof);
+}
+
+
+static int mms_load_ua_profile_cache(char *dir)
+{
+
+ DIR *dirp;
+ struct dirent *dp;
+ dirp = opendir(dir);
+
+ if (!dirp) {
+ error(0, "mms_uaprof: Failed to open UA prof cache directory %s",
+ dir);
+ return -1;
+ }
+
+ while ((dp = readdir(dirp)) != NULL) {
+ Octstr *fname;
+ Octstr *xml = NULL;
+ MmsUaProfile *prof = NULL;
+ Octstr *key = NULL;
+
+
+ if (strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0 ||
+ dp->d_type & DT_DIR) /* If a directory, keep going. */
+ continue;
+
+ fname = octstr_format("%.255s/%.254s", dir, dp->d_name);
+
+ xml = octstr_read_file(octstr_get_cstr(fname));
+ octstr_destroy(fname);
+ if (!xml) {
+ error(0, "mms_uaprof: Failed to read UA prof doc %s in %s (%s)\n",
+ dp->d_name, dir, strerror(errno));
+ continue;
+ }
+
+ prof = parse_uaprofile(xml);
+ if (!prof) {
+ error(0, "mms_uaprof: Failed to parse UA prof doc %s in %s\n", dp->d_name, dir);
+ goto loop;
+ }
+
+ key = octstr_create(dp->d_name);
+ octstr_convert_range(key, 0, octstr_len(key), unreplace_slash);
+
+ if (dict_put_once(profile_dict, key, prof) != 1)
+ warning(0, "mms_uaprof: Duplicate cache entry(%s)?\n",
+ octstr_get_cstr(key));
+#if 1
+ dump_profile(prof, key);
+#endif
+ loop:
+ if (xml) octstr_destroy(xml);
+ if (key) octstr_destroy(key);
+ }
+ closedir(dirp);
+
+ return 0;
+}
+
+
+static void mms_profile_fetcher(char *cache_dir)
+{
+ Octstr *profile_url, *body;
+ List *h;
+ int status;
+
+ /* Just keep getting the data and putting it in the cache and on file. */
+ client = http_caller_create();
+
+ debug("mms.uaprof", 0, "Entered fetcher");
+ while (http_receive_result(client, &status, &profile_url, &h, &body) != NULL) {
+ if (status == HTTP_OK) {
+ MmsUaProfile *prof = parse_uaprofile(body);
+ Octstr *fname;
+ FILE *f;
+
+ debug("mms.uaprof", 0, "Fetcher got %s", octstr_get_cstr(profile_url));
+
+ if (prof) {
+ if (dict_put_once(profile_dict, profile_url, prof) != 1)
+ warning(0, "mms_uaprof: Duplicate ua profile fetched? (%s)?\n",
+ octstr_get_cstr(profile_url));
+ } else {
+ error(0, "mms_uaprof: Failed to parse UA prof url=%s\n",
+ octstr_get_cstr(profile_url));
+ goto loop;
+ }
+ octstr_convert_range(profile_url, 0, octstr_len(profile_url), replace_slash);
+ fname = octstr_format("%.255s/%.254s", cache_dir, octstr_get_cstr(profile_url));
+
+ f = fopen(octstr_get_cstr(fname), "w");
+
+ if (f) {
+ octstr_print(f, body);
+ fclose(f);
+ } else
+ error(0, "mms_uaprof: Failed to save profile data to cache file %s->%s\n",
+ octstr_get_cstr(fname), strerror(errno));
+ octstr_destroy(fname);
+ }
+ loop:
+ if (body) octstr_destroy(body);
+ if (profile_url) octstr_destroy(profile_url);
+ if (h) http_destroy_headers(h);
+ }
+
+ debug("mms.uaprof", 0, "Fetcher shutdown...");
+ http_caller_destroy(client);
+ client = NULL;
+
+ dict_destroy(profile_dict);
+ profile_dict = NULL;
+}
+
+static void init_format_table(void);
+
+int mms_start_profile_engine(char *cache_dir)
+{
+ init_profiledict();
+ init_format_table();
+ mms_load_ua_profile_cache(cache_dir);
+ gwthread_create((gwthread_func_t *)mms_profile_fetcher, cache_dir);
+
+ return 0;
+}
+
+int mms_stop_profile_engine(void)
+{
+ if (client)
+ http_caller_signal_shutdown(client);
+ /* This will cause thread to stop and also destroy dict. */
+ return 0;
+}
+
+MmsUaProfile *mms_get_ua_profile(char *url)
+{
+ Octstr *s = octstr_create(url);
+ MmsUaProfile *prof = NULL;
+ List *h;
+
+
+ if (!profile_dict) {
+ error(0, "mms_uaprof: get_profile, cache not set!\n");
+ goto done;
+ }
+
+ if ((prof = dict_get(profile_dict, s)) != NULL) {
+ octstr_destroy(s);
+ goto done;
+ }
+ /* Not found, queue get and return NULL. */
+
+ if (client) {
+ h = http_create_empty_headers();
+ http_header_add(h, "User-Agent", MM_NAME "/" GW_VERSION);
+ http_start_request(client,HTTP_METHOD_GET, s, h, NULL, 1, NULL, NULL);
+ } else
+ error(0, "mms_uaprof: get_profile, Fetch thread not started!\n");
+ done:
+ return prof;
+}
+
+/* Content convertors.
+ * content types are listed in order of preference.
+ * Notes: We have a concept of an intermediate format. For audio it is WAV
+ * (of indeterminate frequency or sample size). Each type of command should expect input on stdin
+ * and write output to standard out.
+ * New 25-01-04: For images we now use Imagemagick to convert, hence no intermediate format.
+ */
+
+#define NELEMS(a) (sizeof a/sizeof a[0])
+struct {
+ char *content_type; /* Content type. */
+ unsigned long chash; /* hash value. */
+
+ char *tostandard_cmd; /* Command to convert to standard format. */
+ char *fromstandard_cmd; /* Command to convert from standard format. */
+
+ char *file_ext; /* Standard file extension. */
+ int multi_image; /* whether this format allows for multiple images in one file. */
+ enum {TIMAGE=1,TAUDIO,TTEXT,TPRES,TOTHER} t;
+} cformats[] = {
+ /* Note: Order of listing matters:
+ * For images, we prefer jpeg (smaller, better support),
+ * For audio we prefer MP3 (smaller, well supported).
+ */
+ {"image/jpeg", 0, "jpegtopnm", "pnmtojpeg", "jpg", 0, TIMAGE},
+ {"image/png", 0, "pngtopnm ", "pnmtopng ", "png", 0, TIMAGE},
+ {"image/jpg", 0, "jpegtopnm", "pnmtojpeg", "jpg", 0, TIMAGE},
+ {"image/tiff", 0, "tifftopnm", "pnmtotiff", "tiff", 1, TIMAGE},
+
+ {"image/gif", 0, "giftopnm", "pnmquant 256 | ppmtogif", "gif", 1, TIMAGE},
+ {"image/bmp", 0, "bmptopnm", "pnmquant 256 | ppmtobmp", "bmp", 1, TIMAGE},
+ {"image/vnd.wap.wbmp", 0, "wbmptopbm", "ppmtopgm | pgmtopbm | pbmtowbmp", "wbmp", 0, TIMAGE},
+#if 0
+ {"image/x-bmp", 0, "bmptopnm", "pnmtobmp", "bmp", 0, TIMAGE},
+ {"image/x-wmf", 0, "bmptopnm", "pnmtobmp", "bmp", 0, TIMAGE},
+ {"image/vnd.wap.wpng", 0, "pngtopnm", "pngtobmp", "png", 0, TIMAGE},
+ {"image/x-up-wpng", 0, "pngtopnm", "pnmtopng", "png", 0, TIMAGE},
+#endif
+ {"audio/mpeg", 0, "mpg123 -w - -", "lame - -", "mp3",0, TAUDIO},
+ {"audio/wav", 0, "cat", "cat", "wav",0, TAUDIO},
+ {"audio/x-wav", 0, "cat", "cat", "wav",0, TAUDIO},
+ {"audio/basic", 0, "sox -t au -r 8000 -b -c 1 - -t wav -",
+ "sox -t wav - -t au -b -c 1 -r 8000 - lowpass 3700", "au",0, TAUDIO},
+ {"audio/amr", 0, "amrdecoder - - | sox -t raw -s -w -c 1 -r 8000 - -t wav -",
+ "sox -t wav - -t raw -s -w -c 1 -r 8000 - lowpass 3700 | amrencoder MR122 - -", "amr",0, TAUDIO},
+ {"audio/x-amr", 0, "amrdecoder - - | sox -t raw -s -w -c 1 -r 8000 - -t wav -",
+ "sox -t wav - -t raw -s -w -c 1 -r 8000 - lowpass 3700 | amrencoder MR122 - -", "amr",0, TAUDIO},
+ {"audio/amr-wb", 0, "amrdecoder - - | sox -t raw -s -w -c 1 -r 8000 - -t wav -",
+ "sox -t wav - -t raw -s -w -c 1 -r 8000 - lowpass 3700 | amrencoder MR122 - -", "amr",0, TAUDIO},
+#if 0
+ {"audio/midi", 0, "cat", "cat", "mid",0, TAUDIO},
+ {"audio/sp-midi", 0, "cat", "cat", "mid",0, TAUDIO},
+#endif
+};
+
+/* Image commands for finding resolution, scaling and conversion. */
+#define IMGRESCMD "identify -format '%%w %%h' %s:%s"
+#define IMGSCALECMD "convert -scale '%ldx%ld>' %s:%s %s:-"
+#define IMGCONVERTCMD "convert '%s:%s' '%s:%s'"
+
+static void init_format_table(void)
+{
+ int i;
+
+ for (i = 0; i < NELEMS(cformats); i++)
+ cformats[i].chash = hash_key(octstr_imm(cformats[i].content_type));
+
+}
+
+/* Removes an object by making it text/plain. For now not configurable. */
+static void remove_object(MIMEEntity *m, Octstr *ctype)
+{
+ http_header_remove_all(m->headers, "Content-Type");
+
+ http_header_add(m->headers, "Content-Type", "text/plain");
+
+ octstr_destroy(m->body);
+ m->body = octstr_format("Unsupported object (content type %S) removed", ctype);
+}
+
+static void mktmpfname(char fname[])
+{
+ /* We are not parameterising tmp dir yet. */
+ sprintf(fname, "/tmp/t%ld.%ld.%ld", random(), (long)getpid(), (long)time(NULL));
+}
+
+static Octstr *mknewname(Octstr *oldname, char *ext)
+{
+ Octstr *s;
+
+ int i = octstr_search_char(oldname, '.', 0);
+
+ if (i<0)
+ return octstr_format("%S.%s", oldname, ext);
+
+ s = octstr_copy(oldname, 0, i+1);
+ octstr_append_cstr(s,ext);
+ return s;
+}
+
+static void replace_ctype(List *headers, char *newcontent_type, List *params_h)
+{
+ Octstr *ct;
+ if (list_len(params_h) > 0) {
+ Octstr *tmp = make_value_parameters(params_h);
+ ct = octstr_format("%s; %S", newcontent_type, tmp);
+ octstr_destroy(tmp);
+ } else
+ ct = octstr_format("%s", newcontent_type);
+
+ http_header_remove_all(headers, "Content-Type");
+ http_header_add(headers, "Content-Type", octstr_get_cstr(ct));
+ octstr_destroy(ct);
+}
+
+static void replace_body(MIMEEntity *msg, Octstr *newbody, List *params_h,
+ char *newcontent_type, char *file_ext,
+ int add_disposition_header)
+{
+ Octstr *part_name;
+ Octstr *new_partname = NULL;
+
+ octstr_destroy(msg->body); /* Replace the body. */
+ msg->body = newbody;
+
+ if ((part_name = http_header_value(params_h, octstr_imm("name"))) != NULL) {
+ Octstr *tmp = mknewname(part_name, file_ext);
+ http_header_remove_all(params_h, "name");
+ http_header_add(params_h, "name", octstr_get_cstr(tmp));
+
+ octstr_destroy(part_name);
+ new_partname = tmp;
+ }
+
+ replace_ctype(msg->headers, newcontent_type, params_h);
+
+ if (add_disposition_header) {
+ Octstr *tmp = octstr_format("inline; filename=\"%S\"",
+ new_partname ? new_partname : octstr_imm("any"));
+ http_header_add(msg->headers, "Content-Disposition", octstr_get_cstr(tmp));
+ octstr_destroy(tmp);
+ }
+
+ if (new_partname) octstr_destroy(new_partname);
+}
+
+/* Modify the message based on the user agent profile data. Return 1 if was supported, 0
+ * otherwise
+ */
+static int modify_msg(MIMEEntity *msg, MmsUaProfile *prof)
+{
+ int i, n, type, send_data;
+ int j,m;
+ Octstr *content_type = NULL, *params = NULL, *s;
+ List *params_h;
+
+ unsigned long chash;
+ unsigned char supported = 0;
+
+ int iindex, oindex;
+
+ FILE *pf;
+ char tmpf[40], tmpf2[40];
+ Octstr *cmd = NULL;
+
+ if (!msg) return 0;
+
+ tmpf[0] = tmpf2[0] = 0; /* Clear .*/
+
+ /* Get the content type, hash it. */
+
+ get_content_type(msg->headers, &content_type, ¶ms);
+ params_h = get_value_parameters(params);
+
+#if 0
+ debug("MMS uaprof:", 0, " content_type = ### %s & %s: Header dump follows:",
+ octstr_get_cstr(content_type), params ? octstr_get_cstr(params) : "NULL");
+ http_header_dump(params_h);
+#endif
+
+ if (msg->multiparts && list_len(msg->multiparts) > 0) {
+ Octstr *startp = http_header_value(params_h, octstr_imm("start"));
+ int sflag = 0;
+
+ for (i = 0, n = list_len(msg->multiparts); imultiparts,i);
+ Octstr *cid = http_header_value(x->headers, octstr_imm("Content-ID"));
+ int sup;
+
+ debug("MMS uaprof: cid =###", 0, "%s", cid ? octstr_get_cstr(cid) : "NULL");
+
+ sup = modify_msg(x, prof);
+
+ if (!sup && /* not supported and is the presentation part, set flag */
+ cid && octstr_compare(cid, startp) == 0)
+ sflag = 1;
+ if (cid) octstr_destroy(cid);
+ }
+
+ /* If no start param but content type is other than multipart/mixed OR
+ * There is a start param but presentation type is not supported,
+ * Or presentations are not supported.
+ */
+ if (sflag ||
+ (!startp &&
+ octstr_case_compare(content_type, octstr_imm("multipart/related")) == 0) ||
+ !prof->ccppaccept.presentation) {
+ /* MMS conformance guide says: If presentation part is removed or unsupported,
+ * then change content type to multipart/mixed
+ */
+
+ http_header_remove_all(params_h, "start");
+ http_header_remove_all(params_h, "type");
+
+ replace_ctype(msg->headers, "multipart/mixed", params_h);
+ }
+
+ if (startp) octstr_destroy(startp);
+
+ supported = 1;
+ goto done;
+ }
+
+
+ if (octstr_case_search(content_type, octstr_imm("image/"), 0) == 0)
+ type = TIMAGE;
+ else if (octstr_case_search(content_type, octstr_imm("audio/"), 0) == 0)
+ type = TAUDIO;
+ else if (octstr_case_search(content_type, octstr_imm("text/"), 0) == 0)
+ type = TTEXT;
+ else
+ type = TOTHER;
+
+
+ if (type == TTEXT) { /* Deal with charset issues. */
+ Octstr *charset = http_header_value(params_h, octstr_imm("charset"));
+ char csupport = 0;
+ int i,n;
+
+ if (charset == NULL ||
+ octstr_str_compare(charset, "unknown") == 0) {
+ if (charset) octstr_destroy(charset);
+ charset = octstr_imm(DEFAULT_CHARSET);
+ }
+
+ n = prof->ccppaccept.charset ? list_len(prof->ccppaccept.charset) : 0;
+
+ /* Is this character set supported? If so do nothing. */
+ for (i = 0; iccppaccept.charset,i), charset) == 0) {
+ csupport = 1;
+ break;
+ }
+
+ if (!csupport)
+ for (i = 0; iccppaccept.charset,i); /* Don't free this! */
+ Octstr *ct;
+
+ if (charset_convert(msg->body, octstr_get_cstr(charset),
+ octstr_get_cstr(ncharset)) != -1) { /* using libiconv...*/
+ Octstr *tmp;
+
+ http_header_remove_all(params_h, "charset");
+ http_header_add(params_h, "charset", octstr_get_cstr(ncharset));
+ tmp = make_value_parameters(params_h);
+
+ ct = octstr_format("%S; %S", content_type, tmp);
+ octstr_destroy(tmp);
+ http_header_remove_all(msg->headers, "Content-Type");
+ http_header_add(msg->headers, "Content-Type", octstr_get_cstr(ct));
+ octstr_destroy(ct);
+
+ break; /* We succeeded in converting it so we shd go away. */
+ }
+ }
+
+ octstr_destroy(charset);
+ supported = 1;
+ goto done; /* No further processing for text/plain. */
+ }
+
+ /* find out if it is supported by the user agent. */
+ chash = hash_key(content_type);
+ if (prof->ccppaccept.all) /* Check if it accepts all content types. */
+ supported = 1;
+ else
+ for (i = 0, n = prof->ccppaccept.content ? list_len(prof->ccppaccept.content) : 0;
+ iccppaccept._hash,i) == chash &&
+ octstr_case_compare(list_get(prof->ccppaccept.content,i),content_type) == 0) {
+ supported = 1;
+ break;
+ }
+
+ if (supported && type != TIMAGE)
+ goto done; /* If it is supported, go away now.
+ * But for images we defer since we might have to scale the image.
+ */
+ else if (type == TOTHER)
+ goto done; /* Not supported and not audio or image, will be removed at done. */
+
+
+ /* At this point we have type = IMAGE (supported or not) OR type = AUDIO (unsuppported). */
+
+
+ /* Find out if we have a means of converting this format to our internal format,
+ * and if we have means of converting from internal to a format the UA supports.
+ * For images this means: Can we read it? Can we write out a supported format?
+ */
+
+ iindex = -1;
+ for (i = 0; i < NELEMS(cformats); i++)
+ if (cformats[i].chash == chash &&
+ octstr_case_compare(content_type, octstr_imm(cformats[i].content_type)) == 0) {
+ if (cformats[i].tostandard_cmd)
+ iindex = i; /* Only if the cmd exists actually. */
+ break;
+ }
+
+ oindex = -1;
+ for (i = 0; i < NELEMS(cformats); i++)
+ if (cformats[i].fromstandard_cmd) /* Check only ones we can convert from. */
+ for (j = 0, m = list_len(prof->ccppaccept.content); jccppaccept._hash,j) == cformats[i].chash &&
+ cformats[i].t == type && /* Convert to like type ! */
+ octstr_case_compare(list_get(prof->ccppaccept.content,j),
+ octstr_imm(cformats[i].content_type)) == 0){
+ oindex = i;
+ i = NELEMS(cformats); /* So the other loop breaks too. */
+ break;
+ }
+
+
+ if (iindex < 0 || oindex < 0) { /* We don't know how to convert this one fully, so... */
+ if (!supported)
+ remove_object(msg, content_type);
+ goto done;
+ }
+
+ /* Whatever we have (audio or image) we know how to convert it fully, so ... */
+ mktmpfname(tmpf);
+ if (type == TIMAGE) {
+ FILE *pf;
+ long x = 640, y = 480;
+ Octstr *icmd;
+ char *selector;
+
+ mktmpfname(tmpf2);
+ pf = fopen(tmpf2, "w");
+ if (!pf)
+ goto done;
+
+ n = octstr_print(pf, msg->body);
+ m = fclose(pf);
+
+ if (n < 0 || m != 0)
+ goto done; /* error .*/
+
+ /* Get the image dimensions, see if we need to modify it. */
+ icmd = octstr_format(IMGRESCMD,
+ cformats[iindex].file_ext, tmpf2);
+
+ pf = popen(octstr_get_cstr(icmd), "r");
+ octstr_destroy(icmd);
+
+ if (!pf)
+ goto done;
+ fscanf(pf, "%ld %ld", &x, &y);
+ pclose(pf);
+
+ icmd = NULL; /* Reset to NULL. */
+ if (x > prof->maxres.x ||
+ y > prof->maxres.y)
+ icmd = octstr_format(IMGSCALECMD, prof->maxres.x, prof->maxres.y,
+ cformats[iindex].file_ext,
+ tmpf2,
+ cformats[iindex].file_ext);
+ else if (supported) /* A supported image format and no need to scale, so go away. */
+ goto done;
+
+ /* If the first image is multi but the second isn't, then add selector. */
+ if (cformats[iindex].multi_image &&
+ !cformats[oindex].multi_image)
+ selector = "-[0]";
+ else
+ selector = "-";
+ /* We have an unsupported image now. time to convert it. */
+ if (icmd) {
+ cmd = octstr_format("%S | " IMGCONVERTCMD,
+ icmd, cformats[iindex].file_ext, selector,
+ cformats[oindex].file_ext, tmpf);
+ octstr_destroy(icmd);
+ } else
+ cmd = octstr_format("cat %S | " IMGCONVERTCMD,
+ tmpf2, cformats[iindex].file_ext, selector,
+ cformats[oindex].file_ext, tmpf);
+
+ send_data = 0;
+ } else {/* Type is audio. */
+ cmd = octstr_format("%s | %s > %s",
+ cformats[iindex].tostandard_cmd,
+ cformats[oindex].fromstandard_cmd, tmpf);
+ send_data = 1;
+ }
+
+ pf = popen(octstr_get_cstr(cmd), "w");
+
+ if (!pf)
+ goto done;
+
+ if (send_data) /* If this is not set then write the content... */
+ n = octstr_print(pf, msg->body);
+ else
+ n = 0;
+ m = pclose(pf);
+
+ if (n < 0 || m != 0)
+ goto done; /* Error -- finish up. */
+
+ s = octstr_read_file(tmpf);
+ if (s)
+ replace_body(msg, s, params_h,
+ cformats[oindex].content_type,
+ cformats[oindex].file_ext,0);
+ else
+ goto done;
+
+ supported = 1; /* Means we have sorted it out. */
+
+ done:
+ if (!supported)
+ remove_object(msg, content_type);
+
+ if (content_type)
+ octstr_destroy(content_type);
+ if (params)
+ octstr_destroy(params);
+ if (params_h)
+ http_destroy_headers(params_h);
+ if (tmpf[0])
+ unlink(tmpf);
+
+ if (tmpf2[0])
+ unlink(tmpf2);
+
+ if (cmd)
+ octstr_destroy(cmd);
+ return supported;
+}
+
+
+int mms_transform_msg(MmsMsg *inmsg, MmsUaProfile *prof, MmsMsg **outmsg)
+{
+ MIMEEntity *m;
+ Octstr *s;
+
+ if (!prof)
+ return -1;
+ else if (!prof->ccppaccept.content)
+ return -2;
+
+ m = mms_tomime(inmsg);
+
+#if 0
+ mms_msgdump(inmsg);
+ debug("MMS UA PROF", 0, "### in ua prof");
+ mime_entity_dump(m);
+#endif
+
+ modify_msg(m, prof);
+
+ *outmsg = mms_frommime(m);
+
+ mime_entity_destroy(m);
+
+ s = mms_tobinary(*outmsg);
+
+ if (octstr_len(s) > prof->maxmsgsize) {
+ mms_destroy(*outmsg);
+ *outmsg = NULL;
+ }
+
+ octstr_destroy(s);
+
+ /* Don't free profile! It is cached. */
+ return 0;
+}
+
+/* XXX Needs some work: Ensure we don't mod SMIL other than that specified in the start param.
+ * Also may be we should only mod the SMIL if content type of entity is multipart/related
+ * Also if the start param is missing we should perhaps stick it in.
+ */
+
+static int format_special(MIMEEntity *m,
+ int trans_smil, char *txtmsg, char *htmlmsg, int *counter)
+{
+ int type;
+ Octstr *content_type = NULL, *params = NULL, *s;
+ int i, n;
+ unsigned long chash;
+ FILE *pf;
+ char tmpf[40];
+ Octstr *cmd = NULL;
+ List *params_h;
+
+ tmpf[0] = 0;
+ get_content_type(m->headers, &content_type, ¶ms);
+ params_h = get_value_parameters(params);
+
+ if (m->multiparts && list_len(m->multiparts) > 0) {
+ MIMEEntity *pres = NULL;
+ int presindex = -1;
+ Octstr *presbody;
+ Octstr *start = http_header_value(params_h, octstr_imm("start"));
+
+ for (i = 0, n = list_len(m->multiparts); imultiparts,i);
+ Octstr *ctype = NULL, *charset = NULL;
+ Octstr *cid = http_header_value(x->headers, octstr_imm("Content-ID"));
+
+ http_header_get_content_type(x->headers, &ctype, &charset);
+
+ /* Find presentation part: If we have start param, and it matches
+ * this one, and this one is SMIL, then...
+ */
+ if (start && cid && octstr_compare(cid, start) == 0 &&
+ octstr_case_compare(ctype, octstr_imm(PRES_TYPE)) == 0) {
+ pres = x;
+ presindex = i;
+ }
+
+ if (ctype) octstr_destroy(ctype);
+ if (charset) octstr_destroy(charset);
+ if (cid) octstr_destroy(cid);
+
+ format_special(x, trans_smil, txtmsg, htmlmsg, counter);
+
+ }
+
+ if (start) octstr_destroy(start);
+
+ if (trans_smil && pres) { /* Reformat. */
+ MIMEEntity *x;
+ Octstr *btxt = octstr_create("");
+
+ /* Remove type & start param from top level. */
+ http_header_remove_all(params_h, "type");
+ http_header_remove_all(params_h, "start");
+ replace_ctype(m->headers, "multipart/related", params_h);
+
+
+ /* Put content ids on all siblings, and build html. */
+ for (i = 0, n = list_len(m->multiparts); imultiparts,i);
+ Octstr *cid, *pname;
+ Octstr *ctype = NULL, *cparams = NULL;
+ Octstr *y, *loc, *cidurl;
+ List *cparamsl;
+
+ if (x == pres) continue; /* Skip the presentation param. */
+
+ cid = http_header_value(x->headers, octstr_imm("Content-ID"));
+ if (cid == NULL) {
+ time_t t = time(NULL);
+ char ch[2];
+
+ ch[0] = ((t%2) ? 'A' : 'a') + (t%25); /* Make them a bit more unique. */
+ ch[1] = 0;
+
+ cid = octstr_format("", ch, *counter, (t%99989));
+ http_header_add(x->headers, "Content-ID", octstr_get_cstr(cid));
+
+ ++*counter;
+ }
+ y = octstr_copy(cid, 1, octstr_len(cid) - 2);
+ loc = http_header_value(x->headers, octstr_imm("Content-Location"));
+
+ cidurl = octstr_duplicate(y);
+ octstr_url_encode(cidurl);
+
+ get_content_type(x->headers, &ctype, &cparams); /* Get type of object. */
+
+ if (cparams) { /* Get its name. */
+ if ((cparamsl = get_value_parameters(cparams)) != NULL) {
+ pname = http_header_value(cparamsl, octstr_imm("name"));
+ http_destroy_headers(cparamsl);
+ } else
+ pname = octstr_duplicate(loc ? loc : y);
+ octstr_destroy(cparams);
+ } else
+ pname = octstr_imm("unknown");
+
+ if (octstr_case_search(ctype, octstr_imm("image/"), 0) == 0)
+ octstr_format_append(btxt,
+ "\n
\n",
+ cidurl, pname);
+ else if (octstr_case_search(ctype, octstr_imm("text/"), 0) == 0)
+ octstr_format_append(btxt, "%S
\n",
+ x->body ? x->body : octstr_imm(""));
+#if 0
+ else if (octstr_case_search(ctype, octstr_imm("audio/"), 0) == 0)
+ octstr_format_append(btxt,
+ "
\n",
+ cidurl, ctype, pname);
+#endif
+ else
+ octstr_format_append(btxt,
+ "%S
\n",
+ ctype, cidurl, pname);
+
+ http_header_remove_all(x->headers, "Content-Location");
+
+ if (y) octstr_destroy(y);
+ if (loc) octstr_destroy(loc);
+ if (ctype) octstr_destroy(ctype);
+ if (cidurl) octstr_destroy(cidurl);
+ if (pname) octstr_destroy(pname);
+
+ octstr_destroy(cid);
+ }
+
+
+ http_header_remove_all(pres->headers, "Content-Type");
+ http_header_add(pres->headers, "Content-Type", "multipart/alternative");
+
+ presbody = pres->body;
+ pres->body = NULL;
+ if (!pres->multiparts)
+ pres->multiparts = list_create();
+
+
+ /* first the text part ... */
+ x = mime_entity_create();
+ http_header_add(x->headers, "Content-Type", "text/plain");
+ x->body = octstr_create(txtmsg ? txtmsg : "");
+ list_append(pres->multiparts, x);
+
+ /* Lets also leave the pres part in there, just in case somebody knows how to handle it... */
+ x = mime_entity_create();
+ http_header_add(x->headers, "Content-Type", PRES_TYPE);
+ x->body = presbody;
+ list_append(pres->multiparts, x);
+
+
+ /* then the html part. */
+ x = mime_entity_create();
+ http_header_add(x->headers, "Content-Type", "text/html");
+ x->body = octstr_format("%s
%S
\n",
+ htmlmsg ? htmlmsg : "", btxt);
+ list_append(pres->multiparts, x);
+
+ list_delete(m->multiparts, presindex, 1); /* Put it at the beginning. */
+ list_insert(m->multiparts, 0, pres);
+#if 0
+ http_header_remove_all(pres->headers, "Content-ID"); /* Not needed anymore. */
+#endif
+ octstr_destroy(btxt);
+
+
+ }
+ goto done;
+ }
+
+
+
+ if (octstr_case_search(content_type, octstr_imm("image/"), 0) == 0)
+ type = TIMAGE;
+ else if (octstr_case_search(content_type, octstr_imm("audio/"), 0) == 0)
+ type = TAUDIO;
+ else if (octstr_case_search(content_type, octstr_imm("text/"), 0) == 0)
+ type = TTEXT;
+ else
+ type = TOTHER;
+
+ chash = hash_key(content_type);
+
+ if (type == TAUDIO) { /* Find the preferred format (audio only, leave images alone!),
+ * assuming we can support this one.
+ */
+ int ipref = -1, iindex = -1, o;
+
+ for (i = 0; i < NELEMS(cformats); i++) {
+ if (ipref < 0 && cformats[i].t == type &&
+ cformats[i].fromstandard_cmd)
+ ipref = i;
+
+ if (cformats[i].chash == chash &&
+ octstr_case_compare(content_type,
+ octstr_imm(cformats[i].content_type)) == 0) {
+ if (cformats[i].tostandard_cmd)
+ iindex = i; /* Only if the cmd exists actually. */
+ break;
+ }
+ }
+
+ if (iindex < 0 || ipref < 0) /* Can't change it.... */
+ goto done;
+
+ mktmpfname(tmpf);
+ if (type == TAUDIO)
+ cmd = octstr_format("%s | %s > %s",
+ cformats[iindex].tostandard_cmd,
+ cformats[ipref].fromstandard_cmd, tmpf);
+ else
+ cmd = octstr_format(IMGCONVERTCMD,
+ cformats[iindex].file_ext, "-",
+ cformats[ipref].file_ext, tmpf);
+
+ pf = popen(octstr_get_cstr(cmd), "w");
+
+ if (!pf)
+ goto done;
+ n = octstr_print(pf, m->body);
+ o = pclose(pf);
+
+ if (n < 0 || o != 0)
+ goto done; /* Error -- finish up. */
+
+ s = octstr_read_file(tmpf);
+ if (s)
+ replace_body(m, s, params_h,
+ cformats[ipref].content_type,
+ cformats[ipref].file_ext,1);
+ else
+ goto done;
+
+ } else if (type == TTEXT) {/* change to default charset. */
+ Octstr *charset = http_header_value(params_h, octstr_imm("charset"));
+ if (charset == NULL ||
+ octstr_case_compare(charset, octstr_imm("unknown")) == 0 ||
+ octstr_case_compare(charset, octstr_imm(DEFAULT_CHARSET)) == 0) {
+ if (charset) octstr_destroy(charset);
+ goto done; /* Nothing more to do here. */
+ }
+
+ if (charset_convert(m->body, octstr_get_cstr(charset),
+ DEFAULT_CHARSET) != -1) { /* using libiconv...*/
+ Octstr *tmp, *ct;
+
+ http_header_remove_all(params_h, "charset");
+ http_header_add(params_h, "charset", DEFAULT_CHARSET);
+ tmp = make_value_parameters(params_h);
+
+ ct = octstr_format("%S; %S", content_type, tmp);
+ octstr_destroy(tmp);
+ http_header_remove_all(m->headers, "Content-Type");
+ http_header_add(m->headers, "Content-Type", octstr_get_cstr(ct));
+ octstr_destroy(ct);
+
+ } /* Else goto done. */
+
+ } /* Else do nothing. */
+
+
+
+ done:
+
+ if (content_type)
+ octstr_destroy(content_type);
+ if (params_h)
+ http_destroy_headers(params_h);
+ if (cmd)
+ octstr_destroy(cmd);
+
+ if (tmpf[0])
+ unlink(tmpf);
+
+ return 0;
+}
+
+int mms_format_special(MmsMsg *inmsg,
+ int trans_smil,
+ char *txtmsg,
+ char *htmlmsg, MIMEEntity **outmsg)
+{
+ MIMEEntity *m = mms_tomime(inmsg);
+ int ct = 0;
+
+ if (!m)
+ return -1;
+
+ format_special(m, trans_smil, txtmsg, htmlmsg, &ct);
+
+ *outmsg = m;
+
+ return 0;
+
+}
diff --git a/mbuni/mmlib/mms_uaprof.h b/mbuni/mmlib/mms_uaprof.h
new file mode 100644
index 0000000..24208ea
--- /dev/null
+++ b/mbuni/mmlib/mms_uaprof.h
@@ -0,0 +1,41 @@
+#ifndef __MMS_UAPROFILE_INCLUDED__
+#define __MMS_UAPROFILE_INCLUDED__
+#include "gwlib/gwlib.h"
+#include "mms_msg.h"
+
+#define PRES_TYPE "application/smil"
+
+typedef struct MmsUaProfile MmsUaProfile;
+
+/* Start/stop profile engine.
+ * Starts a thread. Loads cache contents first.
+ */
+extern int mms_start_profile_engine(char *cache_dir);
+extern int mms_stop_profile_engine(void);
+
+/* Gets the profile. Returns NULL if not cached or not existent. */
+extern MmsUaProfile *mms_get_ua_profile(char *url);
+
+/* Make a UA Profile out of the Accept HTTP headers. */
+extern MmsUaProfile *mms_make_ua_profile(List *req_headers);
+
+/* Transform Mms Message using the profile supplied.
+ * Returns 0 on success (and sets outmsg accordingly)
+ * -1 if profile cannot be fetched (e.g. temporarily)
+ * -2 if profile exists and UA does not support MMS.
+ * If returns 0 and sets outmsg to NULL then transformed message was
+ * too large for recipient (as per profile).
+ */
+extern int mms_transform_msg(MmsMsg *inmsg, MmsUaProfile *prof, MmsMsg **outmsg);
+
+/* Transforms the mms into a more 'readable' format:
+ * SMIL is turned into html (with an alternative of text) if trans_smil is set,
+ * image and audio changed to email preferred formats.
+ */
+extern int mms_format_special(MmsMsg *inmsg,
+ int trans_smil,
+ char *txtmsg,
+ char *htmlmsg, MIMEEntity **outmsg);
+
+#define DEFAULT_CHARSET "UTF-8"
+#endif
diff --git a/mbuni/mmlib/mms_util.c b/mbuni/mmlib/mms_util.c
new file mode 100644
index 0000000..9a37fc0
--- /dev/null
+++ b/mbuni/mmlib/mms_util.c
@@ -0,0 +1,905 @@
+#include
+#include
+#include
+#include
+#include
+#include "mms_util.h"
+#include "mms_uaprof.h"
+
+#define MAXQTRIES 100
+#define BACKOFF_FACTOR 5*60 /* In seconds */
+#define QUEUERUN_INTERVAL 15*60 /* 15 minutes. */
+#define DEFAULT_EXPIRE 3600*24*7 /* One week */
+#define MMS_PORT 8191 /* Default content fetch port. */
+
+static Octstr *cfg_getx(CfgGroup *grp, Octstr *item)
+{
+ Octstr *v = cfg_get(grp, item);
+
+
+ return v ? v : octstr_create("");
+}
+
+
+static void *load_module(CfgGroup *grp, char *config_key, char *symbolname)
+{
+ Octstr *s;
+ void *retval = NULL;
+
+ s = cfg_get(grp, octstr_imm(config_key));
+ if (s) {
+ void *x = dlopen(octstr_get_cstr(s), RTLD_LAZY);
+ void *y = NULL;
+
+ if (x == NULL || (y = dlsym(x, symbolname)) == NULL)
+
+ panic(0,
+ "Error, unable to load dynamic libary (%s) for billing: "
+ "libhandle is %s, billing funcs is %s, err=%s",
+ octstr_get_cstr(s),
+ x ? "OK" : "Not OK", y ? "OK" : "Not OK", dlerror());
+ else
+ retval = y;
+
+ octstr_destroy(s);
+ }
+ return retval;
+}
+
+MmsBoxSettings *mms_load_mmsbox_settings(Cfg *cfg)
+{
+ Octstr *s;
+ List *l;
+ CfgGroup *grp = cfg_get_single_group(cfg, octstr_imm("mmsbox"));
+ MmsBoxSettings *m = gw_malloc(sizeof *m);
+ long port = -1;
+ Octstr *user, *pass, *from;
+
+ memset(m, 0, sizeof *m);
+
+ s = cfg_getx(grp, octstr_imm("local-mmsc-domains"));
+
+ if (s) {
+ l = octstr_split(s, octstr_imm(","));
+ octstr_destroy(s);
+ } else
+ l = list_create();
+ m->local_domains = l;
+
+ if (cfg_get_integer(&m->maxthreads, grp, octstr_imm("max-send-threads")) == -1)
+ m->maxthreads = 10;
+
+ m->unified_prefix = cfg_getx(grp, octstr_imm("unified-prefix"));
+ m->local_prefix = cfg_getx(grp, octstr_imm("local-prefixes"));
+ m->hostname = cfg_getx(grp, octstr_imm("hostname"));
+
+ if (m->hostname == NULL || octstr_len(m->hostname) == 0)
+ m->hostname = octstr_create("localhost");
+
+ m->name = cfg_getx(grp, octstr_imm("name"));
+ m->host_alias = cfg_getx(grp, octstr_imm("host-alias"));
+
+ m->sendmail = cfg_getx(grp, octstr_imm("send-mail-prog"));
+
+ m->global_queuedir = cfg_getx(grp, octstr_imm("send-queue-directory"));
+ m->mm1_queuedir = cfg_getx(grp, octstr_imm("mm1-queue-directory"));
+ m->mm4_queuedir = cfg_getx(grp, octstr_imm("mm4-queue-directory"));
+
+ if (cfg_get_integer(&m->maxsendattempts, grp, octstr_imm("maximum-send-attempts")) == -1)
+ m->maxsendattempts = MAXQTRIES;
+
+ if (cfg_get_integer(&m->default_msgexpiry, grp, octstr_imm("default-message-expiry")) == -1)
+ m->default_msgexpiry = DEFAULT_EXPIRE;
+
+ s = cfg_getx(grp, octstr_imm("queue-run-interval"));
+ if (!s || (m->queue_interval = atof(octstr_get_cstr(s))) <= 0)
+ m->queue_interval = QUEUERUN_INTERVAL;
+
+ if (cfg_get_integer(&m->send_back_off, grp, octstr_imm("send-attempt-back-off")) == -1)
+ m->send_back_off = BACKOFF_FACTOR;
+
+ /* Make send sms url. */
+ m->sendsms_url = cfg_getx(grp, octstr_imm("sendsms-url"));
+
+ user = cfg_getx(grp, octstr_imm("sendsms-username"));
+ pass = cfg_getx(grp, octstr_imm("sendsms-password"));
+ from = cfg_get(grp, octstr_imm("sendsms-global-sender"));
+
+ if (user && octstr_len(user) > 1)
+ octstr_url_encode(user);
+ if (pass && octstr_len(pass) > 1)
+ octstr_url_encode(pass);
+ if (from && octstr_len(from) > 1)
+ octstr_url_encode(from);
+
+
+ octstr_format_append(m->sendsms_url,
+ (from && octstr_len(from) > 1) ?
+ "?username=%S&password=%S&from=%S" :
+ "?username=%S&password=%S",
+ user,
+ pass,from);
+
+ m->system_user = octstr_format("system-user@%S",
+ m->hostname);
+ octstr_destroy(user);
+ octstr_destroy(pass);
+ if (from) octstr_destroy(from);
+
+ cfg_get_integer(&port, grp, octstr_imm("mms-port"));
+
+ m->port = (port > 0) ? port : MMS_PORT;
+
+ m->allow_ip = cfg_getx(grp, octstr_imm("allow-ip"));
+ m->deny_ip = cfg_getx(grp, octstr_imm("deny-ip"));
+
+ m->email2mmsrelay_prefixes = cfg_getx(grp,
+ octstr_imm("email2mms-relay-prefixes"));
+ m->ua_profile_cache_dir = cfg_getx(grp,
+ octstr_imm("ua-profile-cache-directory"));
+
+ m->prov_notify = cfg_getx(grp,octstr_imm("prov-server-notify-script"));
+ m->prov_notify_arg = cfg_getx(grp,octstr_imm("prov-server-notify-script-arg"));
+
+ m->prov_getstatus = cfg_getx(grp,octstr_imm("prov-server-sub-status-script"));
+ m->mms_notify_txt = cfg_getx(grp, octstr_imm("mms-notify-text"));
+ m->mms_notify_unprov_txt = cfg_getx(grp, octstr_imm("mms-notify-unprovisioned-text"));
+ m->mmbox_host = cfg_getx(grp, octstr_imm("mm-box-host"));
+
+ m->mms_email_txt = cfg_getx(grp, octstr_imm("mms-to-email-txt"));
+ m->mms_email_html = cfg_getx(grp, octstr_imm("mms-to-email-html"));
+
+ m->mms_toolarge = cfg_getx(grp, octstr_imm("mms-message-too-large-txt"));
+
+ m->wap_gw_msisdn_header = cfg_get(grp, octstr_imm("mms-client-msisdn-header"));
+ if (!m->wap_gw_msisdn_header) m->wap_gw_msisdn_header = octstr_imm(XMSISDN_HEADER);
+
+ m->wap_gw_ip_header = cfg_get(grp, octstr_imm("mms-client-ip-header"));
+ if (!m->wap_gw_ip_header) m->wap_gw_ip_header = octstr_imm(XIP_HEADER);
+
+ cfg_get_bool(&m->notify_unprovisioned, grp, octstr_imm("notify-unprovisioned"));
+
+ m->billing_params = cfg_getx(grp,
+ octstr_imm("billing-module-parameters"));
+ /* Get and load the billing lib if any. */
+
+ if ((m->mms_billfuncs = load_module(grp, "billing-library", "mms_billfuncs"))) {
+ if (m->mms_billfuncs->mms_billingmodule_init == NULL ||
+ m->mms_billfuncs->mms_billmsg == NULL ||
+ m->mms_billfuncs->mms_billingmodule_fini == NULL ||
+ m->mms_billfuncs->mms_logcdr == NULL)
+ panic(0, "Missing or NULL functions in billing module!");
+ } else
+ m->mms_billfuncs = &mms_billfuncs; /* The default one. */
+
+ m->mms_bill_module_data = m->mms_billfuncs->mms_billingmodule_init(octstr_get_cstr(m->billing_params));
+
+ m->resolver_params = cfg_getx(grp,
+ octstr_imm("billing-module-parameters"));
+
+ /* Get and load the resolver lib if any. */
+ if ((m->mms_resolvefuncs = load_module(grp, "billing-library", "mms_billfuncs"))) {
+ if (m->mms_resolvefuncs->mms_resolvermodule_init == NULL ||
+ m->mms_resolvefuncs->mms_resolve == NULL ||
+ m->mms_resolvefuncs->mms_resolvermodule_fini == NULL)
+ panic(0, "Missing or NULL functions in resolver module!");
+ } else
+ m->mms_resolvefuncs = &mms_resolvefuncs; /* The default one. */
+
+ m->mms_resolver_module_data = m->mms_resolvefuncs->mms_resolvermodule_init(octstr_get_cstr(m->resolver_params));
+
+ return m;
+}
+
+List *mms_proxy_relays(Cfg *cfg)
+{
+ List *gl = cfg_get_multi_group(cfg, octstr_imm("mmsproxy"));
+ int i, n;
+ List *l = list_create();
+
+ for (i = 0, n = list_len(gl); i < n; i++) {
+ CfgGroup *grp = list_get(gl, i);
+ MmsProxyRelay *m = gw_malloc(sizeof *m);
+
+ m->host = cfg_getx(grp, octstr_imm("host"));
+ m->name = cfg_getx(grp, octstr_imm("name"));
+ m->allowed_prefix = cfg_getx(grp, octstr_imm("allowed-prefix"));
+ m->denied_prefix = cfg_getx(grp, octstr_imm("denied-prefix"));
+
+ list_append(l, m);
+ }
+
+ list_destroy(gl, NULL);
+
+ return l;
+}
+
+
+Octstr *mms_makefetchurl(char *qf, Octstr *token,
+ MmsBoxSettings *settings)
+{
+ Octstr *url = octstr_create("");
+ Octstr *host_alias = settings->host_alias;
+ Octstr *hstr;
+
+ if (host_alias && octstr_len(host_alias) > 0)
+ hstr = octstr_duplicate(host_alias);
+ else
+ hstr = octstr_format("%S:%d",
+ settings->hostname, settings->port);
+
+ octstr_format_append(url, "http://%S/%s/%S",
+ hstr,
+ qf,
+ token ? token : octstr_imm("x"));
+ octstr_destroy(hstr);
+ return url;
+}
+
+
+Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *msisdn_header)
+{
+ /* Either we have a WAP gateway header as defined, or we look for
+ * last part of url as our number.
+ */
+ Octstr *xsend_url = *send_url;
+
+ Octstr *phonenum = http_header_value(request_hdrs,
+ msisdn_header);
+
+ if (!phonenum || octstr_len(phonenum) == 0) {
+ List *l = octstr_split(xsend_url, octstr_imm("/"));
+
+ if (l && list_len(l) > 1) {
+ int i, n = list_len(l);
+ Octstr *s;
+ phonenum = octstr_duplicate(list_get(l, list_len(l) - 1));
+
+ /* After getting it, remove it from the end... */
+ for (i = 0, s = octstr_create(""); i < n-1; i++) {
+ Octstr *p = list_get(l, i);
+ if (octstr_len(p) > 0)
+ octstr_format_append(s, "/%S", p);
+ }
+ octstr_destroy(xsend_url);
+ *send_url = s;
+ }
+ if (l)
+ list_destroy(l, (list_item_destructor_t *)octstr_destroy);
+ }
+
+ return phonenum;
+}
+
+Octstr *mms_find_sender_ip(List *request_hdrs, Octstr *ip_header, Octstr *ip, int *isv6)
+{
+ Octstr *xip;
+ /* Look in the headers, if none is defined, return actual IP */
+ Octstr *client_ip = http_header_value(request_hdrs, ip_header);
+ char *s;
+
+ xip = client_ip ? client_ip : ip;
+
+ s = octstr_get_cstr(xip);
+
+ /* Crude test for ipv6 */
+ *isv6 = (index(s, ':') >= 0);
+ return xip;
+}
+
+int mms_decodefetchurl(Octstr *fetch_url,
+ Octstr **qf, Octstr **token)
+{
+ Octstr *xfurl = octstr_duplicate(fetch_url);
+ int i, j, n;
+ char *s, *p;
+
+ for (i = 0, n = 0, s = octstr_get_cstr(xfurl);
+ i < octstr_len(xfurl); i++)
+ if (s[i] == '/')
+ n++;
+ if (n < 2) /* We need at least two slashes. */
+ octstr_append_char(xfurl, '/');
+
+ i = 0;
+ n = octstr_len(xfurl);
+ s = octstr_get_cstr(xfurl);
+
+ p = strrchr(s, '/'); /* Find last slash. */
+ if (p)
+ i = (p - s) - 1;
+ else
+ i = n-1;
+
+ if (i < 0)
+ i = 0;
+
+ while (i>0 && s[i] != '/')
+ i--; /* Go back, find first slash */
+ if (i>=0 && s[i] == '/')
+ i++;
+
+ /* Now we have qf, find its end. */
+
+ j = i;
+ while (j 0 && j < i) {
+ name = octstr_copy(xparams, k, j - k);
+ value = octstr_copy(xparams, j+1,i-j-1);
+ octstr_strip_blanks(name);
+ octstr_strip_blanks(value);
+ strip_quotes(value);
+ if (octstr_len(name) > 0)
+ http_header_add(h,
+ octstr_get_cstr(name),
+ octstr_get_cstr(value));
+ octstr_destroy(name);
+ octstr_destroy(value);
+ }
+ k = i + 1;
+ } else if (c == '"')
+ i += http_header_quoted_string_len(xparams, i) - 1;
+ }
+ octstr_destroy(xparams);
+ return h;
+}
+
+int get_content_type(List *hdrs, Octstr **type, Octstr **params)
+{
+
+ int i, n;
+
+
+ *type = http_header_find_first(hdrs, "Content-Type");
+ *params =NULL;
+
+ if (!*type) {
+ *type = octstr_create("application/octet-stream");
+ *params = octstr_create("");
+ return -1;
+ }
+ for (i = 0, n = octstr_len(*type); i < n; i++) {
+ int c = octstr_get_char(*type, i);
+
+ if (c == ';')
+ break;
+ else if (c == '"')
+ i += http_header_quoted_string_len(*type, i) - 1;
+ }
+
+ if (i < n) {
+ *params = octstr_copy(*type, i+1, octstr_len(*type));
+ octstr_delete(*type, i, octstr_len(*type));
+ } else
+ *params = octstr_create("");
+
+ return 0;
+}
+
+static int needs_quotes(Octstr *s)
+{
+ int i, n;
+ if (!s)
+ return 0;
+
+ for (i = 0, n = octstr_len(s); iheaders); iheaders, i, &header, &value);
+
+ if (header == NULL ||
+ octstr_str_compare(header, "X-Unknown") == 0 ||
+ octstr_search_chars(header, octstr_imm(" \n\t"), 0) >= 0) /* Don't allow space in the name. */
+ goto loop;
+
+ if (octstr_case_compare(header, octstr_imm("Cc")) == 0 ||
+ octstr_case_compare(header, octstr_imm("To")) == 0 ||
+ octstr_case_compare(header, octstr_imm("Bcc")) == 0)
+ skip = 0;
+ else
+ skip = 1;
+ /* XXX This may not be safe. Need to skip over quotes. */
+ if (!skip && octstr_search_char(value, ',', 0) > 0 &&
+ (l = http_header_split_value(value)) != NULL &&
+ list_len(l) > 1)
+ for (j = 0, m = list_len(l); jheaders);
+ mm->headers = h;
+}
+
+
+/* Undo base64 content coding for mime entities that need it. */
+void unbase64_mimeparts(MIMEEntity *m)
+{
+ int i, n;
+
+ if (m->multiparts && list_len(m->multiparts) > 0)
+ for (i = 0, n = list_len(m->multiparts); imultiparts, i));
+ else { /* A non-multipart message .*/
+ Octstr *ctype = http_header_value(m->headers, octstr_imm("Content-Type"));
+ Octstr *te = http_header_value(m->headers, octstr_imm("Content-Transfer-Encoding"));
+
+ if (ctype && te &&
+ octstr_case_compare(te,octstr_imm("base64")) == 0) {
+ octstr_base64_to_binary(m->body);
+ http_header_remove_all(m->headers, "Content-Transfer-Encoding");
+ }
+ if (ctype)
+ octstr_destroy(ctype);
+ if (te)
+ octstr_destroy(te);
+ }
+}
+#if 1
+static int gw_isprint(int c)
+{
+ return isprint(c) || isspace(c);
+}
+#endif
+
+/* Change content coding for mime entities that need it. */
+void base64_mimeparts(MIMEEntity *m)
+{
+ int i, n;
+
+ if (m->multiparts && list_len(m->multiparts) > 0)
+ for (i = 0, n = list_len(m->multiparts); imultiparts, i));
+ else { /* A non-multipart message .*/
+ Octstr *ctype = http_header_value(m->headers, octstr_imm("Content-Type"));
+ Octstr *te = http_header_value(m->headers, octstr_imm("Content-Transfer-Encoding"));
+
+ if (ctype && !te
+#if 1
+&&
+ octstr_check_range(m->body, 0, octstr_len(m->body), gw_isprint) == 0
+#endif
+ ) {
+ octstr_binary_to_base64(m->body);
+ http_header_add(m->headers, "Content-Transfer-Encoding", "base64");
+ }
+ if (ctype)
+ octstr_destroy(ctype);
+ if (te)
+ octstr_destroy(te);
+ }
+}
+
+void notify_prov_server(char *cmd, char *from, char *event, char *arg)
+{
+ Octstr *s;
+
+ if (cmd == NULL || cmd[0] == '\0')
+ return;
+ s = octstr_format("%s '%s' '%s' '%s'", cmd, event, from, arg);
+ if (s) {
+ system(octstr_get_cstr(s));
+ octstr_destroy(s);
+ }
+}
+
+int mms_ind_send(Octstr *prov_cmd, Octstr *to)
+{
+
+ Octstr *s;
+ int res = 1;
+
+ if (prov_cmd == NULL ||
+ octstr_len(prov_cmd) == 0)
+ return 1;
+
+ s = octstr_format("%S %S", prov_cmd, to);
+
+ if (s) {
+ int x = system(octstr_get_cstr(s));
+ int y = WEXITSTATUS(x);
+
+ if (x < 0) {
+ error(0, "Checking MMS Ind.Send: Failed to run command %s!",
+ octstr_get_cstr(s));
+ res = 1;
+ } else if (y != 0 && y != 1)
+ res = -1;
+ else
+ res = y;
+ octstr_destroy(s);
+ } else
+ warning(0, "Checking MMS Ind.Send: Failed call to compose command [%s] ",
+ octstr_get_cstr(prov_cmd));
+
+
+ return res;
+}
+
+
+static void addmmscname(Octstr *s, Octstr *myhostname)
+{
+ int j;
+ int len = octstr_len(s);
+
+ if (octstr_search_char(s, '@', 0) >= 0)
+ return; /* Nothing to do. */
+
+ j = octstr_case_search(s, octstr_imm("/TYPE=PLMN"), 0);
+ if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) { /* A proper number. */
+ octstr_delete(s, j, -1 + sizeof "/TYPE=PLMN"); /* XXX We strip off /TYPE=PLMN, should we ? */
+ octstr_format_append(s, "@%S", myhostname);
+ }
+
+}
+static int send2email(Octstr *to, Octstr *from, Octstr *subject,
+ Octstr *msgid,
+ MIMEEntity *m, int append_hostname, Octstr **error,
+ char *sendmail_cmd, Octstr *myhostname)
+{
+ Octstr *s;
+ FILE *f;
+ int ret = MMS_SEND_OK, i;
+ Octstr *cmd = octstr_create("");
+
+ if (append_hostname) { /* Add our hostname to all phone numbers. */
+ int i, n;
+ List *l = http_create_empty_headers();
+ Octstr *xfrom = http_header_value(m->headers, octstr_imm("From"));
+ List *lto = http_header_find_all(m->headers, "To");
+ List *lcc = http_header_find_all(m->headers, "Cc");
+
+ if (xfrom) {
+ addmmscname(xfrom, myhostname);
+ http_header_add(l, "From", octstr_get_cstr(xfrom));
+ octstr_destroy(xfrom);
+ }
+ http_header_remove_all(m->headers, "From");
+
+ for (i = 0, n = list_len(lto); i < n; i++) {
+ Octstr *name, *value;
+
+ http_header_get(lto, i, &name, &value);
+
+ if (!value || !name ||
+ octstr_case_compare(name, octstr_imm("To")) != 0)
+ goto loop;
+
+ addmmscname(value, myhostname);
+ http_header_add(l, "To", octstr_get_cstr(value));
+ loop:
+ if (value) octstr_destroy(value);
+ if (name) octstr_destroy(name);
+ }
+
+ http_destroy_headers(lto);
+ http_header_remove_all(m->headers, "To");
+
+ for (i = 0, n = list_len(lcc); i < n; i++) {
+ Octstr *name, *value;
+
+ http_header_get(lcc, i, &name, &value);
+
+ if (!value || !name ||
+ octstr_case_compare(name, octstr_imm("Cc")) != 0)
+ goto loop2;
+
+ addmmscname(value, myhostname);
+ http_header_add(l, "Cc", octstr_get_cstr(value));
+ loop2:
+ if (value) octstr_destroy(value);
+ if (name) octstr_destroy(name);
+ }
+
+ http_destroy_headers(lcc);
+ http_header_remove_all(m->headers, "Cc");
+
+ http_append_headers(m->headers, l); /* combine old with new. */
+ http_destroy_headers(l);
+ }
+
+ /* Pack headers, get string rep of mime entity. */
+ http_header_pack(m->headers);
+ s = mime_entity_to_octstr(m);
+
+ /*
+ * Make the command: Transpose % formatting characters:
+ * f - from address
+ * t - recipient
+ * s - subject
+ * m - message id
+ */
+
+ i = 0;
+ for (;;) {
+ while (sendmail_cmd[i]) {
+ char c = sendmail_cmd[i];
+ if (c == '%' && sendmail_cmd[i + 1])
+ break;
+ octstr_append_char(cmd, c);
+ i++;
+ }
+ if (!sendmail_cmd[i])
+ break;
+
+ switch(sendmail_cmd[i+1]) {
+ case 't':
+ octstr_append(cmd, to);
+ break;
+ case 'f':
+ if (append_hostname) {
+ Octstr *xfrom = octstr_duplicate(from);
+ addmmscname(xfrom, myhostname);
+ octstr_append(cmd, xfrom);
+ octstr_destroy(xfrom);
+ } else
+ octstr_append(cmd, from);
+ break;
+ case 's':
+ octstr_append(cmd, subject);
+ break;
+ case 'm':
+ octstr_append(cmd, msgid);
+ break;
+ case '%':
+ octstr_format_append(cmd, "%%");
+ break;
+ default:
+ octstr_format_append(cmd, "%%%c", sendmail_cmd[i+1]);
+ break;
+ }
+ i += 2;
+ }
+
+
+ debug("mms.sendtoemail", 0, "preparing to execute %s to send to email: ", octstr_get_cstr(cmd));
+
+ if ((f = popen(octstr_get_cstr(cmd), "w")) == NULL) {
+ *error = octstr_format("popen failed for %S: %d: %s",
+ cmd, errno, strerror(errno));
+ ret = MMS_SEND_ERROR_TRANSIENT;
+ goto done;
+ }
+
+ if (octstr_print(f, s) < 0) {
+ *error = octstr_format("send email failed in octstr_print %d: %s",
+ errno, strerror(errno));
+ pclose(f);
+ ret = MMS_SEND_ERROR_TRANSIENT;
+ goto done;
+ }
+
+ if ((ret = pclose(f)) != 0) {
+ *error = octstr_format("Send email command returned non-zero %d: errno=%s",
+ ret, strerror(errno));
+ ret = MMS_SEND_ERROR_TRANSIENT;
+ } else
+ ret = MMS_SEND_OK;
+
+ done:
+ octstr_destroy(cmd);
+ octstr_destroy(s);
+ return ret;
+}
+
+
+/* Send this message to email recipient. */
+int mms_sendtoemail(Octstr *from, Octstr *to,
+ Octstr *subject, Octstr *msgid,
+ MmsMsg *msg, int dlr, Octstr **error, char *sendmail_cmd,
+ Octstr *myhostname,
+ int trans_msg,
+ int trans_smil, char *txt, char *html,
+ int append_hostname)
+{
+
+ MIMEEntity *m = NULL;
+
+ List *newhdrs = http_create_empty_headers();
+ int ret;
+
+ if (!to ||
+ octstr_search_char(to, '@', 0) < 0) {
+ *error = octstr_format("Invalid email address %S!", to);
+ return MMS_SEND_ERROR_FATAL;
+ }
+
+ if (!trans_msg)
+ m = mms_tomime(msg);
+ else
+ if ((ret = mms_format_special(msg, trans_smil, txt, html, &m)) < 0 ||
+ m == NULL) {
+ warning(0, "MMS: send2email failed to format message (msg=%s,ret=%d)",
+ m ? "OK" : "Not transformed",ret);
+ return -ret;
+ }
+
+ base64_mimeparts(m);
+
+ /* Before we send it, we insert some email friendly headers if they are missing. */
+ http_header_add(newhdrs, "Subject", subject ? octstr_get_cstr(subject) : "MMS Message");
+ http_header_add(newhdrs, "From", octstr_get_cstr(from));
+ http_header_add(newhdrs, "To", octstr_get_cstr(to));
+ http_header_add(newhdrs, "Message-ID", msgid ? octstr_get_cstr(msgid) : "");
+ http_header_combine(newhdrs, m->headers);
+ http_destroy_headers(m->headers);
+ m->headers = newhdrs;
+
+
+ ret = send2email(to, from, subject, msgid, m, append_hostname, error, sendmail_cmd, myhostname);
+ mime_entity_destroy(m);
+
+ return ret;
+}
+
+void mms_log2(char *logmsg, Octstr *from, Octstr *to,
+ int msize, Octstr *msgid,
+ Octstr *acct,
+ Octstr *viaproxy,
+ char *interface, Octstr *ua)
+{
+ List *l;
+ if (to) {
+ l = list_create();
+ list_append(l, to);
+ } else
+ l = NULL;
+
+ mms_log(logmsg, from,l,msize,msgid,acct,viaproxy,interface,ua);
+
+ if (l)
+ list_destroy(l, NULL);
+}
+
+void mms_log(char *logmsg, Octstr *from, List *to,
+ int msize, Octstr *msgid,
+ Octstr *acct,
+ Octstr *viaproxy,
+ char *interface, Octstr *ua)
+{
+ Octstr *xto = octstr_create("");
+ int i, n = to ? list_len(to) : 0;
+
+ for (i = 0; i < n; i++)
+ octstr_format_append(xto,
+ "%s%S",
+ (i == 0) ? "" : ", ",
+ list_get(to,i));
+
+ alog("%s MMS [INT:%s] [ACT:%s] [MMSC:%s] [from:%s] [to:%s] [msgid:%s] [size=%d] [UA:%s]",
+ logmsg, interface,
+ acct ? octstr_get_cstr(acct) : "",
+ viaproxy ? octstr_get_cstr(viaproxy) : "",
+ from ? octstr_get_cstr(from) : "",
+ octstr_get_cstr(xto),
+ msgid ? octstr_get_cstr(msgid) : "",
+ msize,
+ ua ? octstr_get_cstr(ua) : "");
+
+ octstr_destroy(xto);
+}
+
diff --git a/mbuni/mmlib/mms_util.h b/mbuni/mmlib/mms_util.h
new file mode 100644
index 0000000..506311f
--- /dev/null
+++ b/mbuni/mmlib/mms_util.h
@@ -0,0 +1,159 @@
+#ifndef __MMS_GLOBAL__INCLUDED__
+#define __MMS_GLOBAL__INCLUDED__
+
+#include "gwlib/gwlib.h"
+#include "gwlib/mime.h"
+
+#include "config.h"
+#include "mms_strings.h"
+#include "mms_msg.h"
+#include "mms_billing.h"
+#include "mms_resolve.h"
+
+/* Send errors */
+#define MMS_SEND_OK 0
+#define MMS_SEND_ERROR_TRANSIENT -1
+#define MMS_SEND_ERROR_FATAL -2
+
+#define SEND_ERROR_STR(e) ((e) == MMS_SEND_OK ? "Sent" : (e) == MMS_SEND_ERROR_TRANSIENT ? "Retry later" : "Failed")
+/* Useful headers. */
+#define XMSISDN_HEADER "X-WAP-Network-Client-MSISDN"
+#define XIP_HEADER "X-WAP-Network-Client-Address"
+#define MM_NAME "DS_MM"
+
+typedef struct MmsProxyRelay {
+ Octstr *host;
+ Octstr *name;
+ Octstr *allowed_prefix;
+ Octstr *denied_prefix;
+} MmsProxyRelay;
+
+typedef struct MmsBoxSettings {
+ Octstr *system_user;
+ Octstr *name, *hostname, *host_alias;
+ List *local_domains;
+ Octstr *unified_prefix, *local_prefix;
+ Octstr *sendmail;
+ Octstr *global_queuedir, *mm1_queuedir, *mm4_queuedir;
+
+ Octstr *ua_profile_cache_dir;
+
+ long maxthreads;
+ long maxsendattempts;
+ long default_msgexpiry;
+ double queue_interval;
+ long send_back_off;
+
+ long port;
+
+ Octstr *allow_ip;
+ Octstr *deny_ip;
+
+ Octstr *email2mmsrelay_prefixes;
+ Octstr *sendsms_url;
+#if 0
+ Octstr *sendsms_user, *sendsms_pass, *sendsms_globalsender;
+#endif
+ Octstr *billing_params;
+
+ MmsBillingFuncStruct *mms_billfuncs; /* Link to billing funcs. */
+ void *mms_bill_module_data;
+
+ Octstr *resolver_params;
+ MmsResolverFuncStruct *mms_resolvefuncs; /* Link to resolver funcs. */
+ void *mms_resolver_module_data;
+
+ Octstr *prov_notify;
+ Octstr *prov_notify_arg;
+ Octstr *prov_getstatus;
+ int notify_unprovisioned;
+ Octstr *mms_notify_txt;
+ Octstr *mms_notify_unprov_txt;
+ Octstr *mms_toolarge;
+ Octstr *mmbox_host;
+
+ Octstr *mms_email_txt;
+ Octstr *mms_email_html;
+ Octstr *wap_gw_msisdn_header;
+ Octstr *wap_gw_ip_header;
+} MmsBoxSettings;
+
+/* Global variables and shared code used by all modules. */
+
+
+extern char *mms_hostname; /* Our hostname. */
+#define MMSC_VERSION VERSION
+#define MMS_NAME PACKAGE
+
+#if 0
+#define EMAILPROFILE "http://localhost/email.xml" /* For now we hard code it. */
+#define MMBOXPROFILE "http://localhost/mmbox.xml"
+#endif
+
+/* Returns mmsbox settings. */
+MmsBoxSettings *mms_load_mmsbox_settings(Cfg *cfg);
+
+
+/* Returns list of MmsProxyRelay */
+extern List *mms_proxy_relays(Cfg *cfg);
+
+extern Octstr *mms_makefetchurl(char *qf, Octstr *token,
+ MmsBoxSettings *settings);
+
+extern Octstr *mms_maketransid(char *qf, Octstr *mmscname);
+
+extern Octstr *mms_getqf_fromtransid(Octstr *transid);
+
+extern int mms_decodefetchurl(Octstr *fetch_url,
+ Octstr **qf, Octstr **token);
+
+Octstr *mms_find_sender_msisdn(Octstr **send_url, List *request_hdrs, Octstr *msisdn_header);
+Octstr *mms_find_sender_ip(List *request_hdrs, Octstr *ip_header, Octstr *ip, int *isv6);
+
+extern Octstr *mms_isodate(time_t t);
+void mms_lib_init(void);
+
+/* get content type while stripping params. If any param is null, fails. */
+int get_content_type(List *hdrs, Octstr **type, Octstr **params);
+
+/* Returns a list of parameters as http_headers given the semi-comma delimited string.*/
+List *get_value_parameters(Octstr *params);
+
+Octstr *make_value_parameters(List *params);
+
+/* Where value is comma-separated, make separate header items. */
+void unpack_mimeheaders(MIMEEntity *m);
+
+/* Where element has base64 encoding, decode. */
+void unbase64_mimeparts(MIMEEntity *m);
+
+/* Where element contains binary data, encode it base64. */
+void base64_mimeparts(MIMEEntity *m);
+
+void notify_prov_server(char *cmd, char *from, char *event, char *arg);
+int mms_ind_send(Octstr *prov_cmd, Octstr *to);
+
+
+/* Send this message to email recipient: Returns 0 on success 1 or 2 on profile error
+ * (negate to get right one), -ve on some other error
+ */
+int mms_sendtoemail(Octstr *from, Octstr *to,
+ Octstr *subject, Octstr *msgid,
+ MmsMsg *msg, int dlr, Octstr **error,
+ char *sendmail_cmd, Octstr *myhostname,
+ int trans_msg,
+ int trans_smil, char *txt, char *html, int append_hostname);
+
+/* log to access log. */
+void mms_log(char *logmsg, Octstr *from, List *to,
+ int msize, Octstr *msgid,
+ Octstr *acct,
+ Octstr *viaproxy,
+ char *interface, Octstr *ua);
+
+void mms_log2(char *logmsg, Octstr *from, Octstr *to,
+ int msize, Octstr *msgid,
+ Octstr *acct,
+ Octstr *viaproxy,
+ char *interface, Octstr *ua);
+#endif
diff --git a/mbuni/mmsc/Makefile.am b/mbuni/mmsc/Makefile.am
new file mode 100644
index 0000000..f0e0626
--- /dev/null
+++ b/mbuni/mmsc/Makefile.am
@@ -0,0 +1,2 @@
+bin_PROGRAMS = mmsglobalsender mmsproxy mmsmobilesender mmsfromemail mmssend
+
diff --git a/mbuni/mmsc/Makefile.in b/mbuni/mmsc/Makefile.in
new file mode 100644
index 0000000..7a164ad
--- /dev/null
+++ b/mbuni/mmsc/Makefile.in
@@ -0,0 +1,425 @@
+# Makefile.in generated by automake 1.9.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004 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@
+
+SOURCES = mmsfromemail.c mmsglobalsender.c mmsmobilesender.c mmsproxy.c mmssend.c
+
+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 = :
+bin_PROGRAMS = mmsglobalsender$(EXEEXT) mmsproxy$(EXEEXT) \
+ mmsmobilesender$(EXEEXT) mmsfromemail$(EXEEXT) \
+ mmssend$(EXEEXT)
+subdir = mmsc
+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)/config.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+mmsfromemail_SOURCES = mmsfromemail.c
+mmsfromemail_OBJECTS = mmsfromemail.$(OBJEXT)
+mmsfromemail_LDADD = $(LDADD)
+mmsglobalsender_SOURCES = mmsglobalsender.c
+mmsglobalsender_OBJECTS = mmsglobalsender.$(OBJEXT)
+mmsglobalsender_LDADD = $(LDADD)
+mmsmobilesender_SOURCES = mmsmobilesender.c
+mmsmobilesender_OBJECTS = mmsmobilesender.$(OBJEXT)
+mmsmobilesender_LDADD = $(LDADD)
+mmsproxy_SOURCES = mmsproxy.c
+mmsproxy_OBJECTS = mmsproxy.$(OBJEXT)
+mmsproxy_LDADD = $(LDADD)
+mmssend_SOURCES = mmssend.c
+mmssend_OBJECTS = mmssend.$(OBJEXT)
+mmssend_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = mmsfromemail.c mmsglobalsender.c mmsmobilesender.c \
+ mmsproxy.c mmssend.c
+DIST_SOURCES = mmsfromemail.c mmsglobalsender.c mmsmobilesender.c \
+ mmsproxy.c mmssend.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXE_EXT = @EXE_EXT@
+GW_CONFIG = @GW_CONFIG@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+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_CC = @ac_ct_CC@
+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__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build_alias = @build_alias@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+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@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .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 mmsc/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu mmsc/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-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+mmsfromemail$(EXEEXT): $(mmsfromemail_OBJECTS) $(mmsfromemail_DEPENDENCIES)
+ @rm -f mmsfromemail$(EXEEXT)
+ $(LINK) $(mmsfromemail_LDFLAGS) $(mmsfromemail_OBJECTS) $(mmsfromemail_LDADD) $(LIBS)
+mmsglobalsender$(EXEEXT): $(mmsglobalsender_OBJECTS) $(mmsglobalsender_DEPENDENCIES)
+ @rm -f mmsglobalsender$(EXEEXT)
+ $(LINK) $(mmsglobalsender_LDFLAGS) $(mmsglobalsender_OBJECTS) $(mmsglobalsender_LDADD) $(LIBS)
+mmsmobilesender$(EXEEXT): $(mmsmobilesender_OBJECTS) $(mmsmobilesender_DEPENDENCIES)
+ @rm -f mmsmobilesender$(EXEEXT)
+ $(LINK) $(mmsmobilesender_LDFLAGS) $(mmsmobilesender_OBJECTS) $(mmsmobilesender_LDADD) $(LIBS)
+mmsproxy$(EXEEXT): $(mmsproxy_OBJECTS) $(mmsproxy_DEPENDENCIES)
+ @rm -f mmsproxy$(EXEEXT)
+ $(LINK) $(mmsproxy_LDFLAGS) $(mmsproxy_OBJECTS) $(mmsproxy_LDADD) $(LIBS)
+mmssend$(EXEEXT): $(mmssend_OBJECTS) $(mmssend_DEPENDENCIES)
+ @rm -f mmssend$(EXEEXT)
+ $(LINK) $(mmssend_LDFLAGS) $(mmssend_OBJECTS) $(mmssend_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmsfromemail.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmsglobalsender.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmsmobilesender.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmsproxy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mmssend.Po@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) '$<'`
+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 $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; 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-binPROGRAMS clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+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
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic ctags distclean distclean-compile \
+ distclean-generic distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-exec install-exec-am \
+ install-info install-info-am install-man install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-info-am
+
+# 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/mbuni/mmsc/mmsfromemail.c b/mbuni/mmsc/mmsfromemail.c
new file mode 100644
index 0000000..c3e9d26
--- /dev/null
+++ b/mbuni/mmsc/mmsfromemail.c
@@ -0,0 +1,397 @@
+/*
+ * The Email2MMS interface. Receives email and queues it to MMS. This program
+ * also implements the MM4 interface by detecting MMS headers in the email.
+ */
+
+#include
+#include "mms_queue.h"
+#include "mms_util.h"
+
+static MmsBoxSettings *settings;
+
+static Octstr *xfrom;
+static Octstr *xto;
+static Octstr *xproxy;
+
+enum {TPLMN, TEMAIL, TOTHER} ttype;
+
+static int find_own(int i, int argc, char *argv[]);
+static int isphonenum(Octstr *s);
+static void fixup_recipient(void);
+static void fixup_sender(void);
+
+static Cfg *cfg;
+static List *proxyrelays;
+int main(int argc, char *argv[])
+{
+ int cfidx;
+ Octstr *fname;
+ CfgGroup *grp;
+ Octstr *log, *alog;
+ long loglevel;
+ MIMEEntity *mm;
+ MmsMsg *msg;
+
+ Octstr *email;
+
+ mms_lib_init();
+
+ srandom(time(NULL));
+
+ cfidx = get_and_set_debugs(argc, argv, find_own);
+
+ if (argv[cfidx] == NULL)
+ fname = octstr_imm("mmsc.conf");
+ else
+ fname = octstr_create(argv[cfidx]);
+
+ cfg = cfg_create(fname);
+
+ if (cfg_read(cfg) == -1)
+ panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
+
+ octstr_destroy(fname);
+
+ info(0, "----------------------------------------");
+ info(0, " MMSC Email2MMS Tool version %s starting", MMSC_VERSION);
+
+ grp = cfg_get_single_group(cfg, octstr_imm("core"));
+ log = cfg_get(grp, octstr_imm("log-file"));
+ if (log != NULL) {
+ if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
+ loglevel = 0;
+ log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
+ octstr_destroy(log);
+ }
+
+
+ /* Get access log and open it. */
+ alog = cfg_get(grp, octstr_imm("access-log"));
+ if (alog) {
+ alog_open(octstr_get_cstr(alog), 1, 1);
+ octstr_destroy(alog);
+ }
+
+ /* Load proxy relays. */
+
+ proxyrelays = mms_proxy_relays(cfg);
+
+ /* Load settings. */
+ settings = mms_load_mmsbox_settings(cfg);
+
+ if (!settings)
+ panic(0, "No global MMSC configuration!");
+
+ if (!xto || !xfrom)
+ panic(0, "usage: %s -f from -t to!", argv[0]);
+
+ /* normalize recipient address, then if phone number,
+ * check whether we are allowed to process.
+ */
+ fixup_recipient();
+ fixup_sender();
+
+ if (!xto ||
+ (ttype == TPLMN && !does_prefix_match(settings->email2mmsrelay_prefixes, xto))) {
+ error(0, " Not allowed to send to this recipient %s!",
+ xto ? octstr_get_cstr(xto) : "(null)");
+ return -1;
+ }
+
+
+ email = octstr_read_pipe(stdin);
+
+ if (!email || octstr_len(email) == 0) {
+ error(0, "Empty email message!");
+ return -1;
+ }
+
+ if ((mm = mime_octstr_to_entity(email)) == NULL) {
+ error(0, "Unable to decode mime entity!");
+ return -1;
+ }
+ octstr_destroy(email);
+
+ /* Take the entity, recode it --> remove base64 stuff, split headers. */
+ unbase64_mimeparts(mm);
+ unpack_mimeheaders(mm);
+
+ /* Now convert from mime to MMS message. */
+ msg = mms_frommime(mm);
+ mime_entity_destroy(mm);
+
+ if (!msg) {
+ error(0, "Unable to create MM!");
+ return -1;
+ }
+
+ switch(mms_messagetype(msg)) {
+ case MMS_MSGTYPE_SEND_REQ:
+ if (ttype != TPLMN ||/* We only send to phones from this interface */
+ !does_prefix_match(settings->email2mmsrelay_prefixes,
+ xto)) {
+ error(0, "Not allowed to send to %s!", octstr_get_cstr(xto));
+ } else {
+ List *lto = list_create();
+ Octstr *qf;
+ Octstr *msgid = mms_get_header_value(msg, octstr_imm("Message-ID"));
+ Octstr *transid = mms_get_header_value(msg, octstr_imm("X-Mms-Transaction-ID"));
+ Octstr *dreport = mms_get_header_value(msg,
+ octstr_imm("X-Mms-Delivery-Report"));
+ char *err;
+ Octstr *rto;
+ int dlr;
+
+ octstr_format_append(xto, "/TYPE=PLMN");
+ list_append(lto, xto);
+
+ if (dreport &&
+ octstr_case_compare(dreport, octstr_imm("Yes")) == 0)
+ dlr = 1;
+ else
+ dlr = 0;
+
+ qf = mms_queue_add(xfrom, lto, msgid, NULL, xproxy, NULL,
+ 0, time(NULL) + settings->default_msgexpiry, msg, NULL, dlr,
+ octstr_get_cstr(settings->global_queuedir));
+ if (qf) {
+
+ info(0, "Email2MMS Queued message to %s from %s (via %s) => %s",
+ octstr_get_cstr(xto), octstr_get_cstr(xfrom),
+ xproxy ? octstr_get_cstr(xproxy) : "(None)", octstr_get_cstr(qf));
+ octstr_destroy(qf);
+
+ /* Queue our response to the chap. */
+ err = "Ok";
+ } else
+ err = "Error-transient-failure";
+ if (xproxy) {
+ MmsMsg *mresp;
+ List *xlto;
+ mresp = mms_sendconf(err, octstr_get_cstr(msgid),
+ transid ? octstr_get_cstr(transid) : "001",
+ 0);
+
+ rto = octstr_format("system-user@%S", xproxy);
+ xlto = list_create();
+ list_append(xlto, rto);
+
+ qf = mms_queue_add(settings->system_user, xlto, msgid, NULL,
+ xproxy, NULL,
+ 0, time(NULL) + settings->default_msgexpiry,
+ mresp, NULL, 0,
+ octstr_get_cstr(settings->global_queuedir));
+
+ list_destroy(xlto, (list_item_destructor_t *)octstr_destroy);
+ mms_destroy(mresp);
+ octstr_destroy(qf);
+ }
+
+ mms_log("Received", xfrom, lto,
+ -1, msgid, NULL, xproxy, xproxy ? "MM4" : "MM3", NULL);
+
+ list_destroy(lto,NULL);
+ octstr_destroy(transid);
+ octstr_destroy(msgid);
+ if (dreport)
+ octstr_destroy(dreport);
+
+ }
+ break;
+
+ case MMS_MSGTYPE_SEND_CONF:
+ {
+ Octstr *transid = mms_get_header_value(msg, octstr_imm("X-Mms-Transaction-ID"));
+ Octstr *qf = mms_getqf_fromtransid(transid);
+
+ octstr_destroy(transid);
+ if (qf) {
+ MmsEnvelope *e = mms_queue_readenvelope(octstr_get_cstr(qf),
+ octstr_get_cstr(settings->mm4_queuedir),
+ 1);
+ if (!e)
+ warning(0, "Received confirm MMS but cannot find message %s [%s] in queue!",
+ octstr_get_cstr(transid),
+ octstr_get_cstr(qf));
+ else {
+ MmsEnvelopeTo *t;
+ int i, n;
+
+ for (i = 0, n = list_len(e->to); ito, i)) != NULL)
+ t->process = 0; /* Should make it go away. */
+ mms_queue_update(e);
+ info(0, "Email2MMS received send conf from proxy %s to %s from %s => %s",
+ octstr_get_cstr(xproxy), octstr_get_cstr(xto),
+ octstr_get_cstr(xfrom),
+ octstr_get_cstr(qf));
+ }
+
+ } else
+ warning(0, "Received confirm MMS but cannot find message %s in queue!",
+ octstr_get_cstr(transid));
+ }
+ break;
+ case MMS_MSGTYPE_DELIVERY_IND:
+ if (ttype != TPLMN ||/* We only send to phones from this interface */
+ !does_prefix_match(settings->email2mmsrelay_prefixes,
+ xto)) {
+ error(0, "Not allowed to send to %s!", octstr_get_cstr(xto));
+ } else {
+ List *lto = list_create();
+ Octstr *qf;
+ Octstr *msgid = mms_get_header_value(msg, octstr_imm("Message-ID"));
+
+ octstr_format_append(xto, "/TYPE=PLMN");
+ list_append(lto, xto);
+ qf = mms_queue_add(xfrom, lto, msgid, NULL,
+ xproxy, NULL,
+ 0, time(NULL) + settings->default_msgexpiry, msg, NULL, 0,
+ octstr_get_cstr(settings->global_queuedir));
+ list_destroy(lto, NULL);
+ if (qf) {
+ info(0, "Email2MMS Queued DLR from proxy %s to %s from %s => %s",
+ octstr_get_cstr(xproxy), octstr_get_cstr(xto), octstr_get_cstr(xfrom),
+ octstr_get_cstr(qf));
+
+ octstr_destroy(qf);
+ }
+
+ octstr_destroy(msgid);
+ list_destroy(lto, NULL);
+ }
+ break;
+
+ case MMS_MSGTYPE_READ_REC_IND:
+
+ mms_convert_readrec2readorig(msg);
+
+ /* Fall through. */
+ case MMS_MSGTYPE_READ_ORIG_IND:
+ if (ttype != TPLMN ||/* We only send to phones from this interface */
+ !does_prefix_match(settings->email2mmsrelay_prefixes,
+ xto)) {
+ error(0, "Not allowed to send to %s!", octstr_get_cstr(xto));
+ } else {
+ List *lto = list_create();
+ Octstr *qf;
+ Octstr *msgid = mms_get_header_value(msg, octstr_imm("Message-ID"));
+
+ octstr_format_append(xto, "/TYPE=PLMN");
+ list_append(lto, xto);
+ qf = mms_queue_add(xfrom, lto, msgid, NULL,
+ xproxy, NULL,
+ 0, time(NULL) + settings->default_msgexpiry, msg, NULL,0,
+ octstr_get_cstr(settings->global_queuedir));
+ list_destroy(lto, NULL);
+ if (qf) {
+ info(0, "Email2MMS Queued read report from proxy %s to %s from %s => %s",
+ octstr_get_cstr(xproxy), octstr_get_cstr(xto), octstr_get_cstr(xfrom),
+ octstr_get_cstr(qf));
+
+ octstr_destroy(qf);
+ }
+
+ octstr_destroy(msgid);
+ list_destroy(lto, NULL);
+ }
+ default:
+ {
+ int x = mms_messagetype(msg);
+ warning(0, "Unexpected message type: %d=>%s",
+ x,
+ mms_message_type_to_cstr(x));
+ break;
+ }
+ }
+ mms_destroy(msg);
+
+ return 0;
+
+}
+
+
+static int find_own(int i, int argc, char *argv[])
+{
+ if (argv[i][1] == 'f')
+ if (i + 1 < argc) {
+ xfrom = octstr_create(argv[i+1]);
+ return 1;
+ } else
+ return -1;
+ else if (argv[i][1] == 't') /* recipient. */
+ if (i + 1 < argc) {
+ xto = octstr_create(argv[i+1]);
+ return 1;
+ } else
+ return -1;
+ else if (argv[i][1] == 'p') /* Proxy name if any. */
+ if (i + 1 < argc) {
+ xproxy = octstr_create(argv[i+1]);
+ return 1;
+ } else
+ return -1;
+ else
+ return -1;
+}
+
+static int isphonenum(Octstr *s)
+{
+ int i = 0, n = octstr_len(s);
+ char *cs;
+
+ if (s && octstr_len(s) >= 1 &&
+ octstr_get_cstr(s)[0] == '+')
+ i++;
+ for ( cs = octstr_get_cstr(s); i0)
+ octstr_delete(xto, i, octstr_len(xto));
+
+ i = octstr_search(xto, octstr_imm("/TYPE="), 0);
+ if (i > 0) {
+ typ = octstr_copy(xto, i+1, octstr_len(xto));
+ octstr_delete(xto, i, octstr_len(xto));
+ }
+
+ if (isphonenum(xto) &&
+ (!typ || octstr_str_compare(typ, "TYPE=PLMN") == 0)) { /* A phone number. */
+ normalize_number(octstr_get_cstr(settings->unified_prefix), &xto);
+ ttype = TPLMN;
+ } else { /* For now everything else is email. */
+ ttype = TEMAIL;
+ }
+ octstr_destroy(typ);
+}
+
+static void fixup_sender(void)
+{
+ int i;
+
+
+ if (!xfrom) xfrom = octstr_imm("");
+ i = octstr_search_char(xfrom, '@', 0);
+ if (i>0)
+ return;
+
+ i = octstr_search(xfrom, octstr_imm("/TYPE="), 0);
+ if (i > 0)
+ return;
+
+ if (isphonenum(xfrom))
+ octstr_append(xfrom, octstr_imm("/TYPE=PLMN"));
+ else
+ octstr_append(xfrom, octstr_imm("@unknown"));
+}
diff --git a/mbuni/mmsc/mmsglobalsender.c b/mbuni/mmsc/mmsglobalsender.c
new file mode 100644
index 0000000..41c559e
--- /dev/null
+++ b/mbuni/mmsc/mmsglobalsender.c
@@ -0,0 +1,488 @@
+/*
+ * The global queue runner, dispatches messages to email, mobile and to other proxies.
+ */
+
+#include
+#include
+#include
+#include "mms_queue.h"
+#include "mms_uaprof.h"
+#include "mms_util.h"
+
+#define NMAX 256
+static char mobile_qdir[NMAX];
+static char mm4_qdir[NMAX];
+static char sendmail_cmd[NMAX];
+
+
+/* Set the queue directory for messages going to mobile. */
+static int mms_setmobile_queuedir(char *mqdir);
+
+/* Set the queue directory for messages going to remote proxies. */
+static int mms_setmm4_queuedir(char *mqdir);
+
+/* Send command for sending mail. It will be called as with
+ * headers and message on stdin.
+ *
+ * The following % formatting characters are allowed:
+ * f - from address
+ * t - recipient
+ * s - subject
+ * m - message id
+ *
+ */
+static int mms_setsendmail_cmd(char *sendmail);
+
+/* Queue this message for delivery to mobile terminal. */
+static int mms_sendtomobile(Octstr *from, Octstr *to,
+ Octstr *subject, Octstr *fromproxy,
+ Octstr *msgid, time_t expires, MmsMsg *m, int dlr, Octstr **error);
+
+/* Send this message via an intermediate proxy (MM4 interface).
+ * The caller must modify the MmsMsg sender and recipient address if necessary.
+ */
+static int mms_sendtoproxy(Octstr *from, Octstr *to,
+ Octstr *subject, Octstr *proxy,
+ Octstr *msgid, time_t expires, MmsMsg *m, int dlr, Octstr **error);
+
+/* Send errors */
+#define MMS_SEND_OK 0
+#define MMS_SEND_ERROR_TRANSIENT -1
+#define MMS_SEND_ERROR_FATAL -2
+
+
+#define NMAX 256
+static char qdir[NMAX];
+
+static Cfg *cfg;
+static MmsBoxSettings *settings;
+static List *proxyrelays;
+
+
+static List *cdr_list; /* List for cdr as used by cdr consumer thread. */
+
+static int rstop = 0; /* Set to 1 to stop queue runner. */
+
+static int sendMsg(MmsEnvelope *e)
+{
+ int i, n;
+ MmsMsg *msg = NULL;
+
+
+ if (!e->bill.billed) { /* Attempt to bill. */
+ List *l = list_create();
+ double amt;
+
+ for (i = 0, n = list_len(e->to); i < n; i++) {
+ MmsEnvelopeTo *to = list_get(e->to, i);
+ list_append(l, to->rcpt);
+ }
+
+ amt = settings->mms_billfuncs->mms_billmsg(e->from, l,
+ e->msize,
+ settings->mms_bill_module_data);
+ list_destroy(l, NULL);
+
+ info(0, "Global Queue MMS Bill: From %s, to_count=%ld, msgid=%s, msgsize=%ld: returned=%.2f",
+ octstr_get_cstr(e->from), list_len(e->to), e->msgId ? octstr_get_cstr(e->msgId) : "",
+ e->msize, amt);
+
+ if (amt == -1) { /* Delete message. */
+ for (i = 0, n = list_len(e->to); i < n; i++) {
+ MmsEnvelopeTo *to = list_get(e->to, i);
+ to->process = 0;
+ }
+ } else if (amt >= 0) {
+ e->bill.billed = 1;
+ e->bill.amt = amt;
+ }
+
+ if (amt >= -1)
+ if (mms_queue_update(e) == 1) /* Write queue just in case we crash. */
+ e = NULL;
+
+ if (e == NULL ||
+ !e->bill.billed)
+ goto done2; /* If queue is gone, or we didn't manage to bill, go away */
+ }
+
+
+
+ msg = mms_queue_getdata(e);
+#if 0
+ if (msg) mms_msgdump(msg,1);
+#endif
+
+
+ for (i = 0, n = list_len(e->to); i < n; i++) {
+ Octstr *err = NULL;
+ int res = MMS_SEND_OK, m;
+ MmsEnvelopeTo *to = list_get(e->to, i);
+ time_t tnow = time(NULL);
+
+
+ if (!to || !to->process) /* Already processed. */
+ continue;
+
+ if (e->expiryt != 0 && /* Handle message expiry. */
+ e->expiryt < tnow) {
+ err = octstr_format("MMSC error: Message expired while sending to %S!", to->rcpt);
+ res = MMS_SEND_ERROR_FATAL;
+
+ goto done;
+ } else if (e->attempts >= settings->maxsendattempts) {
+ err = octstr_format("MMSC error: Failed to deliver to %S after %ld attempts!",
+ to->rcpt, e->attempts);
+ res = MMS_SEND_ERROR_FATAL;
+ goto done;
+ }
+
+ /* first check if it is an email address */
+ if (octstr_search_char(to->rcpt, '@', 0) > 0) {
+ res = mms_sendtoemail(e->from, to->rcpt,
+ e->subject,
+ e->msgId, msg, e->dlr, &err, sendmail_cmd,
+ settings->hostname, 1, 1, octstr_get_cstr(settings->mms_email_txt),
+ octstr_get_cstr(settings->mms_email_html), 1);
+ mms_log2("Sent", e->from, to->rcpt,
+ -1, e->msgId, NULL, NULL, "MM3", NULL);
+
+ } else if (e->viaproxy && octstr_len(e->viaproxy) > 0) /* If proxy to send through is already set, use it. */
+ res = mms_sendtoproxy(e->from,
+ to->rcpt, e->subject, e->viaproxy,
+ e->msgId, e->expiryt, msg, e->dlr, &err);
+ else {
+ int j = octstr_case_search(to->rcpt, octstr_imm("/TYPE=PLMN"), 0);
+ int k = octstr_case_search(to->rcpt, octstr_imm("/TYPE=IPv"), 0);
+ int len = octstr_len(to->rcpt);
+ Octstr *phonenum = NULL;
+ Octstr *mmsc;
+ int sent = 0;
+
+ if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) /* A proper number. */
+ phonenum = octstr_copy(to->rcpt, 0, j);
+ else if (k > 0 && k + sizeof "/TYPE=IPv" == len) {
+ res = mms_sendtomobile(e->from,
+ to->rcpt, e->subject, e->fromproxy,
+ e->msgId, e->expiryt, msg, e->dlr, &err);
+ sent = 1;
+ goto done;
+ } else {
+ /* We don't handle other types for now. */
+ err = octstr_format("MMSC error: Unsupported recipient type %S", to->rcpt);
+ res = MMS_SEND_ERROR_FATAL;
+
+ goto done;
+ }
+
+ /* Normalise the number, then match against local prefixes. */
+ normalize_number(octstr_get_cstr(settings->unified_prefix), &phonenum);
+
+ if ((mmsc = settings->mms_resolvefuncs->mms_resolve(phonenum,
+ settings->mms_resolver_module_data, settings, proxyrelays))) {
+ info(0, "mmsc for \"%s\" resolved to: \"%s\"",
+ octstr_get_cstr(phonenum), octstr_get_cstr(mmsc));
+
+ if (octstr_compare(mmsc, settings->hostname) == 0) {
+ res =
+ mms_sendtomobile(e->from, to->rcpt,
+ e->subject, e->fromproxy,
+ e->msgId, e->expiryt, msg, e->dlr,
+ &err);
+ sent = 1;
+ } else if (proxyrelays && list_len(proxyrelays) > 0)
+ /* Step through proxies. */
+ for (j = 0, m = list_len(proxyrelays); jhost, mmsc)) {
+ res = mms_sendtoproxy(e->from, to->rcpt,
+ e->subject, mp->host,
+ e->msgId, e->expiryt, msg,
+ e->dlr, &err);
+ sent = 1;
+ break;
+ }
+ }
+ }
+ if (!sent) {
+ res = MMS_SEND_ERROR_FATAL;
+ err = octstr_format("MMSC error: Don't know how to deliver to %S !", to->rcpt);
+
+ }
+ if (phonenum) octstr_destroy(phonenum);
+ }
+
+ done:
+ if (res == MMS_SEND_OK)
+ to->process = 0;
+ else { /* If there was a report request, queue it. */
+
+ if (e->dlr) {
+
+ MmsMsg *m = mms_deliveryreport(e->msgId, to->rcpt, tnow,
+ (e->expiryt != 0 && e->expiryt < tnow) ?
+ octstr_imm("Expired") : octstr_imm("Rejected"));
+
+
+ List *l = list_create();
+
+ list_append(l, octstr_duplicate(e->from));
+
+ /* Add to queue, switch via proxy to be from proxy. */
+ mms_queue_add(settings->system_user, l, e->msgId, err, NULL, e->fromproxy,
+ tnow, tnow+settings->default_msgexpiry, m, NULL, 0,
+ qdir);
+ list_destroy(l, NULL);
+
+ mms_destroy(m);
+ }
+ if (res == MMS_SEND_ERROR_FATAL)
+ to->process = 0; /* No more attempts. */
+ }
+
+ /* Write to log */
+ info(0, "%s Global Queue MMS Send: From %s, to %s, msgsize=%ld: err=%s",
+ SEND_ERROR_STR(res),
+ octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize,
+ err ? octstr_get_cstr(err) : "(null)");
+
+ if (res == MMS_SEND_OK) { /* Do CDR writing. */
+ MmsCdrStruct *cdr = gw_malloc(sizeof *cdr);
+
+ cdr->module_data = settings->mms_bill_module_data;
+ cdr->sdate = e->created;
+ strncpy(cdr->from, octstr_get_cstr(e->from), sizeof cdr->from);
+ strncpy(cdr->to, octstr_get_cstr(to->rcpt), sizeof cdr->to);
+ strncpy(cdr->msgid, e->msgId ? octstr_get_cstr(e->msgId) : "", sizeof cdr->msgid);
+ cdr->msg_size = e->msize;
+
+ list_produce(cdr_list, cdr); /* Put it on list so sending thread sends it. */
+ }
+
+ e->lasttry = tnow;
+ e->attempts++;
+ e->sendt = e->lasttry + settings->send_back_off * e->attempts;
+
+ if (mms_queue_update(e) == 1) {
+ e = NULL;
+ break; /* Queue entry gone. */
+ }
+ }
+
+ done2:
+ if (msg)
+ mms_destroy(msg);
+ if (e)
+ mms_queue_free_env(e);
+
+ return 1; /* Always deletes the queue entry. */
+}
+
+
+static void quit_now(int notused)
+{
+ rstop = 1;
+}
+
+static void cdr_thread(void *unused)
+{
+ MmsCdrStruct *cdr;
+
+ while ((cdr = list_consume(cdr_list)) != NULL) {
+ settings->mms_billfuncs->mms_logcdr(cdr);
+ /* We should probably write to log here... */
+ gw_free(cdr);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int cfidx;
+ Octstr *fname;
+ CfgGroup *grp;
+ Octstr *log, *alog;
+ long loglevel;
+
+ mms_lib_init();
+
+ srandom(time(NULL));
+
+ cfidx = get_and_set_debugs(argc, argv, NULL);
+
+ if (argv[cfidx] == NULL)
+ fname = octstr_imm("mmsc.conf");
+ else
+ fname = octstr_create(argv[cfidx]);
+
+ cfg = cfg_create(fname);
+
+ if (cfg_read(cfg) == -1)
+ panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
+
+ octstr_destroy(fname);
+
+ info(0, "----------------------------------------");
+ info(0, " MMSC Global queue runner version %s starting", MMSC_VERSION);
+
+ grp = cfg_get_single_group(cfg, octstr_imm("core"));
+ log = cfg_get(grp, octstr_imm("log-file"));
+ if (log != NULL) {
+ if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
+ loglevel = 0;
+ log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
+ octstr_destroy(log);
+ }
+
+ /* Get access log and open it. */
+ alog = cfg_get(grp, octstr_imm("access-log"));
+ if (alog) {
+ alog_open(octstr_get_cstr(alog), 1, 1);
+ octstr_destroy(alog);
+ }
+
+ /* Load proxy relays. */
+
+ proxyrelays = mms_proxy_relays(cfg);
+ /* Load settings. */
+
+ settings = mms_load_mmsbox_settings(cfg);
+
+ if (!settings)
+ panic(0, "No global MMSC configuration!");
+
+ mms_start_profile_engine(octstr_get_cstr(settings->ua_profile_cache_dir));
+
+ mms_setmobile_queuedir(octstr_get_cstr(settings->mm1_queuedir));
+ mms_setmm4_queuedir(octstr_get_cstr(settings->mm4_queuedir));
+
+ mms_setsendmail_cmd(octstr_get_cstr(settings->sendmail));
+
+ strncpy(qdir, octstr_get_cstr(settings->global_queuedir), sizeof qdir);
+
+
+ /* Start the thread for CDR */
+ cdr_list = list_create();
+ list_add_producer(cdr_list);
+ gwthread_create(cdr_thread, NULL);
+
+
+ signal(SIGHUP, quit_now);
+ signal(SIGTERM, quit_now);
+ signal(SIGPIPE,SIG_IGN); /* Ignore pipe errors. They kill us sometimes for nothing*/
+ mms_queue_run(qdir, sendMsg, settings->queue_interval, settings->maxthreads, &rstop);
+ mms_stop_profile_engine(); /* Stop profile stuff. */
+ sleep(2);
+ list_remove_producer(cdr_list); /* Stop CDR thread. */
+ sleep(2); /* Wait for them to die. */
+ return 0;
+}
+
+
+
+static int mms_setmobile_queuedir(char *mqdir)
+{
+ strncpy(mobile_qdir, mqdir, sizeof mobile_qdir);
+ return 0;
+}
+
+static int mms_setmm4_queuedir(char *mqdir)
+{
+ strncpy(mm4_qdir, mqdir, sizeof mm4_qdir);
+ return 0;
+}
+
+static int mms_setsendmail_cmd(char *sendmail)
+{
+ strncpy(sendmail_cmd, sendmail, -1 + sizeof sendmail_cmd);
+ return 0;
+}
+
+/*
+ * Queue this message for delivery to mobile terminal.
+ * A queue thread will handle sending of notifications to phone.
+ * When a deliver is received, another thread will remove the queue entry.
+ */
+int mms_sendtomobile(Octstr *from, Octstr *to,
+ Octstr *subject, Octstr *fromproxy,
+ Octstr *msgid, time_t expires, MmsMsg *m, int dlr, Octstr **error)
+{
+
+ Octstr *ret, *x;
+ List *l = list_create();
+ char tokenstr[128];
+
+ list_append(l, to);
+
+ /* We generate a special token that will be added to message ID to make
+ * stealing messages a bit harder.
+ */
+ snprintf(tokenstr, -1 + sizeof tokenstr,
+ "wx%ld",
+ random() % 100);
+
+ x = octstr_create(tokenstr);
+
+ ret = mms_queue_add(from, l, msgid, subject, fromproxy, NULL, 0, expires, m,
+ x, dlr, mobile_qdir);
+ octstr_destroy(x);
+
+ list_destroy(l, NULL);
+ octstr_destroy(ret);
+ if (ret == NULL)
+ return MMS_SEND_ERROR_TRANSIENT;
+ else
+ return MMS_SEND_OK;
+}
+
+
+/* Send this message via an intermediate proxy (MM4 interface).
+ * The way it works: We email the message to the proxy but we also keep a local copy in the queue
+ * so we can handle delivery receipts and such.
+ */
+static int mms_sendtoproxy(Octstr *from, Octstr *to,
+ Octstr *subject, Octstr *proxy,
+ Octstr *msgid, time_t expires, MmsMsg *msg, int dlr, Octstr **error)
+{
+
+ Octstr *pto;
+
+
+ int x;
+
+
+ if (!to ||
+ octstr_search_char(to, '@', 0) >= 0) {
+ *error = octstr_format("Bad recipient address sent to MM4 interface, addresss is %S!", to);
+ return MMS_SEND_ERROR_FATAL;
+ }
+
+ if (mms_messagetype(msg) == MMS_MSGTYPE_SEND_REQ) { /* Only queue these ones for future response. */
+ List *l = list_create();
+ Octstr *ret;
+ list_append(l, to);
+ ret = mms_queue_add(from, l, msgid, subject, NULL, proxy, 0, expires, msg,NULL, dlr, mm4_qdir);
+ list_destroy(l, NULL);
+
+ if (ret == NULL) {
+ *error = octstr_format("MM4: Failed to queue message to %S for future tracking. ", to);
+ return MMS_SEND_ERROR_TRANSIENT;
+ }
+ octstr_destroy(ret);
+ }
+
+
+ pto = octstr_format("%S@%S", to, proxy);
+
+
+ x = mms_sendtoemail(from, pto, subject, msgid, msg, 0,
+ error, sendmail_cmd,
+ settings->hostname, 0, 0,NULL,NULL,0);
+
+ mms_log2("Sent", from, to,
+ -1, msgid, NULL, proxy, "MM4", NULL);
+
+ octstr_destroy(pto);
+
+ return x;
+}
diff --git a/mbuni/mmsc/mmsmobilesender.c b/mbuni/mmsc/mmsmobilesender.c
new file mode 100644
index 0000000..a4dde57
--- /dev/null
+++ b/mbuni/mmsc/mmsmobilesender.c
@@ -0,0 +1,574 @@
+/*
+ * The queue runner for dispatching notifications to mobiles via WAP PUSH.
+ */
+#include
+#include
+#include
+
+
+#include "mms_queue.h"
+#include "mms_uaprof.h"
+#include "mms_util.h"
+
+#define WAPPUSH_PORT 2948
+
+static MmsBoxSettings *settings;
+static HTTPCaller *httpcaller;
+static int rstop = 0;
+static MmsEnvelope edummy;
+
+
+static MmsEnvelope *update_env_success(MmsEnvelope *env, MmsEnvelopeTo *xto)
+{
+ time_t tnow = time(NULL);
+
+ if (xto && env->msgtype != MMS_MSGTYPE_SEND_REQ)
+ xto->process = 0; /* No more processing. */
+ else {
+ env->lasttry = tnow;
+ env->attempts++;
+ env->sendt = env->lasttry + settings->send_back_off * env->attempts;
+ }
+
+ if (mms_queue_update(env) == 1)
+ env = NULL;
+ return env;
+}
+
+static MmsEnvelope *update_env_failed(MmsEnvelope *env)
+{
+ time_t tnow = time(NULL);
+ if (env && env != &edummy) {
+ env->sendt = tnow + settings->send_back_off;
+ env->lasttry = tnow;
+
+ if (mms_queue_update(env) == 1)
+ env = NULL;
+ }
+ return env;
+}
+
+static void start_push(Octstr *rcpt_to, int isphonenum, MmsEnvelope *e, MmsMsg *msg)
+{
+ List *pheaders;
+ static unsigned char ct; /* Transaction counter -- do we need it? */
+ Octstr *to = NULL;
+
+ Octstr *pduhdr = octstr_create("");
+
+ Octstr *s = NULL;
+
+
+ info(0, "mms2mobile.startpush: notification to %s\n", octstr_get_cstr(rcpt_to));
+
+ if (!rcpt_to) {
+ error(0, "mobilesender: Queue entry %s has no recipient address!", e->qf.name);
+ goto done;
+ } else
+ to = octstr_duplicate(rcpt_to);
+
+
+ ct++;
+ octstr_append_char(pduhdr, ct);
+ octstr_append_char(pduhdr, 0x06); /* Pushd id */
+
+
+#if 1
+ octstr_append_char(pduhdr, 1 + 1 + 1);
+ octstr_append_char(pduhdr, 0xbe); /* content type. */
+#else
+ octstr_append_char(pduhdr,
+ 1 + 1 + sizeof "application/vnd.wap.mms-message"); /*header length. */
+ octstr_append_cstr(pduhdr, "application/vnd.wap.mms-message");
+ octstr_append_char(pduhdr, 0x0); /* string terminator. */
+#endif
+ octstr_append_char(pduhdr, 0xaf); /* charset. */
+ octstr_append_char(pduhdr, 0x84); /* ... */
+
+ s = mms_tobinary(msg);
+
+ if (isphonenum) {
+ Octstr *url;
+
+ octstr_url_encode(to);
+ octstr_url_encode(s);
+
+ octstr_url_encode(pduhdr);
+
+ url = octstr_format("%S&text=%S%S&to=%S&udh=%%06%%05%%04%%0B%%84%%23%%F0",
+ settings->sendsms_url, pduhdr, s, to);
+
+ pheaders = http_create_empty_headers();
+ http_header_add(pheaders, "Connection", "close");
+ http_header_add(pheaders, "User-Agent", MM_NAME "/" GW_VERSION);
+
+ http_start_request(httpcaller, HTTP_METHOD_GET, url,
+ pheaders, NULL, 0, e, NULL);
+
+ http_destroy_headers(pheaders);
+ octstr_destroy(url);
+ } else { /* An IP Address: Send packet, forget. */
+ Octstr *addr = udp_create_address(to, WAPPUSH_PORT);
+ int sock = udp_client_socket();
+
+ if (sock > 0) {
+ MmsEnvelopeTo *xto = list_get(e->to,0);
+ octstr_append(pduhdr, s);
+ udp_sendto(sock, pduhdr, addr);
+ close(sock); /* ?? */
+ mms_log2("Notify", octstr_imm("system"), to,
+ -1, e ? e->msgId : NULL,
+ NULL, NULL, "MM1", NULL);
+ e = update_env_success(e, xto);
+ } else {
+ e = update_env_failed(e);
+ error(0, "push to %s:%d failed, no reason found", octstr_get_cstr(to), WAPPUSH_PORT);
+ }
+ octstr_destroy(addr);
+ if (e)
+ mms_queue_free_env(e);
+ }
+ done:
+ if (to) octstr_destroy(to);
+ if (pduhdr) octstr_destroy(pduhdr);
+ if (s) octstr_destroy(s);
+}
+
+
+static int receive_push_reply(HTTPCaller *caller)
+{
+ int http_status;
+ List *reply_headers;
+ Octstr *final_url,
+ *reply_body;
+
+ MmsEnvelope *env;
+
+ http_status = HTTP_UNAUTHORIZED;
+
+ while ((env = http_receive_result(caller, &http_status, &final_url, &reply_headers,
+ &reply_body)) != NULL) {
+ MmsEnvelopeTo *xto;
+ Octstr *to = NULL;
+
+ if (http_status == -1 || final_url == NULL) {
+ error(0, "push failed, no reason found");
+ goto push_failed;
+ }
+
+ if (env == &edummy) /* Skip this one it is a dummy. */
+ goto push_free_env;
+ xto = list_get(env->to, 0);
+ if (xto)
+ to = xto->rcpt;
+ else {
+ error(0, "mobilesender: Queue entry %s has no recipient address!", env->qf.name);
+ goto push_failed;
+ }
+
+ info(0, "send2mobile.push_reply[%s]: From %s, to %s => %d",
+ env->qf.name,
+ octstr_get_cstr(env->from), octstr_get_cstr(to), http_status);
+
+ if (http_status == HTTP_UNAUTHORIZED ||
+ http_status == HTTP_NOT_FOUND ||
+ http_status == HTTP_FORBIDDEN) { /* This is a temporary system error
+ * do not increase attempts, count,
+ * merely reschedule
+ * for a minute or so later.
+ */
+
+ error(0, "Deffered notification, WAP Push failed for "
+ "msgid %s to %s, http error: %d!", octstr_get_cstr(env->msgId),
+ octstr_get_cstr(to), http_status);
+ goto push_failed;
+ }
+
+
+ debug("mobilesender.push", 0, "Push reply headers were");
+ http_header_dump(reply_headers);
+
+ mms_log2("Notify", octstr_imm("system"), to,
+ -1, env ? env->msgId : NULL, NULL, NULL, "MM1", NULL);
+
+ if (update_env_success(env, xto) != NULL)
+ goto push_free_env;
+
+ /* Fall through. */
+ push_failed:
+ octstr_destroy(final_url);
+ octstr_destroy(reply_body);
+ http_destroy_headers(reply_headers);
+
+ env = update_env_failed(env);
+ push_free_env:
+ if (env && env != &edummy)
+ mms_queue_free_env(env);
+ }
+
+ return 0;
+}
+
+static int sendNotify(MmsEnvelope *e)
+{
+ Octstr *to;
+ MmsMsg *msg, *smsg = NULL;
+ MmsEnvelopeTo *xto = list_get(e->to, 0);
+ Octstr *err = NULL;
+ time_t tnow = time(NULL);
+ int j, k, len;
+ Octstr *phonenum = NULL, *rcpt_ip = NULL, *msgId, *from, *fromproxy;
+ int mtype, msize;
+ int res = MMS_SEND_OK, dlr;
+ time_t expiryt;
+ char *prov_notify_event = NULL;
+ char *rtype = NULL;
+
+
+ if (e->lastaccess != 0) { /* This message has been fetched at least once, no more signals. */
+ e->sendt = e->expiryt + 3600*24*30*12;
+ return mms_queue_update(e);
+ }
+
+ if (!xto) {
+ error(0, "mobilesender: Queue entry %s with no recipients!",
+ e->qf.name);
+ return 0;
+ }
+
+ msg = mms_queue_getdata(e);
+ to = octstr_duplicate(xto->rcpt);
+ expiryt = e->expiryt;
+ msgId = e->msgId ? octstr_duplicate(e->msgId) : NULL;
+ from = octstr_duplicate(e->from);
+ fromproxy = e->fromproxy ? octstr_duplicate(e->fromproxy) : NULL;
+ msize = e->msize;
+ dlr = e->dlr;
+
+ if (e->expiryt != 0 && /* Handle message expiry. */
+ e->expiryt < tnow) {
+ err = octstr_format("MMSC error: Message expired while sending to %S!", to);
+ res = MMS_SEND_ERROR_FATAL;
+ prov_notify_event = "failedfetch";
+ rtype = "Expired";
+ goto done;
+ } else if (e->attempts >= settings->maxsendattempts) {
+ err = octstr_format("MMSC error: Failed to deliver to %S after %ld attempts!",
+ to, e->attempts);
+ res = MMS_SEND_ERROR_FATAL;
+
+ prov_notify_event = "failedfetch";
+ rtype = "Expired";
+ goto done;
+ }
+
+ j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0);
+ k = octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0);
+ len = octstr_len(to);
+
+ if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) { /* A proper number. */
+ phonenum = octstr_copy(to, 0, j);
+ normalize_number(octstr_get_cstr(settings->unified_prefix), &phonenum);
+ } else if (k > 0 && k + sizeof "/TYPE=IPv" == len)
+ rcpt_ip = octstr_copy(to, 0, k);
+ else {
+ /* We only handle phone numbers here. */
+ err = octstr_format("Unexpected recipient %s in MT queue!", octstr_get_cstr(to));
+ res = MMS_SEND_ERROR_FATAL;
+ goto done;
+ }
+
+ mtype = mms_messagetype(msg);
+
+ /* For phone, getting here means the message can be delivered. So:
+ * - Check whether the recipient is provisioned, if not, wait (script called will queue creation req)
+ * - Send to MMBox if not yet done.
+ * - If the recipient can't take MMS, then send SMS.
+ */
+
+ /* We handle two types of requests: send and delivery/read notifications.
+ * other types of messages cannot possibly be in this queue!
+ */
+
+ if (mtype == MMS_MSGTYPE_SEND_REQ ||
+ mtype == MMS_MSGTYPE_RETRIEVE_CONF) {
+ Octstr *url, *transid;
+
+ if (phonenum) {
+ int send_ind = mms_ind_send(settings->prov_getstatus, phonenum);
+
+ if (send_ind < 0) { /* That is, recipient is not (yet) provisioned. */
+ res = MMS_SEND_ERROR_TRANSIENT;
+ err = octstr_format("%S is not provisioned for MMS reception, delivery deferred!",
+ phonenum);
+
+ /* Do not increase delivery attempts counter. */
+ e->lasttry = tnow;
+ e->sendt = e->lasttry + settings->send_back_off * (1 + e->attempts);
+
+ if (mms_queue_update(e) == 1)
+ e = NULL; /* Queue entry gone. */
+ else
+ mms_queue_free_env(e);
+
+ goto done;
+ } else if (e->mdata == NULL) { /* Not yet sent to MMBox etc, but provisioned. */
+
+ int x;
+ if (settings->mmbox_host &&
+ octstr_len(settings->mmbox_host) > 0) { /* Only if mmbox is configured. */
+ Octstr *mto = octstr_format("%S@%S", phonenum, settings->mmbox_host);
+ x = mms_sendtoemail(from, mto, e->subject, e->msgId, msg, 0, &err,
+ octstr_get_cstr(settings->sendmail), settings->hostname, 1,
+ 1, octstr_get_cstr(settings->mms_email_txt),
+ octstr_get_cstr(settings->mms_email_html), 1);
+ octstr_destroy(mto);
+ } else
+ x = 0;
+
+ if (x != 0) { /* Failed to send to MMBox...*/
+ res = MMS_SEND_ERROR_TRANSIENT;
+ err = octstr_format("Failed to send to MMBox %d", x);
+ e->attempts++;
+ e->lasttry = tnow;
+ e->sendt = e->lasttry + settings->send_back_off * e->attempts;
+
+ if (mms_queue_update(e) == 1)
+ e = NULL; /* Queue entry gone. */
+ else
+ mms_queue_free_env(e);
+ goto done;
+ }
+
+ /* else Send to MMBox succeeded or non-provisioned.
+ * But if phone cannot handle MMS-Ind, then send it sms.
+ */
+ if (send_ind == 0) {
+ Octstr *s = octstr_format(octstr_get_cstr(settings->mms_notify_txt),
+ from);
+ List *pheaders;
+
+ Octstr *xto = octstr_duplicate(phonenum);
+
+ octstr_url_encode(s);
+ octstr_url_encode(xto);
+
+ url = octstr_format("%S&text=%S&to=%S",settings->sendsms_url,s, xto);
+ pheaders = http_create_empty_headers();
+ http_header_add(pheaders, "Connection", "close");
+ http_header_add(pheaders, "User-Agent", MM_NAME "/" GW_VERSION);
+
+ http_start_request(httpcaller, HTTP_METHOD_GET, url,
+ pheaders, NULL, 0, &edummy, NULL);
+
+
+ http_destroy_headers(pheaders);
+ octstr_destroy(url);
+ octstr_destroy(s);
+ octstr_destroy(xto);
+
+ }
+ e->mdata = octstr_imm("MMSent"); /* Mark as sent to MMBox. */
+ if (mms_queue_update(e) == 1) {
+ e = NULL;
+ goto done;
+ }
+ }
+
+ if (send_ind == 0) { /* No MMS Ind, go away but first update queue entry. */
+ res = MMS_SEND_OK;
+ err = octstr_imm("No MMS Ind support, sent SMS instead");
+
+ xto->process = 0; /* No more processing. */
+ if (mms_queue_update(e) == 1)
+ e = NULL;
+ else
+ mms_queue_free_env(e);
+ goto done;
+ }
+ }
+
+ /* To get here means we can send Ind. */
+ url = mms_makefetchurl(e->qf.name, e->token,
+ settings);
+ transid = mms_maketransid(e->qf.name, settings->host_alias);
+
+ smsg = mms_notification(msg, e->msize, url, transid,
+ e->expiryt ? e->expiryt :
+ tnow + settings->default_msgexpiry);
+ octstr_destroy(transid);
+ octstr_destroy(url);
+ } else if (mtype == MMS_MSGTYPE_DELIVERY_IND ||
+ mtype == MMS_MSGTYPE_READ_ORIG_IND)
+ smsg = msg;
+ else {
+ error(0, "Unexpected message type %s for %s found in MT queue!",
+ mms_message_type_to_cstr(mtype), octstr_get_cstr(to));
+ res = MMS_SEND_ERROR_FATAL;
+ goto done;
+ }
+
+ if (smsg)
+ start_push(phonenum ? phonenum : rcpt_ip,
+ phonenum ? 1 : 0,
+ e, smsg); /* Send the message.
+ * Don't touch 'e' after this point!
+ * It may be freed by receive thread.
+ */
+
+ if (smsg != msg && smsg)
+ mms_destroy(smsg);
+
+ done:
+ if (err != NULL &&
+ res != MMS_SEND_ERROR_TRANSIENT) { /* If there was a report request and this is a legit error
+ * queue it.
+ */
+
+ if (dlr) {
+ MmsMsg *m = mms_deliveryreport(msgId, to, tnow,
+ rtype ? octstr_imm(rtype) :
+ octstr_imm("Indeterminate"));
+
+ List *l = list_create();
+ Octstr *res;
+ list_append(l, from);
+
+ /* Add to queue, switch via proxy to be from proxy. */
+ res = mms_queue_add(settings->system_user, l, msgId, err,
+ NULL, fromproxy,
+ tnow, tnow+settings->default_msgexpiry, m, NULL, 0,
+ octstr_get_cstr(settings->mm1_queuedir));
+ list_destroy(l, NULL);
+ mms_destroy(m);
+ octstr_destroy(res);
+ }
+
+ }
+
+ /* Write to log */
+ info(0, "%s Mobile Queue MMS Send Notify: From=%s, to=%s, msgsize=%d, reason=%s",
+ SEND_ERROR_STR(res),
+ octstr_get_cstr(from), octstr_get_cstr(to), msize,
+ err ? octstr_get_cstr(err) : "");
+
+
+ if (res == MMS_SEND_ERROR_FATAL) {
+ xto->process = 0; /* No more attempts to deliver, delete this. */
+ if (mms_queue_update(e) == 1)
+ e = NULL; /* Queue entry gone. */
+ else
+ mms_queue_free_env(e);
+ } /* Else queue will be updated/freed elsewhere. */
+
+
+ if (prov_notify_event)
+ notify_prov_server(octstr_get_cstr(settings->prov_notify),
+ to ? octstr_get_cstr(to) : "unknown",
+ prov_notify_event,
+ octstr_get_cstr(settings->prov_notify_arg));
+
+ if (msg) mms_destroy(msg);
+ if (phonenum)
+ octstr_destroy(phonenum);
+ if (rcpt_ip)
+ octstr_destroy(rcpt_ip);
+ octstr_destroy(to);
+ if (msgId) octstr_destroy(msgId);
+ if (fromproxy) octstr_destroy(fromproxy);
+ octstr_destroy(from);
+ if (err) octstr_destroy(err);
+
+ return 1;
+}
+
+static void quit_now(int notused)
+{
+ rstop = 1;
+}
+
+static Cfg *cfg;
+static List *proxyrelays;
+int main(int argc, char *argv[])
+{
+ int cfidx;
+ Octstr *fname;
+ CfgGroup *grp;
+ Octstr *log, *alog;
+ long loglevel;
+
+ mms_lib_init();
+ srandom(time(NULL));
+
+ cfidx = get_and_set_debugs(argc, argv, NULL);
+
+ if (argv[cfidx] == NULL)
+ fname = octstr_imm("mmsc.conf");
+ else
+ fname = octstr_create(argv[cfidx]);
+
+ cfg = cfg_create(fname);
+
+ if (cfg_read(cfg) == -1)
+ panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
+
+ octstr_destroy(fname);
+
+ info(0, "----------------------------------------");
+ info(0, " MMSC Mobile queue runner version %s starting", MMSC_VERSION);
+
+ grp = cfg_get_single_group(cfg, octstr_imm("core"));
+ log = cfg_get(grp, octstr_imm("log-file"));
+ if (log != NULL) {
+ if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
+ loglevel = 0;
+ log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
+ octstr_destroy(log);
+ }
+
+ /* Get access log and open it. */
+ alog = cfg_get(grp, octstr_imm("access-log"));
+ if (alog) {
+ alog_open(octstr_get_cstr(alog), 1, 1);
+ octstr_destroy(alog);
+ }
+
+ /* Load proxy relays. */
+
+ proxyrelays = mms_proxy_relays(cfg);
+
+ /* Load settings. */
+ settings = mms_load_mmsbox_settings(cfg);
+
+ if (!settings)
+ panic(0, "No global MMSC configuration!");
+
+
+
+
+ mms_start_profile_engine(octstr_get_cstr(settings->ua_profile_cache_dir));
+
+ httpcaller = http_caller_create();
+ if (gwthread_create((gwthread_func_t *)receive_push_reply, httpcaller) < 0) { /* Listener thread. */
+ error(0, "Mobile sender: Failed to create push reply thread: %d: %s!",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ signal(SIGHUP, quit_now);
+ signal(SIGTERM, quit_now);
+ signal(SIGPIPE,SIG_IGN); /* Ignore pipe errors. They kill us sometimes for nothing*/
+
+ mms_queue_run(octstr_get_cstr(settings->mm1_queuedir),
+ sendNotify, settings->queue_interval, settings->maxthreads, &rstop);
+ mms_stop_profile_engine();
+ sleep(2); /* Wait for it to die. */
+ http_caller_signal_shutdown(httpcaller);
+ sleep(2);
+ http_caller_destroy(httpcaller);
+
+
+ return 0;
+}
+
+
diff --git a/mbuni/mmsc/mmsproxy.c b/mbuni/mmsc/mmsproxy.c
new file mode 100644
index 0000000..dddfbd5
--- /dev/null
+++ b/mbuni/mmsc/mmsproxy.c
@@ -0,0 +1,897 @@
+/*
+ * MMS proxy gateway: Receives MMS messages from clients, dispatches to
+ * delivery queues. Also provides interface for collecting messages.
+ */
+
+#include
+#include
+#include
+
+#include "mms_msg.h"
+#include "mms_queue.h"
+
+#include "mms_uaprof.h"
+#include "mms_util.h"
+
+static Cfg *cfg;
+static List *proxyrelays;
+static MmsBoxSettings *settings;
+
+static int rstop = 0;
+static void quit_now(int notused)
+{
+ rstop = 1;
+ if (settings)
+ http_close_port(settings->port);
+}
+
+typedef struct MmsHTTPClientInfo {
+ HTTPClient *client;
+ Octstr *ua;
+ Octstr *ip;
+ List *headers;
+ Octstr *url;
+ Octstr *body;
+ List *cgivars;
+ MmsUaProfile *prof;
+ Octstr *base_client_addr;
+ Octstr *client_addr;
+} MmsHTTPClientInfo;
+
+static void fetchmms_proxy(MmsHTTPClientInfo *h);
+static void sendmms_proxy(MmsHTTPClientInfo *h);
+
+int main(int argc, char *argv[])
+{
+ int cfidx;
+ Octstr *fname;
+ CfgGroup *grp;
+ Octstr *log, *alog;
+ long loglevel;
+
+ MmsHTTPClientInfo h;
+
+ mms_lib_init();
+ srandom(time(NULL));
+
+ cfidx = get_and_set_debugs(argc, argv, NULL);
+
+ if (argv[cfidx] == NULL)
+ fname = octstr_imm("mmsc.conf");
+ else
+ fname = octstr_create(argv[cfidx]);
+
+ cfg = cfg_create(fname);
+
+ if (cfg_read(cfg) == -1)
+ panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
+
+ octstr_destroy(fname);
+
+ info(0, "----------------------------------------");
+ info(0, " MMSC Proxy Relay server version %s starting", MMSC_VERSION);
+
+ grp = cfg_get_single_group(cfg, octstr_imm("core"));
+ log = cfg_get(grp, octstr_imm("log-file"));
+ if (log != NULL) {
+ if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
+ loglevel = 0;
+ log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
+ octstr_destroy(log);
+ }
+
+ /* Get access log and open it. */
+ alog = cfg_get(grp, octstr_imm("access-log"));
+ if (alog) {
+ alog_open(octstr_get_cstr(alog), 1, 1);
+ octstr_destroy(alog);
+ }
+ /* Load proxy relays. */
+
+ proxyrelays = mms_proxy_relays(cfg);
+
+ /* Load settings. */
+ settings = mms_load_mmsbox_settings(cfg);
+
+ if (!settings)
+ panic(0, "No global MMSC configuration!");
+
+
+ signal(SIGHUP, quit_now);
+ signal(SIGTERM, quit_now);
+
+ /* Start cache engine. */
+ mms_start_profile_engine(octstr_get_cstr(settings->ua_profile_cache_dir));
+
+ /* Now open port and start dispatching requests. */
+
+ if (http_open_port(settings->port, 0) < 0) {
+ error(0, "MMS Proxy: Failed to start http server: %d => %s!",
+ errno, strerror(errno));
+ return -1;
+ }
+
+ while(rstop == 0 && (h.client = http_accept_request(settings->port,
+ &h.ip, &h.url, &h.headers,
+ &h.body, &h.cgivars)) != NULL)
+ if (is_allowed_ip(settings->deny_ip, settings->allow_ip, h.ip)) {
+ MmsHTTPClientInfo *hx = gw_malloc(sizeof *hx);
+ Octstr *profile_url;
+
+ h.ua = http_header_value(h.headers, octstr_imm("User-Agent"));
+
+ /* Get the profile URL and store it. Has effect of fetching if missing. */
+ if ((profile_url = http_header_value(h.headers,
+ octstr_imm("X-Wap-Profile"))) == NULL)
+ profile_url = http_header_value(h.headers, octstr_imm("Profile"));
+
+ if (profile_url) {
+ octstr_strip_nonalphanums(profile_url);
+ h.prof = mms_get_ua_profile(octstr_get_cstr(profile_url));
+ octstr_destroy(profile_url);
+ } else
+
+ h.prof = mms_make_ua_profile(h.headers);
+
+ /* Get the sender address. */
+
+ h.base_client_addr = mms_find_sender_msisdn(&h.url, h.headers, settings->wap_gw_msisdn_header);
+
+ if (!h.base_client_addr) { /* Set to IP sender... XXXX assumes ipv4 only for now*/
+ int ipv6 = 0;
+ h.base_client_addr = mms_find_sender_ip(h.headers,
+ settings->wap_gw_ip_header,
+ h.ip, &ipv6);
+ h.client_addr = octstr_format("%S/TYPE=IPv%s",
+ h.ip, ipv6 ? "6" : "4");
+ } else {
+ normalize_number(octstr_get_cstr(settings->unified_prefix), &h.base_client_addr);
+ h.client_addr = octstr_format("%S/TYPE=PLMN", h.base_client_addr);
+ }
+
+ /* Dump headers, url etc. */
+#if 0
+ http_header_dump(h.headers);
+ if (h.body) octstr_dump(h.body, 0);
+ if (h.ip) octstr_dump(h.ip, 0);
+#endif
+ /* Determine if this is the fetch interface or the send interface being used,
+ * by checking if http request has a body.
+ * then call relevant function in a thread (use threads because these functions
+ * can block)
+ */
+ *hx = h; /* Copy it all over. */
+ if (hx->body == NULL || octstr_len(hx->body) == 0)
+ gwthread_create((gwthread_func_t *)fetchmms_proxy, hx);
+ else
+ gwthread_create((gwthread_func_t *)sendmms_proxy, hx);
+
+ } else {
+ octstr_destroy(h.ip);
+ octstr_destroy(h.url);
+ if (h.ua) octstr_destroy(h.ua);
+ if (h.base_client_addr)
+ octstr_destroy(h.base_client_addr);
+ octstr_destroy(h.client_addr);
+ octstr_destroy(h.body);
+ http_destroy_headers(h.headers);
+ http_destroy_headers(h.cgivars);
+
+ http_close_client(h.client);
+ }
+
+ debug("proxy", 0, "Shutdown requested");
+ http_close_all_ports();
+ debug("proxy", 0, "Port closed");
+ sleep(2); /* Give them time to shut down. */
+ mms_stop_profile_engine();
+ sleep(2); /* Give them time to shut down. */
+ return 0;
+}
+
+
+void fetchmms_proxy(MmsHTTPClientInfo *h)
+{
+ Octstr *qf = NULL, *token = NULL, *s = NULL, *transid = NULL;
+ MmsEnvelope *e = NULL;
+ MmsMsg *m = NULL, *mr = NULL;
+ List *rh;
+
+ debug("proxy.fetchinterface", 0, " ---> Entered fetch interface <---");
+
+ rh = http_create_empty_headers();
+ http_header_add(rh, "Pragma", "no-cache");
+ http_header_add(rh, "Cache-Control", "no-cache");
+
+ if (mms_decodefetchurl(h->url, &qf, &token) != 0) {
+ error(0, "MMS Fetch interface: failed to decode request url (%s) from %s!",
+ octstr_get_cstr(h->url),
+ octstr_get_cstr(h->ip));
+ goto failed;
+ }
+ e = mms_queue_readenvelope(octstr_get_cstr(qf),
+ octstr_get_cstr(settings->mm1_queuedir), 1);
+
+ if (!e ||
+ (m = mms_queue_getdata(e)) == NULL) {
+ error(0, "MMS Fetch interface: failed to find envelope/data %s for request url (%s) from %s (e=%s)!",
+ octstr_get_cstr(qf), octstr_get_cstr(h->url), octstr_get_cstr(h->ip),
+ (e)? "found" : "not found");
+
+ mr = mms_retrieveconf(NULL, NULL, "Error-permanent-message-not-found", "Message not found",
+ settings->system_user);
+ s = mms_tobinary(mr);
+ goto failed;
+ }
+
+ /* Adapt content. */
+ transid = mms_maketransid(e->qf.name, settings->host_alias);
+ if (h->prof) {
+ MmsMsg *outmsg = NULL;
+ int x = mms_transform_msg(m, h->prof, &outmsg);
+
+ if (x == -1) { /* Temporary failure, we need to fetch profile. */
+ mr = mms_retrieveconf(NULL, transid, "Error-transient-failure", "Mobile MMS Settings not found",
+ settings->system_user);
+ s = mms_tobinary(mr);
+ goto failed;
+ } else if (x < 0) { /* Doesn't support MMS */
+ mr = mms_retrieveconf(NULL, transid, "Error-permanent-content-unsupported", "No MMS Support",
+ settings->system_user);
+ s = mms_tobinary(mr);
+ goto failed;
+ } else if (x == 0) {
+ if (outmsg == NULL) { /* Too large so truncated. */
+ Octstr *xx = octstr_format(octstr_get_cstr(settings->mms_toolarge), e->from);
+
+ mr = mms_retrieveconf(NULL, transid,
+#if 0
+ "Error-permanent-content-unsupported",
+#else
+ "Ok",
+#endif
+ octstr_get_cstr(xx),
+ settings->system_user);
+ octstr_destroy(xx);
+
+ s = mms_tobinary(mr);
+ goto failed;
+ } else {
+ mms_destroy(m);
+ m = outmsg;
+ }
+ }
+ }
+
+ mr = mms_retrieveconf(m, transid, "Error-permanent-message-not-found", NULL, e->from);
+ s = mms_tobinary(mr);
+
+ if ((token == NULL && e->token != NULL) ||
+ (e->token == NULL && token != NULL) ||
+ (octstr_compare(e->token, token) != 0)) {
+ error(0, "MMS Fetch interface: token mismatch, did client mod the fetch url?? "
+ " env=%s for request url (%s) from %s!",
+ octstr_get_cstr(qf), octstr_get_cstr(h->url), octstr_get_cstr(h->ip));
+ goto failed;
+ }
+
+
+ if (!m) {
+ error(0, "MMS Fetch interface: Failed to get message for request url (%s) from %s!",
+ octstr_get_cstr(h->url), octstr_get_cstr(h->ip));
+ goto failed;
+ }
+
+ if (!s) {
+ error(0, "MMS Fetch interface: Failed to convert message to binary for "
+ "request url (%s) from %s!",
+ octstr_get_cstr(h->url), octstr_get_cstr(h->ip));
+ goto failed;
+ }
+
+
+
+ e->lastaccess = time(NULL); /* No more notifications requests. */
+ e->sendt = e->expiryt + 3600*24*30*12;
+ mms_queue_update(e);
+
+
+ http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
+ http_send_reply(h->client, HTTP_OK, rh, s);
+
+#if 1
+ debug("proxy.fetchinterface", 0,
+ " $$$$$$ fetch message replying with [type=%s,content_len=%ld]: ",
+ mr ? mms_message_type_to_cstr(mms_messagetype(mr)) : (unsigned char *)"none",
+ s ? octstr_len(s) : 0);
+ if (mr)
+ mms_msgdump(mr,1);
+#endif
+
+ /* Send to access log with success. */
+ mms_log2("Fetched", e ? e->from : NULL, h->client_addr,
+ e ? e->msize : 0, e ? e->msgId : NULL, NULL, NULL, "MM1", h->ua);
+
+ goto free_stuff; /* Skip to end. */
+
+ failed:
+#if 1
+ debug("proxy.fetchinterface", 0,
+ " $$$$$$ fetch message [fail] replying with [type=%s,content_len=%ld]: ",
+ mr ? mms_message_type_to_cstr(mms_messagetype(mr)) : (unsigned char *)"none",
+ s ? octstr_len(s) : 0);
+ if (mr)
+ mms_msgdump(mr,1);
+#endif
+
+ /* Send to access log on failure?? */
+ mms_log2("Failed Fetch", e ? e->from : NULL, h->client_addr,
+ e ? e->msize : 0, e ? e->msgId : NULL, NULL, NULL, "MM1", h->ua);
+
+ if (!s) {
+ http_header_add(rh, "Content-Type", "text/plain");
+ http_send_reply(h->client, HTTP_NOT_FOUND, rh, octstr_imm("Not found"));
+ } else {
+ http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
+ http_send_reply(h->client, HTTP_OK, rh, s);
+ }
+
+ free_stuff:
+
+ http_destroy_headers(rh);
+ if (e) mms_queue_free_env(e);
+
+ if (s) octstr_destroy(s);
+ if (m) mms_destroy(m);
+ if (mr) mms_destroy(mr);
+
+ if (qf) octstr_destroy(qf);
+ if (token) octstr_destroy(token);
+ if (transid) octstr_destroy(transid);
+
+ octstr_destroy(h->ip);
+ octstr_destroy(h->url);
+ if (h->ua) octstr_destroy(h->ua);
+ if (h->body) octstr_destroy(h->body);
+
+ if (h->base_client_addr)
+ octstr_destroy(h->base_client_addr);
+ octstr_destroy(h->client_addr);
+
+ http_destroy_cgiargs(h->cgivars);
+ http_destroy_headers(h->headers);
+
+ gw_free(h);
+
+}
+
+/* Make list of recipients and also sender. */
+static void collect_senddata(List *mh, List **xto,
+ Octstr **from, Octstr **subject,
+ Octstr **otransid, time_t *expiryt, time_t *deliveryt)
+{
+
+ Octstr *s;
+ List *l = http_header_find_all(mh, "To");
+ if (l) {
+ int i, n;
+ for (i = 0, n = list_len(l); idefault_msgexpiry;
+ }
+
+ if (deliveryt) {
+ s = http_header_value(mh, octstr_imm("X-Mms-Delivery-Time"));
+ if (s) {
+ *deliveryt = date_parse_http(s);
+ octstr_destroy(s);
+ } else
+ *deliveryt = 0;
+ }
+ if (subject)
+ *subject = http_header_value(mh, octstr_imm("Subject"));
+
+ if (otransid)
+ *otransid = http_header_value(mh, octstr_imm("X-Mms-Transaction-ID"));
+
+}
+
+static void sendmms_proxy(MmsHTTPClientInfo *h)
+{
+ List *rh = http_create_empty_headers();
+ MmsMsg *m, *mresp = NULL;
+ Octstr *reply_body = NULL;
+ int ctype_set = 0;
+ int mtype = 0;
+ int hstatus = HTTP_OK;
+ char *notify_cmd = NULL;
+ int msize = h->body ? octstr_len(h->body) : 0;
+
+ debug("proxy.sendinterface", 0,
+ " --> Enterred sendmms interface, blen=%d <--- ",
+ msize);
+
+ http_header_add(rh, "Pragma", "no-cache");
+ http_header_add(rh, "Cache-Control", "no-cache");
+
+
+
+ if (!h->body) { /* A body is required. */
+ http_header_add(rh, "Content-Type", "text/plain");
+ hstatus = HTTP_FORBIDDEN;
+ reply_body = octstr_format("Unexpected MMS message[%s], no body?",
+ mms_message_type_to_cstr(mtype));
+
+ goto done;
+ }
+
+ m = mms_frombinary(h->body, h->client_addr);
+
+ if (!m) {
+ http_header_add(rh, "Content-Type", "text/plain");
+ ctype_set = 1;
+ hstatus = HTTP_BAD_REQUEST;
+ reply_body = octstr_format("Malformed MMS message");
+ debug("proxy.sendinterface", 0, " Parse error on incoming message.");
+ goto done;
+ }
+
+ debug("proxy.sendinterface", 0, " Client sent us: ");
+
+#if 1
+ mms_msgdump(m,1);
+ /* octstr_dump(h->body, 0); */
+#endif
+ mtype = mms_messagetype(m);
+
+ switch(mtype) {
+
+ case MMS_MSGTYPE_SEND_REQ:
+ {
+ Octstr *qf;
+ List *mh = mms_message_headers(m);
+ Octstr *from;
+ List *to = list_create();
+ Octstr *subject;
+ time_t expiryt, deliveryt;
+
+ Octstr *otransid, *value;
+ int dlr;
+
+
+ collect_senddata(mh, &to, &from, &subject, &otransid, &expiryt, &deliveryt);
+
+ /*Delete some headers that must be sent on. */
+ mms_remove_headers(m, "Bcc");
+ mms_remove_headers(m, "X-Mms-Delivery-Time");
+ mms_remove_headers(m, "X-Mms-Expiry");
+ mms_remove_headers(m, "X-Mms-Sender-Visibility");
+
+
+ value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report"));
+ if (value &&
+ octstr_case_compare(value, octstr_imm("Yes")) == 0)
+ dlr = 1;
+ else
+ dlr = 0;
+
+
+ qf = mms_queue_add(from, to, NULL, subject,
+ NULL, NULL, deliveryt, expiryt, m, NULL, dlr,
+ octstr_get_cstr(settings->global_queuedir));
+
+ if (!qf)
+ mresp = mms_sendconf("Error-transient-failure", "None", octstr_get_cstr(otransid),0);
+ else {
+ Octstr *transid = mms_maketransid(octstr_get_cstr(qf), settings->host_alias);
+ mresp = mms_sendconf("Ok", octstr_get_cstr(transid), octstr_get_cstr(otransid),0);
+
+ /* Log to access log */
+ mms_log("Received", from, to, msize, transid, NULL, NULL, "MM1", h->ua);
+
+ octstr_destroy(transid);
+ octstr_destroy(qf);
+ }
+
+ if (otransid)
+ octstr_destroy(otransid);
+ if (value)
+ octstr_destroy(value);
+ octstr_destroy(from);
+ octstr_destroy(subject);
+ http_destroy_headers(mh);
+ list_destroy(to, (list_item_destructor_t *)octstr_destroy);
+
+ notify_cmd = "sent";
+ reply_body = mms_tobinary(mresp);
+ }
+ break;
+ case MMS_MSGTYPE_FORWARD_REQ:
+ {
+ Octstr *qf = NULL, *token = NULL;
+ List *mh = mms_message_headers(m);
+ Octstr *from;
+ List *to = list_create();
+ Octstr *subject;
+ time_t expiryt, deliveryt;
+ MmsMsg *mfwd = NULL;
+ MmsEnvelope *e = NULL;
+
+ Octstr *otransid;
+ Octstr *url = http_header_value(mh, octstr_imm("X-Mms-Content-Location"));
+ Octstr *read_report = http_header_value(mh, octstr_imm("X-Mms-Read-Report"));
+ Octstr *delivery_report = http_header_value(mh,
+ octstr_imm("X-Mms-Delivery-Report"));
+ Octstr *allow_report = http_header_value(mh,
+ octstr_imm("X-Mms-Report-Allowed"));
+ int dlr;
+
+ collect_senddata(mh, &to, &from, &subject, &otransid, &expiryt, &deliveryt);
+
+ if (mms_decodefetchurl(url, &qf, &token) != 0) {
+ error(0, "MMS Send interface: failed to decode forward url (%s) from %s!",
+ octstr_get_cstr(url),
+ octstr_get_cstr(h->ip));
+ mresp = mms_sendconf("Error-permanent-message-not-found", "None",
+ octstr_get_cstr(otransid),1);
+ goto forward_done;
+ }
+
+ e = mms_queue_readenvelope(octstr_get_cstr(qf),
+ octstr_get_cstr(settings->mm1_queuedir), 1);
+
+ if (!e ||
+ (mfwd = mms_queue_getdata(e)) == NULL) {
+ error(0,
+ "MMS Send interface: failed to find envelope/data %s for forward url "
+ "(%s) from %s (e=%s)!",
+ octstr_get_cstr(qf), octstr_get_cstr(url), octstr_get_cstr(h->ip),
+ (e) ? "found" : "not found");
+
+ mresp = mms_sendconf("Error-permanent-message-not-found", "None",
+ octstr_get_cstr(otransid),1);
+ goto forward_done;
+ } else { /* Found it, etc. */
+
+ Octstr *transid;
+ Octstr *pfrom = mms_get_header_value(mfwd, octstr_imm("From"));
+ Octstr *pdate = mms_get_header_value(mfwd, octstr_imm("Date"));
+ Octstr *pdelivery_report = mms_get_header_value(mfwd,
+ octstr_imm("X-Mms-Delivery-Report"));
+ Octstr *pmsgid = mms_get_header_value(mfwd, octstr_imm("Message-ID"));
+ Octstr *s;
+ Octstr *qf2;
+ int n = 0;
+
+
+ /* Modify the message before sending on as per spec. */
+ mms_replace_header_value(mfwd, "From", octstr_get_cstr(from));
+
+ mms_remove_headers(mfwd, "X-Mms-Read-Report");
+ if (read_report)
+ mms_replace_header_value(mfwd, "X-Mms-Read-Report",
+ octstr_get_cstr(read_report));
+
+ mms_remove_headers(mfwd, "X-Mms-Delivery-Report");
+ if (delivery_report)
+ mms_replace_header_value(mfwd, "X-Mms-Delivery-Report",
+ octstr_get_cstr(delivery_report));
+
+
+ if ((s = mms_get_header_value(mfwd, octstr_imm("X-Mms-Previously-Sent-By"))) != NULL) {
+ sscanf(octstr_get_cstr(s), "%d", &n);
+ octstr_destroy(s);
+ }
+ s = octstr_format("%d %S", n+1, pfrom);
+ mms_replace_header_value(mfwd, "X-Mms-Previously-Sent-By", octstr_get_cstr(s));
+
+
+ if ((s = mms_get_header_value(mfwd,
+ octstr_imm("X-Mms-Previously-Sent-Date")))
+ != NULL) {
+ sscanf(octstr_get_cstr(s), "%d", &n);
+ octstr_destroy(s);
+ }
+ s = octstr_format("%d %S", n+1, pdate);
+ mms_replace_header_value(mfwd,
+ "X-Mms-Previously-Sent-Date",
+ octstr_get_cstr(s));
+ octstr_destroy(pdate);
+
+ if (delivery_report &&
+ octstr_case_compare(delivery_report, octstr_imm("Yes")) == 0)
+ dlr = 1;
+ else
+ dlr = 0;
+ /* Message to forward is now ready, write it to queue. */
+ qf2 = mms_queue_add(from, to, NULL, subject,
+ NULL, NULL, deliveryt, expiryt, mfwd, NULL,
+ dlr,
+ octstr_get_cstr(settings->global_queuedir));
+
+
+ if (!qf2)
+ mresp = mms_sendconf("Error-transient-failure",
+ "None", octstr_get_cstr(otransid),1);
+ else {
+ transid = mms_maketransid(octstr_get_cstr(qf), settings->host_alias);
+ mresp = mms_sendconf("Ok",
+ octstr_get_cstr(transid),
+ octstr_get_cstr(otransid),1);
+
+ /* Log to access log */
+ mms_log("Forwarded", h->client_addr, to, msize, transid, NULL, NULL, "MM1", h->ua);
+
+ octstr_destroy(transid);
+ octstr_destroy(qf2);
+ }
+
+ /* You have queued it, now check if the original sender asked for a delivery notify.
+ * if so and this forward has not refused it, then send a notify and we are done for now.
+ */
+
+ if ((!allow_report ||
+ octstr_case_compare(allow_report, octstr_imm("Yes")) == 0) &&
+ (pdelivery_report && octstr_case_compare(pdelivery_report,
+ octstr_imm("Yes")))) {
+
+ MmsMsg *mrep = mms_deliveryreport(pmsgid, h->client_addr, time(NULL), octstr_imm("Forwarded"));
+ Octstr *x;
+ List *l = list_create();
+ list_append(l, pfrom);
+
+ x = mms_queue_add(settings->system_user, l, NULL, NULL, NULL, NULL, 0,
+ time(NULL) + settings->default_msgexpiry,
+ mrep, NULL,0,
+ octstr_get_cstr(settings->global_queuedir));
+ octstr_destroy(x);
+
+ list_destroy(l, (list_item_destructor_t *)octstr_destroy);
+ mms_destroy(mrep);
+ }
+ octstr_destroy(pfrom);
+ octstr_destroy(pdelivery_report);
+ octstr_destroy(pmsgid);
+
+ }
+
+ forward_done:
+
+ if (mfwd)
+ mms_destroy(mfwd);
+
+ if (e) { /* Update the message queue and go. */
+ e->lastaccess = time(NULL);
+ if (mms_queue_update(e) != 1) /* Should be freed. */
+ mms_queue_free_env(e);
+ e = NULL;
+ }
+
+ if (qf)
+ octstr_destroy(qf);
+ if (token)
+ octstr_destroy(token);
+ if (from)
+ octstr_destroy(from);
+ if (subject)
+ octstr_destroy(subject);
+ if (mh)
+ http_destroy_headers(mh);
+ if (to)
+ list_destroy(to, (list_item_destructor_t *)octstr_destroy);
+ if (otransid)
+ octstr_destroy(otransid);
+ if (url)
+ octstr_destroy(url);
+
+ if (read_report)
+ octstr_destroy(read_report);
+ if (allow_report)
+ octstr_destroy(allow_report);
+ if (delivery_report)
+ octstr_destroy(delivery_report);
+
+ reply_body = mms_tobinary(mresp);
+ notify_cmd = "fetched";
+ }
+ break;
+ case MMS_MSGTYPE_NOTIFYRESP:
+ case MMS_MSGTYPE_ACKNOWLEDGE_IND:
+ {
+ Octstr *transid = mms_get_header_value(m, octstr_imm("X-Mms-Transaction-ID"));
+ Octstr *allow_report = mms_get_header_value(m, octstr_imm("X-Mms-Report-Allowed"));
+
+ Octstr *qf = mms_getqf_fromtransid(transid);
+ MmsEnvelope *e = mms_queue_readenvelope(octstr_get_cstr(qf),
+ octstr_get_cstr(settings->mm1_queuedir), 1);
+ Octstr *status;
+
+ MmsMsg *mrpt;
+
+
+ if (mtype == MMS_MSGTYPE_NOTIFYRESP)
+ status = mms_get_header_value(m, octstr_imm("X-Mms-Status"));
+ else /* This (acknowledge-ind) is the same as notify_resp with status=retrieved. */
+ status = octstr_imm("Retrieved");
+
+ if (!e) {
+ error(0, "MMS Send interface: Received notification type=%s "
+ "[url=%s, transid=%s, qf=%s] but could not find queue entry!\n",
+ mms_message_type_to_cstr(mtype), octstr_get_cstr(h->url),
+ octstr_get_cstr(transid), octstr_get_cstr(qf));
+ goto mdone;
+ }
+
+ if (octstr_str_compare(status, "Retrieved") == 0) {
+ MmsEnvelopeTo *t = list_get(e->to, 0);
+ if (t)
+ t->process = 0;
+ } else
+ e->lastaccess = time(NULL); /* Note now that it has been touched. */
+
+ /* If the allow report header is missing (default is Yes)
+ * or it is there and has said we must send report,
+ * and sender requested a report, then queue a report.
+ */
+ if ((allow_report == NULL
+ || octstr_case_compare(allow_report, octstr_imm("Yes")) == 0) &&
+ e->dlr) {
+ Octstr *x;
+ List *l = list_create();
+
+ mrpt = mms_deliveryreport(e->msgId, h->client_addr, time(NULL), status);
+ list_append(l, octstr_duplicate(e->from));
+
+ x = mms_queue_add(settings->system_user, l, NULL, NULL, NULL, NULL, 0,
+ time(NULL) + settings->default_msgexpiry, mrpt, NULL, 0,
+ octstr_get_cstr(settings->global_queuedir));
+ octstr_destroy(x);
+
+ list_destroy(l, (list_item_destructor_t *)octstr_destroy);
+ mms_destroy(mrpt);
+ }
+
+ mdone:
+
+ /* Log to access log */
+ mms_log2("NotifyResp", h->client_addr, NULL, msize, transid, NULL, NULL, "MM1", h->ua);
+
+ if (e &&
+ mms_queue_update(e) != 1) /* Should be freed. */
+ mms_queue_free_env(e);
+
+ octstr_destroy(qf);
+ octstr_destroy(transid);
+ octstr_destroy(allow_report);
+ octstr_destroy(status);
+ http_header_add(rh, "Content-Type", "text/plain");
+ ctype_set = 1;
+ reply_body = octstr_imm("Received");
+
+ notify_cmd = "fetched";
+ }
+ break;
+
+ case MMS_MSGTYPE_READ_REC_IND:
+ {
+ List *mh = mms_message_headers(m);
+ Octstr *from;
+ List *to = list_create();
+ Octstr *x;
+
+ if (mms_convert_readrec2readorig(m) < 0)
+ goto mdone2;
+
+ collect_senddata(mh, &to, &from, NULL, NULL, NULL, NULL);
+
+ x = mms_queue_add(from, to, NULL, NULL, NULL,
+ NULL, time(NULL), time(NULL) + settings->default_msgexpiry,
+ m, NULL, 0, octstr_get_cstr(settings->global_queuedir));
+
+ /* Log to access log */
+ mms_log("ReadReport", h->client_addr, NULL, msize, NULL, NULL, NULL, "MM1", h->ua);
+
+ octstr_destroy(x);
+ octstr_destroy(from);
+ http_destroy_headers(mh);
+ mdone2:
+
+ list_destroy(to, (list_item_destructor_t *)octstr_destroy);
+ http_header_add(rh, "Content-Type", "text/plain");
+ ctype_set = 1;
+ reply_body = octstr_imm("Received");
+
+ notify_cmd = "fetched";
+ break;
+ }
+ default:
+ http_header_add(rh, "Content-Type", "text/plain");
+ ctype_set = 1;
+ hstatus = HTTP_FORBIDDEN;
+ reply_body = octstr_format("Unexpected MMS message type %s", mms_message_type_to_cstr(mtype));
+ break;
+ }
+
+
+ if (notify_cmd) /* Inform provisioning server */
+ notify_prov_server(octstr_get_cstr(settings->prov_notify),
+ h->base_client_addr ? octstr_get_cstr(h->base_client_addr) : "unknown",
+ notify_cmd,
+ octstr_get_cstr(settings->prov_notify_arg));
+
+ mms_destroy(m);
+ /* Send reply. */
+
+ done:
+
+ if (mresp)
+ mms_destroy(mresp);
+ if (!ctype_set)
+ http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
+
+ http_send_reply(h->client, hstatus, rh, reply_body);
+ http_destroy_headers(rh);
+ octstr_destroy(reply_body);
+
+ octstr_destroy(h->ip);
+ octstr_destroy(h->url);
+
+ if (h->base_client_addr)
+ octstr_destroy(h->base_client_addr);
+ octstr_destroy(h->client_addr);
+
+ if (h->ua) octstr_destroy(h->ua);
+ if (h->body) octstr_destroy(h->body);
+ http_destroy_cgiargs(h->cgivars);
+ http_destroy_headers(h->headers);
+
+ gw_free(h);
+
+}
diff --git a/mbuni/mmsc/mmssend.c b/mbuni/mmsc/mmssend.c
new file mode 100644
index 0000000..e360418
--- /dev/null
+++ b/mbuni/mmsc/mmssend.c
@@ -0,0 +1,135 @@
+#include
+#include
+#include "mms_queue.h"
+#include "mms_uaprof.h"
+#include "mms_util.h"
+
+static Octstr *data;
+static Octstr *from;
+static List *to;
+static MmsMsg *m;
+
+static MmsBoxSettings *settings;
+
+static int find_own(int i, int argc, char *argv[])
+{
+
+ if (argv[i][1] == 'f')
+ if (i + 1 < argc) {
+ from = octstr_create(argv[i+1]);
+ return 1;
+ } else
+ return -1;
+ else if (argv[i][1] == 't')
+ if (i + 1 < argc) {
+ int j, m;
+ List *l = octstr_split(octstr_create(argv[i+1]),
+ octstr_imm(":"));
+ for (j = 0, m = list_len(l); j < m; j++)
+ list_append(to, list_get(l, j));
+ list_destroy(l, NULL);
+ return 1;
+ } else
+ return -1;
+ else if (argv[i][1] == 'm')
+ if (i + 1 < argc) {
+ data = octstr_read_file(argv[i+1]);
+ return 1;
+ } else
+ return -1;
+ else
+ return -1;
+}
+
+static Cfg *cfg;
+
+static List *proxyrelays;
+
+int main(int argc, char *argv[])
+{
+ Octstr *fname, *s;
+
+ int cfidx;
+ CfgGroup *grp;
+ Octstr *log, *alog;
+ long loglevel;
+ int msize;
+
+ if (argc < 2)
+ return -1;
+
+ mms_lib_init();
+ to = list_create();
+ srandom(time(NULL));
+
+ cfidx = get_and_set_debugs(argc, argv, find_own);
+
+ if (argv[cfidx] == NULL)
+ fname = octstr_imm("mmsc.conf");
+ else
+ fname = octstr_create(argv[cfidx]);
+
+ cfg = cfg_create(fname);
+
+ if (cfg_read(cfg) == -1)
+ panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
+
+ octstr_destroy(fname);
+
+ info(0, "----------------------------------------");
+ info(0, " MMSC Message sender runner version %s starting", MMSC_VERSION);
+
+ grp = cfg_get_single_group(cfg, octstr_imm("core"));
+ log = cfg_get(grp, octstr_imm("log-file"));
+ if (log != NULL) {
+ if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
+ loglevel = 0;
+ log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
+ octstr_destroy(log);
+ }
+
+ /* Get access log and open it. */
+ alog = cfg_get(grp, octstr_imm("access-log"));
+ if (alog) {
+ alog_open(octstr_get_cstr(alog), 1, 1);
+ octstr_destroy(alog);
+ }
+
+ /* Load proxy relays. */
+
+ proxyrelays = mms_proxy_relays(cfg);
+
+ /* Load settings. */
+ settings = mms_load_mmsbox_settings(cfg);
+
+ if (!settings)
+ panic(0, "No global MMSC configuration!");
+
+ if (from == NULL ||
+ to == NULL) {
+ error(0, "Sender and recipient addresses required!\n");
+ exit(-1);
+ }
+
+ mms_start_profile_engine(octstr_get_cstr(settings->ua_profile_cache_dir));
+
+ if (data) {
+ m = mms_frombinary(data, from ? from : octstr_imm("anon@anon"));
+ if (m)
+ mms_msgdump(m,0);
+ msize = octstr_len(data);
+ } else
+ msize = 0;
+ if (!m)
+ panic(0, "No Message supplied, or failed to decode binary data!");
+
+ s = mms_queue_add(from, to, NULL, NULL, NULL, NULL, time(NULL),
+ time(NULL) + settings->default_msgexpiry, m,
+ NULL, 0, octstr_get_cstr(settings->global_queuedir));
+
+ mms_log("Received", from, to, msize, s, NULL, NULL, "mmssend",NULL);
+
+ printf("Queued: %s\n", octstr_get_cstr(s));
+ octstr_destroy(s);
+ return 0;
+}
diff --git a/mbuni/stamp-h1 b/mbuni/stamp-h1
new file mode 100644
index 0000000..4547fe1
--- /dev/null
+++ b/mbuni/stamp-h1
@@ -0,0 +1 @@
+timestamp for config.h
diff --git a/mbuni/todo b/mbuni/todo
new file mode 100644
index 0000000..b2683f1
--- /dev/null
+++ b/mbuni/todo
@@ -0,0 +1,5 @@
+- correct handling of sender-visibility flag when receiving message (and also use correct address for billing. no spoofing).
+- Sending DLR correctly when sending from/to email.
+- In content adaptation: Colour depth adjustment
+- logging a la access.log (one log per interface -- mm1-log, mm4-log, etc)
+- Need to parameterise some values: tmp dir, response messages (say on failed content adaptation)