From fd2ed9038fb96ff19d2f140741ebbd6f87d65c58 Mon Sep 17 00:00:00 2001 From: bagyenda <> Date: Tue, 26 Oct 2010 10:18:13 +0000 Subject: [PATCH] added mm4 incoming handler for mmsbox --- mbuni/ChangeLog | 4 + mbuni/INSTALL | 252 +- mbuni/doc/userguide.shtml | 80 +- mbuni/extras/pgsql-queue/mms_pgsql_queue.c | 6 +- mbuni/mmlib/mms_cfg.def | 4 +- mbuni/mmlib/mms_mm7soap.c | 5 +- mbuni/mmlib/mms_msg.c | 14 +- mbuni/mmlib/mms_msg.h | 9 + mbuni/mmlib/mms_util.c | 3045 ++++++++++---------- mbuni/mmlib/mms_util.h | 8 +- mbuni/mmsbox/Makefile.am | 7 +- mbuni/mmsbox/bearerbox.c | 681 ++++- mbuni/mmsbox/mmsbox.h | 1 + mbuni/mmsbox/mmsbox_cfg.c | 101 +- mbuni/mmsbox/mmsbox_cfg.h | 13 +- mbuni/mmsc/mmsfromemail.c | 77 +- 16 files changed, 2634 insertions(+), 1673 deletions(-) diff --git a/mbuni/ChangeLog b/mbuni/ChangeLog index 9be5022..ba98d8b 100644 --- a/mbuni/ChangeLog +++ b/mbuni/ChangeLog @@ -1,3 +1,7 @@ +2010-10-25 P. A. Bagyenda + * Added MM4 incoming handler for mmsbox +2010-10-22 P. A. Bagyenda + * Make a lib for mmsbox, make it easier to link external apps to its engine 2010-10-19 P. A. Bagyenda * Added new func to mms_cfg -- make it easier to implement module-based configuration * Extended mmsbox_cfg load functions to make it easier to configure using modules diff --git a/mbuni/INSTALL b/mbuni/INSTALL index 5e3b1ca..7d1c323 100644 --- a/mbuni/INSTALL +++ b/mbuni/INSTALL @@ -1,16 +1,25 @@ Installation Instructions ************************* -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free -Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. -This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. + 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. Basic Installation ================== -These are generic installation instructions. + 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. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -23,9 +32,9 @@ debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. (Caching is +the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale -cache files.) +cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail @@ -35,30 +44,37 @@ some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You only need -`configure.ac' if you want to change it or regenerate `configure' using -a newer version of `autoconf'. +`configure' by a program called `autoconf'. You need `configure.ac' if +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 - `./bootstrap' followed by `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. + `./configure' to configure the package for your system. - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with - the package. + the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and - documentation. + 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. - 5. You can remove the program binaries and object files from the + 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 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 @@ -67,65 +83,120 @@ The simplest way to compile this package is: 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 is an example: - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. 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 must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the +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 `..'. +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. - If you have to use a `make' that does not support the `VPATH' -variable, you have 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. + 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' will install the package's files in -`/usr/local/bin', `/usr/local/man', etc. You can specify an -installation prefix other than `/usr/local' by giving `configure' the -option `--prefix=PREFIX'. + 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. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you -give `configure' the option `--exec-prefix=PREFIX', the package will -use PREFIX as the prefix for installing programs and libraries. -Documentation and other data files will still use the regular prefix. +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +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. +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 +================= 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'. -Optional Features -================= - -Some packages pay attention to `--enable-FEATURE' options to + 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 @@ -137,14 +208,53 @@ 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 `' 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: @@ -152,14 +262,15 @@ 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 need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should -use the `--target=TYPE' option to select the type of system they will +use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a @@ -170,9 +281,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. @@ -181,7 +292,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 @@ -189,17 +300,30 @@ them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc -will cause the specified gcc to be used as the C compiler (unless it is +causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + `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 the options to `configure', and exit. + 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. `--version' `-V' @@ -226,6 +350,16 @@ overridden in the site shell script). 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. diff --git a/mbuni/doc/userguide.shtml b/mbuni/doc/userguide.shtml index 04739f1..ae84372 100644 --- a/mbuni/doc/userguide.shtml +++ b/mbuni/doc/userguide.shtml @@ -285,7 +285,7 @@ provisioned, etc.
  • Operating as a VAS Gateway, Mbuni provides:
      -
    • Support for both SOAP and EAIF connectivity with an operator +
    • Support for SOAP, EAIF and MM4 connectivity with an operator MMSC (plus a special HTTP-based relay mechanism)
    • Multiple connections to different MMSC of different types can be maintained @@ -1235,6 +1235,40 @@ value given above (queue-run-interval)     + + + + mm4-port + +     + + + MMSBOX +     + + + + Integer +     + + Port on which mmsbox listens for MM4 requests from Value + Added Services providers. If this port is not supplied, the MM4 receiver + sub-system is not started. +     + + + + + + mmsbox-mm4-domain-number-prefixes + +     + + + MMSBOX +     + + allow-ip @@ -2432,7 +2466,8 @@ Supported configuration parameters are: Mandatory: Protocol spoken by this MMSC, one of soap for 3GPP MM7 - SOAP, eaif for Nokia EAIF protocol, http for + SOAP, eaif for Nokia EAIF protocol, mm4 for 3GPP + MM4, http for special HTTP-based inter-mmsbox message relay (see below), or custom for a custom implementation handled by a loadable module (see mmsc-library below).
      For type = http the VAS GW @@ -2508,10 +2543,29 @@ Supported configuration parameters are: Mandatory: - URL address for the MMSC. Used for outgoing messages + URL address for the MMSC. Used for outgoing messages. When type + is MM4, this must be set to the MM4 domain. If you + wish to support email senders, create an mmsc group where + the domain is set to *. + + + maximum-request-size + + + + int + + + Optional: + Maximum request size that this interface will receive. Larger + requests will be dropped. Default is 500k. + + + + incoming-port @@ -2521,11 +2575,29 @@ Supported configuration parameters are: Number - Port at which Mbuni listens for incoming messages from MMSC + Port at which Mbuni listens for incoming messages from MMSC. Not + used for MM4 incoming connections (mm4-port is used instead). + + + strip-domain + + + + boolean + + + Optional: + MM4 MMSC connections only: Whether to strip the domain name from + the received sender/recipient addresses (if they are phone numbers) + + + + + incoming-user diff --git a/mbuni/extras/pgsql-queue/mms_pgsql_queue.c b/mbuni/extras/pgsql-queue/mms_pgsql_queue.c index 6ec4a48..c8fca01 100644 --- a/mbuni/extras/pgsql-queue/mms_pgsql_queue.c +++ b/mbuni/extras/pgsql-queue/mms_pgsql_queue.c @@ -66,10 +66,10 @@ static int pgq_init_module(Octstr *conninfo, char *xtopdir, int max_connections) /* Now look for flags */ if ((i = octstr_search_char(xcinfo, ';', 0)) > 0) { - Octstr *x = octstr_copy(xcinfo, 0, i); + Octstr *x = octstr_copy(xcinfo, i+1, octstr_len(xcinfo)); + + octstr_delete(xcinfo, i, octstr_len(xcinfo)); - octstr_delete(xcinfo, 0, i+1); - if (octstr_case_search(x, octstr_imm("internal"), 0) >= 0) external_storage = 0; if (octstr_case_search(x, octstr_imm("no-archive"), 0) >= 0) diff --git a/mbuni/mmlib/mms_cfg.def b/mbuni/mmlib/mms_cfg.def index 96909b7..4635c19 100644 --- a/mbuni/mmlib/mms_cfg.def +++ b/mbuni/mmlib/mms_cfg.def @@ -75,6 +75,7 @@ SINGLE_GROUP(mbuni, OCTSTR(sendsms-global-sender) OCTSTR(mms-port) OCTSTR(mm7-port) + OCTSTR(mm4-port) OCTSTR(allow-ip) OCTSTR(deny-ip) OCTSTR(email2mms-relay-hosts) @@ -121,7 +122,6 @@ SINGLE_GROUP(mbuni, OCTSTR(mmsbox-cdr-module) OCTSTR(mmsbox-cdr-module-parameters) - OCTSTR(mmsc-services) ) @@ -191,6 +191,8 @@ MULTI_GROUP(mmsc, OCTSTR(no-sender-address) OCTSTR(default-vasid) + OCTSTR(maximum-request-size) + OCTSTR(strip-domain) ) MULTI_GROUP(mms-service, diff --git a/mbuni/mmlib/mms_mm7soap.c b/mbuni/mmlib/mms_mm7soap.c index 0bf0409..3df18bb 100644 --- a/mbuni/mmlib/mms_mm7soap.c +++ b/mbuni/mmlib/mms_mm7soap.c @@ -1025,6 +1025,9 @@ int mm7_msgtype_to_soaptype(int mtype, int isclientside) case MMS_MSGTYPE_DELIVERY_IND: t = MM7_TAG_DeliveryReportReq; break; + case MMS_MSGTYPE_SEND_CONF: + t = isclientside ? MM7_TAG_SubmitRsp : MM7_TAG_DeliverRsp; + break; case -1: t = isclientside ? MM7_TAG_RSErrorRsp : MM7_TAG_VASPErrorRsp; break; @@ -1233,7 +1236,7 @@ MSoapMsg_t *mm7_mmsmsg_to_soap(MmsMsg *msg, Octstr *from, List *xto, } if (m) { /* Add custom headers, hope caller knows what they are doing */ - List *l = http_header_find_all(hdrs, "X-Mbuni-MM7-Headers"); + List *l = hdrs ? http_header_find_all(hdrs, "X-Mbuni-MM7-Headers") : NULL; int i, n; diff --git a/mbuni/mmlib/mms_msg.c b/mbuni/mmlib/mms_msg.c index e50e7a3..45853e5 100644 --- a/mbuni/mmlib/mms_msg.c +++ b/mbuni/mmlib/mms_msg.c @@ -29,6 +29,16 @@ struct MmsMsg { }; +struct MM4_types_map_t mm4_types[] = { + {"MM4_forward.REQ", MMS_MSGTYPE_SEND_REQ}, + {"MM4_forward.RES",MMS_MSGTYPE_SEND_CONF}, + {"MM4_read_reply_report.REQ", MMS_MSGTYPE_READ_REC_IND}, + {"MM4_read_reply_report.RES",-1}, + {"MM4_delivery_report.REQ",MMS_MSGTYPE_DELIVERY_IND}, + {"MM4_delivery_report.RES",-1}, + {NULL} +}; + #define SIZHINT 47 @@ -1960,7 +1970,9 @@ int mms_msgsize(MmsMsg *m) Octstr *s; int n; - gw_assert(m); + if (m == NULL) + return 0; + s = mms_tobinary(m); /* Dirty, but works... */ n = octstr_len(s); octstr_destroy(s); diff --git a/mbuni/mmlib/mms_msg.h b/mbuni/mmlib/mms_msg.h index c9c236a..ca81f14 100644 --- a/mbuni/mmlib/mms_msg.h +++ b/mbuni/mmlib/mms_msg.h @@ -133,4 +133,13 @@ int mms_make_sendreq(MmsMsg *retrieveconf); /* Compute message size -- not altogether efficiently */ int mms_msgsize(MmsMsg *m); + +/* MM4 stuff */ +enum MM4_types_t {MM4_FORWARD_REQ = 0, MM4_FORWARD_RES, MM4_READ_REPLY_REPORT_REQ, + MM4_READ_REPLY_REPORT_RES, MM4_DELIVERY_REPORT_REQ, MM4_DELIVERY_REPORT_RES}; +extern struct MM4_types_map_t { + char *mm4str; + int mm1_type; +} mm4_types[]; + #endif diff --git a/mbuni/mmlib/mms_util.c b/mbuni/mmlib/mms_util.c index 97b3dcb..2c6d08b 100644 --- a/mbuni/mmlib/mms_util.c +++ b/mbuni/mmlib/mms_util.c @@ -34,341 +34,343 @@ Octstr *_mms_cfg_getx(mCfg *cfg, mCfgGrp *grp, Octstr *item) { - Octstr *v = mms_cfg_get(cfg, grp, item); + Octstr *v = mms_cfg_get(cfg, grp, item); - void *x = v ? v : octstr_create(""); + void *x = v ? v : octstr_create(""); - return x; + return x; } int mms_load_core_settings(mCfg *cfg, mCfgGrp *cgrp) { - Octstr *log, *alog; - Octstr *http_proxy_host; - Octstr *our_interface; - long loglevel; + Octstr *log, *alog; + Octstr *http_proxy_host; + Octstr *our_interface; + long loglevel; - if (cgrp == NULL) - panic(0,"Missing required group `core' in config file!"); + if (cgrp == NULL) + panic(0,"Missing required group `core' in config file!"); - /* Set the log file. */ - log = mms_cfg_get(cfg, cgrp, octstr_imm("log-file")); - if (log != NULL) { - if (mms_cfg_get_int(cfg, cgrp, octstr_imm("log-level"), &loglevel) == -1) - loglevel = 0; - log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL); - octstr_destroy(log); - } + /* Set the log file. */ + log = mms_cfg_get(cfg, cgrp, octstr_imm("log-file")); + if (log != NULL) { + log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL); + octstr_destroy(log); + } - /* Get access log and open it. */ - alog = mms_cfg_get(cfg, cgrp, octstr_imm("access-log")); - if (alog) { - alog_open(octstr_get_cstr(alog), 1, 1); - octstr_destroy(alog); - } + if (mms_cfg_get_int(cfg, cgrp, octstr_imm("log-level"), &loglevel) == -1) + loglevel = 0; + log_set_output_level(loglevel); - if ((our_interface = mms_cfg_get(cfg, cgrp, octstr_imm("http-interface-name"))) != NULL) { - http_set_interface(our_interface); - octstr_destroy(our_interface); - } + /* Get access log and open it. */ + alog = mms_cfg_get(cfg, cgrp, octstr_imm("access-log")); + if (alog) { + alog_open(octstr_get_cstr(alog), 1, 1); + octstr_destroy(alog); + } - /* look for http proxy. If set, use it. */ - if ((http_proxy_host = mms_cfg_get(cfg, cgrp, octstr_imm("http-proxy-host"))) != NULL) { + if ((our_interface = mms_cfg_get(cfg, cgrp, octstr_imm("http-interface-name"))) != NULL) { + http_set_interface(our_interface); + octstr_destroy(our_interface); + } + + /* look for http proxy. If set, use it. */ + if ((http_proxy_host = mms_cfg_get(cfg, cgrp, octstr_imm("http-proxy-host"))) != NULL) { - Octstr *username = mms_cfg_get(cfg, cgrp, - octstr_imm("http-proxy-username")); - Octstr *password = mms_cfg_get(cfg, cgrp, - octstr_imm("http-proxy-password")); - List *exceptions = mms_cfg_get_list(cfg, cgrp, - octstr_imm("http-proxy-exceptions")); - Octstr *except_regex = mms_cfg_get(cfg, cgrp, - octstr_imm("http-proxy-exceptions-regex")); - long http_proxy_port = -1; + Octstr *username = mms_cfg_get(cfg, cgrp, + octstr_imm("http-proxy-username")); + Octstr *password = mms_cfg_get(cfg, cgrp, + octstr_imm("http-proxy-password")); + List *exceptions = mms_cfg_get_list(cfg, cgrp, + octstr_imm("http-proxy-exceptions")); + Octstr *except_regex = mms_cfg_get(cfg, cgrp, + octstr_imm("http-proxy-exceptions-regex")); + long http_proxy_port = -1; - mms_cfg_get_int(cfg, cgrp, octstr_imm("http-proxy-port"), &http_proxy_port); + mms_cfg_get_int(cfg, cgrp, octstr_imm("http-proxy-port"), &http_proxy_port); - if (http_proxy_port > 0) - http_use_proxy(http_proxy_host, http_proxy_port, 0, - exceptions, username, password, except_regex); - octstr_destroy(http_proxy_host); - octstr_destroy(username); - octstr_destroy(password); - octstr_destroy(except_regex); - gwlist_destroy(exceptions, octstr_destroy_item); - } + if (http_proxy_port > 0) + http_use_proxy(http_proxy_host, http_proxy_port, 0, + exceptions, username, password, except_regex); + octstr_destroy(http_proxy_host); + octstr_destroy(username); + octstr_destroy(password); + octstr_destroy(except_regex); + gwlist_destroy(exceptions, octstr_destroy_item); + } #ifdef HAVE_LIBSSL - /* We expect that gwlib_init() has been called already, so only need - * to setup cert files. - * -- adapted from gwlib/conn.c - */ - { - Octstr *ssl_client_certkey_file = NULL; - Octstr *ssl_server_cert_file = NULL; - Octstr *ssl_server_key_file = NULL; - Octstr *ssl_trusted_ca_file = NULL; + /* We expect that gwlib_init() has been called already, so only need + * to setup cert files. + * -- adapted from gwlib/conn.c + */ + { + Octstr *ssl_client_certkey_file = NULL; + Octstr *ssl_server_cert_file = NULL; + Octstr *ssl_server_key_file = NULL; + Octstr *ssl_trusted_ca_file = NULL; - /* - * check if SSL is desired for HTTP servers and then - * load SSL client and SSL server public certificates - * and private keys - */ - ssl_client_certkey_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-client-certkey-file")); - if (ssl_client_certkey_file != NULL) - use_global_client_certkey_file(ssl_client_certkey_file); + /* + * check if SSL is desired for HTTP servers and then + * load SSL client and SSL server public certificates + * and private keys + */ + ssl_client_certkey_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-client-certkey-file")); + if (ssl_client_certkey_file != NULL) + use_global_client_certkey_file(ssl_client_certkey_file); - ssl_server_cert_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-server-cert-file")); - ssl_server_key_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-server-key-file")); + ssl_server_cert_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-server-cert-file")); + ssl_server_key_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-server-key-file")); - if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) - use_global_server_certkey_file(ssl_server_cert_file, - ssl_server_key_file); + if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) + use_global_server_certkey_file(ssl_server_cert_file, + ssl_server_key_file); - ssl_trusted_ca_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-trusted-ca-file")); + ssl_trusted_ca_file = mms_cfg_get(cfg, cgrp, octstr_imm("ssl-trusted-ca-file")); - use_global_trusted_ca_file(ssl_trusted_ca_file); + use_global_trusted_ca_file(ssl_trusted_ca_file); - octstr_destroy(ssl_client_certkey_file); - octstr_destroy(ssl_server_cert_file); - octstr_destroy(ssl_server_key_file); - octstr_destroy(ssl_trusted_ca_file); - } + octstr_destroy(ssl_client_certkey_file); + octstr_destroy(ssl_server_cert_file); + octstr_destroy(ssl_server_key_file); + octstr_destroy(ssl_trusted_ca_file); + } #endif - return 0; + return 0; } Octstr *mms_maketransid(char *qf, Octstr *mmscname) { - Octstr *res; - Octstr *x, *y = NULL; - static int ct; + Octstr *res; + Octstr *x, *y = NULL; + static int ct; - if (!qf) - x = octstr_format("msg.%ld.x%d.%d.%d", - (long)time(NULL) % 10000, (++ct % 1000), getpid()%100, random()%100); - else - x = octstr_create(qf); + if (!qf) + x = octstr_format("msg.%ld.x%d.%d.%d", + (long)time(NULL) % 10000, (++ct % 1000), getpid()%100, random()%100); + else + x = octstr_create(qf); - res = octstr_format("%S-%S", mmscname, x); + res = octstr_format("%S-%S", mmscname, x); - octstr_destroy(x); - octstr_destroy(y); + octstr_destroy(x); + octstr_destroy(y); - return res; + return res; } Octstr *mms_make_msgid(char *qf, Octstr *mmscname) {/* Message ID is a little differently done. */ - Octstr *res; - Octstr *x, *y = NULL; - static int ct; + Octstr *res; + Octstr *x, *y = NULL; + static int ct; - if (!qf) - x = octstr_format("msg.%ld.x%d.%d.%d", - (long)time(NULL) % 10000, (++ct % 1000), getpid()%100, random()%100); - else - x = octstr_create(qf); + if (!qf) + x = octstr_format("msg.%ld.x%d.%d.%d", + (long)time(NULL) % 10000, (++ct % 1000), getpid()%100, random()%100); + else + x = octstr_create(qf); - if (mmscname) - res = octstr_format("%S@%S", x,mmscname); - else - res = octstr_duplicate(x); + if (mmscname) + res = octstr_format("%S@%S", x,mmscname); + else + res = octstr_duplicate(x); - octstr_destroy(x); - octstr_destroy(y); + octstr_destroy(x); + octstr_destroy(y); - return res; + return res; } extern Octstr *mms_getqf_fromtransid(Octstr *transid) { - int i; + int i; - if (transid == NULL) - return NULL; - i = octstr_search_char(transid, '-', 0); - if (i < 0) - i = octstr_search_char(transid, '@', 0); /* XXX backward compartibility. */ + if (transid == NULL) + return NULL; + i = octstr_search_char(transid, '-', 0); + if (i < 0) + i = octstr_search_char(transid, '@', 0); /* XXX backward compartibility. */ - return (i >= 0) ? octstr_copy(transid, i+1, octstr_len(transid)) : octstr_duplicate(transid); + return (i >= 0) ? octstr_copy(transid, i+1, octstr_len(transid)) : octstr_duplicate(transid); } extern Octstr *mms_getqf_from_msgid(Octstr *msgid) { - int i; + int i; - if (msgid == NULL) - return NULL; - if ((i = octstr_search_char(msgid, '@', 0)) > 0) - return octstr_copy(msgid, 0, i); - else - return mms_getqf_fromtransid(msgid); /* For older ones where transid = msgid. */ + if (msgid == NULL) + return NULL; + if ((i = octstr_search_char(msgid, '@', 0)) > 0) + return octstr_copy(msgid, 0, i); + else + return mms_getqf_fromtransid(msgid); /* For older ones where transid = msgid. */ } Octstr *mms_isodate(time_t t) { - Octstr *current_time; - struct tm now; + 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); + 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; + return current_time; } void mms_lib_init(void) { - srandom(time(NULL)); /* Seed random number generator. */ - gwlib_init(); - mms_strings_init(); + srandom(time(NULL)); /* Seed random number generator. */ + gwlib_init(); + mms_strings_init(); } void mms_lib_shutdown(void) { - mms_strings_shutdown(); - gwlib_shutdown(); + mms_strings_shutdown(); + gwlib_shutdown(); } -static void strip_quotes(Octstr *s) +void strip_quotes(Octstr *s) { - int l = s ? octstr_len(s) : 0; + 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); + 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); + 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) */ + 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); + 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; + 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 split_header_value(Octstr *value, Octstr **base_value, Octstr **params) { - int i, n; - for (i = 0, n = octstr_len(value); i < n; i++) { - int c = octstr_get_char(value, i); + int i, n; + for (i = 0, n = octstr_len(value); i < n; i++) { + int c = octstr_get_char(value, i); - if (c == ';') - break; - else if (c == '"') - i += http_header_quoted_string_len(value, i) - 1; - } + if (c == ';') + break; + else if (c == '"') + i += http_header_quoted_string_len(value, i) - 1; + } - *base_value = octstr_duplicate(value); - if (i < n) { - *params = octstr_copy(value, i+1, octstr_len(value)); - octstr_delete(*base_value, i, octstr_len(*base_value)); - } else - *params = octstr_create(""); - return 0; + *base_value = octstr_duplicate(value); + if (i < n) { + *params = octstr_copy(value, i+1, octstr_len(value)); + octstr_delete(*base_value, i, octstr_len(*base_value)); + } else + *params = octstr_create(""); + return 0; } int get_content_type(List *hdrs, Octstr **type, Octstr **params) { - Octstr *v; + Octstr *v; - v = http_header_find_first(hdrs, "Content-Type"); - *params =NULL; + v = http_header_find_first(hdrs, "Content-Type"); + *params =NULL; - if (!v) { - *type = octstr_create("application/octet-stream"); - *params = octstr_create(""); - return -1; - } + if (!v) { + *type = octstr_create("application/octet-stream"); + *params = octstr_create(""); + return -1; + } - split_header_value(v, type, params); + split_header_value(v, type, params); - octstr_destroy(v); - return 0; + octstr_destroy(v); + return 0; } static int is_mime_special_char(int ch) { - const char *x = "=;<>[]?()@:\\/,"; - char *p; - for (p = (char *)x; *p; p++) - if (ch == *p) - return 1; - return 0; + const char *x = "=;<>[]?()@:\\/,"; + char *p; + for (p = (char *)x; *p; p++) + if (ch == *p) + return 1; + return 0; } static int needs_quotes(Octstr *s) { - int i, n; - if (!s) - return 0; + int i, n; + if (!s) + return 0; - for (i = 0, n = octstr_len(s); i= 0) /* Don't allow space in the name. */ - goto loop; + 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 && - gwlist_len(l) > 1) - for (j = 0, m = gwlist_len(l); j 0 && + (l = http_header_split_value(value)) != NULL && + gwlist_len(l) > 1) + for (j = 0, m = gwlist_len(l); j 0) - for (i = 0; i 0) + for (i = 0; i 0) - for (i = 0; i 0) + for (i = 0; i= 0) - return; /* Nothing to do. */ + 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_format_append(s, "@%S", myhostname); + j = octstr_case_search(s, octstr_imm("/TYPE=PLMN"), 0); + if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) /* A proper number. */ + octstr_format_append(s, "@%S", myhostname); } @@ -529,167 +531,167 @@ static int send2email(Octstr *to, Octstr *from, Octstr *subject, MIMEEntity *m, int append_hostname, Octstr **error, char *sendmail_cmd, Octstr *myhostname) { - Octstr *s; - FILE *f; - int ret = MMS_SEND_OK, i, n; - Octstr *cmd = octstr_create(""); - List *headers = mime_entity_headers(m); /* we don't want the mime version header removed. */ + Octstr *s; + FILE *f; + int ret = MMS_SEND_OK, i, n; + Octstr *cmd = octstr_create(""); + List *headers = mime_entity_headers(m); /* we don't want the mime version header removed. */ - if (append_hostname) { /* Add our hostname to all phone numbers. */ - List *l = http_create_empty_headers(); - Octstr *xfrom = http_header_value(headers, octstr_imm("From")); - List *lto = http_header_find_all(headers, "To"); - List *lcc = http_header_find_all(headers, "Cc"); + if (append_hostname) { /* Add our hostname to all phone numbers. */ + List *l = http_create_empty_headers(); + Octstr *xfrom = http_header_value(headers, octstr_imm("From")); + List *lto = http_header_find_all(headers, "To"); + List *lcc = http_header_find_all(headers, "Cc"); - if (xfrom) { - addmmscname(xfrom, myhostname); - http_header_add(l, "From", octstr_get_cstr(xfrom)); - octstr_destroy(xfrom); - } - http_header_remove_all(headers, "From"); + if (xfrom) { + addmmscname(xfrom, myhostname); + http_header_add(l, "From", octstr_get_cstr(xfrom)); + octstr_destroy(xfrom); + } + http_header_remove_all(headers, "From"); - for (i = 0, n = gwlist_len(lto); i < n; i++) { - Octstr *name, *value; + for (i = 0, n = gwlist_len(lto); i < n; i++) { + Octstr *name, *value; - http_header_get(lto, i, &name, &value); + http_header_get(lto, i, &name, &value); - if (!value || !name || - octstr_case_compare(name, octstr_imm("To")) != 0) - goto loop; + 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: - octstr_destroy(value); - octstr_destroy(name); - } + addmmscname(value, myhostname); + http_header_add(l, "To", octstr_get_cstr(value)); + loop: + octstr_destroy(value); + octstr_destroy(name); + } - http_destroy_headers(lto); - http_header_remove_all(headers, "To"); + http_destroy_headers(lto); + http_header_remove_all(headers, "To"); - for (i = 0, n = gwlist_len(lcc); i < n; i++) { - Octstr *name, *value; + for (i = 0, n = gwlist_len(lcc); i < n; i++) { + Octstr *name, *value; - http_header_get(lcc, i, &name, &value); + http_header_get(lcc, i, &name, &value); - if (!value || !name || - octstr_case_compare(name, octstr_imm("Cc")) != 0) - goto loop2; + 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: - octstr_destroy(value); - octstr_destroy(name); - } + addmmscname(value, myhostname); + http_header_add(l, "Cc", octstr_get_cstr(value)); + loop2: + octstr_destroy(value); + octstr_destroy(name); + } - http_destroy_headers(lcc); - http_header_remove_all(headers, "Cc"); + http_destroy_headers(lcc); + http_header_remove_all(headers, "Cc"); - http_append_headers(headers, l); /* combine old with new. */ - http_destroy_headers(l); - } + http_append_headers(headers, l); /* combine old with new. */ + http_destroy_headers(l); + } - /* Pack headers, get string rep of mime entity. */ - http_header_pack(headers); - mime_replace_headers(m, headers); - s = mime_entity_to_octstr(m); + /* Pack headers, get string rep of mime entity. */ + http_header_pack(headers); + mime_replace_headers(m, headers); + s = mime_entity_to_octstr(m); - /* - * Make the command: Transpose % formatting characters: - * f - from address - * t - recipient - * s - subject - * m - message id - */ + /* + * Make the command: Transpose % formatting characters: + * f - from address + * t - recipient + * s - subject + * m - message id + */ - i = 0; - for (;;) { - Octstr *tmp; - 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; + i = 0; + for (;;) { + Octstr *tmp; + 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': - tmp = octstr_duplicate(to); - escape_shell_chars(tmp); - octstr_append(cmd, tmp); - octstr_destroy(tmp); - break; - case 'f': - if (append_hostname) { - Octstr *xfrom = octstr_duplicate(from); - addmmscname(xfrom, myhostname); - escape_shell_chars(xfrom); + switch(sendmail_cmd[i+1]) { + case 't': + tmp = octstr_duplicate(to); + escape_shell_chars(tmp); + octstr_append(cmd, tmp); + octstr_destroy(tmp); + break; + case 'f': + if (append_hostname) { + Octstr *xfrom = octstr_duplicate(from); + addmmscname(xfrom, myhostname); + escape_shell_chars(xfrom); - octstr_append(cmd, xfrom); - octstr_destroy(xfrom); - } else { - tmp = octstr_duplicate(from); - escape_shell_chars(tmp); - octstr_append(cmd, tmp); - octstr_destroy(tmp); - } - break; - case 's': - tmp = octstr_duplicate(subject); - escape_shell_chars(tmp); - octstr_append(cmd, subject); - octstr_destroy(tmp); - break; - case 'm': - tmp = octstr_duplicate(msgid); - escape_shell_chars(tmp); - octstr_append(cmd, msgid); - octstr_destroy(tmp); - break; - case '%': - octstr_format_append(cmd, "%%"); - break; - default: - octstr_format_append(cmd, "%%%c", sendmail_cmd[i+1]); - break; - } - i += 2; - } + octstr_append(cmd, xfrom); + octstr_destroy(xfrom); + } else { + tmp = octstr_duplicate(from); + escape_shell_chars(tmp); + octstr_append(cmd, tmp); + octstr_destroy(tmp); + } + break; + case 's': + tmp = octstr_duplicate(subject); + escape_shell_chars(tmp); + octstr_append(cmd, subject); + octstr_destroy(tmp); + break; + case 'm': + tmp = octstr_duplicate(msgid); + escape_shell_chars(tmp); + octstr_append(cmd, msgid); + octstr_destroy(tmp); + 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)); + 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 ((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 (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_QUEUED; + 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_QUEUED; - done: - http_destroy_headers(headers); - octstr_destroy(cmd); - octstr_destroy(s); - return ret; +done: + http_destroy_headers(headers); + octstr_destroy(cmd); + octstr_destroy(s); + return ret; } @@ -698,7 +700,7 @@ int mm_send_to_email(Octstr *to, Octstr *from, Octstr *subject, MIMEEntity *m, int append_hostname, Octstr **error, char *sendmail_cmd, Octstr *myhostname) { - return send2email(to,from,subject,msgid,m,append_hostname,error,sendmail_cmd,myhostname); + return send2email(to,from,subject,msgid,m,append_hostname,error,sendmail_cmd,myhostname); } /* Send this message to email recipient. */ @@ -714,140 +716,140 @@ int mms_sendtoemail(Octstr *from, Octstr *to, List *extra_headers) { - MIMEEntity *m = NULL; - List *headers = NULL; - List *newhdrs = http_create_empty_headers(); - int ret = 0, mtype; + MIMEEntity *m = NULL; + List *headers = NULL; + List *newhdrs = http_create_empty_headers(); + int ret = 0, mtype; - gw_assert(msg); - mtype = mms_messagetype(msg); + gw_assert(msg); + mtype = mms_messagetype(msg); - if (!to || - octstr_search_char(to, '@', 0) < 0) { - *error = octstr_format("Invalid email address %S!", to); - return MMS_SEND_ERROR_FATAL; - } + 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,0); - else if ((ret = mms_format_special(msg, trans_smil, txt, html, &m)) < 0 || - m == NULL) { - mms_warning(0, "send2email", NULL, "Failed to format message (msg=%s,ret=%d)", - m ? "OK" : "Not transformed",ret); - return -ret; - } + if (!trans_msg) + m = mms_tomime(msg,0); + else if ((ret = mms_format_special(msg, trans_smil, txt, html, &m)) < 0 || + m == NULL) { + mms_warning(0, "send2email", NULL, "Failed to format message (msg=%s,ret=%d)", + m ? "OK" : "Not transformed",ret); + return -ret; + } - base64_mimeparts(m,0); /* make sure parts are base64 formatted. */ + base64_mimeparts(m,0); /* make sure parts are base64 formatted. */ - if (extra_headers) /* add any other headers into the mix. */ - http_header_combine(newhdrs, extra_headers); + if (extra_headers) /* add any other headers into the mix. */ + http_header_combine(newhdrs, extra_headers); - headers = mime_entity_headers(m); + headers = mime_entity_headers(m); - /* Before we send it, we insert some email friendly headers if they are missing. */ - if (!mm4) { - http_header_add(newhdrs, "Subject", subject ? octstr_get_cstr(subject) : "MMS Message"); - http_header_remove_all(headers, "From"); - http_header_add(newhdrs, "From", octstr_get_cstr(from)); - http_header_remove_all(headers, "To"); - http_header_add(newhdrs, "To", octstr_get_cstr(to)); - http_header_add(newhdrs, "Message-ID", msgid ? octstr_get_cstr(msgid) : ""); - http_header_add(newhdrs, "MIME-Version", "1.0"); - } else { - char *x, tmp[32]; - Octstr *xsender = octstr_format("system-user@%S", myhostname); - Octstr *y; + /* Before we send it, we insert some email friendly headers if they are missing. */ + if (!mm4) { + http_header_add(newhdrs, "Subject", subject ? octstr_get_cstr(subject) : "MMS Message"); + http_header_remove_all(headers, "From"); + http_header_add(newhdrs, "From", octstr_get_cstr(from)); + http_header_remove_all(headers, "To"); + http_header_add(newhdrs, "To", octstr_get_cstr(to)); + http_header_add(newhdrs, "Message-ID", msgid ? octstr_get_cstr(msgid) : ""); + http_header_add(newhdrs, "MIME-Version", "1.0"); + } else { + char *x, tmp[32]; + Octstr *xsender = octstr_format("system-user@%S", myhostname); + Octstr *y; - if (msgid) { - y = (octstr_get_char(msgid, 0) == '"') ? octstr_duplicate(msgid) : - octstr_format("\"%S\"", msgid); + if (msgid) { + y = (octstr_get_char(msgid, 0) == '"') ? octstr_duplicate(msgid) : + octstr_format("\"%S\"", msgid); - http_header_add(newhdrs, "X-Mms-Message-ID", octstr_get_cstr(y)); - octstr_destroy(y); - } + http_header_add(newhdrs, "X-Mms-Message-ID", octstr_get_cstr(y)); + octstr_destroy(y); + } - /* fixup messageid */ - if ((y = http_header_value(headers, octstr_imm("Message-ID"))) != NULL) { - if (octstr_get_char(y, 0) != '<') { - octstr_insert_char(y, 0, '<'); - octstr_append_char(y, '>'); - } - http_header_remove_all(headers, "Message-ID"); + /* fixup messageid */ + if ((y = http_header_value(headers, octstr_imm("Message-ID"))) != NULL) { + if (octstr_get_char(y, 0) != '<') { + octstr_insert_char(y, 0, '<'); + octstr_append_char(y, '>'); + } + http_header_remove_all(headers, "Message-ID"); - http_header_add(newhdrs, "Message-ID", octstr_get_cstr(y)); - octstr_destroy(y); - } - sprintf(tmp, "%d.%d.%d", - MAJOR_VERSION(MMS_3GPP_VERSION), - MINOR1_VERSION(MMS_3GPP_VERSION), - MINOR2_VERSION(MMS_3GPP_VERSION)); - http_header_add(newhdrs, "X-Mms-3GPP-MMS-Version", tmp); - http_header_add(newhdrs, "X-Mms-Originator-System", - octstr_get_cstr(xsender)); - http_header_remove_all(headers, "X-Mms-Message-Type"); - if (mtype == MMS_MSGTYPE_SEND_REQ || - mtype == MMS_MSGTYPE_RETRIEVE_CONF) - x = "MM4_forward.REQ"; - else if (mtype == MMS_MSGTYPE_DELIVERY_IND) { - Octstr *s = http_header_value(headers, octstr_imm("X-Mms-Status")); - x = "MM4_delivery_report.REQ"; + http_header_add(newhdrs, "Message-ID", octstr_get_cstr(y)); + octstr_destroy(y); + } + sprintf(tmp, "%d.%d.%d", + MAJOR_VERSION(MMS_3GPP_VERSION), + MINOR1_VERSION(MMS_3GPP_VERSION), + MINOR2_VERSION(MMS_3GPP_VERSION)); + http_header_add(newhdrs, "X-Mms-3GPP-MMS-Version", tmp); + http_header_add(newhdrs, "X-Mms-Originator-System", + octstr_get_cstr(xsender)); + http_header_remove_all(headers, "X-Mms-Message-Type"); + if (mtype == MMS_MSGTYPE_SEND_REQ || + mtype == MMS_MSGTYPE_RETRIEVE_CONF) + x = "MM4_forward.REQ"; + else if (mtype == MMS_MSGTYPE_DELIVERY_IND) { + Octstr *s = http_header_value(headers, octstr_imm("X-Mms-Status")); + x = "MM4_delivery_report.REQ"; #if 0 - /* insert FROM address as recipient as per spec */ - http_header_add(newhdrs, "From", octstr_get_cstr(to)); + /* insert FROM address as recipient as per spec */ + http_header_add(newhdrs, "From", octstr_get_cstr(to)); #else - http_header_add(newhdrs, "To", octstr_get_cstr(to)); + http_header_add(newhdrs, "To", octstr_get_cstr(to)); #endif - /* rename status header. */ - http_header_remove_all(headers, "X-Mms-Status"); - http_header_add(newhdrs, "X-Mms-MM-Status-Code", - s ? octstr_get_cstr(s) : "Unrecognised"); - if (!s) - mms_warning(0, NULL, NULL, "MMS Delivery report with missing Status!"); - octstr_destroy(s); - } else if (mtype == MMS_MSGTYPE_READ_REC_IND) { - x = "MM4_read_reply_report.REQ"; + /* rename status header. */ + http_header_remove_all(headers, "X-Mms-Status"); + http_header_add(newhdrs, "X-Mms-MM-Status-Code", + s ? octstr_get_cstr(s) : "Unrecognised"); + if (!s) + mms_warning(0, NULL, NULL, "MMS Delivery report with missing Status!"); + octstr_destroy(s); + } else if (mtype == MMS_MSGTYPE_READ_REC_IND) { + x = "MM4_read_reply_report.REQ"; #if 0 - /* insert FROM address as recipient as per spec */ - http_header_add(newhdrs, "From", octstr_get_cstr(to)); + /* insert FROM address as recipient as per spec */ + http_header_add(newhdrs, "From", octstr_get_cstr(to)); #else - http_header_add(newhdrs, "To", octstr_get_cstr(to)); + http_header_add(newhdrs, "To", octstr_get_cstr(to)); #endif - } else { - *error = octstr_format("Invalid message type %s on MM4 outgoing interface!", - mms_message_type_to_cstr(mtype)); - x = ""; - ret = MMS_SEND_ERROR_FATAL; - goto done; - } + } else { + *error = octstr_format("Invalid message type %s on MM4 outgoing interface!", + mms_message_type_to_cstr(mtype)); + x = ""; + ret = MMS_SEND_ERROR_FATAL; + goto done; + } - http_header_add(newhdrs, "X-Mms-Message-Type", x); - /* Add a few more MM4 headers. */ - http_header_add(newhdrs, "X-Mms-Ack-Request", dlr ? "Yes" : "No"); - http_header_add(newhdrs, "Sender", octstr_get_cstr(from)); + http_header_add(newhdrs, "X-Mms-Message-Type", x); + /* Add a few more MM4 headers. */ + http_header_add(newhdrs, "X-Mms-Ack-Request", dlr ? "Yes" : "No"); + http_header_add(newhdrs, "Sender", octstr_get_cstr(from)); - y = (transid && transid[0] == '"') ? octstr_create(transid) : - octstr_format("\"%s\"", transid ? transid : "x"); + y = (transid && transid[0] == '"') ? octstr_create(transid) : + octstr_format("\"%s\"", transid ? transid : "x"); - http_header_add(newhdrs, "X-Mms-Transaction-ID", octstr_get_cstr(y)); + http_header_add(newhdrs, "X-Mms-Transaction-ID", octstr_get_cstr(y)); - octstr_destroy(y); - octstr_destroy(xsender); - } + octstr_destroy(y); + octstr_destroy(xsender); + } - http_header_combine(headers, newhdrs); - mime_replace_headers(m, headers); + http_header_combine(headers, newhdrs); + mime_replace_headers(m, headers); - done: - http_destroy_headers(headers); - http_destroy_headers(newhdrs); +done: + http_destroy_headers(headers); + http_destroy_headers(newhdrs); - if (ret == 0) - ret = send2email(to, - from, subject, msgid, m, mm4 == 0, error, sendmail_cmd, myhostname); - mime_entity_destroy(m); + if (ret == 0) + ret = send2email(to, + from, subject, msgid, m, mm4 == 0, error, sendmail_cmd, myhostname); + mime_entity_destroy(m); - return ret; + return ret; } void mms_log2(char *logmsg, Octstr *from, Octstr *to, @@ -856,17 +858,17 @@ void mms_log2(char *logmsg, Octstr *from, Octstr *to, Octstr *viaproxy, char *interface, Octstr *ua, Octstr *mmboxloc) { - List *l; - if (to) { - l = gwlist_create(); - gwlist_append(l, to); - } else - l = NULL; + List *l; + if (to) { + l = gwlist_create(); + gwlist_append(l, to); + } else + l = NULL; - mms_log(logmsg, from,l,msize,msgid,acct,viaproxy,interface,ua,mmboxloc); + mms_log(logmsg, from,l,msize,msgid,acct,viaproxy,interface,ua,mmboxloc); - if (l) - gwlist_destroy(l, NULL); + if (l) + gwlist_destroy(l, NULL); } void mms_log(char *logmsg, Octstr *from, List *to, @@ -875,43 +877,43 @@ void mms_log(char *logmsg, Octstr *from, List *to, Octstr *viaproxy, char *interface, Octstr *ua, Octstr *mmboxloc) { - Octstr *xto = octstr_create(""); - int i, n = to ? gwlist_len(to) : 0; - Octstr *xfrom = from ? octstr_duplicate(from) : NULL; - int j = xfrom ? octstr_case_search(xfrom, octstr_imm("/TYPE=PLMN"), 0) : -1; + Octstr *xto = octstr_create(""); + int i, n = to ? gwlist_len(to) : 0; + Octstr *xfrom = from ? octstr_duplicate(from) : NULL; + int j = xfrom ? octstr_case_search(xfrom, octstr_imm("/TYPE=PLMN"), 0) : -1; - if (j >= 0) - octstr_delete(xfrom, j, octstr_len(xfrom)); + if (j >= 0) + octstr_delete(xfrom, j, octstr_len(xfrom)); - for (i = 0; i < n; i++) { - void *y; - Octstr *x = (y = gwlist_get(to,i)) ? octstr_duplicate(y) : NULL; - int j = x ? octstr_case_search(x, octstr_imm("/TYPE=PLMN"), 0) : -1; + for (i = 0; i < n; i++) { + void *y; + Octstr *x = (y = gwlist_get(to,i)) ? octstr_duplicate(y) : NULL; + int j = x ? octstr_case_search(x, octstr_imm("/TYPE=PLMN"), 0) : -1; - if (j >= 0) - octstr_delete(x, j, octstr_len(x)); + if (j >= 0) + octstr_delete(x, j, octstr_len(x)); - octstr_format_append(xto, - "%s%S", - (i == 0) ? "" : ", ", - x); + octstr_format_append(xto, + "%s%S", + (i == 0) ? "" : ", ", + x); - octstr_destroy(x); - } + octstr_destroy(x); + } - alog("%s MMS [INT:%s] [ACT:%s] [MMSC:%s] [from:%s] [to:%s] [msgid:%s] [size=%d] [UA:%s] [MMBox:%s]", - logmsg, interface, - acct ? octstr_get_cstr(acct) : "", - viaproxy ? octstr_get_cstr(viaproxy) : "", - xfrom ? octstr_get_cstr(xfrom) : "", - octstr_get_cstr(xto), - msgid ? octstr_get_cstr(msgid) : "", - msize, - ua ? octstr_get_cstr(ua) : "", - mmboxloc ? octstr_get_cstr(mmboxloc) : ""); + alog("%s MMS [INT:%s] [ACT:%s] [MMSC:%s] [from:%s] [to:%s] [msgid:%s] [size=%d] [UA:%s] [MMBox:%s]", + logmsg, interface, + acct ? octstr_get_cstr(acct) : "", + viaproxy ? octstr_get_cstr(viaproxy) : "", + xfrom ? octstr_get_cstr(xfrom) : "", + octstr_get_cstr(xto), + msgid ? octstr_get_cstr(msgid) : "", + msize, + ua ? octstr_get_cstr(ua) : "", + mmboxloc ? octstr_get_cstr(mmboxloc) : ""); - octstr_destroy(xto); - octstr_destroy(xfrom); + octstr_destroy(xto); + octstr_destroy(xfrom); } @@ -924,14 +926,14 @@ int file_lock_inode_cmp(void *_lhs, void *_rhs); for each inode number. Assumes a uni */ typedef struct { - dev_t dev; - ino_t inode; + dev_t dev; + ino_t inode; } file_key; typedef struct { - file_key key; - pthread_cond_t condition; - int fd; + file_key key; + pthread_cond_t condition; + int fd; } file_lock; static List *openFileList = NULL; @@ -939,71 +941,71 @@ static pthread_mutex_t listMutex = PTHREAD_MUTEX_INITIALIZER; void release_file_lock(int fd, file_key *key) { - debug("mm_util",0,"----->Locked"); - pthread_mutex_lock(&listMutex); + debug("mm_util",0,"----->Locked"); + pthread_mutex_lock(&listMutex); - if (openFileList == NULL) { - openFileList = (List *)gwlist_create(); - } + if (openFileList == NULL) { + openFileList = (List *)gwlist_create(); + } - file_lock *item = (file_lock*)gwlist_search(openFileList, key, file_lock_inode_cmp); - if (item && item->fd == fd) { - /* we own the lock */ - gwlist_delete_equal(openFileList, item); - pthread_cond_broadcast(&item->condition); - pthread_cond_destroy(&item->condition); - gw_free(item); - } - debug("mm_util",0,"<-----UnLocked"); - pthread_mutex_unlock(&listMutex); + file_lock *item = (file_lock*)gwlist_search(openFileList, key, file_lock_inode_cmp); + if (item && item->fd == fd) { + /* we own the lock */ + gwlist_delete_equal(openFileList, item); + pthread_cond_broadcast(&item->condition); + pthread_cond_destroy(&item->condition); + gw_free(item); + } + debug("mm_util",0,"<-----UnLocked"); + pthread_mutex_unlock(&listMutex); } int unlock_and_close(int fd) { #ifdef SunOS - struct stat buf; - if (fstat(fd, &buf)) { - perror("Unable to fstat file for lock"); - return close(fd); - } + struct stat buf; + if (fstat(fd, &buf)) { + perror("Unable to fstat file for lock"); + return close(fd); + } - file_key key; - key.inode = buf.st_ino; - key.dev = buf.st_dev; + file_key key; + key.inode = buf.st_ino; + key.dev = buf.st_dev; - release_file_lock(fd, &key); + release_file_lock(fd, &key); #endif - return close(fd); + return close(fd); } int unlock_and_fclose(FILE *fp) { #ifdef SunOS - int fd = fileno(fp); - struct stat buf; - if (fstat(fd, &buf)) { - perror("Unable to fstat file for lock"); - return fclose(fp); - } + int fd = fileno(fp); + struct stat buf; + if (fstat(fd, &buf)) { + perror("Unable to fstat file for lock"); + return fclose(fp); + } - file_key key; - key.inode = buf.st_ino; - key.dev = buf.st_dev; + file_key key; + key.inode = buf.st_ino; + key.dev = buf.st_dev; - release_file_lock(fd, &key); + release_file_lock(fd, &key); #endif - return fclose(fp); + return fclose(fp); } /* Compare a file_lock(lhs) to the file_key(rhs) and see if they match */ int file_lock_inode_cmp(void *_lhs, void *_rhs) { - file_key *rhs = (file_key*)_rhs; - file_lock *lhs = (file_lock *)_lhs; + file_key *rhs = (file_key*)_rhs; + file_lock *lhs = (file_lock *)_lhs; - return ( + return ( lhs && lhs->key.inode == rhs->inode && lhs->key.dev == rhs->dev @@ -1014,152 +1016,152 @@ int sun_lockfile(int fd, int shouldblock) { #ifdef SunOS - int n, stop; - int flg = shouldblock ? F_SETLKW : F_SETLK; - flock_t lock; + int n, stop; + int flg = shouldblock ? F_SETLKW : F_SETLK; + flock_t lock; - struct stat buf; - if (fstat(fd, &buf)) { - int e = errno; - perror("Unable to fstat file for lock"); - errno = e; - return(-1); - } + struct stat buf; + if (fstat(fd, &buf)) { + int e = errno; + perror("Unable to fstat file for lock"); + errno = e; + return(-1); + } - file_key key; - key.inode = buf.st_ino; - key.dev = buf.st_dev; + file_key key; + key.inode = buf.st_ino; + key.dev = buf.st_dev; - debug("mm_util",0,"----->Locked"); - pthread_mutex_lock(&listMutex); + debug("mm_util",0,"----->Locked"); + pthread_mutex_lock(&listMutex); - if (openFileList == NULL) { - openFileList = (List *)gwlist_create(); - } + if (openFileList == NULL) { + openFileList = (List *)gwlist_create(); + } - /* See if the inode exists in the list */ - file_lock *item = NULL; - do { - item = (file_lock*)gwlist_search(openFileList, &key, file_lock_inode_cmp); - if (item) { - /* It exists, that means that someone has already locked the file */ - if (!shouldblock) { - n = -1; - debug("mm_util",0,"<-----UnLocked"); - pthread_mutex_unlock(&listMutex); - errno = EWOULDBLOCK; - return n; - } + /* See if the inode exists in the list */ + file_lock *item = NULL; + do { + item = (file_lock*)gwlist_search(openFileList, &key, file_lock_inode_cmp); + if (item) { + /* It exists, that means that someone has already locked the file */ + if (!shouldblock) { + n = -1; + debug("mm_util",0,"<-----UnLocked"); + pthread_mutex_unlock(&listMutex); + errno = EWOULDBLOCK; + return n; + } - pthread_cond_wait(&item->condition, &listMutex); - /* O.k. we've got the file, but now item is invalid, - the unlock_and_close removes it. - */ - } - } while (item != NULL); + pthread_cond_wait(&item->condition, &listMutex); + /* O.k. we've got the file, but now item is invalid, + the unlock_and_close removes it. + */ + } + } while (item != NULL); - /* No one else has locked the file, create the condition for - anyone else. - */ - item = (file_lock*)gw_malloc(sizeof(file_lock)); - item->key.inode = key.inode; - item->key.dev = key.dev; - item->fd = fd; - pthread_cond_init(&item->condition, NULL); - gwlist_append(openFileList, item); + /* No one else has locked the file, create the condition for + anyone else. + */ + item = (file_lock*)gw_malloc(sizeof(file_lock)); + item->key.inode = key.inode; + item->key.dev = key.dev; + item->fd = fd; + pthread_cond_init(&item->condition, NULL); + gwlist_append(openFileList, item); - /* Release the global lock so that we don't block the - entire system waiting for fnctl to return - */ - debug("mm_util",0,"<-----UnLocked"); - pthread_mutex_unlock(&listMutex); + /* Release the global lock so that we don't block the + entire system waiting for fnctl to return + */ + debug("mm_util",0,"<-----UnLocked"); + pthread_mutex_unlock(&listMutex); - do { - lock.l_whence = SEEK_SET; - lock.l_start = 0; - lock.l_len = 0; - lock.l_type = F_WRLCK; - n = fcntl(fd, flg, &lock); - if (n < 0) { - if (errno == EINTR) - stop = 0; - else - stop = 1; - } else - stop = 1; - } while (!stop); + do { + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + lock.l_type = F_WRLCK; + n = fcntl(fd, flg, &lock); + if (n < 0) { + if (errno == EINTR) + stop = 0; + else + stop = 1; + } else + stop = 1; + } while (!stop); - /* If we failed to get the fcntl lock, then we need to - release the local lock */ - if (n != 0) { - release_file_lock(fd, &key); - } + /* If we failed to get the fcntl lock, then we need to + release the local lock */ + if (n != 0) { + release_file_lock(fd, &key); + } - return (n == 0) ? 0 : errno; + return (n == 0) ? 0 : errno; #else - panic(0, "Attempt to call sun_lockfile on a non-solaris system"); - return 0; + panic(0, "Attempt to call sun_lockfile on a non-solaris system"); + return 0; #endif } int lockfile(int fd, int shouldblock) { #ifdef SunOS - return sun_lockfile(fd, shouldblock); + return sun_lockfile(fd, shouldblock); #else - int n, stop; - unsigned flg = shouldblock ? 0 : LOCK_NB; + 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); + 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; + return (n == 0) ? 0 : errno; #endif } static int check_lock(int fd, char *fname) { - struct stat fs = {0}, ds = {0}; + struct stat fs = {0}, ds = {0}; - /* You might grab a lock on a file, but the file - * might be changed just before you grabbed the lock. Detect that and fail.. - */ - if (fstat(fd, &ds) < 0 || - stat(fname, &fs) < 0 || + /* You might grab a lock on a file, but the file + * might be changed just before you grabbed the lock. Detect that and fail.. + */ + 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; + 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; } int mm_lockfile(int fd, char *fname, int shouldblock) { - int ret = lockfile(fd,shouldblock); + int ret = lockfile(fd,shouldblock); - if (ret != 0 && errno != EWOULDBLOCK) { - debug("mm_util", 0, "Unable to lock '%s', error= %d, %s, shouldblock=%d", - fname, errno, strerror(errno), shouldblock); - perror("Unable to lock file"); - } + if (ret != 0 && errno != EWOULDBLOCK) { + debug("mm_util", 0, "Unable to lock '%s', error= %d, %s, shouldblock=%d", + fname, errno, strerror(errno), shouldblock); + perror("Unable to lock file"); + } - if (ret != 0 || - (ret = check_lock(fd,fname)) != 0) - return ret; - return 0; + if (ret != 0 || + (ret = check_lock(fd,fname)) != 0) + return ret; + return 0; } void mms_collect_envdata_from_msgheaders(List *mh, List **xto, @@ -1170,326 +1172,326 @@ void mms_collect_envdata_from_msgheaders(List *mh, List **xto, char *unified_prefix, List *strip_prefixes) { - Octstr *s; - List *l; + Octstr *s; + List *l; - if (xto) { - l = http_header_find_all(mh, "To"); - if (l != NULL) { - int i, n; - for (i = 0, n = gwlist_len(l); i 0 - && (*expiryt - time(NULL)) > max_msgexpiry) - *expiryt = time(NULL) + max_msgexpiry; - } + if (max_msgexpiry > 0 + && (*expiryt - time(NULL)) > max_msgexpiry) + *expiryt = time(NULL) + max_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 (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")); + if (otransid) + *otransid = http_header_value(mh, octstr_imm("X-Mms-Transaction-ID")); } unsigned long _mshash(char *s) { - unsigned h = 0; + unsigned h = 0; - while (*s) { - unsigned int ch = tolower(*s); - s++; - h += ((unsigned)(ch) << 4) + 1249; - } - return h; + while (*s) { + unsigned int ch = tolower(*s); + s++; + h += ((unsigned)(ch) << 4) + 1249; + } + return h; } int isphonenum(Octstr *s) { - int i = 0, n = octstr_len(s); - char *cs; + 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= 1 && + octstr_get_cstr(s)[0] == '+') + i++; + for ( cs = octstr_get_cstr(s); i0) /* an email address. */ - return; + if (!address || !*address) return; + i = octstr_search_char(*address, '@', 0); + if (i>0) /* an email address. */ + return; - i = octstr_case_search(*address, octstr_imm("/TYPE="), 0); - if (i > 0) { - typ = octstr_copy(*address, i, octstr_len(*address)); - octstr_delete(*address, i, octstr_len(*address)); - } else - typ = NULL; + i = octstr_case_search(*address, octstr_imm("/TYPE="), 0); + if (i > 0) { + typ = octstr_copy(*address, i, octstr_len(*address)); + octstr_delete(*address, i, octstr_len(*address)); + } else + typ = NULL; - if (isphonenum(*address) || (typ && octstr_str_case_compare(typ, "/TYPE=PLMN") == 0)) { - mms_normalize_phonenum(address, unified_prefix, strip_prefixes); - octstr_append(*address, keep_suffix ? octstr_imm("/TYPE=PLMN") : octstr_imm("")); - } else if (typ) - octstr_append(*address, keep_suffix ? typ : octstr_imm("")); - else - octstr_append(*address, keep_suffix ? octstr_imm("@unknown") : octstr_imm("")); - octstr_destroy(typ); + if (isphonenum(*address) || (typ && octstr_str_case_compare(typ, "/TYPE=PLMN") == 0)) { + mms_normalize_phonenum(address, unified_prefix, strip_prefixes); + octstr_append(*address, keep_suffix ? octstr_imm("/TYPE=PLMN") : octstr_imm("")); + } else if (typ) + octstr_append(*address, keep_suffix ? typ : octstr_imm("")); + else + octstr_append(*address, keep_suffix ? octstr_imm("@unknown") : octstr_imm("")); + octstr_destroy(typ); } /* compare, reversed result! */ static int comp_fn(void *item, void *pattern) { - return (octstr_case_compare(item, pattern) == 0) ? 1 : 0; + return (octstr_case_compare(item, pattern) == 0) ? 1 : 0; } int is_allowed_host(Octstr *host, Octstr *host_list) { - List *l; - int ret; - gw_assert(host_list); - gw_assert(host); + List *l; + int ret; + gw_assert(host_list); + gw_assert(host); - l = octstr_split(host_list, octstr_imm(";")); + l = octstr_split(host_list, octstr_imm(";")); - ret = (gwlist_search(l, host, comp_fn) != NULL) ? 1 : 0; + ret = (gwlist_search(l, host, comp_fn) != NULL) ? 1 : 0; - gwlist_destroy(l, (void *)octstr_destroy); + gwlist_destroy(l, (void *)octstr_destroy); - return ret; + return ret; } #define SHELLCHARS "'|\"()[]{}$&!?*><%`\n \t\\" void escape_shell_chars(Octstr *str) { - Octstr *tmp; - int i, n; + Octstr *tmp; + int i, n; - octstr_strip_blanks(str); + octstr_strip_blanks(str); - tmp = octstr_duplicate(str); - octstr_delete(str, 0, octstr_len(str)); + tmp = octstr_duplicate(str); + octstr_delete(str, 0, octstr_len(str)); - for (i = 0, n = octstr_len(tmp); i < n; i++) { - int ch = octstr_get_char(tmp,i); + for (i = 0, n = octstr_len(tmp); i < n; i++) { + int ch = octstr_get_char(tmp,i); - if (strchr(SHELLCHARS, ch) != NULL) - octstr_append_char(str, '\\'); - octstr_append_char(str, ch); - } - octstr_destroy(tmp); + if (strchr(SHELLCHARS, ch) != NULL) + octstr_append_char(str, '\\'); + octstr_append_char(str, ch); + } + octstr_destroy(tmp); } int parse_cgivars(List *request_headers, Octstr *request_body, List **cgivars, List **cgivar_ctypes) { - Octstr *ctype = NULL, *charset = NULL; - int ret = 0; + Octstr *ctype = NULL, *charset = NULL; + int ret = 0; - if (request_body == NULL || - octstr_len(request_body) == 0 || cgivars == NULL) - return 0; /* Nothing to do, this is a normal GET request. */ + if (request_body == NULL || + octstr_len(request_body) == 0 || cgivars == NULL) + return 0; /* Nothing to do, this is a normal GET request. */ - http_header_get_content_type(request_headers, &ctype, &charset); + http_header_get_content_type(request_headers, &ctype, &charset); - if (*cgivars == NULL) - *cgivars = gwlist_create(); + if (*cgivars == NULL) + *cgivars = gwlist_create(); - if (*cgivar_ctypes == NULL) - *cgivar_ctypes = gwlist_create(); + if (*cgivar_ctypes == NULL) + *cgivar_ctypes = gwlist_create(); - if (!ctype) { - mms_warning(0, NULL, NULL, "MMS: Parse CGI Vars: Missing Content Type!"); - ret = -1; - goto done; - } + if (!ctype) { + mms_warning(0, NULL, NULL, "MMS: Parse CGI Vars: Missing Content Type!"); + ret = -1; + goto done; + } - if (octstr_case_compare(ctype, octstr_imm("application/x-www-form-urlencoded")) == 0) { - /* This is a normal POST form */ - List *l = octstr_split(request_body, octstr_imm("&")); - Octstr *v; + if (octstr_case_compare(ctype, octstr_imm("application/x-www-form-urlencoded")) == 0) { + /* This is a normal POST form */ + List *l = octstr_split(request_body, octstr_imm("&")); + Octstr *v; - while ((v = gwlist_extract_first(l)) != NULL) { - List *r = octstr_split(v, octstr_imm("=")); + while ((v = gwlist_extract_first(l)) != NULL) { + List *r = octstr_split(v, octstr_imm("=")); - if (gwlist_len(r) == 0) - mms_warning(0, NULL, NULL, "MMS: Parse CGI Vars: Missing CGI var name/value in POST data: %s", - octstr_get_cstr(request_body)); - else { - HTTPCGIVar *x = gw_malloc(sizeof *x); - x->name = gwlist_extract_first(r); - x->value = gwlist_extract_first(r); - if (!x->value) - x->value = octstr_create(""); + if (gwlist_len(r) == 0) + mms_warning(0, NULL, NULL, "MMS: Parse CGI Vars: Missing CGI var name/value in POST data: %s", + octstr_get_cstr(request_body)); + else { + HTTPCGIVar *x = gw_malloc(sizeof *x); + x->name = gwlist_extract_first(r); + x->value = gwlist_extract_first(r); + if (!x->value) + x->value = octstr_create(""); - octstr_strip_blanks(x->name); - octstr_strip_blanks(x->value); + octstr_strip_blanks(x->name); + octstr_strip_blanks(x->value); - octstr_url_decode(x->name); - octstr_url_decode(x->value); + octstr_url_decode(x->name); + octstr_url_decode(x->value); - gwlist_append(*cgivars, x); - } - octstr_destroy(v); - gwlist_destroy(r, octstr_destroy_item); - } - gwlist_destroy(l, NULL); - } else if (octstr_case_compare(ctype, octstr_imm("multipart/form-data")) == 0) { - /* multi-part form data */ - MIMEEntity *m = mime_http_to_entity(request_headers, request_body); - int i, n; + gwlist_append(*cgivars, x); + } + octstr_destroy(v); + gwlist_destroy(r, octstr_destroy_item); + } + gwlist_destroy(l, NULL); + } else if (octstr_case_compare(ctype, octstr_imm("multipart/form-data")) == 0) { + /* multi-part form data */ + MIMEEntity *m = mime_http_to_entity(request_headers, request_body); + int i, n; - if (!m) { - mms_warning(0, NULL, NULL, "MMS: Parse CGI Vars: Failed to parse multipart/form-data body: %s", - octstr_get_cstr(request_body)); - ret = -1; - goto done; - } - /* Go through body parts, pick out what we need. */ - for (i = 0, n = mime_entity_num_parts(m); i < n; i++) { - MIMEEntity *mp = mime_entity_get_part(m, i); - List *headers = mime_entity_headers(mp); - Octstr *body = mime_entity_body(mp); - Octstr *ct = http_header_value(headers, - octstr_imm("Content-Type")); - Octstr *cd = http_header_value(headers, - octstr_imm("Content-Disposition")); - Octstr *name = http_get_header_parameter(cd, octstr_imm("name")); + if (!m) { + mms_warning(0, NULL, NULL, "MMS: Parse CGI Vars: Failed to parse multipart/form-data body: %s", + octstr_get_cstr(request_body)); + ret = -1; + goto done; + } + /* Go through body parts, pick out what we need. */ + for (i = 0, n = mime_entity_num_parts(m); i < n; i++) { + MIMEEntity *mp = mime_entity_get_part(m, i); + List *headers = mime_entity_headers(mp); + Octstr *body = mime_entity_body(mp); + Octstr *ct = http_header_value(headers, + octstr_imm("Content-Type")); + Octstr *cd = http_header_value(headers, + octstr_imm("Content-Disposition")); + Octstr *name = http_get_header_parameter(cd, octstr_imm("name")); - if (name) { - HTTPCGIVar *x = gw_malloc(sizeof *x); + if (name) { + HTTPCGIVar *x = gw_malloc(sizeof *x); - /* Strip quotes */ - if (octstr_get_char(name, 0) == '"') { - octstr_delete(name, 0, 1); - octstr_truncate(name, octstr_len(name) - 1); - } + /* Strip quotes */ + if (octstr_get_char(name, 0) == '"') { + octstr_delete(name, 0, 1); + octstr_truncate(name, octstr_len(name) - 1); + } - x->name = octstr_duplicate(name); - x->value = octstr_duplicate(body); + x->name = octstr_duplicate(name); + x->value = octstr_duplicate(body); - gwlist_append(*cgivars, x); + gwlist_append(*cgivars, x); - if (ct) { /* If the content type is set, use it. */ - x = gw_malloc(sizeof *x); - x->name = octstr_duplicate(name); - x->value = octstr_duplicate(ct); + if (ct) { /* If the content type is set, use it. */ + x = gw_malloc(sizeof *x); + x->name = octstr_duplicate(name); + x->value = octstr_duplicate(ct); - gwlist_append(*cgivar_ctypes, x); - } - octstr_destroy(name); - } + gwlist_append(*cgivar_ctypes, x); + } + octstr_destroy(name); + } - octstr_destroy(ct); - octstr_destroy(cd); - octstr_destroy(body); - http_destroy_headers(headers); - mime_entity_destroy(mp); - } - mime_entity_destroy(m); + octstr_destroy(ct); + octstr_destroy(cd); + octstr_destroy(body); + http_destroy_headers(headers); + mime_entity_destroy(mp); + } + mime_entity_destroy(m); - } else /* else it is nothing that we know about, so simply go away... */ - ret = -1; - done: - octstr_destroy(ctype); - octstr_destroy(charset); - return ret; + } else /* else it is nothing that we know about, so simply go away... */ + ret = -1; +done: + octstr_destroy(ctype); + octstr_destroy(charset); + return ret; } /* get content-ID header, fix: WAP decoder may leave \" at beginning */ Octstr *_x_get_content_id(List *headers) { - Octstr *cid = http_header_value(headers, octstr_imm("Content-ID")); + Octstr *cid = http_header_value(headers, octstr_imm("Content-ID")); - if (cid) - if (octstr_get_char(cid, 0) == '"' && - octstr_get_char(cid, octstr_len(cid) - 1) != '"') - octstr_delete(cid, 0,1); - return cid; + if (cid) + if (octstr_get_char(cid, 0) == '"' && + octstr_get_char(cid, octstr_len(cid) - 1) != '"') + octstr_delete(cid, 0,1); + return cid; } /* Utility: Take a header list, remove any boundary parameter from the content-type @@ -1497,158 +1499,158 @@ Octstr *_x_get_content_id(List *headers) */ void strip_boundary_element(List *headers, char *s) { - Octstr *ctype = NULL, *params = NULL; - Octstr *value; - int n; + Octstr *ctype = NULL, *params = NULL; + Octstr *value; + int n; - gw_assert(headers); + gw_assert(headers); - if ((n = get_content_type(headers, &ctype, ¶ms)) < 0) { - octstr_destroy(ctype); - ctype = NULL; /* no ctype found, so do not replace it! */ - } else if (ctype && - DRM_CONTENT_TYPE(ctype)) { - octstr_destroy(ctype); - ctype = NULL; /* leave drm alone! */ - } + if ((n = get_content_type(headers, &ctype, ¶ms)) < 0) { + octstr_destroy(ctype); + ctype = NULL; /* no ctype found, so do not replace it! */ + } else if (ctype && + DRM_CONTENT_TYPE(ctype)) { + octstr_destroy(ctype); + ctype = NULL; /* leave drm alone! */ + } - if (s) {/* we are replacing the content type as well as stripping */ - octstr_destroy(ctype); - ctype = octstr_create(s); - } + if (s) {/* we are replacing the content type as well as stripping */ + octstr_destroy(ctype); + ctype = octstr_create(s); + } - if (params && ctype) { - List *h = get_value_parameters(params); - Octstr *ps; - http_header_remove_all(h,"boundary"); /* We don't need the boundary param if it is there. */ - ps = make_value_parameters(h); + if (params && ctype) { + List *h = get_value_parameters(params); + Octstr *ps; + http_header_remove_all(h,"boundary"); /* We don't need the boundary param if it is there. */ + ps = make_value_parameters(h); - value = octstr_format("%S%s%S", ctype, - (ps && octstr_len(ps) > 0) ? "; " : "", - ps); - octstr_destroy(ps); - http_destroy_headers(h); - } else - value = ctype; - if (value) { - http_header_remove_all(headers, "Content-Type"); - http_header_add(headers, "Content-Type", octstr_get_cstr(value)); - } - if (ctype != value) - octstr_destroy(ctype); - octstr_destroy(value); - octstr_destroy(params); + value = octstr_format("%S%s%S", ctype, + (ps && octstr_len(ps) > 0) ? "; " : "", + ps); + octstr_destroy(ps); + http_destroy_headers(h); + } else + value = ctype; + if (value) { + http_header_remove_all(headers, "Content-Type"); + http_header_add(headers, "Content-Type", octstr_get_cstr(value)); + } + if (ctype != value) + octstr_destroy(ctype); + octstr_destroy(value); + octstr_destroy(params); } /* Mapping file extensions to content types. */ static struct { - char *ctype, *file_ext; + char *ctype, *file_ext; } exts[] = { - {"text/plain", "txt"}, - {"image/jpeg", "jpg"}, - {"image/jpeg", "jpeg"}, - {"image/png", "png"}, - {"image/tiff", "tiff"}, - {"image/gif", "gif"}, - {"image/bmp", "bmp"}, - {"image/vnd.wap.wbmp", "wbmp"}, - {"image/x-bmp", "bmp"}, - {"image/x-wmf", "bmp"}, - {"image/vnd.wap.wpng", "png"}, - {"image/x-up-wpng", "png"}, - {"audio/mpeg", "mp3"}, - {"audio/wav", "wav"}, - {"audio/basic", "au"}, - {"audio/amr", "amr"}, - {"audio/x-amr", "amr"}, - {"audio/amr-wb", "amr"}, - {"audio/midi", "mid"}, - {"audio/sp-midi", "mid"}, - {"application/smil", "smil"}, - {"application/smil", "smi"}, - {"application/vnd.wap.mms-message", "mms"}, - {"application/java-archive", "jar"}, - {"video/3gpp", "3gp"}, - {"video/3gpp", "3gp2"}, - {"video/3gpp2","3g2"}, - {"audio/vnd.qcelp", "qcp"}, + {"text/plain", "txt"}, + {"image/jpeg", "jpg"}, + {"image/jpeg", "jpeg"}, + {"image/png", "png"}, + {"image/tiff", "tiff"}, + {"image/gif", "gif"}, + {"image/bmp", "bmp"}, + {"image/vnd.wap.wbmp", "wbmp"}, + {"image/x-bmp", "bmp"}, + {"image/x-wmf", "bmp"}, + {"image/vnd.wap.wpng", "png"}, + {"image/x-up-wpng", "png"}, + {"audio/mpeg", "mp3"}, + {"audio/wav", "wav"}, + {"audio/basic", "au"}, + {"audio/amr", "amr"}, + {"audio/x-amr", "amr"}, + {"audio/amr-wb", "amr"}, + {"audio/midi", "mid"}, + {"audio/sp-midi", "mid"}, + {"application/smil", "smil"}, + {"application/smil", "smi"}, + {"application/vnd.wap.mms-message", "mms"}, + {"application/java-archive", "jar"}, + {"video/3gpp", "3gp"}, + {"video/3gpp", "3gp2"}, + {"video/3gpp2","3g2"}, + {"audio/vnd.qcelp", "qcp"}, - {MBUNI_MULTIPART_TYPE, "urls"}, /* mbuni url list type. */ - {NULL, NULL} + {MBUNI_MULTIPART_TYPE, "urls"}, /* mbuni url list type. */ + {NULL, NULL} }; /* Some of Web languages used for generating content, but can't be a content itself. */ static struct { - char *language, *file_ext; + char *language, *file_ext; } l_exts[] = { - {"Perl", "pl"}, - {"Php", "php"}, - {"Python", "py"}, - {"Common Gateway Interface", "cgi"}, - {"Active Server Page", "asp"}, - {"Java Server Page", "jsp"}, - {"Ruby on Rails", "rb"}, - {"Tool Command Language", "tcl"}, - {"Shell Command Language", "sh"}, - {"Executables", "exe"}, - {NULL, NULL} + {"Perl", "pl"}, + {"Php", "php"}, + {"Python", "py"}, + {"Common Gateway Interface", "cgi"}, + {"Active Server Page", "asp"}, + {"Java Server Page", "jsp"}, + {"Ruby on Rails", "rb"}, + {"Tool Command Language", "tcl"}, + {"Shell Command Language", "sh"}, + {"Executables", "exe"}, + {NULL, NULL} }; Octstr *filename2content_type(char *fname) { - char *p = strrchr(fname, '.'); - int i; + char *p = strrchr(fname, '.'); + int i; - if (p) - for (i = 0; exts[i].file_ext; i++) - if (strcasecmp(p+1, exts[i].file_ext) == 0) - return octstr_imm(exts[i].ctype); + if (p) + for (i = 0; exts[i].file_ext; i++) + if (strcasecmp(p+1, exts[i].file_ext) == 0) + return octstr_imm(exts[i].ctype); - return octstr_imm("application/octet-stream"); + return octstr_imm("application/octet-stream"); } static char *content_type2file_ext(Octstr *ctype) { - int i, j; + int i, j; - /* Take the first value, expecting content-type! */ - if ((j = octstr_search_char(ctype, ';', 0)) != -1) - octstr_delete(ctype, j, octstr_len(ctype)); + /* Take the first value, expecting content-type! */ + if ((j = octstr_search_char(ctype, ';', 0)) != -1) + octstr_delete(ctype, j, octstr_len(ctype)); - for (i = 0; exts[i].file_ext; i++) - if (octstr_str_case_compare(ctype, exts[i].ctype) == 0) - return exts[i].file_ext; + for (i = 0; exts[i].file_ext; i++) + if (octstr_str_case_compare(ctype, exts[i].ctype) == 0) + return exts[i].file_ext; - return "dat"; + return "dat"; } char *make_file_ext(Octstr *url, Octstr *ctype, char fext[5]) { - int i; - fext[0] = 0; - if (url) { - HTTPURLParse *h = parse_url(url); - char *s, *p; - if (!h) - goto done; + int i; + fext[0] = 0; + if (url) { + HTTPURLParse *h = parse_url(url); + char *s, *p; + if (!h) + goto done; - s = h->path ? octstr_get_cstr(h->path) : ""; + s = h->path ? octstr_get_cstr(h->path) : ""; - if ((p = strrchr(s, '.')) != NULL) - strncpy(fext, p+1, 4); /* max length of 4. */ + if ((p = strrchr(s, '.')) != NULL) + strncpy(fext, p+1, 4); /* max length of 4. */ - http_urlparse_destroy(h); + http_urlparse_destroy(h); - for (i = 0; l_exts[i].file_ext; i++) - if (strcasecmp(fext, l_exts[i].file_ext) == 0) - return content_type2file_ext(ctype); + for (i = 0; l_exts[i].file_ext; i++) + if (strcasecmp(fext, l_exts[i].file_ext) == 0) + return content_type2file_ext(ctype); - if (fext[0]) - return fext; - } - done: - return content_type2file_ext(ctype); + if (fext[0]) + return fext; + } +done: + return content_type2file_ext(ctype); } static int fetch_url_with_auth(HTTPCaller *c, int method, Octstr *url, List *request_headers, Octstr *body, Octstr *auth_hdr, List **reply_headers, Octstr **reply_body); @@ -1657,101 +1659,101 @@ int mms_url_fetch_content(int method, Octstr *url, List *request_headers, Octstr *body, List **reply_headers, Octstr **reply_body) { - int status = 0; - Octstr *furl = NULL; + int status = 0; + Octstr *furl = NULL; - 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); + 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 *n = NULL, *h = NULL; + Octstr *n = NULL, *h = NULL; - if (octstr_len(ctype) == 0) - octstr_append_cstr(ctype, "text/plain; charset=us-ascii"); + if (octstr_len(ctype) == 0) + octstr_append_cstr(ctype, "text/plain; charset=us-ascii"); - split_header_value(ctype, &n, &h); + split_header_value(ctype, &n, &h); - if (h) { - List *ph = get_value_parameters(h); - Octstr *v = NULL; + if (h) { + List *ph = get_value_parameters(h); + Octstr *v = NULL; - if ((ph && (v = http_header_value(ph, octstr_imm("base64"))) != NULL) || - octstr_case_search(h, octstr_imm("base64"), 0) >= 0) { /* has base64 item */ - Octstr *p = NULL; + if ((ph && (v = http_header_value(ph, octstr_imm("base64"))) != NULL) || + octstr_case_search(h, octstr_imm("base64"), 0) >= 0) { /* has base64 item */ + Octstr *p = NULL; - octstr_base64_to_binary(data); - http_header_remove_all(ph, "base64"); + octstr_base64_to_binary(data); + http_header_remove_all(ph, "base64"); - octstr_destroy(ctype); + octstr_destroy(ctype); - if (gwlist_len(ph) > 0) { - p = make_value_parameters(ph); - ctype = octstr_format("%S; %S", - n,p); - octstr_destroy(p); - } else - ctype = octstr_format("%S", n); - } + if (gwlist_len(ph) > 0) { + p = make_value_parameters(ph); + ctype = octstr_format("%S; %S", + n,p); + octstr_destroy(p); + } else + ctype = octstr_format("%S", n); + } - if (ph) - http_destroy_headers(ph); + if (ph) + http_destroy_headers(ph); - octstr_destroy(v); - octstr_destroy(h); - } + octstr_destroy(v); + octstr_destroy(h); + } - octstr_destroy(n); + octstr_destroy(n); - *reply_body = data; - *reply_headers = http_create_empty_headers(); - http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype)); + *reply_body = data; + *reply_headers = http_create_empty_headers(); + http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype)); - octstr_destroy(ctype); - status = HTTP_OK; - } else if (octstr_search(url, octstr_imm("file://"), 0) == 0) { - char *file = octstr_get_cstr(url) + 6; - Octstr *ctype = filename2content_type(file); - Octstr *data = octstr_read_file(file); + octstr_destroy(ctype); + status = HTTP_OK; + } else if (octstr_search(url, octstr_imm("file://"), 0) == 0) { + char *file = octstr_get_cstr(url) + 6; + Octstr *ctype = filename2content_type(file); + Octstr *data = octstr_read_file(file); - *reply_body = data; - *reply_headers = http_create_empty_headers(); - http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype)); + *reply_body = data; + *reply_headers = http_create_empty_headers(); + http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype)); - status = data ? HTTP_OK : HTTP_NOT_FOUND; - octstr_destroy(ctype); - } else { - HTTPCaller *c = http_caller_create(); - http_start_request(c, method, url, request_headers, body, 1, NULL, NULL); - if (http_receive_result_real(c, &status, &furl, reply_headers, reply_body,1) == NULL) - status = -1; - if (status == HTTP_UNAUTHORIZED) { - Octstr *v = http_header_value(*reply_headers, octstr_imm("WWW-Authenticate")); + status = data ? HTTP_OK : HTTP_NOT_FOUND; + octstr_destroy(ctype); + } else { + HTTPCaller *c = http_caller_create(); + http_start_request(c, method, url, request_headers, body, 1, NULL, NULL); + if (http_receive_result_real(c, &status, &furl, reply_headers, reply_body,1) == NULL) + status = -1; + if (status == HTTP_UNAUTHORIZED) { + Octstr *v = http_header_value(*reply_headers, octstr_imm("WWW-Authenticate")); - status = fetch_url_with_auth(c, method, url, request_headers, body, v, - reply_headers, reply_body); + status = fetch_url_with_auth(c, method, url, request_headers, body, v, + reply_headers, reply_body); - octstr_destroy(v); - } - http_caller_destroy(c); - } + octstr_destroy(v); + } + http_caller_destroy(c); + } - octstr_destroy(furl); + octstr_destroy(furl); - return status; + return status; } Octstr *get_stripped_param_value(Octstr *value, Octstr *param) { - Octstr *x = http_get_header_parameter(value, param); + Octstr *x = http_get_header_parameter(value, param); - if (x != NULL && - octstr_get_char(x, 0) == '"' && - octstr_get_char(x, octstr_len(x) - 1) == '"') { - octstr_delete(x, 0, 1); - octstr_delete(x, octstr_len(x) - 1, 1); - } - return x; + if (x != NULL && + octstr_get_char(x, 0) == '"' && + octstr_get_char(x, octstr_len(x) - 1) == '"') { + octstr_delete(x, 0, 1); + octstr_delete(x, octstr_len(x) - 1, 1); + } + return x; } @@ -1761,448 +1763,483 @@ static Octstr *make_url(HTTPURLParse *h); static int fetch_url_with_auth(HTTPCaller *c, int method, Octstr *url, List *request_headers, Octstr *body, Octstr *auth_hdr, List **reply_headers, Octstr **reply_body) { - Octstr *xauth_value = auth_hdr ? octstr_duplicate(auth_hdr) : octstr_create(""); - Octstr *domain = NULL, *nonce = NULL, *opaque = NULL, *algo = NULL, *auth_type = NULL, *x; - Octstr *realm = NULL, *xurl = NULL; - Octstr *cnonce = NULL; - char *nonce_count = "00000001"; - Octstr *A1 = NULL, *A2 = NULL, *rd = NULL; - List *qop = NULL, *l = NULL; - int i, status = HTTP_UNAUTHORIZED, has_auth = 0, has_auth_int = 0; - HTTPURLParse *h = parse_url(url); - char *m_qop = NULL; - time_t t = time(NULL); + Octstr *xauth_value = auth_hdr ? octstr_duplicate(auth_hdr) : octstr_create(""); + Octstr *domain = NULL, *nonce = NULL, *opaque = NULL, *algo = NULL, *auth_type = NULL, *x; + Octstr *realm = NULL, *xurl = NULL; + Octstr *cnonce = NULL; + char *nonce_count = "00000001"; + Octstr *A1 = NULL, *A2 = NULL, *rd = NULL; + List *qop = NULL, *l = NULL; + int i, status = HTTP_UNAUTHORIZED, has_auth = 0, has_auth_int = 0; + HTTPURLParse *h = parse_url(url); + char *m_qop = NULL; + time_t t = time(NULL); - /* Check that there is a username and password in the URL! */ + /* Check that there is a username and password in the URL! */ - if (h == NULL || h->user == NULL || octstr_len(h->user) == 0) - goto done; + if (h == NULL || h->user == NULL || octstr_len(h->user) == 0) + goto done; - /* First we get the auth type: */ + /* First we get the auth type: */ - if ((i = octstr_search_char(xauth_value, ' ', 0)) < 0) { - mms_warning(0, NULL, NULL, "Mal-formed WWW-Authenticate header (%s) received while fetching %s!", - octstr_get_cstr(xauth_value), url ? octstr_get_cstr(url) : ""); - status = -1; - goto done; - } - auth_type = octstr_copy(xauth_value, 0, i); - octstr_delete(xauth_value, 0, i+1); + if ((i = octstr_search_char(xauth_value, ' ', 0)) < 0) { + mms_warning(0, NULL, NULL, "Mal-formed WWW-Authenticate header (%s) received while fetching %s!", + octstr_get_cstr(xauth_value), url ? octstr_get_cstr(url) : ""); + status = -1; + goto done; + } + auth_type = octstr_copy(xauth_value, 0, i); + octstr_delete(xauth_value, 0, i+1); - if (octstr_str_case_compare(auth_type, "Basic") == 0) { - status = HTTP_UNAUTHORIZED; /* suported by default by GWLIB so if we get here, means bad passwd. */ - goto done; - } /* else digest. */ + if (octstr_str_case_compare(auth_type, "Basic") == 0) { + status = HTTP_UNAUTHORIZED; /* suported by default by GWLIB so if we get here, means bad passwd. */ + goto done; + } /* else digest. */ - /* Put back some fake data so what we have can be parsed easily. */ - if ((l = http_header_split_auth_value(xauth_value)) != NULL) { - Octstr *x = gwlist_get(l, 0); - octstr_insert(x, octstr_imm("_none; "), 0); /* make it easier to parse. */ - octstr_destroy(xauth_value); - xauth_value = octstr_duplicate(x); + /* Put back some fake data so what we have can be parsed easily. */ + if ((l = http_header_split_auth_value(xauth_value)) != NULL) { + Octstr *x = gwlist_get(l, 0); + octstr_insert(x, octstr_imm("_none; "), 0); /* make it easier to parse. */ + octstr_destroy(xauth_value); + xauth_value = octstr_duplicate(x); - gwlist_destroy(l, (gwlist_item_destructor_t *)octstr_destroy); - } else - mms_warning(0, NULL, NULL, "Mal-formed Digest header (%s) while fetching (%s)!", - octstr_get_cstr(xauth_value), url ? octstr_get_cstr(url) : ""); + gwlist_destroy(l, (gwlist_item_destructor_t *)octstr_destroy); + } else + mms_warning(0, NULL, NULL, "Mal-formed Digest header (%s) while fetching (%s)!", + octstr_get_cstr(xauth_value), url ? octstr_get_cstr(url) : ""); - realm = get_stripped_param_value(xauth_value, octstr_imm("realm")); - domain = get_stripped_param_value(xauth_value, octstr_imm("domain")); - nonce = get_stripped_param_value(xauth_value, octstr_imm("nonce")); - opaque = get_stripped_param_value(xauth_value, octstr_imm("opaque")); - algo = get_stripped_param_value(xauth_value, octstr_imm("algorithm")); + realm = get_stripped_param_value(xauth_value, octstr_imm("realm")); + domain = get_stripped_param_value(xauth_value, octstr_imm("domain")); + nonce = get_stripped_param_value(xauth_value, octstr_imm("nonce")); + opaque = get_stripped_param_value(xauth_value, octstr_imm("opaque")); + algo = get_stripped_param_value(xauth_value, octstr_imm("algorithm")); - if ((x = get_stripped_param_value(xauth_value, octstr_imm("qop"))) != NULL) { - int i; - qop = octstr_split(x, octstr_imm(",")); - octstr_destroy(x); - for (i = 0; iuser, realm, h->pass ? h->pass : octstr_imm("")); - A1 = md5(x); - octstr_destroy(x); + /* Make A1 */ + x = octstr_format("%S:%S:%S", + h->user, realm, h->pass ? h->pass : octstr_imm("")); + A1 = md5(x); + octstr_destroy(x); - if (algo != NULL && octstr_str_case_compare(algo, "MD5-sess") == 0) { - x = octstr_format("%S:%S:%S", - A1, nonce, cnonce); - octstr_destroy(A1); - A1 = md5(x); - octstr_destroy(x); - } - octstr_binary_to_hex(A1,0); + if (algo != NULL && octstr_str_case_compare(algo, "MD5-sess") == 0) { + x = octstr_format("%S:%S:%S", + A1, nonce, cnonce); + octstr_destroy(A1); + A1 = md5(x); + octstr_destroy(x); + } + octstr_binary_to_hex(A1,0); - /* Make A2. */ - x = octstr_format("%s:%S", - http_method2name(method), - h->path); - if (qop != NULL && has_auth_int && !has_auth) { /* if qop, and qop=auth-int */ - Octstr *y; - m_qop = "auth-int"; + /* Make A2. */ + x = octstr_format("%s:%S", + http_method2name(method), + h->path); + if (qop != NULL && has_auth_int && !has_auth) { /* if qop, and qop=auth-int */ + Octstr *y; + m_qop = "auth-int"; - y = md5(body); - octstr_binary_to_hex(y,0); + y = md5(body); + octstr_binary_to_hex(y,0); - octstr_append_char(x, ':'); - octstr_append(x, y); + octstr_append_char(x, ':'); + octstr_append(x, y); - octstr_destroy(y); - } else if (qop) - m_qop = "auth"; + octstr_destroy(y); + } else if (qop) + m_qop = "auth"; - A2 = md5(x); - octstr_destroy(x); - octstr_binary_to_hex(A2,0); + A2 = md5(x); + octstr_destroy(x); + octstr_binary_to_hex(A2,0); - /* Finally make the digest response */ - if (qop) - x = octstr_format("%S:%S:%s:%S:%s:%S", - A1, nonce, nonce_count, cnonce, - m_qop, A2); - else - x = octstr_format("%S:%S:%S", A1, nonce, A2); + /* Finally make the digest response */ + if (qop) + x = octstr_format("%S:%S:%s:%S:%s:%S", + A1, nonce, nonce_count, cnonce, + m_qop, A2); + else + x = octstr_format("%S:%S:%S", A1, nonce, A2); - rd = md5(x); - octstr_destroy(x); - octstr_binary_to_hex(rd, 0); + rd = md5(x); + octstr_destroy(x); + octstr_binary_to_hex(rd, 0); - /* make the header value */ - x = octstr_format("Digest username=\"%S\", realm=\"%S\", response=\"%S\", nonce=\"%S\", uri=\"%S\"", - h->user, realm, rd, nonce, h->path); + /* make the header value */ + x = octstr_format("Digest username=\"%S\", realm=\"%S\", response=\"%S\", nonce=\"%S\", uri=\"%S\"", + h->user, realm, rd, nonce, h->path); - if (opaque) - octstr_format_append(x, ", opaque=\"%S\"", opaque); + if (opaque) + octstr_format_append(x, ", opaque=\"%S\"", opaque); - if (cnonce) - octstr_format_append(x, ", cnonce=\"%S\", nc=%s", cnonce, nonce_count); - if (m_qop) - octstr_format_append(x,", qop=%s", m_qop); - if (algo) - octstr_format_append(x,", algorithm=%S", algo); + if (cnonce) + octstr_format_append(x, ", cnonce=\"%S\", nc=%s", cnonce, nonce_count); + if (m_qop) + octstr_format_append(x,", qop=%s", m_qop); + if (algo) + octstr_format_append(x,", algorithm=%S", algo); - http_header_remove_all(request_headers, "Authorization"); - http_header_add(request_headers, "Authorization", octstr_get_cstr(x)); - octstr_destroy(x); + http_header_remove_all(request_headers, "Authorization"); + http_header_add(request_headers, "Authorization", octstr_get_cstr(x)); + octstr_destroy(x); - /* Remove username, password, then remake URL */ - octstr_destroy(h->user); - h->user = NULL; + /* Remove username, password, then remake URL */ + octstr_destroy(h->user); + h->user = NULL; - octstr_destroy(h->pass); - h->pass = NULL; + octstr_destroy(h->pass); + h->pass = NULL; - xurl = make_url(h); - x = NULL; - http_start_request(c, method, xurl, request_headers, body, 1, NULL, NULL); - if (http_receive_result_real(c, &status, &x, reply_headers, reply_body,1) == NULL) - status = -1; - if (x) - octstr_destroy(x); - done: - octstr_destroy(xauth_value); - octstr_destroy(realm); - octstr_destroy(domain); - octstr_destroy(nonce); - octstr_destroy(opaque); - octstr_destroy(algo); - octstr_destroy(xurl); - octstr_destroy(cnonce); - gwlist_destroy(qop, (gwlist_item_destructor_t *)octstr_destroy); - if (h) - http_urlparse_destroy(h); + xurl = make_url(h); + x = NULL; + http_start_request(c, method, xurl, request_headers, body, 1, NULL, NULL); + if (http_receive_result_real(c, &status, &x, reply_headers, reply_body,1) == NULL) + status = -1; + if (x) + octstr_destroy(x); +done: + octstr_destroy(xauth_value); + octstr_destroy(realm); + octstr_destroy(domain); + octstr_destroy(nonce); + octstr_destroy(opaque); + octstr_destroy(algo); + octstr_destroy(xurl); + octstr_destroy(cnonce); + gwlist_destroy(qop, (gwlist_item_destructor_t *)octstr_destroy); + if (h) + http_urlparse_destroy(h); - return status; + return status; } static Octstr *make_url(HTTPURLParse *h) { - Octstr *url = octstr_duplicate(h->scheme); + Octstr *url = octstr_duplicate(h->scheme); - if (h->user) { - octstr_format_append(url, "%S", h->user); + if (h->user) { + octstr_format_append(url, "%S", h->user); - if (h->pass) - octstr_format_append(url, ":%S", h->pass); - octstr_format_append(url, "@"); - } - octstr_format_append(url, "%S:%d%S", h->host, h->port, h->path); + if (h->pass) + octstr_format_append(url, ":%S", h->pass); + octstr_format_append(url, "@"); + } + octstr_format_append(url, "%S:%d%S", h->host, h->port, h->path); - if (h->query) - octstr_format_append(url, "?%S", h->query); + if (h->query) + octstr_format_append(url, "?%S", h->query); - if (h->fragment) - octstr_format_append(url, "#%S", h->fragment); - return url; + if (h->fragment) + octstr_format_append(url, "#%S", h->fragment); + return url; } static int is_separator_char(int c) { - switch (c) { - case '(': - case ')': - case '<': - case '>': - case '@': - case ',': - case ';': - case ':': - case '\\': - case '"': - case '/': - case '[': - case ']': - case '?': - case '=': - case '{': - case '}': - case 32: /* SP */ - case 9: /* HT */ - return 1; - default: - return 0; - } + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '@': + case ',': + case ';': + case ':': + case '\\': + case '"': + case '/': + case '[': + case ']': + case '?': + case '=': + case '{': + case '}': + case 32: /* SP */ + case 9: /* HT */ + return 1; + default: + return 0; + } } /* Is this char part of a 'token' as defined by HTTP? */ static int is_token_char(int c) { - return c >= 32 && c < 127 && !is_separator_char(c); + return c >= 32 && c < 127 && !is_separator_char(c); } /* Is this string a 'token' as defined by HTTP? */ int mms_is_token(Octstr *token) { - return octstr_len(token) > 0 && - octstr_check_range(token, 0, octstr_len(token), is_token_char); + return octstr_len(token) > 0 && + octstr_check_range(token, 0, octstr_len(token), is_token_char); } int has_node_children(xmlNodePtr node) { - xmlNodePtr x; + xmlNodePtr x; - for (x = node->xmlChildrenNode; x; x = x->next) - if (x->type == XML_ELEMENT_NODE) - return 1; - return 0; + for (x = node->xmlChildrenNode; x; x = x->next) + if (x->type == XML_ELEMENT_NODE) + return 1; + return 0; } /* strip all but content-type, content-id, content-transfer-disposition, content-location */ void strip_non_essential_headers(MIMEEntity *mime) { - Octstr *v; - List *h, *h2; + Octstr *v; + List *h, *h2; - if (!mime) return; + if (!mime) return; - h = mime_entity_headers(mime); - h2 = http_create_empty_headers(); + h = mime_entity_headers(mime); + h2 = http_create_empty_headers(); - if ((v = http_header_value(h, octstr_imm("Content-Type"))) != NULL) { - http_header_add(h2, "Content-Type", octstr_get_cstr(v)); - octstr_destroy(v); - } + if ((v = http_header_value(h, octstr_imm("Content-Type"))) != NULL) { + http_header_add(h2, "Content-Type", octstr_get_cstr(v)); + octstr_destroy(v); + } - if ((v = http_header_value(h, octstr_imm("Content-ID"))) != NULL) { - http_header_add(h2, "Content-ID", octstr_get_cstr(v)); - octstr_destroy(v); - } + if ((v = http_header_value(h, octstr_imm("Content-ID"))) != NULL) { + http_header_add(h2, "Content-ID", octstr_get_cstr(v)); + octstr_destroy(v); + } - if ((v = http_header_value(h, octstr_imm("Content-Location"))) != NULL) { - http_header_add(h2, "Content-Location", octstr_get_cstr(v)); - octstr_destroy(v); - } + if ((v = http_header_value(h, octstr_imm("Content-Location"))) != NULL) { + http_header_add(h2, "Content-Location", octstr_get_cstr(v)); + octstr_destroy(v); + } - if ((v = http_header_value(h, octstr_imm("Content-Transfer-Encoding"))) != NULL) { - http_header_add(h2, "Content-Transfer-Encoding", octstr_get_cstr(v)); - octstr_destroy(v); - } + if ((v = http_header_value(h, octstr_imm("Content-Transfer-Encoding"))) != NULL) { + http_header_add(h2, "Content-Transfer-Encoding", octstr_get_cstr(v)); + octstr_destroy(v); + } - mime_replace_headers(mime,h2); - http_destroy_headers(h); - http_destroy_headers(h2); + mime_replace_headers(mime,h2); + http_destroy_headers(h); + http_destroy_headers(h2); } void *_mms_load_module(mCfg *cfg, mCfgGrp *grp, char *config_key, char *symbolname, void *shell_builtin) { - Octstr *s = NULL; - void *retval = NULL; + Octstr *s = NULL; + void *retval = NULL; - s = mms_cfg_get(cfg, grp, octstr_imm(config_key)); + s = mms_cfg_get(cfg, grp, octstr_imm(config_key)); - if (s) { - void *x; - void *y = NULL; + if (s) { + void *x; + void *y = NULL; #ifdef __APPLE__ - char sbuf[512]; + char sbuf[512]; #endif - /* First look for the builtin: keyword. - * For now only builtin:shell is supported. - */ - if (octstr_case_search(s, octstr_imm("builtin:shell"), 0) >= 0) - retval = shell_builtin; - else { - x = dlopen(octstr_get_cstr(s), RTLD_LAZY); + /* First look for the builtin: keyword. + * For now only builtin:shell is supported. + */ + if (octstr_case_search(s, octstr_imm("builtin:shell"), 0) >= 0) + retval = shell_builtin; + else { + x = dlopen(octstr_get_cstr(s), RTLD_LAZY); #ifdef __APPLE__ - sprintf(sbuf, "_%s", symbolname); + sprintf(sbuf, "_%s", symbolname); #endif - if (x == NULL || ((y = dlsym(x, symbolname)) == NULL + if (x == NULL || ((y = dlsym(x, symbolname)) == NULL #ifdef __APPLE__ /* fink version of dlsym has issues it seems. */ - && (y = dlsym(x, sbuf)) == NULL + && (y = dlsym(x, sbuf)) == NULL #endif )) - panic(0, "Unable to load dynamic libary (%s): %s", - octstr_get_cstr(s), - dlerror()); - else - retval = y; - } - octstr_destroy(s); - } + panic(0, "Unable to load dynamic libary (%s): %s", + octstr_get_cstr(s), + dlerror()); + else + retval = y; + } + octstr_destroy(s); + } - return retval; + return retval; } Octstr *extract_phonenum(Octstr *num, Octstr *unified_prefix) { - Octstr *phonenum; - int j = octstr_case_search(num, octstr_imm("/TYPE=PLMN"), 0); + Octstr *phonenum; + int j = octstr_case_search(num, octstr_imm("/TYPE=PLMN"), 0); - if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == octstr_len(num)) - phonenum = octstr_copy(num, 0, j); - else - phonenum = octstr_duplicate(num); + if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == octstr_len(num)) + phonenum = octstr_copy(num, 0, j); + else + phonenum = octstr_duplicate(num); - if (unified_prefix) - normalize_number(octstr_get_cstr(unified_prefix), &phonenum); + if (unified_prefix) + normalize_number(octstr_get_cstr(unified_prefix), &phonenum); - return phonenum; + return phonenum; } void strip_quoted_string(Octstr *s) { - if (s == NULL) return; + if (s == NULL) return; - octstr_strip_blanks(s); - if (octstr_get_char(s, 0) == '"') { - octstr_delete(s, 0, 1); - octstr_delete(s, octstr_len(s)-1, 1); - } + octstr_strip_blanks(s); + if (octstr_get_char(s, 0) == '"') { + octstr_delete(s, 0, 1); + octstr_delete(s, octstr_len(s)-1, 1); + } } MIMEEntity *make_multipart_formdata(void) { - MIMEEntity *x = mime_entity_create(); - List *rh = http_create_empty_headers(); + MIMEEntity *x = mime_entity_create(); + List *rh = http_create_empty_headers(); - http_header_add(rh, "User-Agent", MM_NAME "/" VERSION); - http_header_add(rh, "Accept", "*/*"); - http_header_add(rh, "Content-Type", "multipart/form-data"); - mime_replace_headers(x, rh); - http_destroy_headers(rh); + http_header_add(rh, "User-Agent", MM_NAME "/" VERSION); + http_header_add(rh, "Accept", "*/*"); + http_header_add(rh, "Content-Type", "multipart/form-data"); + mime_replace_headers(x, rh); + http_destroy_headers(rh); - return x; + return x; } void add_multipart_form_field(MIMEEntity *multipart, char *field_name, char *ctype, char *content_loc, Octstr *data) { - MIMEEntity *p = mime_entity_create(); - List *xh = http_create_empty_headers(); - Octstr *cd = octstr_format("form-data; name=\"%s\"", field_name); + MIMEEntity *p = mime_entity_create(); + List *xh = http_create_empty_headers(); + Octstr *cd = octstr_format("form-data; name=\"%s\"", field_name); - if (content_loc) - octstr_format_append(cd, "; filename=\"%s\"", content_loc); + if (content_loc) + octstr_format_append(cd, "; filename=\"%s\"", content_loc); - http_header_add(xh, "Content-Disposition", octstr_get_cstr(cd)); - if (ctype) /* This header must come after the above it seems. */ - http_header_add(xh, "Content-Type", ctype); + http_header_add(xh, "Content-Disposition", octstr_get_cstr(cd)); + if (ctype) /* This header must come after the above it seems. */ + http_header_add(xh, "Content-Type", ctype); - mime_entity_set_body(p, data); - mime_replace_headers(p, xh); + mime_entity_set_body(p, data); + mime_replace_headers(p, xh); - mime_entity_add_part(multipart, p); /* add it to list so far. */ + mime_entity_add_part(multipart, p); /* add it to list so far. */ - mime_entity_destroy(p); - http_destroy_headers(xh); - octstr_destroy(cd); + mime_entity_destroy(p); + http_destroy_headers(xh); + octstr_destroy(cd); } +void fixup_address_type(List *headers, char *hdr, + char *unified_prefix, List *strip_prefixes) +{ + List *l; + int i, n; + + l = http_header_find_all(headers, hdr); + + http_header_remove_all(headers,hdr); + for (i = 0, n = gwlist_len(l); im->id, mm7_msgtype(mreq), 0, s, 0, + mmsbox_event_cb(h->m->id, mm7_msgtype(mreq), 0, s, 200, octstr_len(h->body), 0, from, to && gwlist_len(to) > 0 ? gwlist_get(to,0) : NULL, r, transid, NULL, value); octstr_destroy(s); @@ -466,7 +466,12 @@ static int queue_dlr(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *msgid, Octs qdir = get_mmsbox_queue_dir(from, lto, mmc, &mmc_id); /* get routing info. */ rr_uri = mmsbox_get_report_info(m, mmc, mmc_id, "delivery-report", status, rqh, NULL, 0, msgid); - + + mmsbox_event_cb(mmc->id, MM7_TAG_DeliveryReportReq, 0,octstr_imm("5.3.0"), 200, + 0, 0, from, + lto && gwlist_len(lto) > 0 ? gwlist_get(lto,0) : NULL, + msgid, NULL, NULL, status); + qf = qfs->mms_queue_add(from, lto, NULL, mmc ? mmc->id : NULL, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, @@ -699,7 +704,7 @@ static int mm7eaif_receive(MmsBoxHTTPClientInfo *h) s = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-Version")); - mmsbox_event_cb(h->m->id, mm7type, 0, s, 0, + mmsbox_event_cb(h->m->id, mm7type, 0, s, hstatus, msize, 0, hfrom, to && gwlist_len(to) > 0 ? gwlist_get(to,0) : NULL, msgid, otransid, NULL, value); @@ -963,7 +968,7 @@ static int mm7http_receive(MmsBoxHTTPClientInfo *h) } - mmsbox_event_cb(h->m->id, mm7type, 0, octstr_imm("1.0"), 0, + mmsbox_event_cb(h->m->id, mm7type, 0, octstr_imm("1.0"), 200, msize, 0, hfrom, to && gwlist_len(to) > 0 ? gwlist_get(to,0) : NULL, msgid, octstr_imm("0000"), NULL, value); @@ -1181,7 +1186,7 @@ static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, Octstr *to, /* Invoke call back */ s = mm7_soap_header_value(mreq, octstr_imm("MM7Version")); r = mm7_soap_header_value(mreq, octstr_imm("MessageID")); - mmsbox_event_cb(mmc->id, mm7_msgtype(mreq), 0, s, 0, + mmsbox_event_cb(mmc->id, mm7_msgtype(mreq), 0, s, hstatus, mms_msgsize(m), e->attempts, e->from, to,r, transid, hdrs, NULL); octstr_destroy(s); @@ -1497,12 +1502,16 @@ static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e, Octstr *to, id = mm7eaif_send(mmc, from, to, transid, vasid, e, m, &err, &retry); else if (mmc->type == HTTP_MMSC) id = mm7http_send(mmc,e, from, to, m, &err, &retry); - else if (mmc->type == CUSTOM_MMSC && mmc->custom_started) + else if (mmc->type == CUSTOM_MMSC && mmc->started) id = mmc->fns->send_msg(mmc->data, from, to, transid, linkedid, vasid, service_code, m, hdrs, &err, &retry); - else - mms_error_ex("MT", 0, "MM7", mmc->id, "MMC[%s] of unknown type, can't send!", +#if 0 + else if (mmc->type == MM4_MMSC && mmc->started) + (void )0; /* Already sent above */ +#endif + else + mms_error_ex("MT", 0, "MM7", mmc->id, "Can't send to MMC[%s]!", mmc->id ? octstr_get_cstr(mmc->id) : ""); throughput = mmc->throughput; @@ -1591,11 +1600,11 @@ static int sendMsg(MmsEnvelope *e) goto done; } - if (is_email) { + if (is_email || (mmc->type == MM4_MMSC && mmc->started)) { /* Handle MM4 recipient here as well */ int j = octstr_case_search(e->from, octstr_imm("/TYPE=PLMN"), 0); int k = octstr_case_search(e->from, octstr_imm("/TYPE=IPv"), 0); int len = octstr_len(e->from); - Octstr *pfrom; + Octstr *pfrom, *xto; if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) @@ -1604,11 +1613,18 @@ static int sendMsg(MmsEnvelope *e) pfrom = octstr_copy(e->from, 0, k); else pfrom = octstr_duplicate(e->from); + + if (!is_email) + xto = octstr_format("%S@%S", to->rcpt, + mmc && octstr_str_compare(mmc->mmsc_url, "*") != 0 ? mmc->mmsc_url : + octstr_imm("unknown")); + else + xto = octstr_duplicate(to->rcpt); if (octstr_search_char(e->from, '@', 0) < 0) octstr_format_append(pfrom,"@%S", myhostname); - res = mms_sendtoemail(pfrom, to->rcpt, + res = mms_sendtoemail(pfrom, xto, e->subject ? e->subject : octstr_imm(""), e->msgId, msg, 0, &err, octstr_get_cstr(sendmail_cmd), myhostname, 0, 0, @@ -1616,7 +1632,13 @@ static int sendMsg(MmsEnvelope *e) "", 0, e->xqfname, e->hdrs); + if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) + mmsbox_event_cb(NULL, MM7_TAG_SubmitReq, 1, octstr_imm("1.0"), 200, + mms_msgsize(msg), e->attempts, pfrom, + to->rcpt,NULL, NULL, e->hdrs, NULL); + octstr_destroy(pfrom); + octstr_destroy(xto); } else { res = mms_sendtommsc(mmc, e, to->rcpt, @@ -1740,3 +1762,640 @@ void mmsbox_outgoing_queue_runner(volatile sig_atomic_t *rstop) sendMsg, queue_interval, maxthreads, rstop); hmon->unregister_thread(); } + + +/* MM4 handler stuff */ +static void fixup_addresses(List *headers) +{ + fixup_address_type(headers, "To", + octstr_get_cstr(unified_prefix), strip_prefixes); + fixup_address_type(headers, "From", + octstr_get_cstr(unified_prefix), strip_prefixes); +} + + +static int send_mm4_res(int mtype, Octstr *to, Octstr *sender, Octstr *transid, + char *status, Octstr *msgid, + char *sendmail_cmd) +{ + char tmp[32]; + List *h = http_create_empty_headers(); + MIMEEntity *m = mime_entity_create(); + Octstr *err = NULL; + + /* Make headers */ + sprintf(tmp, "%d.%d.%d", + MAJOR_VERSION(MMS_3GPP_VERSION), + MINOR1_VERSION(MMS_3GPP_VERSION), + MINOR2_VERSION(MMS_3GPP_VERSION)); + + http_header_add(h, "X-Mms-3GPP-MMS-Version", tmp); + http_header_add(h, "X-Mms-Transaction-ID", octstr_get_cstr(transid)); + http_header_add(h, "X-Mms-Message-Type", mm4_types[mtype].mm4str); + if (msgid) + http_header_add(h, "X-Mms-Message-ID", octstr_get_cstr(msgid)); + http_header_add(h, "X-Mms-Request-Status-Code", status); + http_header_add(h, "Sender", octstr_get_cstr(sender)); + http_header_add(h, "To", octstr_get_cstr(to)); + + mime_replace_headers(m, h); + http_destroy_headers(h); + + mm_send_to_email(to, sender, octstr_imm(""), msgid, m, 0, + &err, sendmail_cmd, + myhostname); + if (err) { + mms_warning(0, "MM4", NULL, "send.RES reported: %s!", octstr_get_cstr(err)); + octstr_destroy(err); + } + mime_entity_destroy(m); + + return 0; +} + +static Octstr *handle_msg(MIMEEntity *mm, Octstr *from, List *to, MmscGrp *mmc) +{ + char *err = NULL; + List *headers, *h2; + Octstr *mm4_type; + Octstr *transid = NULL, *orig_sys = NULL, *ack = NULL, *res = NULL, *me = NULL, *rstatus = NULL; + int i, mtype = -1, mm1_type = -1, mm7type; + MmsMsg *msg = NULL; + Octstr *qdir = NULL, *mmc_id = NULL, *value = NULL, *msgid = NULL; + + Octstr *xproxy = mmc != NULL && octstr_str_compare(mmc->mmsc_url, "*") != 0 ? mmc->mmsc_url : NULL; + + /* Taken largely from mmsfromeamil.c */ + /* Take the entity, recode it --> remove base64 stuff, split headers. */ + unbase64_mimeparts(mm); + unpack_mimeheaders(mm); + + /* Delete some headers... */ + headers = mime_entity_headers(mm); + http_header_remove_all(headers, "Received"); + http_header_remove_all(headers, "X-MimeOLE"); + http_header_remove_all(headers, "X-Mailer"); + + /* rebuild headers, removing nasty looking ones. */ + h2 = http_create_empty_headers(); + for (i = 0; i= 0 || + octstr_case_search(name, octstr_imm("mailscanner"), 0) >= 0) + goto loop; + + http_header_add(h2, octstr_get_cstr(name), octstr_get_cstr(value)); + loop: + octstr_destroy(name); + octstr_destroy(value); + } + http_destroy_headers(headers); + headers = h2; + + /* Look for MM4 headers... */ + mm4_type = http_header_value(headers, octstr_imm("X-Mms-Message-Type")); + ack = http_header_value(headers, octstr_imm("X-Mms-Ack-Request")); + rstatus = http_header_value(headers, octstr_imm("X-Mms-Request-Status-Code")); + + if ((transid = http_header_value(headers, octstr_imm("X-Mms-Transaction-ID"))) == NULL) + transid = octstr_create("001"); + /* get originator system. */ + if ((orig_sys = http_header_value(headers, octstr_imm("X-Mms-Originator-System"))) == NULL) + orig_sys = http_header_value(headers, octstr_imm("Sender")); + + if ((msgid = http_header_value(headers, octstr_imm("X-Mms-Message-ID"))) == NULL) + msgid = http_header_value(headers, octstr_imm("Message-ID")); + + strip_quoted_string(msgid); + strip_quoted_string(transid); + + + debug("mmsbox.MM4receive", 0, + "Received [message type: %s] [transaction id: %s] [msgid: %s]", + mm4_type ? octstr_get_cstr(mm4_type) : "", + transid ? octstr_get_cstr(transid) : "", + msgid ? octstr_get_cstr(msgid) : ""); + + /* ... and remove non-essential ones */ + http_header_remove_all(headers, "X-Mms-3GPP-MMS-Version"); + http_header_remove_all(headers, "MIME-Version"); + http_header_remove_all(headers, "X-Mms-Message-ID"); + http_header_remove_all(headers, "Message-ID"); + http_header_remove_all(headers, "X-Mms-Ack-Request"); + http_header_remove_all(headers, "X-Mms-Originator-System"); + + http_header_remove_all(headers, "Sender"); + + /* msgid was there, put it back in proper form. */ + if (msgid) + http_header_add(headers, "Message-ID", octstr_get_cstr(msgid)); + + fixup_addresses(headers); + + + if (mm4_type) { + unsigned char *x = NULL; + Octstr *y; + int i; + + http_header_remove_all(headers, "X-Mms-Message-Type"); + for (i = 0; mm4_types[i].mm4str; i++) + if (octstr_str_case_compare(mm4_type, mm4_types[i].mm4str) == 0) { + mtype = i; + mm1_type = mm4_types[i].mm1_type; + x = mms_message_type_to_cstr(mm1_type); + break; + } + + if (x) { + http_header_add(headers, "X-Mms-Message-Type", (char *)x); + if (orig_sys == NULL) /* Make it up! */ + orig_sys = octstr_format("system-user@%S", + xproxy ? xproxy : octstr_imm("unknown")); + } else { + octstr_destroy(mm4_type); + mm4_type = NULL; /* So that we assume normal message below. */ + } + + if ((y = http_header_value(headers, octstr_imm("X-Mms-MM-Status-Code"))) != NULL) { + /* This field is different on MM1. */ + http_header_remove_all(headers, "X-Mms-MM-Status-Code"); + http_header_add(headers, "X-Mms-Status", octstr_get_cstr(y)); + octstr_destroy(y); + } + } + if (mm4_type == NULL) { /* else assume a normal send message. */ + http_header_add(headers, "X-Mms-Message-Type", "m-send-req"); + mm1_type = MMS_MSGTYPE_SEND_REQ; + mtype = MM4_FORWARD_REQ; + } + + mime_replace_headers(mm, headers); + http_destroy_headers(headers); + + /* Now convert from mime to MMS message, if we should */ + if (mm1_type >= 0) { + if ((msg = mms_frommime(mm)) == NULL) { + mms_error(0, "MM4", mmc ? mmc->id : NULL, "Unable to parse Message!"); + MMSC_ISSUE_ALARM(mmc ? mmc : NULL, MMSBOX_ALARM_MM4_PARSING_FAILURE, 3); + res = NULL; + + goto done; + } else + MMSC_CLEAR_ALARM(mmc ? mmc : NULL, MMSBOX_ALARM_MM4_PARSING_FAILURE); + } else + msg = NULL; + + me = octstr_format("system-user@%S", myhostname); + + qdir = get_mmsbox_queue_dir(from, to, mmc, &mmc_id); /* get routing info. */ + switch(mtype) { + case MM4_FORWARD_REQ: + { + Octstr *qf; + Octstr *dreport = mms_get_header_value(msg, octstr_imm("X-Mms-Delivery-Report")); + Octstr *subject = mms_get_header_value(msg, octstr_imm("Subject")); + int dlr; + + if (dreport && + octstr_case_compare(dreport, octstr_imm("Yes")) == 0) + dlr = 1; + else + dlr = 0; + + qf = qfs->mms_queue_add(from, to, subject, mmc ? mmc->id : NULL, mmc_id, + 0, time(NULL) + default_msgexpiry, msg, NULL, + NULL, NULL, + NULL, NULL, + NULL, + dlr, + octstr_get_cstr(qdir), + "MM7/MM4-IN", + NULL); + if (qf) { + res = mms_make_msgid(octstr_get_cstr(qf), NULL); + mms_log("Received", from, to, -1, res, NULL, mmc->id, "MMSBox", octstr_imm("smtp"), NULL); + err = "Ok"; + 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(dreport); + octstr_destroy(subject); + octstr_destroy(qf); + } + break; + case MM4_DELIVERY_REPORT_REQ: + { + Octstr *qf; + Octstr *value2 = NULL, *rr_uri = NULL; + List *rqh = http_create_empty_headers(); + + value = mms_get_header_value(msg, octstr_imm("X-Mms-Status")); + value2 = mms_get_header_value(msg, octstr_imm("X-Mbuni-Orig-Message-ID")); + + + rr_uri = mmsbox_get_report_info(msg, mmc, mmc_id, "delivery-report", + value, rqh, NULL, 0, msgid); + if (value2 && mmc_id == NULL) + http_header_add(rqh, "X-Mbuni-Orig-Message-ID", octstr_get_cstr(value2)); + + qf = qfs->mms_queue_add(from, to, NULL, + mmc ? mmc->id : NULL, mmc_id, + 0, time(NULL) + default_msgexpiry, msg, NULL, + NULL, NULL, + rr_uri, NULL, + rqh, + 0, + octstr_get_cstr(qdir), + "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"; + } + + octstr_destroy(qf); + octstr_destroy(value2); + octstr_destroy(rr_uri); + http_destroy_headers(rqh); + } + break; + + case MM4_READ_REPLY_REPORT_REQ: + { + Octstr *qf; + Octstr *value2 = NULL, *rr_uri = NULL; + List *rqh = http_create_empty_headers(); + + value = mms_get_header_value(msg, octstr_imm("X-Mms-Read-Status")); + value2 = mms_get_header_value(msg, octstr_imm("X-Mbuni-Orig-Message-ID")); + + rr_uri = mmsbox_get_report_info(msg, mmc, mmc_id, "read-report", + value, rqh, NULL, 0, msgid); + if (value2 && mmc_id == NULL) + http_header_add(rqh, "X-Mbuni-Orig-Message-ID", octstr_get_cstr(value2)); + + + qf = qfs->mms_queue_add(from, to, NULL, + mmc->id,mmc_id, + 0, time(NULL) + default_msgexpiry, msg, NULL, + NULL, NULL, + rr_uri, NULL, + rqh, + 0, + octstr_get_cstr(qdir), + "MM7/MM4-IN", + NULL); + if (qf) { + mms_log("Received RR", from, to, -1, msgid, value, mmc->id, "MMSBox", octstr_imm("smtp"), NULL); + res = octstr_duplicate(qf); + err = "Ok"; + MMSC_CLEAR_ALARM(mmc, MMSBOX_ALARM_QUEUE_WRITE_ERROR); + } else { + err = "Error-network-problem"; + MMSC_ISSUE_ALARM(mmc, MMSBOX_ALARM_QUEUE_WRITE_ERROR, 4); + } + octstr_destroy(qf); + octstr_destroy(value2); + octstr_destroy(rr_uri); + http_destroy_headers(rqh); + + } + + break; + case MM4_FORWARD_RES: + case MM4_READ_REPLY_REPORT_RES: + case MM4_DELIVERY_REPORT_RES: /* remove corresponding queue entry. */ + /* Do nothing */ + break; + default: + mms_warning(0, "MM4", xproxy, "Unexpected message type: %s", + mm4_type ? octstr_get_cstr(mm4_type) : "not given!"); + break; + } + + mm7type = mm7_msgtype_to_soaptype(mm1_type,1); + if (mm7type >= 0) /* Issue event call back */ + mmsbox_event_cb(mmc->id, mm7type, 1, octstr_imm("1.0"), 200, + mms_msgsize(msg), 0, from, + to && gwlist_len(to) > 0 ? gwlist_get(to,0) : NULL, + msgid, transid, NULL, value); + + /* respond to the sender as necessary. */ + 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)); + + 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); + } + octstr_destroy(mm4_type); + octstr_destroy(transid); + octstr_destroy(orig_sys); + octstr_destroy(msgid); + + octstr_destroy(rstatus); + octstr_destroy(ack); + + octstr_destroy(me); + + octstr_destroy(mmc_id); + octstr_destroy(value); + mms_destroy(msg); + +done: + + return res; +} + +static void clean_address(Octstr **addr, int *isphone, Octstr **xproxy) +{ + int i; + + octstr_strip_blanks(*addr); + *isphone = 1; + if ((i = octstr_search_char(*addr, '<', 0)) >= 0) { + octstr_delete(*addr, 0, i+1); + + i = octstr_search_char(*addr, '>', 0); + if (i > 0) + octstr_delete(*addr, i, octstr_len(*addr)); + + } + /* Find number type */ + i = octstr_case_search(*addr, octstr_imm("/TYPE="), 0); + if (i>0) { + int j = octstr_search_char(*addr, '@', 0); + if (j > i) { /* we have @, remove it */ + *xproxy = octstr_copy(*addr, j+1, octstr_len(*addr)); + octstr_delete(*addr, j, octstr_len(*addr)); + } + } else if (isphonenum(*addr)) /* Add the TYPE element if missing. */ + octstr_append(*addr, octstr_imm("/TYPE=PLMN")); + else { + i = octstr_search_char(*addr, '@', 0); + if (i<0) + octstr_format_append(*addr, "@unknown"); + else if (*xproxy == NULL) + *xproxy = octstr_copy(*addr, i+1, octstr_len(*addr)); + *isphone = 0; + } + /* clean the number. */ + if (*isphone) + _mms_fixup_address(addr, + octstr_get_cstr(unified_prefix), + strip_prefixes, 1); + +} + +static void smtp_process(int fd, Octstr *ip) +{ + enum smtp_state_t {MLISTEN, MFROM, MTO, MDATA,MERROR}; + int i, state = MLISTEN; + Connection *c = conn_wrap_fd(fd,0); + Octstr *from = NULL; + MmscGrp *mmc = NULL; + List *to = NULL; + Octstr *body = NULL; + MIMEEntity *m = NULL; + Octstr *line; + + socket_set_blocking(fd,1); /* Because we want each line as it comes */ + + /* Issue greeting */ + line = octstr_format("220 %S SMTP Mbuni %s\r\n", myhostname, MMSC_VERSION); + conn_write(c, line); + octstr_destroy(line); + + do { + Octstr *res; + Octstr *cmd = NULL, *arg = NULL; + int stop, max_size; + + line = conn_read_line(c); + if (line == NULL) + state = MERROR; + else if (state != MDATA) { + i = octstr_search_char(line, ' ', 0); + if (i > 0) { + cmd = octstr_copy(line, 0, i); + arg = octstr_copy(line, i+1, octstr_len(line)); + } else { + cmd = octstr_copy(line, 0, octstr_len(line)); + arg = octstr_create(""); + } + octstr_strip_blanks(cmd); + octstr_strip_blanks(arg); + } + switch(state) { + + case MLISTEN: + if (octstr_str_case_compare(cmd, "HELO") == 0) + conn_write(c, octstr_imm("250 Hello and welcome\r\n")); /* ... and stay in same state */ + else if (octstr_str_case_compare(cmd, "MAIL") == 0) { /* Sender */ + if ((i = octstr_case_search(arg, octstr_imm("FROM:"), 0)) < 0) /* No From? */ + conn_write(c, octstr_imm("500 Error. Missing FROM:\r\n")); + else { + int isphone = 1; + Octstr *xproxy = NULL; + from = octstr_copy(arg, i+5, octstr_len(arg)); + + 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); + + /* 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); + } + } else + conn_write(c, octstr_imm("500 Error.\r\n")); + break; + + case MTO: + if (octstr_str_case_compare(cmd, "DATA") == 0) { + if (gwlist_len(to) == 0) { + conn_write(c, octstr_imm("421 No recipients? Go away!\r\n")); + state = MERROR; + } else { + state = MDATA; + conn_write(c, octstr_imm("354 Proceed\r\n")); + body = octstr_create(""); + } + } else if (octstr_str_case_compare(cmd, "RCPT") != 0) /* recipient */ + conn_write(c, octstr_imm("500 send recipient please\r\n")); /* ... and stay in same state */ + else if ((i = octstr_case_search(arg, octstr_imm("TO:"), 0)) < 0) /* No To? */ + conn_write(c, octstr_imm("500 send TO field\r\n")); /* ... and stay in same state */ + else { /* Got it. Clean it up */ + Octstr *xto = octstr_copy(arg, i+3, octstr_len(arg)); + int isphone = 1; + Octstr *xproxy = NULL; + + clean_address(&xto, &isphone, &xproxy); + + if (mmc && !mmc->strip_domain && isphone && xproxy) + octstr_format_append(from, "@%S", xproxy); + + if (xproxy == NULL) + conn_write(c, octstr_imm("500 send correct recipient please\r\n")); /* ... and stay in same state */ + else { /* Stay in same state */ + conn_write(c, octstr_imm("250 Ok\r\n")); /* Accept recipient */ + if (to == NULL) + to = gwlist_create(); + gwlist_append(to, xto); + xto = NULL; + } + octstr_destroy(xproxy); + octstr_destroy(xto); + } + break; + case MDATA: + stop = 0; + max_size = (mmc ? mmc->max_pkt_size : DEFAULT_MAX_PKT_SIZE); + do { + if (octstr_get_char(line, 0) == '.') { + if (octstr_get_char(line, 1) != '.') { + stop = 1; + goto end_loop; + } else + octstr_delete(line, 0, 1); /* Remove period */ + } + + if (octstr_len(body) < max_size) + octstr_format_append(body, "%S\r\n", line); + else if (octstr_len(body) == max_size) + octstr_append_char(body, ' '); /* So we exceed length */ + end_loop: + octstr_destroy(line); + line = NULL; /* So no double free below */ + } while (!stop && !conn_eof(c) && (line = conn_read_line(c)) != NULL); + + if (octstr_len(body) > max_size) { + conn_write(c, octstr_imm("452 Message too large\r\n")); + state = MERROR; + goto loop; + } + + /* We got message, time to process it */ + if ((m = mime_octstr_to_entity(body)) == NULL) { + conn_write(c, octstr_imm("501 Invalid MIME content\r\n")); + state = MERROR; + goto loop; + } else { + octstr_destroy(body); /* Release space */ + body = NULL; + } + + if ((res = handle_msg(m, from, to, mmc)) != NULL) { + Octstr *x = octstr_format("250 Ok: %S\r\n", res); + + conn_write(c, x); + octstr_destroy(x); + octstr_destroy(res); + } else + conn_write(c, octstr_imm("451 Invalid message content\r\n")); + state = MERROR; /* Not really, but we gotta go */ + break; + default: + /* Do nothing */ + break; + } + + loop: + octstr_destroy(cmd); + octstr_destroy(arg); + octstr_destroy(line); + } while (state != MERROR); + + octstr_destroy(body); + octstr_destroy(from); + gwlist_destroy(to, (void *)octstr_destroy); + if (m) + mime_entity_destroy(m); + + conn_destroy(c); + if (mmc) + return_mmsc_conn(mmc); + return ; +} + +struct mm4_req_t { + Octstr *ip; + int fd; +}; + +static List *slist = NULL; /* Request list */ + +static void smtp_thread(void *unused) +{ + struct mm4_req_t *m; + + while ((m = gwlist_consume(slist)) != NULL) { + smtp_process(m->fd, m->ip); + octstr_destroy(m->ip); + gw_free(m); + } +} + +void mm4_receive_func(int *sock) +{ + int i, fd, tcount = 0; + Octstr *ip; + /* Start the threads, then receive requests, build, go */ + slist = gwlist_create(); + + gwlist_add_producer(slist); + + for (i = 0; i < maxthreads; i++) + if (gwthread_create((void *)smtp_thread, NULL) >= 0) + tcount++; + if (tcount > 0) + while (!rstop && ((fd = gw_accept(*sock, &ip)) >= 0 || + errno == EINTR)) { + struct mm4_req_t *m; + + if (fd < 0) + continue; + + m = gw_malloc(sizeof *m); + m->ip = ip; + m->fd = fd; + + gwlist_produce(slist, m); + } + else + mms_error(0, "MM4", NULL, "Failed to start SMTP listener threads: %s!", strerror(errno)); + gwlist_remove_producer(slist); + + gwthread_join_every((void *)smtp_thread); + + gwlist_destroy(slist, NULL); + +} diff --git a/mbuni/mmsbox/mmsbox.h b/mbuni/mmsbox/mmsbox.h index 8ff9be5..5dd2d92 100644 --- a/mbuni/mmsbox/mmsbox.h +++ b/mbuni/mmsbox/mmsbox.h @@ -25,6 +25,7 @@ Octstr *mmsbox_get_report_info(MmsMsg *m, MmscGrp *mmsc, Octstr *out_mmc_id, Octstr *msgid); void mmsc_receive_func(MmscGrp *m); void mmsbox_outgoing_queue_runner(volatile sig_atomic_t *rstop); +void mm4_receive_func(int *sock); /* Just a convenience, should go away in future! */ #define mmsbox_url_fetch_content mms_url_fetch_content diff --git a/mbuni/mmsbox/mmsbox_cfg.c b/mbuni/mmsbox/mmsbox_cfg.c index 5ba1691..197023d 100644 --- a/mbuni/mmsbox/mmsbox_cfg.c +++ b/mbuni/mmsbox/mmsbox_cfg.c @@ -23,6 +23,7 @@ #include "mmsbox_cfg.h" #include "mms_queue.h" #include "mmsbox_resolve_shell.h" +#include "mmsbox.h" #define WAIT_TIME 0.2 @@ -54,11 +55,13 @@ static List *mmsc_del_list = NULL; /* List of items to be deleted. */ /* admin handler variables. */ static long admin_port; static long admin_thread = -1; +static long mm4_thread = -1; static Octstr *admin_pass = NULL; static Octstr *admin_allow_ip = NULL; static Octstr *admin_deny_ip = NULL; - +static long mm4_port; +static int mm4_sock; struct SendMmsPortInfo sendmms_port = {-1}; @@ -269,6 +272,19 @@ int mms_load_mmsbox_settings(struct mCfgImpFuncs *cfg_funcs, Octstr *init, sendmms_port.allow_ip = mms_cfg_get(cfg, grp, octstr_imm("allow-ip")); sendmms_port.deny_ip = mms_cfg_get(cfg, grp, octstr_imm("deny-ip")); + + /* Get MM4 port */ + mms_cfg_get_int(cfg, grp, octstr_imm("mm4-port"), &mm4_port); + if (mm4_port > 0 && (mm4_sock = make_server_socket(mm4_port, NULL)) >= 0 && + (mm4_thread = gwthread_create((void *)mm4_receive_func, &mm4_sock)) < 0) { + mms_error(0, "mmsbox", NULL, "Failed to start MM4 server thread: %s", strerror(errno)); + mm4_port = 0; + + if (mm4_sock >= 0) + close(mm4_sock); + } else + hmon->register_port(mm4_port); + /* load the filter if any. */ if ((mt_filter = _mms_load_module(cfg, grp, "mmsbox-mt-filter-library", "mmsbox_mt_filter", NULL)) != NULL) mms_info(0, "mmsbox", NULL, "Loaded MT Filter [%s]", mt_filter->name); @@ -525,12 +541,14 @@ static void mmsbox_stop_mmsc_conn_real(MmscGrp *mmc) { if (mmc->type == CUSTOM_MMSC && mmc->fns - && mmc->custom_started) { + && mmc->started) { mmc->fns->stop_conn(mmc->data); - mmc->custom_started = 0; - } else if (mmc->incoming.port > 0) { + mmc->started = 0; + } else if (mmc->type == MM4_MMSC) + mmc->started = 0; + else if (mmc->incoming.port > 0) { http_close_port(mmc->incoming.port); - hmon->unregister_port(mmc->incoming.port); + hmon->unregister_port(mmc->incoming.port); MMSC_ISSUE_ALARM(mmc, MMSBOX_ALARM_HTTP_DOWN, 1); if (mmc->threadid >= 0) gwthread_join(mmc->threadid); @@ -546,9 +564,17 @@ static void mmsbox_start_mmsc_conn(MmscGrp *m, List *errors, List *warnings) if (m->fns == NULL || m->fns->start_conn(m, qfs, unified_prefix, strip_prefixes, &m->data) != 0) { WARNING("MMSBox: Failed to start custom MMSC [%s]", octstr_get_cstr(m->id)); - m->custom_started = 0; + m->started = 0; } else - m->custom_started = 1; + m->started = 1; + } else if (m->type == MM4_MMSC) { + if (mm4_port <= 0) /* Can't start */ + WARNING("MMSBox: Ca not start MM4 MMSC since MM4 port is not open" + " MMSC %s: %s!", + octstr_get_cstr(m->id), + strerror(errno)); + else + m->started = 1; } else { if (m->incoming.port > 0 && http_open_port(m->incoming.port, m->incoming.ssl) < 0) { @@ -615,7 +641,14 @@ static MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, List *warnings, List m->incoming.allow_ip = mms_cfg_get(cfg, x, octstr_imm("allow-ip")); m->incoming.deny_ip = mms_cfg_get(cfg, x, octstr_imm("deny-ip")); + + if (mms_cfg_get_bool(cfg, x, octstr_imm("strip-domain"), &m->strip_domain) < 0) + m->strip_domain = 1; + + if (mms_cfg_get_int(cfg,x, octstr_imm("maximum-request-size"), &m->max_pkt_size) < 0 || + m->max_pkt_size <= 0) + m->max_pkt_size = DEFAULT_MAX_PKT_SIZE; mms_info(0, "mmsbox", NULL,"Loaded MMSC[%s], allow=[%s], deny=[%s] group_id=[%s]", octstr_get_cstr(m->id), octstr_get_cstr(m->incoming.allow_ip), @@ -641,6 +674,8 @@ static MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, List *warnings, List m->type = EAIF_MMSC; else if (octstr_case_compare(type, octstr_imm("soap")) == 0) m->type = SOAP_MMSC; + else if (octstr_case_compare(type, octstr_imm("mm4")) == 0) + m->type = MM4_MMSC; else if (octstr_case_compare(type, octstr_imm("http")) == 0) m->type = HTTP_MMSC; else if (octstr_case_compare(type, octstr_imm("custom")) == 0) { @@ -743,6 +778,29 @@ static void delete_stale_mmsc(int delete_all) } } +MmscGrp *mmsbox_get_mmsc_by_url(Octstr *mmc_url) +{ + List *l = dict_keys(mmscs); + Octstr *key; + MmscGrp *mmc = NULL; + if (l) + while ((key = gwlist_extract_first(l)) != NULL) + if ((mmc = dict_get(mmscs, key)) != NULL && + octstr_compare(mmc_url, mmc->mmsc_url) == 0) { + + MMSBOX_MMSC_MARK_INUSE(mmc); /* Vital! */ + octstr_destroy(key); + break; + } else { + mmc = NULL; + octstr_destroy(key); + } + + gwlist_destroy(l, (void *)octstr_destroy); + + return mmc; +} + int mmsbox_stop_mmsc(Octstr *mmc_id) { MmscGrp *mmc = dict_remove(mmscs, mmc_id); /* remove it so no one else can get it. */ @@ -762,12 +820,19 @@ int mmsbox_stop_mmsc(Octstr *mmc_id) int mmsbox_start_mmsc(Octstr *mmc_id) { int ret; - MmscGrp *mmc = dict_get(mmscs, mmc_id); /* remove it so no one else can get it. */ + mCfgGrp *m; List *l = gwlist_create(), *r = gwlist_create(); - if (mmc == NULL) - return -1; - mmsbox_start_mmsc_conn(mmc, l, r); + + gw_assert(cfg); + m = mms_get_multi_by_field(cfg, + octstr_imm("mmsc"), + octstr_imm("id"), + mmc_id); + if (m == NULL) + return -1; + + start_mmsc_from_conf(cfg, m, l, r); ret = gwlist_len(l) > 0 ? -1 : 0; gwlist_destroy(l, (void *)octstr_destroy); @@ -864,6 +929,7 @@ done: void mmsbox_settings_cleanup(void) { + rstop = 1; delete_stale_mmsc(1); /* eventually we will destroy the object. For now, we only cleanup queue module. */ @@ -878,6 +944,15 @@ void mmsbox_settings_cleanup(void) gwthread_join(admin_thread); mms_info(0, "mmsbox", NULL,"Admin port on %d, shutdown", (int)admin_port); } + + if (mm4_port > 0 && mm4_sock >= 0) { + close(mm4_sock); + + if (mm4_thread >= 0) { + gwthread_wakeup(mm4_thread); + gwthread_join(mm4_thread); + } + } cdrfs->cleanup(); mms_event_logger_cleanup(); mms_cfg_destroy(cfg); /* only delete at end of session. */ @@ -968,6 +1043,8 @@ static void append_mmsc_status(Octstr *rbody, MmscGrp *m, List *warnings) typ = "SOAP"; else if (m->type == EAIF_MMSC) typ = "EAIF"; + else if (m->type == MM4_MMSC) + typ = "MM4"; else if (m->type == CUSTOM_MMSC) typ = "CUSTOM"; else @@ -1006,7 +1083,7 @@ static void append_mmsc_status(Octstr *rbody, MmscGrp *m, List *warnings) strcat(ubuf, tmp); } - if (m->type != CUSTOM_MMSC) + if (m->type != CUSTOM_MMSC && m->type != MM4_MMSC) sprintf(xport, "%d", (int)m->incoming.port); else sprintf(xport, "n/a"); diff --git a/mbuni/mmsbox/mmsbox_cfg.h b/mbuni/mmsbox/mmsbox_cfg.h index 22b0de6..ffdfd42 100644 --- a/mbuni/mmsbox/mmsbox_cfg.h +++ b/mbuni/mmsbox/mmsbox_cfg.h @@ -31,6 +31,7 @@ enum MmsBoxAlarms { MMSBOX_ALARM_MM7_PARSING_FAILURE, MMSBOX_ALARM_MM7_NON_200_RESULT, MMSBOX_ALARM_RETRIEVE_MMS_ERROR, + MMSBOX_ALARM_MM4_PARSING_FAILURE, MMSBOX_ALARM_MAX_ALARM /* Must be last one */ }; @@ -48,7 +49,7 @@ typedef struct MmscGrp { } incoming; /* user, pass, port (and whether SSL) that MMSC uses to connect to us. */ Octstr *allowed_prefix, *denied_prefix; Octstr *allowed_sender_prefix, *denied_sender_prefix; - enum {UNKNOWN_MMSC = -1, CUSTOM_MMSC, SOAP_MMSC, EAIF_MMSC, HTTP_MMSC} type; /* type of connection. */ + enum {UNKNOWN_MMSC = -1, CUSTOM_MMSC, SOAP_MMSC, EAIF_MMSC, MM4_MMSC, HTTP_MMSC} type; /* type of connection. */ double throughput; /* Max send rate. */ long threadid; /* handler thread. */ @@ -65,8 +66,7 @@ typedef struct MmscGrp { MmsBoxMmscFuncs *fns; /* pointer to functions for handling this mmsc connection type */ Octstr *settings; /* settings for the above module. */ void *data; /* data for above module. */ - int custom_started; /* set to 1 if custom mmc started. */ - + int started; /* Whether it is active */ unsigned long mt_pdus; /* number of MT PDUs since start. */ unsigned long mo_pdus; /* number of MO PDUs since start. */ unsigned long mt_errors; /* number of MT errors since start */ @@ -78,8 +78,13 @@ typedef struct MmscGrp { time_t last_alarm[MMSBOX_ALARM_MAX_ALARM]; int use_count; /* use counter. */ time_t delete_after; /* used to control deletion of object -- not ver clean, but... */ + + long max_pkt_size; + + int strip_domain; /* MM4 only */ } MmscGrp; +#define DEFAULT_MAX_PKT_SIZE 1024*1024 #define MMSBOX_MMSC_MARK_INUSE(mmc) do {\ mutex_lock((mmc)->mutex); \ @@ -229,7 +234,7 @@ int mmsbox_stop_mmsc(Octstr *mmc); int mmsbox_start_mmsc(Octstr *mmc_id); - +MmscGrp *mmsbox_get_mmsc_by_url(Octstr *mmc_url); void mmsbox_stop_all_mmsc_conn(void); typedef struct MmsBoxHTTPClientInfo { HTTPClient *client; diff --git a/mbuni/mmsc/mmsfromemail.c b/mbuni/mmsc/mmsfromemail.c index 1f04292..d29848d 100644 --- a/mbuni/mmsc/mmsfromemail.c +++ b/mbuni/mmsc/mmsfromemail.c @@ -22,21 +22,7 @@ static Octstr *xto; static Octstr *xproxy; enum {TPLMN, TEMAIL, TOTHER} ttype; -/* MM4 message types. */ -enum {MM4_FORWARD_REQ = 0, MM4_FORWARD_RES, MM4_READ_REPLY_REPORT_REQ, - MM4_READ_REPLY_REPORT_RES, MM4_DELIVERY_REPORT_REQ, MM4_DELIVERY_REPORT_RES}; -static struct { - char *mm4str; - int mm1_type; -} mm4_types[] = { - {"MM4_forward.REQ", MMS_MSGTYPE_SEND_REQ}, - {"MM4_forward.RES",-1}, - {"MM4_read_reply_report.REQ", MMS_MSGTYPE_READ_REC_IND}, - {"MM4_read_reply_report.RES",-1}, - {"MM4_delivery_report.REQ",MMS_MSGTYPE_DELIVERY_IND}, - {"MM4_delivery_report.RES",-1}, - {NULL} -}; + /* above indexed by types! */ static int find_own(int i, int argc, char *argv[]); @@ -45,10 +31,9 @@ static void fixup_recipient(Octstr **host); static void fixup_sender(void); static void fixup_addresses(List *headers); -static void send_mm4_res(int mtype, Octstr *to, Octstr *sender, Octstr *transid, char *status, Octstr *msgid, - Octstr *sendmail_cmd); - -static void strip_quotes(Octstr *s); +static void send_mm4_res(int mtype, Octstr *to, Octstr *sender, + Octstr *transid, char *status, Octstr *msgid, + Octstr *sendmail_cmd); static List *proxyrelays; static int no_strip = 0, strip_type = 0; @@ -619,44 +604,13 @@ static void fixup_sender(void) octstr_format_append(xfrom, "@%S", xproxy); } -static void fixup_address_type(List *headers, char *hdr) -{ - List *l; - int i, n; - - l = http_header_find_all(headers, hdr); - - http_header_remove_all(headers,hdr); - for (i = 0, n = gwlist_len(l); iunified_prefix), settings->strip_prefixes); + fixup_address_type(headers, "From", + octstr_get_cstr(settings->unified_prefix), settings->strip_prefixes); } static void send_mm4_res(int mtype, Octstr *to, Octstr *sender, Octstr *transid, char *status, Octstr *msgid, @@ -692,18 +646,3 @@ static void send_mm4_res(int mtype, Octstr *to, Octstr *sender, Octstr *transid, } mime_entity_destroy(m); } - -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); -} -