Initial import
This commit is contained in:
parent
aa50693b59
commit
e13e3b0b4b
|
@ -0,0 +1 @@
|
|||
SUBDIRS = mmlib mmsc
|
|
@ -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:
|
|
@ -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.
|
||||
|
|
@ -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 <emph>Digital Solutions</emph>"
|
||||
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"
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <pinard@iro.umontreal.ca>, 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 <bug-automake@gnu.org>."
|
||||
;;
|
||||
|
||||
-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:
|
|
@ -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
|
||||
|
||||
|
|
@ -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:
|
|
@ -0,0 +1,51 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef __MMS_BILLING_INCLUDED__
|
||||
#define __MMS_BILLING_INCLUDED__
|
||||
|
||||
#include <time.h>
|
||||
#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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -0,0 +1,797 @@
|
|||
/*
|
||||
* MMS Queue handler functions - P. A. Bagyenda
|
||||
*/
|
||||
#include <sys/file.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#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; i<n; i++) {
|
||||
MmsEnvelopeTo *t = gw_malloc(sizeof *t);
|
||||
Octstr *a = list_get(to, i);
|
||||
|
||||
t->rcpt = 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); i<n; i++) {
|
||||
MmsEnvelopeTo *to = list_get(e->to, 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; i<num_threads; i++) { /* Create threads for sending. */
|
||||
tlist[i].l = list_create();
|
||||
list_add_producer(tlist[i].l);
|
||||
tlist[i].deliver = deliver;
|
||||
gwthread_create((gwthread_func_t *)tdeliver, &tlist[i]);
|
||||
}
|
||||
|
||||
i = 0; /* For stepping through above array. */
|
||||
do {
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
time_t tnow = time(NULL);
|
||||
|
||||
dirp = opendir(dir);
|
||||
|
||||
if (!dirp) {
|
||||
error(0, "mms_queue_run: Failed to read queue directory %s, error=%s",
|
||||
dir, strerror(errno));
|
||||
goto qsleep;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dirp)) != NULL && !qstop)
|
||||
if (dp->d_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<num_threads; i++)
|
||||
if (tlist[i].l)
|
||||
list_remove_producer(tlist[i].l);
|
||||
gwthread_join_every((gwthread_func_t *)tdeliver); /* Wait for them all to terminate. */
|
||||
|
||||
for (i = 0; i<num_threads; i++)
|
||||
if (tlist[i].l)
|
||||
list_destroy(tlist[i].l,NULL); /* Final destroy if needed. */
|
||||
gw_free(tlist);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
#ifndef _MMSQUEUE_INCLUDED__
|
||||
#define _MMSQUEUE_INCLUDED__
|
||||
|
||||
#include "mms_msg.h"
|
||||
|
||||
#define QFNAMEMAX 32
|
||||
|
||||
typedef struct MmsEnvelopeTo {
|
||||
Octstr *rcpt; /* Recipient address. */
|
||||
int process; /* 1 if delivery to this recipient should be attempted.
|
||||
* Flags below for details.
|
||||
*/
|
||||
enum {SFailed=0, SSuccess, SDefered, SUnknown} flag;
|
||||
} MmsEnvelopeTo;
|
||||
|
||||
typedef struct MmsEnvelope {
|
||||
int msgtype; /* type of message. */
|
||||
Octstr *msgId; /* message id (for reference). */
|
||||
Octstr *token; /* User level token, may be null. */
|
||||
Octstr *from; /* from address. */
|
||||
|
||||
List *to; /* List of recipients: MmsEnvelopeTo */
|
||||
|
||||
Octstr *subject; /* Message subject (if any). */
|
||||
|
||||
time_t created; /* date/time this queue entry was made. */
|
||||
time_t sendt; /* date/time attempt should be made to send this message.*/
|
||||
time_t lasttry; /* date/time this queue item was last run. */
|
||||
time_t expiryt; /* date/time when this message expires. */
|
||||
time_t lastaccess; /* Last fetch of the corresponding data. */
|
||||
|
||||
int dlr; /* Whether to send delivery receipts or not. */
|
||||
|
||||
long attempts; /* Delivery attempts made so far. */
|
||||
|
||||
unsigned long msize; /* Size of message in octets. */
|
||||
|
||||
struct {
|
||||
int billed;
|
||||
double amt;
|
||||
} bill; /* Whether this has been billed and how much. */
|
||||
|
||||
Octstr *mdata; /* Generic string data used by any interface. */
|
||||
Octstr *fromproxy; /* Which proxy sent us this message.*/
|
||||
Octstr *viaproxy; /* Which proxy must we send this message through. */
|
||||
struct { /* Name of the queue file, pointer to it (locked). DO NOT MUCK WITH THESE! */
|
||||
char name[QFNAMEMAX]; /* Name of the file. */
|
||||
char dir[QFNAMEMAX]; /* Directory in which file is .*/
|
||||
char _pad[16];
|
||||
int fd;
|
||||
} qf;
|
||||
} MmsEnvelope;
|
||||
|
||||
|
||||
/*
|
||||
* Add a message to the queue, returns 0 on success -1 otherwise (error is logged).
|
||||
* 'to' is a list of Octstr * *.
|
||||
* Returns a queue file name.
|
||||
*/
|
||||
extern 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);
|
||||
|
||||
/*
|
||||
* Update queue status. Returns -1 on error, 0 if queue is updated fine and
|
||||
* envelope is still valid, 1 if envelope is no longer valid (no more recipients.)
|
||||
*/
|
||||
extern int mms_queue_update(MmsEnvelope *e);
|
||||
|
||||
/*
|
||||
* Get the message associated with this queue entry.
|
||||
*/
|
||||
extern MmsMsg *mms_queue_getdata(MmsEnvelope *e);
|
||||
|
||||
/*
|
||||
* Reads queue, returns up to lim queue entries that are ready for processing. send 0 for no limit.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 *dir, int shouldblock);
|
||||
|
||||
/*
|
||||
* Run the queue in the given directory. For each envelope that is due for sending, call
|
||||
* deliver(). If deliver() returns 0, then queue_run needs to destroy envelope
|
||||
* structure it passed to deliver()
|
||||
* if deliver() returns 1, it has deleted envelope.
|
||||
* Also if rstop becomes true, queue run must stop.
|
||||
*/
|
||||
void mms_queue_run(char *dir,
|
||||
int (*deliver)(MmsEnvelope *),
|
||||
double sleepsecs,
|
||||
int num_threads,
|
||||
int *rstop);
|
||||
|
||||
/* Get rid of memory used by this. */
|
||||
extern int mms_queue_free_env(MmsEnvelope *e);
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef __MMS_RESOLVE_INCLUDED__
|
||||
#define __MMS_RESOLVE_INCLUDED__
|
||||
|
||||
#include <time.h>
|
||||
#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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -0,0 +1,905 @@
|
|||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#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<n && s[j] != '/')
|
||||
j++; /* Skip to next slash. */
|
||||
|
||||
*qf = octstr_copy(fetch_url, i, j-i);
|
||||
|
||||
if (j<n)
|
||||
*token = octstr_copy(fetch_url, j + 1, n - (j+1));
|
||||
else
|
||||
*token = octstr_create("");
|
||||
octstr_destroy(xfurl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Octstr *mms_maketransid(char *qf, Octstr *mmscname)
|
||||
{
|
||||
Octstr *res = octstr_format("%s@%S", qf, mmscname);
|
||||
return res;
|
||||
}
|
||||
|
||||
extern Octstr *mms_getqf_fromtransid(Octstr *transid)
|
||||
{
|
||||
int i = octstr_search_char(transid, '@', 0);
|
||||
return octstr_copy(transid, 0, i);
|
||||
}
|
||||
|
||||
Octstr *mms_isodate(time_t t)
|
||||
{
|
||||
Octstr *current_time;
|
||||
struct tm now;
|
||||
|
||||
now = gw_gmtime(t);
|
||||
current_time = octstr_format("%04d-%02d-%02dT%02d:%02d:%02dZ",
|
||||
now.tm_year + 1900, now.tm_mon + 1,
|
||||
now.tm_mday, now.tm_hour, now.tm_min,
|
||||
now.tm_sec);
|
||||
|
||||
return current_time;
|
||||
}
|
||||
|
||||
void mms_lib_init(void)
|
||||
{
|
||||
gwlib_init();
|
||||
mms_strings_init();
|
||||
|
||||
}
|
||||
|
||||
static void strip_quotes(Octstr *s)
|
||||
{
|
||||
int l = s ? octstr_len(s) : 0;
|
||||
|
||||
if (l == 0)
|
||||
return;
|
||||
if (octstr_get_char(s, 0) == '"') {
|
||||
octstr_delete(s, 0, 1);
|
||||
l--;
|
||||
}
|
||||
if (octstr_get_char(s, l-1) == '"')
|
||||
octstr_delete(s, l-1, 1);
|
||||
}
|
||||
|
||||
List *get_value_parameters(Octstr *params)
|
||||
{
|
||||
int i,n, k = 0;
|
||||
List *h = http_create_empty_headers();
|
||||
Octstr *xparams = octstr_duplicate(params);
|
||||
|
||||
octstr_format_append(xparams, ";"); /* So parsing is easier. (aka cheap hack) */
|
||||
|
||||
for (i = 0, n = octstr_len(xparams); i < n; i++) {
|
||||
int c = octstr_get_char(xparams, i);
|
||||
|
||||
if (c == ';') {
|
||||
int j = octstr_search_char(xparams, '=', k);
|
||||
Octstr *name, *value;
|
||||
if (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); i<n; i++) {
|
||||
int ch = octstr_get_char(s,i);
|
||||
if (isspace(ch) || ispunct(ch))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Octstr *make_value_parameters(List *params)
|
||||
{
|
||||
Octstr *s = octstr_create(""), *name, *value;
|
||||
int i, n;
|
||||
|
||||
for (i = 0, n = params ? list_len(params) : 0; i<n; i++) {
|
||||
int space;
|
||||
http_header_get(params, i, &name, &value);
|
||||
space = needs_quotes(value);
|
||||
octstr_format_append(s, "%s%S=%s%S%s",
|
||||
(i==0) ? "" : "; ",
|
||||
name,
|
||||
(space) ? "\"" : "",
|
||||
value,
|
||||
(space) ? "\"" : "");
|
||||
octstr_destroy(name);
|
||||
octstr_destroy(value);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Take each header with a comma separated set of values (for To,Cc,Bcc),
|
||||
* re-create as a series of header/value pairs.
|
||||
* Remove all non-conformant headers (e.g. old unix-style from
|
||||
*/
|
||||
void unpack_mimeheaders(MIMEEntity *mm)
|
||||
{
|
||||
int i, n;
|
||||
List *h = http_create_empty_headers();
|
||||
|
||||
|
||||
for (i = 0, n = list_len(mm->headers); i<n; i++) {
|
||||
Octstr *header = NULL, *value = NULL;
|
||||
List *l = NULL;
|
||||
int j, m;
|
||||
int skip;
|
||||
|
||||
http_header_get(mm->headers, 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); j<m; j++)
|
||||
http_header_add(h, octstr_get_cstr(header),
|
||||
octstr_get_cstr(list_get(l, j)));
|
||||
else
|
||||
http_header_add(h, octstr_get_cstr(header),
|
||||
octstr_get_cstr(value));
|
||||
|
||||
if (l) list_destroy(l, (list_item_destructor_t *)octstr_destroy);
|
||||
|
||||
loop:
|
||||
if (header) octstr_destroy(header);
|
||||
if (value) octstr_destroy(value);
|
||||
}
|
||||
|
||||
http_destroy_headers(mm->headers);
|
||||
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); i<n; i++)
|
||||
unbase64_mimeparts(list_get(m->multiparts, 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); i<n; i++)
|
||||
base64_mimeparts(list_get(m->multiparts, 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);
|
||||
}
|
||||
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
bin_PROGRAMS = mmsglobalsender mmsproxy mmsmobilesender mmsfromemail mmssend
|
||||
|
|
@ -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:
|
|
@ -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 <signal.h>
|
||||
#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); i<n; i++)
|
||||
if ((t = list_get(e->to, 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); i<n; i++)
|
||||
if (!gw_isdigit(cs[i]))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void fixup_recipient(void)
|
||||
{
|
||||
int i;
|
||||
Octstr *typ = NULL;
|
||||
|
||||
|
||||
if (!xto) xto = octstr_imm("");
|
||||
i = octstr_search_char(xto, '@', 0);
|
||||
if (i>0)
|
||||
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"));
|
||||
}
|
|
@ -0,0 +1,488 @@
|
|||
/*
|
||||
* The global queue runner, dispatches messages to email, mobile and to other proxies.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#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 <sendmail> <to> 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); j<m; j++) {
|
||||
MmsProxyRelay *mp = list_get(proxyrelays, j);
|
||||
|
||||
if (!octstr_compare(mp->host, 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;
|
||||
}
|
|
@ -0,0 +1,574 @@
|
|||
/*
|
||||
* The queue runner for dispatching notifications to mobiles via WAP PUSH.
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,897 @@
|
|||
/*
|
||||
* MMS proxy gateway: Receives MMS messages from clients, dispatches to
|
||||
* delivery queues. Also provides interface for collecting messages.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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); i<n; i++) {
|
||||
Octstr *name, *value;
|
||||
http_header_get(l, i, &name, &value);
|
||||
list_append(*xto, value);
|
||||
octstr_destroy(name);
|
||||
|
||||
}
|
||||
http_destroy_headers(l);
|
||||
}
|
||||
|
||||
l = http_header_find_all(mh, "Cc");
|
||||
if (l) {
|
||||
int i, n;
|
||||
for (i = 0, n = list_len(l); i<n; i++) {
|
||||
Octstr *name, *value;
|
||||
http_header_get(l, i, &name, &value);
|
||||
list_append(*xto, value);
|
||||
octstr_destroy(name);
|
||||
|
||||
}
|
||||
http_destroy_headers(l);
|
||||
}
|
||||
|
||||
|
||||
l = http_header_find_all(mh, "Bcc");
|
||||
if (l) {
|
||||
int i, n;
|
||||
|
||||
for (i = 0, n = list_len(l); i<n; i++) {
|
||||
Octstr *name, *value;
|
||||
http_header_get(l, i, &name, &value);
|
||||
list_append(*xto, value);
|
||||
octstr_destroy(name);
|
||||
|
||||
}
|
||||
http_destroy_headers(l);
|
||||
}
|
||||
|
||||
|
||||
*from = http_header_value(mh, octstr_imm("From"));
|
||||
|
||||
|
||||
/* Find expiry and delivery times */
|
||||
if (expiryt) {
|
||||
s = http_header_value(mh, octstr_imm("X-Mms-Expiry"));
|
||||
if (s) {
|
||||
*expiryt = date_parse_http(s);
|
||||
octstr_destroy(s);
|
||||
} else
|
||||
*expiryt = time(NULL) + settings->default_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);
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
timestamp for config.h
|
|
@ -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)
|
Loading…
Reference in New Issue