moved mm1 mm7 code into base
parent
6a34ce5ca2
commit
1e14a17e39
|
@ -1,3 +1,5 @@
|
|||
2011-03-24 P. A. Bagyenda <bagyenda@dsmagic.com>
|
||||
* Rolled MM1 MM7 module into main MMSBox code
|
||||
2011-01-28 P. A. Bagyenda <bagyenda@dsmagic.com>
|
||||
* Fix bug in http mmsc module
|
||||
2011-01-12 P. A. Bagyenda <bagyenda@dsmagic.com>
|
||||
|
|
197
mbuni/INSTALL
197
mbuni/INSTALL
|
@ -2,24 +2,18 @@ Installation Instructions
|
|||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
2006 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
This file is free documentation; the Free Software Foundation gives
|
||||
unlimited permission to copy, distribute and modify it.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
instructions specific to this package.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
|
@ -48,7 +42,7 @@ may remove or edit it.
|
|||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
@ -59,22 +53,12 @@ of `autoconf'.
|
|||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
the package.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
documentation.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
5. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
|
@ -83,22 +67,12 @@ of `autoconf'.
|
|||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
Some systems require unusual options for compilation or linking that the
|
||||
`configure' script does not know about. Run `./configure --help' for
|
||||
details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
|
@ -111,41 +85,25 @@ is an example:
|
|||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
`configure' the option `--prefix=PREFIX'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
|
@ -156,47 +114,16 @@ Documentation and other data files still use the regular prefix.
|
|||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
you can set and what kinds of files go in them.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
|
@ -208,53 +135,14 @@ find the X include and library files automatically, but if it doesn't,
|
|||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
There may be some features `configure' cannot figure out automatically,
|
||||
but needs to determine by the type of machine the package will run on.
|
||||
Usually, assuming the package is built to be run on the _same_
|
||||
architectures, `configure' can figure that out, but if it prints a
|
||||
message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
|
@ -262,8 +150,7 @@ type, such as `sun4', or a canonical name which has the form:
|
|||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
OS KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
|
@ -281,9 +168,9 @@ eventually be run) with `--host=TYPE'.
|
|||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
If you want to set default values for `configure' scripts to share, you
|
||||
can create a site shell script called `config.site' that gives default
|
||||
values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
|
@ -292,7 +179,7 @@ A warning: not all `configure' scripts look for a site script.
|
|||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
|
@ -311,19 +198,11 @@ an Autoconf bug. Until the bug is fixed you can use this workaround:
|
|||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
`configure' recognizes the following options to control how it operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
|
@ -350,16 +229,6 @@ operates.
|
|||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
|
|
|
@ -350,7 +350,10 @@ if test "$CURL_CONFIG" != "no"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB([curl], [curl_global_init], [has_libcurl=true])
|
||||
AC_CHECK_LIB([curl], [curl_global_init], [
|
||||
CFLAGS="-DHAVE_LIBCURL=1 $CFLAGS";
|
||||
has_libcurl=true
|
||||
])
|
||||
|
||||
AM_CONDITIONAL([BUILD_MMSBOXMM1], [test x$has_libcurl = xtrue])
|
||||
|
||||
|
|
|
@ -21,12 +21,17 @@ incoming-port = 12345
|
|||
type = soap
|
||||
|
||||
# Sample conf for MMSBox using a modem (MM1)
|
||||
#group = mmsc
|
||||
#id = modem
|
||||
#type = custom
|
||||
#custom-settings = "smsc-on=lynx -dump 'http://localhost:13000/start-smsc?password=bar&smsc=nokia-modem';smsc-off=lynx -dump 'http://localhost:13000/stop-smsc?password=bar&smsc=nokia-modem';gprs-on=/usr/local/sbin/start-net-gprs;gprs-pid=cat /var/run/ppp-net.pid|head -1;port=13014;mmsc-url=http://net.mmsc/servlets/mms;proxy=10.11.12.13:8080;msisdn=100"
|
||||
#mmsc-library = /usr/local/lib/libmmsbox_mm1.so
|
||||
|
||||
group = mmsc
|
||||
id = modem
|
||||
type = mm1
|
||||
mm1-sms-on-command = lynx -dump 'http://localhost:13000/start-smsc?password=bar&smsc=nokia-modem'
|
||||
mm1-sms-off-command = lynx -dump 'http://localhost:13000/stop-smsc?password=bar&smsc=nokia-modem'
|
||||
mm1-msisdn = "100"
|
||||
mm1-http-proxy = 10.11.12.13:8080
|
||||
incoming-port = 13014
|
||||
mmsc-url = http://net.mmsc/servlets/mms
|
||||
mm1-gprs-on-command = /usr/local/sbin/start-net-gprs
|
||||
mm1-gprs-pid-command = "cat /var/run/ppp-net.pid|head -1"
|
||||
|
||||
group = mms-service
|
||||
name = me
|
||||
|
|
|
@ -285,7 +285,7 @@ provisioned, etc.
|
|||
<li>Operating as a <b>VAS Gateway</b>, Mbuni provides:
|
||||
|
||||
<ul>
|
||||
<li> Support for SOAP, EAIF and MM4 connectivity with an operator
|
||||
<li> Support for SOAP, EAIF, MM1 and MM4 connectivity with an operator
|
||||
MMSC (plus a special HTTP-based relay mechanism)
|
||||
<li> Multiple connections to different MMSC of different types can
|
||||
be maintained
|
||||
|
@ -2488,15 +2488,23 @@ Supported configuration parameters are:
|
|||
<td valign=top >
|
||||
Mandatory:
|
||||
Protocol spoken by this MMSC, one of <tt>soap</tt> for 3GPP MM7
|
||||
SOAP, <tt>eaif</tt> for Nokia EAIF protocol, <tt>mm4</t> for 3GPP
|
||||
SOAP, <tt>eaif</tt> for Nokia EAIF protocol, <tt>mm4</tt> for 3GPP
|
||||
MM4, <tt>http</tt> for
|
||||
special HTTP-based inter-mmsbox message relay (see below), or <tt>custom</tt> for
|
||||
special HTTP-based inter-mmsbox message relay (see
|
||||
below), <tt>mm1</tt> for GPRS/3G modem access to an operator MMSC, or <tt>custom</tt> for
|
||||
a custom implementation handled by a loadable module (see
|
||||
<tt>mmsc-library</tt> below).<br> For <tt>type = http</tt> the VAS GW
|
||||
will forward the message to the URL provided using HTTP POST, with
|
||||
CGI parameters: <tt>mms</tt> – the binary mms, <tt>from</tt>
|
||||
– the sender address, <tt>to</tt> – the recipient
|
||||
address. This allows fast inter-mmsbox message exchange.
|
||||
address. This allows fast inter-mmsbox message
|
||||
exchange. <br>For <tt>type=mm1</tt> it is expected
|
||||
that <tt>mmsbox</tt> will send/receive messages directly from the
|
||||
operator using an attached modem. To receive MMS, Kannel (or similar
|
||||
SMS Gateway) must pass all received SMS to Mbuni via the
|
||||
MMSC <tt>port</tt>. To send MMS, Mbuni will use
|
||||
the <tt>mm1-sms-off-command</tt> (see below) to temporarily shutdown
|
||||
the SMS Gateway, and then use the modem to send MMS
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -2598,7 +2606,10 @@ Supported configuration parameters are:
|
|||
</td>
|
||||
<td valign=top >
|
||||
Port at which Mbuni listens for incoming messages from MMSC. Not
|
||||
used for MM4 incoming connections (<tt>mm4-port</tt> is used instead).
|
||||
used for MM4 incoming connections (<tt>mm4-port</tt> is used
|
||||
instead). For <tt>mm1</tt> MMSCs this is the port to which (MO) MMS
|
||||
notification messages should be routed. In this case, the
|
||||
notification SMS should be contained in a <tt>text</tt> CGI parameter.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -2888,6 +2899,132 @@ string
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-http-proxy</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
HTTP Proxy (in the form <i>host:port</i> to be used when sending MMS to the MMSC. (<tt>mm1</tt> MMSC only)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-http-proxy</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
HTTP Proxy (in the form <i>host:port</i>) to be used when sending MMS to the MMSC. (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-gprs-on-command</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
Command <tt>mmsbox</tt> will call to start a GPRS/3G operator
|
||||
connection when sending MT MMS via the <tt>mm1</tt> type. This
|
||||
command typically invokes <tt>pppd</tt> with suitable
|
||||
parameters. <b>NOTE</b>: This command should return immediately
|
||||
(i.e. it shouldn't block). (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-gprs-off-command</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
Command <tt>mmsbox</tt> will call to stop the GPRS/3G operator
|
||||
connection after sending MT MMS via the <tt>mm1</tt> type. This
|
||||
command typically kills the <tt>pppd</tt> in charge of the
|
||||
connection started with the command above. (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-gprs-pid-command</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
Command <tt>mmsbox</tt> will call to determine the ID of
|
||||
the process controlling the GPRS/3G operator
|
||||
connection after it is started. If this option is provided, then
|
||||
a <tt>kill(2)</tt> will be used to terminate the GPRS/3G
|
||||
connection, rather than the <tt>mm1-gprs-off-command</tt>. (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-sms-off-command</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
Command <tt>mmsbox</tt> will call to stop the SMS Gateway modem link, just
|
||||
before starting the GPRS/3G operator
|
||||
connection. Because MO MMS is received as (SMS) notifications, the
|
||||
modem must be shared with the SMS Gateway (such as Kannel). When a
|
||||
notification is received by <tt>mmsbox</tt>, we must shutdown the
|
||||
SMS Gateway's connection to the modem (typically, if using Kannel,
|
||||
this means a call to the admin interface), fetch the MMS (via a
|
||||
GPRS/3G connection initiated using the same modem), and then turn
|
||||
SMS reception back on (see below). (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-sms-on-command</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
Command <tt>mmsbox</tt> will call to start the SMS Gateway modem
|
||||
link, once <tt>mmsbox</tt> has completed fetching MO MMS or sending
|
||||
MT MMS via a GPRS/3G operator
|
||||
connection. Typically, if using Kannel,
|
||||
this means a call to the Kannel admin interface to start the
|
||||
specific modem SMSC link. (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign=top >
|
||||
<tt>mm1-ua-string</tt>
|
||||
</td>
|
||||
<td valign=top >
|
||||
String
|
||||
</td>
|
||||
<td valign=top >
|
||||
HTTP USer Agent String to send to MMSC in HTTP requests (e.g. "Mozilla/5.0 (SymbianOS/9.4;U;
|
||||
Series60/5.0 Nokia5800d-1/52.50.2008.24;
|
||||
Profile/MIDP-2.1Configuration/CLDC-1.1 )
|
||||
AppleWebKit/413 (KHTML, like Gecko)
|
||||
Safari/413" to fake a request as
|
||||
a Nokia 5800). This is
|
||||
useful if the MMSC transcodes MT MMS based on the receiver type. (<tt>mm1</tt> MMSC only.)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ typedef struct {
|
|||
long h_tid, d_tid; /* thread IDs. */
|
||||
|
||||
int sender_alive;
|
||||
|
||||
} MM1Settings;
|
||||
|
||||
typedef struct {
|
||||
|
@ -99,15 +100,15 @@ static int open_mm1(MmscGrp *mmc, MmsQueueHandlerFuncs *qfs,
|
|||
proxy = value;
|
||||
else if (octstr_str_case_compare(item, "gprs-on") == 0)
|
||||
gprs_on = value;
|
||||
else if (octstr_str_case_compare(item, "gprs-off") == 0)
|
||||
gprs_off = value;
|
||||
else if (octstr_str_case_compare(item, "gprs-off") == 0)
|
||||
gprs_off = value;
|
||||
else if (octstr_str_case_compare(item, "gprs-pid") == 0)
|
||||
gprs_pid = value;
|
||||
else if (octstr_str_case_compare(item, "port") == 0) {
|
||||
port = value ? atoi(octstr_get_cstr(value)) : 80;
|
||||
if (http_open_port(port, 0) != 0)
|
||||
mms_warning(0, "mmsbox-mm1", NULL, "failed to open incoming notifications port %d: %s",
|
||||
port, strerror(errno));
|
||||
port, strerror(errno));
|
||||
}else if (octstr_str_case_compare(item, "http-interface") == 0)
|
||||
interface = value;
|
||||
else if (octstr_str_case_compare(item, "smsc-on") == 0)
|
||||
|
@ -229,7 +230,7 @@ static void handle_notify(MM1Settings *mm1)
|
|||
dlr_url = mmsbox_get_report_info(m, mm1->info, mmc_id,
|
||||
(mtype == MMS_MSGTYPE_DELIVERY_IND) ?
|
||||
"delivery-report" : "read-report",
|
||||
status_value, rqh, NULL, 0, msgid);
|
||||
status_value, rqh, NULL, 0, msgid);
|
||||
|
||||
qf = mm1->qfs->mms_queue_add(from, to, NULL,
|
||||
mm1->info->id, mmc_id,
|
||||
|
@ -308,9 +309,9 @@ static void handle_notify(MM1Settings *mm1)
|
|||
|
||||
|
||||
static Octstr *send_msg(void *data, Octstr *from, Octstr *to,
|
||||
Octstr *transid,
|
||||
Octstr *linkedid, char *vasid, Octstr *service_code,
|
||||
MmsMsg *m, List *hdrs, Octstr **err, int *retry)
|
||||
Octstr *transid,
|
||||
Octstr *linkedid, char *vasid, Octstr *service_code,
|
||||
MmsMsg *m, List *hdrs, Octstr **err, int *retry)
|
||||
{
|
||||
MM1Request *r = gw_malloc(sizeof *r);
|
||||
MM1Settings *s = data;
|
||||
|
@ -348,13 +349,13 @@ static Octstr *send_msg(void *data, Octstr *from, Octstr *to,
|
|||
|
||||
id = r->result;
|
||||
mms_info(0, "mmsbox-mm1", NULL, "sent message, type=%s, result=%s",
|
||||
mms_message_type_to_cstr(mms_messagetype(m)), r->error ? octstr_get_cstr(r->error) : "(none)");
|
||||
mms_message_type_to_cstr(mms_messagetype(m)), r->error ? octstr_get_cstr(r->error) : "(none)");
|
||||
/* destroy the structure. */
|
||||
if(r->error && (octstr_compare(r->error, octstr_imm("Error-service-denied")) == 0 ||
|
||||
octstr_compare(r->error, octstr_imm("Error-permanent-failure")) == 0))
|
||||
*retry = 0;
|
||||
*retry = 0;
|
||||
else
|
||||
*retry = 1;
|
||||
*retry = 1;
|
||||
|
||||
pthread_cond_destroy(&r->cond);
|
||||
pthread_mutex_destroy(&r->mutex);
|
||||
|
@ -382,7 +383,8 @@ static void handle_mm1(MM1Settings *mm1)
|
|||
pid = start_gprs(mm1->gprs_on, mm1->gprs_pid);
|
||||
|
||||
if (pid < 0) {
|
||||
mms_warning(0, "mmsbox-mm1", NULL,"failed to start GPRS connection. waiting...");
|
||||
mms_warning(0, "mmsbox-mm1", NULL,
|
||||
"Failed to start GPRS connection. waiting...");
|
||||
gwthread_sleep(2);
|
||||
goto kill_gprs;
|
||||
} else
|
||||
|
@ -408,7 +410,7 @@ static void handle_mm1(MM1Settings *mm1)
|
|||
if (r->type == MM1_GET) {
|
||||
if (m == NULL)
|
||||
mms_error(0, "mmsbox-mm1", NULL, "failed to fetch mms from URL: %s!",
|
||||
octstr_get_cstr(url));
|
||||
octstr_get_cstr(url));
|
||||
else {
|
||||
List *mh = mms_message_headers(m), *to = gwlist_create();
|
||||
Octstr *subject = NULL, *otransid = NULL, *msgid = NULL, *value;
|
||||
|
@ -466,7 +468,7 @@ static void handle_mm1(MM1Settings *mm1)
|
|||
msgid, NULL, mm1->info->id, "MMSBox",octstr_imm("MM1"), NULL);
|
||||
else
|
||||
mms_error(0, "mmsbox-mm1", NULL, "failed to create queue entry for URL %s",
|
||||
octstr_get_cstr(url));
|
||||
octstr_get_cstr(url));
|
||||
|
||||
if (otransid) { /* tell mmsc that we fetched fine. */
|
||||
int _status;
|
||||
|
@ -504,17 +506,17 @@ static void handle_mm1(MM1Settings *mm1)
|
|||
(r->result = mms_get_header_value(m, octstr_imm("Message-ID"))) == NULL ||
|
||||
octstr_compare(mms_get_header_value(m, octstr_imm("X-Mms-Response-Status")),
|
||||
octstr_imm("Ok")) != 0
|
||||
) {
|
||||
) {
|
||||
Octstr *err = m ? mms_get_header_value(m, octstr_imm("X-Mms-Response-Text")) : NULL;
|
||||
Octstr *status = m ? mms_get_header_value(m, octstr_imm("X-Mms-Response-Status")) : NULL;
|
||||
if(status && (octstr_compare(status, octstr_imm("Error-service-denied")) == 0 ||
|
||||
octstr_compare(status, octstr_imm("Error-permanent-failure")) == 0)) {
|
||||
r->error = octstr_duplicate(status);
|
||||
r->error = octstr_duplicate(status);
|
||||
}
|
||||
r->result = NULL; /* indicate failure to bearerbox */
|
||||
mms_error(0, "mmsbox-mm1", NULL, "Sending failed: %s, %s!",
|
||||
err ? octstr_get_cstr(err) : "(none)",
|
||||
status ? octstr_get_cstr(status) : "(none)");
|
||||
err ? octstr_get_cstr(err) : "(none)",
|
||||
status ? octstr_get_cstr(status) : "(none)");
|
||||
octstr_destroy(err);
|
||||
octstr_destroy(status);
|
||||
}
|
||||
|
@ -535,8 +537,8 @@ static void handle_mm1(MM1Settings *mm1)
|
|||
int st;
|
||||
wp = waitpid(pid, &st, WNOHANG);
|
||||
if(wp == pid && WIFEXITED(st)) {
|
||||
mms_info(0, "mmsbox-mm1", NULL, "GPRS pid (%d) appears to be dead - quitting loop", pid);
|
||||
goto after_gprs_dead;
|
||||
mms_info(0, "mmsbox-mm1", NULL, "GPRS pid (%d) appears to be dead - quitting loop", pid);
|
||||
goto after_gprs_dead;
|
||||
}
|
||||
gwthread_sleep(2); /* according to Piotr Isajew, this makes life better */
|
||||
} while (gwlist_len(mm1->requests) > 0 &&
|
||||
|
@ -544,19 +546,19 @@ static void handle_mm1(MM1Settings *mm1)
|
|||
|
||||
kill_gprs:
|
||||
if(r != NULL) {
|
||||
if(r->waiter_exists) {
|
||||
pthread_mutex_unlock(&r->mutex);
|
||||
pthread_cond_signal(&r->cond);
|
||||
} else{
|
||||
gw_free(r);
|
||||
}
|
||||
if(r->waiter_exists) {
|
||||
pthread_mutex_unlock(&r->mutex);
|
||||
pthread_cond_signal(&r->cond);
|
||||
} else{
|
||||
gw_free(r);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (mm1->gprs_off) {
|
||||
stop_gprs(mm1->gprs_off);
|
||||
} else if (pid > 0) { /* stop GPRS, restart SMSC connection. */
|
||||
} else if (pid > 0) { /* stop GPRS, restart SMSC connection. */
|
||||
int xkill, status;
|
||||
pid_t wpid;
|
||||
do {
|
||||
|
@ -627,7 +629,8 @@ static int write_octstr_data(void *buffer, size_t size, size_t nmemb, void *user
|
|||
Octstr *out = userp;
|
||||
|
||||
octstr_append_data(out, buffer, size*nmemb);
|
||||
mms_info(0, "mmsbox-mm1", NULL, "write_data called with nmemn=%ld, size=%ld", nmemb, size);
|
||||
mms_info(0, "mmsbox-mm1", NULL, "write_data called with nmemn=%ld, size=%ld",
|
||||
nmemb, size);
|
||||
return size*nmemb;
|
||||
}
|
||||
|
||||
|
@ -658,6 +661,11 @@ static Octstr *fetch_content(Octstr *url, Octstr *proxy, Octstr *body, int *hsta
|
|||
h = curl_slist_append(h, "Accept: */*");
|
||||
if (body) { /* POST. */
|
||||
h = curl_slist_append(h, "Content-Type: application/vnd.wap.mms-message");
|
||||
h = curl_slist_append(h, "User-Agent: Mozilla/5.0 (SymbianOS/9.4;U;"
|
||||
"Series60/5.0 Nokia5800d-1/52.50.2008.24;"
|
||||
"Profile/MIDP-2.1Configuration/CLDC-1.1 ) "
|
||||
"AppleWebKit/413 (KHTML, like Gecko) "
|
||||
"Safari/413");
|
||||
curl_easy_setopt(cl, CURLOPT_POSTFIELDS, octstr_get_cstr(body));
|
||||
curl_easy_setopt(cl, CURLOPT_POSTFIELDSIZE, octstr_len(body));
|
||||
}
|
||||
|
@ -668,10 +676,12 @@ static Octstr *fetch_content(Octstr *url, Octstr *proxy, Octstr *body, int *hsta
|
|||
|
||||
*hstatus = curl_easy_perform(cl); /* post away! */
|
||||
if (*hstatus != 0)
|
||||
mms_error(0, "mmsbox-mm1", NULL, "failed to fetch/post content: %.256s",
|
||||
errbuf);
|
||||
mms_error(0, "mmsbox-mm1", NULL, "failed to fetch/post content to host %s [proxy: %s] [http_status=%d] : %.256s",
|
||||
octstr_get_cstr(url), octstr_len(proxy) > 0 ? octstr_get_cstr(proxy) : "n/a",
|
||||
*hstatus, errbuf);
|
||||
|
||||
curl_slist_free_all(h); /* free the header list */
|
||||
curl_easy_setopt(cl, CURLOPT_NOSIGNAL, 0L);
|
||||
curl_easy_cleanup(cl);
|
||||
|
||||
return s;
|
||||
|
@ -681,21 +691,21 @@ static Octstr *fetch_content(Octstr *url, Octstr *proxy, Octstr *body, int *hsta
|
|||
|
||||
static void stop_gprs(Octstr *cmd)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
/* in child */
|
||||
List *l = octstr_split_words(cmd);
|
||||
int i, n = gwlist_len(l);
|
||||
char **args = gw_malloc((n+1) * sizeof *args);
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
/* in child */
|
||||
List *l = octstr_split_words(cmd);
|
||||
int i, n = gwlist_len(l);
|
||||
char **args = gw_malloc((n+1) * sizeof *args);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
Octstr *x = gwlist_get(l, i);
|
||||
args[i] = octstr_get_cstr(x);
|
||||
printf("arg %d: %s\n", i, args[i]);
|
||||
}
|
||||
args[i] = NULL;
|
||||
printf("Not reached: %d!", execvp(args[0], args));
|
||||
}
|
||||
for (i = 0; i < n; i++) {
|
||||
Octstr *x = gwlist_get(l, i);
|
||||
args[i] = octstr_get_cstr(x);
|
||||
printf("arg %d: %s\n", i, args[i]);
|
||||
}
|
||||
args[i] = NULL;
|
||||
printf("Not reached: %d!", execvp(args[0], args));
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_GPRS_WAIT 80
|
||||
|
@ -719,21 +729,21 @@ static long start_gprs(Octstr *cmd, Octstr *pid_cmd)
|
|||
}
|
||||
cpid = waitpid(pid, &status, WNOHANG); /* also wait for the child. */
|
||||
mms_info(0, "mmsbox-mm1", NULL, "waiting for connection: %d, pid=%ld cpid=%ld, ifexited=%d, exitstatus=%d",
|
||||
ct, (long)pid, cpid, WIFEXITED(status), WEXITSTATUS(status));
|
||||
ct, (long)pid, cpid, WIFEXITED(status), WEXITSTATUS(status));
|
||||
if (cpid == pid &&
|
||||
WIFEXITED(status))
|
||||
return -1;
|
||||
return -1;
|
||||
} while (GPRS_POLL*ct++ < MAX_GPRS_WAIT);
|
||||
/* Timed out, but still need to wait for child pid, as
|
||||
start-gprs script is still running and we don't need a
|
||||
zombie */
|
||||
start-gprs script is still running and we don't need a
|
||||
zombie */
|
||||
pid_t rpid;
|
||||
int st;
|
||||
|
||||
rpid = waitpid(pid, &st, 0);
|
||||
mms_info(0, "mmsbox-mm1", NULL, "pid %d terminated", pid);
|
||||
return -1;
|
||||
} else if (pid == 0) { /* child. */
|
||||
} else if (pid == 0) { /* child. */
|
||||
List *l = octstr_split_words(cmd);
|
||||
int i, n = gwlist_len(l);
|
||||
char **args = gw_malloc((n+1) * sizeof *args);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
noinst_LIBRARIES = libmms.a
|
||||
libmms_a_SOURCES = mms_eventlogger.c mms_mmbox.c mms_msg.c mms_queue.c mms_strings.c mms_uaprof.c mms_util.c mms_mm7soap.c mms_cfg.c
|
||||
libmms_a_SOURCES = charmibenum.def mms_eventlogger.c mms_mmbox.c mms_msg.c mms_queue.c mms_strings.c mms_uaprof.c mms_util.c mms_mm7soap.c mms_cfg.c
|
||||
|
||||
EXTRA_DIST=mms_strings.def mms_eventlogger.h mms_mm7soap.h mms_mmbox.h mms_msg.h mms_queue.h mms_strings.h mms_uaprof.h mms_util.h mms_cfg.h mms_cfg.def mms_cfg-impl.h
|
||||
|
|
|
@ -198,6 +198,14 @@ MULTI_GROUP(mmsc,
|
|||
OCTSTR(max-recipients)
|
||||
|
||||
OCTSTR(strip-prefixes)
|
||||
OCTSTR(mm1-http-proxy)
|
||||
OCTSTR(mm1-gprs-on-command)
|
||||
OCTSTR(mm1-gprs-off-command)
|
||||
OCTSTR(mm1-gprs-pid-command)
|
||||
OCTSTR(mm1-sms-on-command)
|
||||
OCTSTR(mm1-sms-off-command)
|
||||
OCTSTR(mm1-msisdn)
|
||||
OCTSTR(mm1-ua-string)
|
||||
)
|
||||
|
||||
MULTI_GROUP(mms-service,
|
||||
|
|
|
@ -1784,7 +1784,7 @@ int mms_url_fetch_content(int method, Octstr *url, List *request_headers,
|
|||
if (octstr_search(url, octstr_imm("data:"), 0) == 0) {
|
||||
int i = octstr_search_char(url, ',',0);
|
||||
Octstr *ctype = (i >= 0) ? octstr_copy(url, 5, i-5) : octstr_create("text/plain; charset=us-ascii");
|
||||
Octstr *data = (i >= 0) ? octstr_copy(url, i+1, octstr_len(url)) : octstr_duplicate(url);
|
||||
Octstr *data = (i >= 0) ? octstr_copy(url, i+1, octstr_len(url)) : octstr_copy(url,5,octstr_len(url));
|
||||
|
||||
Octstr *n = NULL, *h = NULL;
|
||||
|
||||
|
|
|
@ -1018,7 +1018,7 @@ done:
|
|||
return http_status_class(hstatus) == HTTP_STATUS_SUCCESSFUL ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
static int mm7mm1_receive(MmsBoxHTTPClientInfo *);
|
||||
static void dispatch_mm7_recv(List *rl)
|
||||
{
|
||||
|
||||
|
@ -1026,9 +1026,10 @@ static void dispatch_mm7_recv(List *rl)
|
|||
|
||||
/* hmon->register_thread( "dispatch_mm7" ); */
|
||||
while ((h = gwlist_consume(rl)) != NULL) {
|
||||
int ret = -1, has_auth = 0;
|
||||
MmscGrp *m = h->m;
|
||||
if (auth_check(m->incoming.user,
|
||||
int ret = -1, has_auth = (m->type != MM1_MMSC); /* We dont authenticate mm1. right? */
|
||||
|
||||
if (!has_auth && auth_check(m->incoming.user,
|
||||
m->incoming.pass,
|
||||
h->headers, &has_auth) != 0) { /* Ask it to authenticate... */
|
||||
List *hh = http_create_empty_headers();
|
||||
|
@ -1047,7 +1048,9 @@ static void dispatch_mm7_recv(List *rl)
|
|||
ret = mm7soap_receive(h);
|
||||
else if (h->m->type == EAIF_MMSC)
|
||||
ret = mm7eaif_receive(h);
|
||||
else
|
||||
else if (h->m->type == MM1_MMSC)
|
||||
ret = mm7mm1_receive(h);
|
||||
else
|
||||
ret = mm7http_receive(h);
|
||||
|
||||
h->m->last_pdu = time(NULL);
|
||||
|
@ -1503,7 +1506,10 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static Octstr *mm7mm1_send(MmscGrp *mmc, Octstr *from, List *lto,
|
||||
Octstr *transid,
|
||||
Octstr *linkedid, char *vasid, Octstr *service_code,
|
||||
MmsMsg *m, List *hdrs, Octstr **err, int *retry);
|
||||
static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e,
|
||||
List *lto, /* Of Octstr * */
|
||||
Octstr *orig_transid,
|
||||
|
@ -1531,6 +1537,9 @@ static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e,
|
|||
id = mm7eaif_send(mmc, from, lto, transid, vasid, e, m, &err, &retry);
|
||||
else if (mmc->type == HTTP_MMSC)
|
||||
id = mm7http_send(mmc,e, from, lto, m, &err, &retry);
|
||||
else if (mmc->type == MM1_MMSC)
|
||||
id = mm7mm1_send(mmc, from, lto, transid, linkedid, vasid,
|
||||
service_code, m, hdrs, &err, &retry);
|
||||
else if (mmc->type == CUSTOM_MMSC && mmc->started) {
|
||||
Octstr *to = gwlist_get(lto, 0); /* XXX Send one at a time*/
|
||||
id = mmc->fns->send_msg(mmc->data,
|
||||
|
@ -1629,7 +1638,7 @@ static void process_send_res(MmsEnvelope *e, MmsMsg *msg,
|
|||
to->process = 0; /* No more attempts. */
|
||||
|
||||
|
||||
/* handle CDR */
|
||||
/* handle CDR */
|
||||
if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED || res == MMS_SEND_ERROR_FATAL) {
|
||||
Octstr *mclass = mms_get_header_value(msg, octstr_imm("X-Mms-Message-Class"));
|
||||
Octstr *prio = mms_get_header_value(msg, octstr_imm("X-Mms-Priority"));
|
||||
|
@ -1642,7 +1651,7 @@ static void process_send_res(MmsEnvelope *e, MmsMsg *msg,
|
|||
octstr_get_cstr(e->msgId),
|
||||
mmc ? octstr_get_cstr(mmc->id) : NULL, /* Should we touch mmc here? XXX */
|
||||
e->src_interface,
|
||||
"MM7",
|
||||
"MM7",
|
||||
e->msize,
|
||||
(char *)mms_message_type_to_cstr(e->msgtype),
|
||||
|
||||
|
@ -2147,7 +2156,7 @@ static Octstr *handle_msg(MIMEEntity *mm, Octstr *from, List *to, MmscGrp *mmc)
|
|||
octstr_destroy(subject);
|
||||
octstr_destroy(qf);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case MM4_DELIVERY_REPORT_REQ:
|
||||
{
|
||||
Octstr *qf;
|
||||
|
@ -2174,20 +2183,20 @@ static Octstr *handle_msg(MIMEEntity *mm, Octstr *from, List *to, MmscGrp *mmc)
|
|||
"MM7/MM4-IN",
|
||||
NULL);
|
||||
|
||||
if (qf) {
|
||||
mms_log("DeliveryReport", from, to, -1, msgid, value, mmc->id, "MMSBox", octstr_imm("smtp"), NULL);
|
||||
err = "Ok";
|
||||
res = octstr_duplicate(qf);
|
||||
MMSC_CLEAR_ALARM(mmc, MMSBOX_ALARM_QUEUE_WRITE_ERROR);
|
||||
} else {
|
||||
MMSC_ISSUE_ALARM(mmc, MMSBOX_ALARM_QUEUE_WRITE_ERROR, 4);
|
||||
err = "Error-network-problem";
|
||||
}
|
||||
if (qf) {
|
||||
mms_log("DeliveryReport", from, to, -1, msgid, value, mmc->id, "MMSBox", octstr_imm("smtp"), NULL);
|
||||
err = "Ok";
|
||||
res = octstr_duplicate(qf);
|
||||
MMSC_CLEAR_ALARM(mmc, MMSBOX_ALARM_QUEUE_WRITE_ERROR);
|
||||
} else {
|
||||
MMSC_ISSUE_ALARM(mmc, MMSBOX_ALARM_QUEUE_WRITE_ERROR, 4);
|
||||
err = "Error-network-problem";
|
||||
}
|
||||
|
||||
octstr_destroy(qf);
|
||||
octstr_destroy(value2);
|
||||
octstr_destroy(rr_uri);
|
||||
http_destroy_headers(rqh);
|
||||
octstr_destroy(qf);
|
||||
octstr_destroy(value2);
|
||||
octstr_destroy(rr_uri);
|
||||
http_destroy_headers(rqh);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2237,7 +2246,7 @@ static Octstr *handle_msg(MIMEEntity *mm, Octstr *from, List *to, MmscGrp *mmc)
|
|||
case MM4_READ_REPLY_REPORT_RES:
|
||||
case MM4_DELIVERY_REPORT_RES: /* remove corresponding queue entry. */
|
||||
/* Do nothing */
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
mms_warning(0, "MM4", xproxy, "Unexpected message type: %s",
|
||||
mm4_type ? octstr_get_cstr(mm4_type) : "not given!");
|
||||
|
@ -2255,11 +2264,11 @@ static Octstr *handle_msg(MIMEEntity *mm, Octstr *from, List *to, MmscGrp *mmc)
|
|||
if (mm4_type &&
|
||||
err &&
|
||||
ack && octstr_str_case_compare(ack, "Yes") == 0) {
|
||||
int size = send_mm4_res(mtype+1, orig_sys, me, transid, err, res, octstr_get_cstr(sendmail_cmd));
|
||||
int size = send_mm4_res(mtype+1, orig_sys, me, transid, err, res, octstr_get_cstr(sendmail_cmd));
|
||||
|
||||
mmsbox_event_cb(mmc->id, mm7type >= 0 ? mm7type + 1 : MM7_TAG_VASPErrorRsp,
|
||||
1, octstr_imm("1.0"), 200,
|
||||
size, 0, me, orig_sys, res, NULL, NULL, NULL);
|
||||
mmsbox_event_cb(mmc->id, mm7type >= 0 ? mm7type + 1 : MM7_TAG_VASPErrorRsp,
|
||||
1, octstr_imm("1.0"), 200,
|
||||
size, 0, me, orig_sys, res, NULL, NULL, NULL);
|
||||
} else if (mtype == MM4_FORWARD_REQ) /* Or straight up SMTP */
|
||||
mmsbox_event_cb(mmc->id, mm7type >= 0 ? mm7type + 1 : MM7_TAG_VASPErrorRsp,
|
||||
1, octstr_imm("1.0"), 200,
|
||||
|
@ -2379,25 +2388,25 @@ static void smtp_process(int fd, Octstr *ip,
|
|||
|
||||
clean_address(&from, &isphone, &xproxy);
|
||||
|
||||
/* We now have the sender domain and the number. Find a matching MMSC */
|
||||
if (!isphone || xproxy == NULL)
|
||||
mmc = mmsbox_get_mmsc_by_url(octstr_imm("*"));
|
||||
else
|
||||
mmc = mmsbox_get_mmsc_by_url(xproxy);
|
||||
/* We now have the sender domain and the number. Find a matching MMSC */
|
||||
if (!isphone || xproxy == NULL)
|
||||
mmc = mmsbox_get_mmsc_by_url(octstr_imm("*"));
|
||||
else
|
||||
mmc = mmsbox_get_mmsc_by_url(xproxy);
|
||||
|
||||
/* Check that we have an mmsc and the sender IP is allowed. */
|
||||
if (mmc == NULL || xproxy == NULL ||
|
||||
!is_allowed_ip(mmc->incoming.allow_ip, mmc->incoming.deny_ip, ip)) {
|
||||
conn_write(c, octstr_imm("421 Sender not allowed\r\n"));
|
||||
state = MERROR;
|
||||
} else {
|
||||
/* Check that we have an mmsc and the sender IP is allowed. */
|
||||
if (mmc == NULL || xproxy == NULL ||
|
||||
!is_allowed_ip(mmc->incoming.allow_ip, mmc->incoming.deny_ip, ip)) {
|
||||
conn_write(c, octstr_imm("421 Sender not allowed\r\n"));
|
||||
state = MERROR;
|
||||
} else {
|
||||
|
||||
if (!mmc->strip_domain && isphone)
|
||||
octstr_format_append(from, "@%S", xproxy);
|
||||
conn_write(c, octstr_imm("250 Ok\r\n"));
|
||||
state = MTO;
|
||||
}
|
||||
octstr_destroy(xproxy);
|
||||
if (!mmc->strip_domain && isphone)
|
||||
octstr_format_append(from, "@%S", xproxy);
|
||||
conn_write(c, octstr_imm("250 Ok\r\n"));
|
||||
state = MTO;
|
||||
}
|
||||
octstr_destroy(xproxy);
|
||||
}
|
||||
} else
|
||||
conn_write(c, octstr_imm("500 Error.\r\n"));
|
||||
|
@ -2562,3 +2571,567 @@ void mm4_receive_func(int *sock)
|
|||
|
||||
gwlist_destroy(slist, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* MM1 functions and data */
|
||||
|
||||
typedef struct {
|
||||
enum {MM1_GET, MM1_PUSH} type;
|
||||
int waiter_exists; /* set to true if after handling, should signal and NOT destroy struct.*/
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
union {
|
||||
MmsMsg *m; /* for push. */
|
||||
Octstr *url; /* for get */
|
||||
} u;
|
||||
void *result; /* set to the result for a PUSH */
|
||||
Octstr *err;
|
||||
} MM1Request;
|
||||
|
||||
static long start_gprs(Octstr *cmd, Octstr *id, Octstr *pid_cmd);
|
||||
static Octstr *fetch_content_with_curl(MmscGrp *mmc, Octstr *url, Octstr *body, int *hstatus);
|
||||
static void stop_gprs(Octstr *cmd);
|
||||
|
||||
static Octstr *mm7mm1_send(MmscGrp *mmc, Octstr *from, List *lto,
|
||||
Octstr *transid,
|
||||
Octstr *linkedid, char *vasid, Octstr *service_code,
|
||||
MmsMsg *m, List *hdrs, Octstr **err, int *retry)
|
||||
{
|
||||
MM1Request *r = gw_malloc(sizeof *r);
|
||||
Octstr *id;
|
||||
struct MM1Info_t *s = &mmc->mm1;
|
||||
|
||||
gw_assert(m);
|
||||
|
||||
if (!s->sender_alive) {
|
||||
*err = octstr_imm("internal error, mm1 notify not started!");
|
||||
*retry = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remove the from address first of all, replace the to address as well */
|
||||
mms_replace_header_value(m, "From", "#insert");
|
||||
mms_replace_header_values(m, "To", lto); /* Put in recipient list */
|
||||
mms_remove_headers(m, "Message-ID");
|
||||
|
||||
r->u.m = m;
|
||||
pthread_cond_init(&r->cond, NULL);
|
||||
pthread_mutex_init(&r->mutex, NULL);
|
||||
r->waiter_exists = 1;
|
||||
r->type = MM1_PUSH;
|
||||
r->result = NULL;
|
||||
r->err = NULL;
|
||||
|
||||
pthread_mutex_lock(&r->mutex); /* at pickup, must grab mutex before signalling. otherwise race condition.*/
|
||||
|
||||
gwlist_produce(s->requests, r);
|
||||
|
||||
pthread_cond_wait(&r->cond, &r->mutex);
|
||||
|
||||
*err = r->err;
|
||||
|
||||
id = r->result;
|
||||
mms_info(0, "MM1", mmc->id, "mm1_send: sent message, type=%s, result=%s",
|
||||
mms_message_type_to_cstr(mms_messagetype(m)),
|
||||
r->err ? octstr_get_cstr(r->err) : "(none)");
|
||||
/* destroy the structure. */
|
||||
if(r->err && (octstr_compare(r->err, octstr_imm("Error-service-denied")) == 0 ||
|
||||
octstr_compare(r->err, octstr_imm("Error-permanent-failure")) == 0))
|
||||
*retry = 0;
|
||||
else
|
||||
*retry = 1;
|
||||
|
||||
pthread_cond_destroy(&r->cond);
|
||||
pthread_mutex_destroy(&r->mutex);
|
||||
gw_free(r);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void handle_mm1_mt_requests(MmscGrp *mmsc)
|
||||
{
|
||||
/* stop smsc, start GPRS, transact, stop GPRS, start SMSC. And so on. */
|
||||
MM1Request *r;
|
||||
|
||||
mms_info(0, "MM7", mmsc->id, "handle_mm1 [%s] started", octstr_get_cstr(mmsc->id));
|
||||
mmsc->mm1.sender_alive++;
|
||||
while ((r = gwlist_consume(mmsc->mm1.requests)) != NULL) {
|
||||
long n, pid = -1;
|
||||
if (mmsc->mm1.smsc_off) {
|
||||
n = system(octstr_get_cstr(mmsc->mm1.smsc_off));
|
||||
gwthread_sleep(5); /* allow it to die. */
|
||||
}
|
||||
|
||||
if (mmsc->mm1.gprs_on)
|
||||
pid = start_gprs(mmsc->mm1.gprs_on, mmsc->id, mmsc->mm1.gprs_pid);
|
||||
|
||||
if (pid < 0) {
|
||||
mms_warning(0, "MM7", mmsc->id,
|
||||
"Failed to start GPRS connection. waiting...");
|
||||
gwthread_sleep(2);
|
||||
goto kill_gprs;
|
||||
} else
|
||||
mms_info(0, "MM7", mmsc->id, "handle_mm1 [start_gprs] returned PID: %ld", pid);
|
||||
|
||||
do {
|
||||
Octstr *body;
|
||||
Octstr *url;
|
||||
int hstatus = 0;
|
||||
Octstr *ms;
|
||||
MmsMsg *m;
|
||||
int msize;
|
||||
pid_t wp;
|
||||
int st;
|
||||
|
||||
if (r->waiter_exists)
|
||||
pthread_mutex_lock(&r->mutex); /* grab lock to avoid race condition */
|
||||
|
||||
body = (r->type == MM1_PUSH) ? mms_tobinary(r->u.m) : NULL;
|
||||
url = (r->type == MM1_PUSH) ? mmsc->mmsc_url : r->u.url;
|
||||
ms = fetch_content_with_curl(mmsc, url, body, &hstatus);
|
||||
msize = ms ? octstr_len(ms) : 0;
|
||||
m = (hstatus == 0 && ms) ? mms_frombinary(ms, mmsc->mm1.msisdn) : NULL;
|
||||
|
||||
if (r->type == MM1_GET) {
|
||||
if (m == NULL)
|
||||
mms_error(0, "MM7", mmsc->id, "failed to fetch mms from URL: %s!",
|
||||
octstr_get_cstr(url));
|
||||
else {
|
||||
List *mh = mms_message_headers(m), *to = gwlist_create();
|
||||
Octstr *subject = NULL, *otransid = NULL, *msgid = NULL, *value;
|
||||
Octstr *hfrom = mh ? http_header_value(mh, octstr_imm("From")) : octstr_imm("anon@anon");
|
||||
Octstr *qf = NULL, *qdir = NULL, *mmc_id = NULL;
|
||||
time_t expiryt = -1, deliveryt = -1;
|
||||
int dlr;
|
||||
|
||||
/* we assume it is a true message (send_req|retrieve_conf) */
|
||||
mms_collect_envdata_from_msgheaders(mh, &to, &subject,
|
||||
&otransid, &expiryt, &deliveryt,
|
||||
DEFAULT_EXPIRE, -1,
|
||||
octstr_get_cstr(unified_prefix),
|
||||
strip_prefixes);
|
||||
|
||||
msgid = http_header_value(mh, octstr_imm("Message-ID"));
|
||||
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;
|
||||
octstr_destroy(value);
|
||||
|
||||
if (deliveryt < 0)
|
||||
deliveryt = time(NULL);
|
||||
|
||||
if (expiryt < 0)
|
||||
expiryt = time(NULL) + DEFAULT_EXPIRE;
|
||||
|
||||
if (hfrom == NULL)
|
||||
hfrom = http_header_value(mh, octstr_imm("From"));
|
||||
|
||||
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");
|
||||
|
||||
qdir = get_mmsbox_queue_dir(hfrom, to, mmsc, &mmc_id); /* get routing info. */
|
||||
/* Save it, put message id in header, return. */
|
||||
qf = qfs->mms_queue_add(hfrom, to, subject,
|
||||
mmsc->id, mmc_id,
|
||||
deliveryt, expiryt, m, NULL,
|
||||
NULL, NULL,
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
dlr,
|
||||
octstr_get_cstr(qdir),
|
||||
"MM7/MM1-IN",
|
||||
octstr_imm(MM_NAME));
|
||||
|
||||
if (qf) {
|
||||
/* Log to access log */
|
||||
mms_log("Received", hfrom, to, msize,
|
||||
msgid, NULL, mmsc->id, "MMSBox",octstr_imm("MM1"), NULL);
|
||||
MMSC_CLEAR_ALARM(mmsc, MMSBOX_ALARM_QUEUE_WRITE_ERROR);
|
||||
} else {
|
||||
mms_error(0, "MM7", mmsc->id, "handle_mm1: failed to create queue entry for URL %s",
|
||||
octstr_get_cstr(url));
|
||||
MMSC_ISSUE_ALARM(mmsc, MMSBOX_ALARM_QUEUE_WRITE_ERROR, 4);
|
||||
}
|
||||
|
||||
if (otransid) { /* tell mmsc that we fetched fine. */
|
||||
int _status;
|
||||
MmsMsg *mresp = mms_notifyresp_ind(octstr_get_cstr(otransid),
|
||||
mms_message_enc(m), "Retrieved", 1);
|
||||
Octstr *sm = mms_tobinary(mresp);
|
||||
Octstr *_x = fetch_content_with_curl(mmsc,
|
||||
NULL,
|
||||
sm,
|
||||
&_status);
|
||||
|
||||
octstr_destroy(_x);
|
||||
octstr_destroy(sm);
|
||||
mms_destroy(mresp);
|
||||
}
|
||||
gwlist_destroy(to, (void *)octstr_destroy);
|
||||
octstr_destroy(hfrom);
|
||||
octstr_destroy(subject);
|
||||
octstr_destroy(otransid);
|
||||
octstr_destroy(msgid);
|
||||
octstr_destroy(qf);
|
||||
octstr_destroy(mmc_id);
|
||||
|
||||
http_destroy_headers(mh);
|
||||
}
|
||||
octstr_destroy(r->u.url); /* For GET only, because caller doesn't wait */
|
||||
} else if (r->type == MM1_PUSH) {
|
||||
Octstr *xs = NULL;
|
||||
/* we expect a send-conf. */
|
||||
if (ms) {
|
||||
octstr_dump(ms, 0);
|
||||
|
||||
mms_msgdump(m, 1);
|
||||
} else
|
||||
mms_warning(0, "MM7", mmsc->id,"handle_mm1: No send-conf returned by operator");
|
||||
|
||||
if (m == NULL ||
|
||||
(r->result = mms_get_header_value(m, octstr_imm("Message-ID"))) == NULL ||
|
||||
octstr_compare((xs = mms_get_header_value(m, octstr_imm("X-Mms-Response-Status"))),
|
||||
octstr_imm("Ok")) != 0) {
|
||||
Octstr *err = m ? mms_get_header_value(m, octstr_imm("X-Mms-Response-Text")) : NULL;
|
||||
Octstr *status = m ? mms_get_header_value(m, octstr_imm("X-Mms-Response-Status")) : NULL;
|
||||
if(status && (octstr_compare(status, octstr_imm("Error-service-denied")) == 0 ||
|
||||
octstr_compare(status, octstr_imm("Error-permanent-failure")) == 0)) {
|
||||
r->err = octstr_duplicate(status);
|
||||
}
|
||||
r->result = NULL; /* indicate failure to bearerbox */
|
||||
mms_error(0, "MM7", mmsc->id, "Sending failed: %s, %s!",
|
||||
err ? octstr_get_cstr(err) : "(none)",
|
||||
status ? octstr_get_cstr(status) : "(none)");
|
||||
octstr_destroy(err);
|
||||
octstr_destroy(status);
|
||||
}
|
||||
octstr_destroy(xs);
|
||||
} else
|
||||
mms_error(0, "MM7", mmsc->id, "unknown type: %d", r->type);
|
||||
|
||||
if (r->waiter_exists) {
|
||||
pthread_mutex_unlock(&r->mutex);
|
||||
pthread_cond_signal(&r->cond);
|
||||
} else /* no waiter, so we free it ourselves. */
|
||||
gw_free(r);
|
||||
|
||||
octstr_destroy(body);
|
||||
octstr_destroy(ms);
|
||||
mms_destroy(m);
|
||||
r = NULL;
|
||||
|
||||
if (pid > 0) {
|
||||
wp = waitpid(pid, &st, WNOHANG);
|
||||
if(wp == pid && WIFEXITED(st)) {
|
||||
mms_info(0, "MM7", mmsc->id, "GPRS pid (%d) appears to be dead - quitting loop", pid);
|
||||
goto after_gprs_dead;
|
||||
}
|
||||
}
|
||||
gwthread_sleep(2); /* according to Piotr Isajew, this makes life better */
|
||||
} while (gwlist_len(mmsc->mm1.requests) > 0 &&
|
||||
(r = gwlist_consume(mmsc->mm1.requests)) != NULL);
|
||||
|
||||
kill_gprs:
|
||||
if(r != NULL) {
|
||||
if(r->waiter_exists) {
|
||||
pthread_mutex_unlock(&r->mutex);
|
||||
pthread_cond_signal(&r->cond);
|
||||
} else{
|
||||
gw_free(r);
|
||||
}
|
||||
}
|
||||
|
||||
if (mmsc->mm1.gprs_off) {
|
||||
stop_gprs(mmsc->mm1.gprs_off);
|
||||
} else if (pid > 0) { /* stop GPRS, restart SMSC connection. */
|
||||
int xkill, status;
|
||||
pid_t wpid;
|
||||
do {
|
||||
xkill = kill(pid, SIGTERM);
|
||||
mms_info(0, "MM7", mmsc->id, "GPRS turned off returned: %d", xkill);
|
||||
if (xkill < 0 && errno == ESRCH)
|
||||
break;
|
||||
wpid = waitpid(pid, &status, 0);
|
||||
if (wpid == pid && WIFEXITED(status))
|
||||
break;
|
||||
else if (wpid < 0 && errno == ECHILD)
|
||||
break;
|
||||
} while (1);
|
||||
gwthread_sleep(2);
|
||||
}
|
||||
after_gprs_dead:
|
||||
if (mmsc->mm1.smsc_on) {
|
||||
system(octstr_get_cstr(mmsc->mm1.smsc_on));
|
||||
gwthread_sleep(5);
|
||||
mms_info(0, "MM7", mmsc->id, "SMSC turned on");
|
||||
}
|
||||
|
||||
}
|
||||
mmsc->mm1.sender_alive--;
|
||||
mms_info(0, "MM7", mmsc->id, "handle_mm1 exits");
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBCURL
|
||||
#include <curl/curl.h>
|
||||
static int write_octstr_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
Octstr *out = userp;
|
||||
|
||||
octstr_append_data(out, buffer, size*nmemb);
|
||||
mms_info(0, "mmsbox-mm1", NULL, "write_data called with nmemn=%ld, size=%ld",
|
||||
nmemb, size);
|
||||
return size*nmemb;
|
||||
}
|
||||
#endif
|
||||
|
||||
static Octstr *fetch_content_with_curl(MmscGrp *mmc, Octstr *url, Octstr *body, int *hstatus)
|
||||
{
|
||||
Octstr *s = octstr_create("");
|
||||
#ifdef HAVE_LIBCURL
|
||||
|
||||
Octstr *proxy = mmc->mm1.proxy;
|
||||
Octstr *ua = mmc->mm1.ua;
|
||||
|
||||
CURL *cl;
|
||||
struct curl_slist *h = NULL;
|
||||
char errbuf[512];
|
||||
static int curl_inited = 0;
|
||||
|
||||
Octstr *xurl = url ? url : mmc->mmsc_url;
|
||||
if (curl_inited == 0) {
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl_inited = 1;
|
||||
}
|
||||
|
||||
cl = curl_easy_init();
|
||||
curl_easy_setopt(cl, CURLOPT_URL, octstr_get_cstr(xurl));
|
||||
if (octstr_len(proxy) > 0)
|
||||
curl_easy_setopt(cl, CURLOPT_PROXY, octstr_get_cstr(proxy));
|
||||
curl_easy_setopt(cl, CURLOPT_WRITEFUNCTION, write_octstr_data);
|
||||
curl_easy_setopt(cl, CURLOPT_WRITEDATA, s);
|
||||
curl_easy_setopt(cl, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(cl, CURLOPT_TIMEOUT, 120L);
|
||||
curl_easy_setopt(cl, CURLOPT_FORBID_REUSE, 1L);
|
||||
curl_easy_setopt(cl, CURLOPT_CONNECTTIMEOUT, 40L);
|
||||
|
||||
h = curl_slist_append(h, "Accept: */*");
|
||||
if (body) { /* POST. */
|
||||
h = curl_slist_append(h, "Content-Type: application/vnd.wap.mms-message");
|
||||
curl_easy_setopt(cl, CURLOPT_POSTFIELDS, octstr_get_cstr(body));
|
||||
curl_easy_setopt(cl, CURLOPT_POSTFIELDSIZE, octstr_len(body));
|
||||
}
|
||||
|
||||
if (ua) {
|
||||
Octstr *x = octstr_format("User-Agent: %S", ua);
|
||||