1
0
Fork 0

Initial import

This commit is contained in:
bagyenda 2005-03-10 08:01:02 +00:00
parent aa50693b59
commit e13e3b0b4b
34 changed files with 15990 additions and 0 deletions

1
mbuni/Makefile.am Normal file
View File

@ -0,0 +1 @@
SUBDIRS = mmlib mmsc

563
mbuni/Makefile.in Normal file
View File

@ -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
mbuni/NEWS Normal file
View File

15
mbuni/Notes Normal file
View File

@ -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
mbuni/README Normal file
View File

View File

@ -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"

6402
mbuni/ltmain.sh Executable file

File diff suppressed because it is too large Load Diff

360
mbuni/missing Executable file
View File

@ -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:

4
mbuni/mmlib/Makefile.am Normal file
View File

@ -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

381
mbuni/mmlib/Makefile.in Normal file
View File

@ -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:

51
mbuni/mmlib/mms_billing.c Normal file
View File

@ -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
};

42
mbuni/mmlib/mms_billing.h Normal file
View File

@ -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

1285
mbuni/mmlib/mms_msg.c Normal file

File diff suppressed because it is too large Load Diff

57
mbuni/mmlib/mms_msg.h Normal file
View File

@ -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

797
mbuni/mmlib/mms_queue.c Normal file
View File

@ -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;
}

107
mbuni/mmlib/mms_queue.h Normal file
View File

@ -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

45
mbuni/mmlib/mms_resolve.c Normal file
View File

@ -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
};

31
mbuni/mmlib/mms_resolve.h Normal file
View File

@ -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

242
mbuni/mmlib/mms_strings.c Normal file
View File

@ -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;
}

191
mbuni/mmlib/mms_strings.def Normal file
View File

@ -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

29
mbuni/mmlib/mms_strings.h Normal file
View File

@ -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

1313
mbuni/mmlib/mms_uaprof.c Normal file

File diff suppressed because it is too large Load Diff

41
mbuni/mmlib/mms_uaprof.h Normal file
View File

@ -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

905
mbuni/mmlib/mms_util.c Normal file
View File

@ -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);
}

159
mbuni/mmlib/mms_util.h Normal file
View File

@ -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

2
mbuni/mmsc/Makefile.am Normal file
View File

@ -0,0 +1,2 @@
bin_PROGRAMS = mmsglobalsender mmsproxy mmsmobilesender mmsfromemail mmssend

425
mbuni/mmsc/Makefile.in Normal file
View File

@ -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:

397
mbuni/mmsc/mmsfromemail.c Normal file
View File

@ -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"));
}

View File

@ -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;
}

View File

@ -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;
}

897
mbuni/mmsc/mmsproxy.c Normal file
View File

@ -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);
}

135
mbuni/mmsc/mmssend.c Normal file
View File

@ -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;
}

1
mbuni/stamp-h1 Normal file
View File

@ -0,0 +1 @@
timestamp for config.h

5
mbuni/todo Normal file
View File

@ -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)